Annotation of previous_trunk/src/debug/profile.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Hatari - profile.c
                      3:  * 
                      4:  * Copyright (C) 2010 by Eero Tamminen
                      5:  *
                      6:  * This file is distributed under the GNU Public License, version 2 or at
                      7:  * your option any later version. Read the file gpl.txt for details.
                      8:  *
                      9:  * profile.c - functions for profiling CPU and DSP and showing the results.
                     10:  */
                     11: const char Profile_fileid[] = "Hatari profile.c : " __DATE__ " " __TIME__;
                     12: 
                     13: #include <stdio.h>
                     14: #include "host.h"
                     15: #include "main.h"
                     16: #include "debug_priv.h"
                     17: #include "m68000.h"
                     18: #include "profile.h"
                     19: #include "nextMemory.h"
                     20: #include "symbols.h"
                     21: 
                     22: #define MAX_PROFILE_VALUE 0xFFFFFFFF
                     23: 
                     24: typedef struct {
                     25:        Uint32 count;   /* how many times this address is used */
                     26:        Uint32 cycles;  /* what address this is (for sorting) */
                     27: } profile_item_t;
                     28: 
                     29: typedef struct {
                     30:        unsigned long long all_cycles, all_count;
                     31:        Uint32 max_cycles, max_cycles_addr;
                     32:        Uint32 max_count, max_count_addr;
                     33:        Uint32 lowest, highest; /* active address range within memory area */
                     34:        Uint32 active;          /* number of active addresses */
                     35: } profile_area_t;
                     36: 
                     37: static struct {
                     38:        unsigned long long all_cycles, all_count;
                     39:        Uint32 size;          /* number of allocated profile data items */
                     40:        profile_item_t *data; /* profile data items */
                     41:        profile_area_t ram;   /* normal RAM stats */
                     42:        profile_area_t rom;   /* cartridge ROM stats */
                     43:        profile_area_t tos;   /* ROM TOS stats */
                     44:        Uint32 active;        /* number of active data items in all areas */
                     45:        Uint32 *sort_arr;     /* data indexes used for sorting */
                     46:        bool enabled;         /* true when profiling enabled */
                     47: } cpu_profile;
                     48: 
                     49: 
                     50: #define DSP_PROFILE_ARR_SIZE 0x10000
                     51: 
                     52: static struct {
                     53:        profile_item_t *data; /* profile data */
                     54:        profile_area_t ram;   /* normal RAM stats */
                     55:        Uint16 *sort_arr;     /* data indexes used for sorting */
                     56:        bool enabled;         /* true when profiling enabled */
                     57: } dsp_profile;
                     58: 
                     59: 
                     60: /* ------------------ CPU profile results ----------------- */
                     61: 
                     62: /**
                     63:  * convert Atari memory address to sorting array profile data index.
                     64:  */
                     65: static inline Uint32 address2index(Uint32 pc)
                     66: {
                     67:        if (unlikely(pc & 1)) {
                     68:                fprintf(stderr, "WARNING: odd CPU profile instruction address 0x%x!\n", pc);
                     69:        }
                     70: //     if (pc >= TosAddress && pc < TosAddress + TosSize) {
                     71:                /* TOS, put it after RAM & ROM data */
                     72: //             pc = pc - TosAddress + STRamEnd + 0x20000;
                     73:        
                     74: //     } else if (pc >= 0xFA0000 && pc < 0xFC0000) {
                     75:                /* ROM, put it after RAM data */
                     76: //             pc = pc - 0xFA0000 + STRamEnd;
                     77: 
                     78: //     } else {
                     79:                /* if in RAM, use as-is */
                     80: //             if (unlikely(pc >= STRamEnd)) {
                     81: //                     fprintf(stderr, "WARNING: 'invalid' CPU PC profile instruction address 0x%x, skipping!\n", pc);
                     82:                        /* extra entry at end reserved for invalid PC values */
                     83: //                     pc = STRamEnd + 0x20000 + TosSize;
                     84: //             }
                     85: //     }
                     86:        /* CPU instructions are at even addresses, save space by halving */
                     87:        return (pc >> 1);
                     88: }
                     89: 
                     90: 
                     91: /**
                     92:  * Get CPU cycles & count for given address.
                     93:  * Return true if data was available and non-zero, false otherwise.
                     94:  */
                     95: bool Profile_CpuAddressData(Uint32 addr, Uint32 *count, Uint32 *cycles)
                     96: {
                     97:        Uint32 idx;
                     98:        if (!cpu_profile.data) {
                     99:                return false;
                    100:        }
                    101:        idx = address2index(addr);
                    102:        *cycles = cpu_profile.data[idx].cycles;
                    103:        *count = cpu_profile.data[idx].count;
                    104:        return (*count > 0);
                    105: }
                    106: 
                    107: 
                    108: /**
                    109:  * convert sorting array profile data index to Atari memory address.
                    110:  */
                    111: static Uint32 index2address(Uint32 idx)
                    112: {
                    113:     return 0;
                    114: }
                    115: 
                    116: 
                    117: /**
                    118:  * Helper to show statistics for specified CPU profile area.
                    119:  */
                    120: static void show_cpu_area_stats(profile_area_t *area)
                    121: {
                    122:        if (!area->active) {
                    123:                fprintf(stderr, "- no activity\n");
                    124:                return;
                    125:        }
                    126:        fprintf(stderr, "- active address range:\n  0x%06x-0x%06x\n",
                    127:                index2address(area->lowest),
                    128:                index2address(area->highest));
                    129:        fprintf(stderr, "- active instruction addresses:\n  %d (%.2f%% of all)\n",
                    130:                area->active,
                    131:                (float)area->active/cpu_profile.active*100);
                    132:        fprintf(stderr, "- executed instructions:\n  %"FMT_ll"d (%.2f%% of all)\n",
                    133:                area->all_count,
                    134:                (float)area->all_count/cpu_profile.all_count*100);
                    135:        fprintf(stderr, "- used cycles:\n  %"FMT_ll"u (%.2f%% of all)\n",
                    136:                area->all_cycles,
                    137:                (float)area->all_cycles/cpu_profile.all_cycles*100);
                    138:        fprintf(stderr, "- address with most cycles:\n  0x%06x, %d cycles (%.2f%% of all in area)\n",
                    139:                index2address(area->max_cycles_addr),
                    140:                area->max_cycles,
                    141:                (float)area->max_cycles/area->all_cycles*100);
                    142:        fprintf(stderr, "- address with most hits:\n  0x%06x, %d hits (%.2f%% of all in area)\n",
                    143:                index2address(area->max_count_addr),
                    144:                area->max_count,
                    145:                (float)area->max_count/area->all_count*100);
                    146:        if (area->max_cycles == MAX_PROFILE_VALUE) {
                    147:                fprintf(stderr, "- Counters OVERFLOW!\n");
                    148:        }
                    149: }
                    150: 
                    151: 
                    152: /**
                    153:  * show CPU area (RAM, ROM, TOS) specific statistics.
                    154:  */
                    155: void Profile_CpuShowStats(void)
                    156: {
                    157: //     fprintf(stderr, "Normal RAM (0-0x%X):\n", STRamEnd);
                    158:        show_cpu_area_stats(&cpu_profile.ram);
                    159: 
                    160:        fprintf(stderr, "Cartridge ROM (0xFA0000-0xFC0000):\n");
                    161:        show_cpu_area_stats(&cpu_profile.rom);
                    162: 
                    163: //     fprintf(stderr, "ROM TOS (0x%X-0x%X):\n", TosAddress, TosAddress+TosSize);
                    164:        show_cpu_area_stats(&cpu_profile.tos);
                    165: }
                    166: 
                    167: 
                    168: /**
                    169:  * compare function for qsort() to sort CPU profile data by descdending
                    170:  * address cycles counts.
                    171:  */
                    172: static int profile_by_cpu_cycles(const void *p1, const void *p2)
                    173: {
                    174:        Uint32 count1 = cpu_profile.data[*(const Uint32*)p1].cycles;
                    175:        Uint32 count2 = cpu_profile.data[*(const Uint32*)p2].cycles;
                    176:        if (count1 > count2) {
                    177:                return -1;
                    178:        }
                    179:        if (count1 < count2) {
                    180:                return 1;
                    181:        }
                    182:        return 0;
                    183: }
                    184: 
                    185: /**
                    186:  * Sort CPU profile data addresses by cycle counts and show the results.
                    187:  */
                    188: void Profile_CpuShowCycles(unsigned int show)
                    189: {
                    190:        unsigned int active;
                    191:        Uint32 *sort_arr, *end, addr;
                    192:        profile_item_t *data = cpu_profile.data;
                    193:        float percentage;
                    194:        Uint32 count;
                    195: 
                    196:        if (!data) {
                    197:                fprintf(stderr, "ERROR: no CPU profiling data available!\n");
                    198:                return;
                    199:        }
                    200: 
                    201:        active = cpu_profile.active;
                    202:        sort_arr = cpu_profile.sort_arr;
                    203:        qsort(sort_arr, active, sizeof(*sort_arr), profile_by_cpu_cycles);
                    204: 
                    205:        printf("addr:\t\tcycles:\n");
                    206:        show = (show < active ? show : active);
                    207:        for (end = sort_arr + show; sort_arr < end; sort_arr++) {
                    208:                addr = index2address(*sort_arr);
                    209:                count = data[*sort_arr].cycles;
                    210:                percentage = 100.0*count/cpu_profile.all_cycles;
                    211:                printf("0x%06x\t%.2f%%\t%d%s\n", addr, percentage, count,
                    212:                       count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    213:        }
                    214:        printf("%d CPU addresses listed.\n", show);
                    215: }
                    216: 
                    217: 
                    218: /**
                    219:  * compare function for qsort() to sort CPU profile data by descdending
                    220:  * address access counts.
                    221:  */
                    222: static int profile_by_cpu_count(const void *p1, const void *p2)
                    223: {
                    224:        Uint32 count1 = cpu_profile.data[*(const Uint32*)p1].count;
                    225:        Uint32 count2 = cpu_profile.data[*(const Uint32*)p2].count;
                    226:        if (count1 > count2) {
                    227:                return -1;
                    228:        }
                    229:        if (count1 < count2) {
                    230:                return 1;
                    231:        }
                    232:        return 0;
                    233: }
                    234: 
                    235: /**
                    236:  * Sort CPU profile data addresses by call counts and show the results.
                    237:  * If symbols are requested and symbols are loaded, show (only) addresses
                    238:  * matching a symbol.
                    239:  */
                    240: void Profile_CpuShowCounts(unsigned int show, bool only_symbols)
                    241: {
                    242:        profile_item_t *data = cpu_profile.data;
                    243:        unsigned int symbols, matched, active;
                    244:        Uint32 *sort_arr, *end, addr;
                    245:        const char *name;
                    246:        float percentage;
                    247:        Uint32 count;
                    248: 
                    249:        if (!data) {
                    250:                fprintf(stderr, "ERROR: no CPU profiling data available!\n");
                    251:                return;
                    252:        }
                    253:        active = cpu_profile.active;
                    254:        show = (show < active ? show : active);
                    255: 
                    256:        sort_arr = cpu_profile.sort_arr;
                    257:        qsort(sort_arr, active, sizeof(*sort_arr), profile_by_cpu_count);
                    258: 
                    259:        if (!only_symbols) {
                    260:                printf("addr:\t\tcount:\n");
                    261:                for (end = sort_arr + show; sort_arr < end; sort_arr++) {
                    262:                        addr = index2address(*sort_arr);
                    263:                        count = data[*sort_arr].count;
                    264:                        percentage = 100.0*count/cpu_profile.all_count;
                    265:                        printf("0x%06x\t%.2f%%\t%d%s\n",
                    266:                               addr, percentage, count,
                    267:                               count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    268:                }
                    269:                printf("%d CPU addresses listed.\n", show);
                    270:                return;
                    271:        }
                    272: 
                    273:        symbols = Symbols_CpuCount();
                    274:        if (!symbols) {
                    275:                fprintf(stderr, "ERROR: no CPU symbols loaded!\n");
                    276:                return;
                    277:        }
                    278:        matched = 0;    
                    279: 
                    280:        printf("addr:\t\tcount:\t\tsymbol:\n");
                    281:        for (end = sort_arr + active; sort_arr < end; sort_arr++) {
                    282: 
                    283:                addr = index2address(*sort_arr);
                    284:                name = Symbols_GetByCpuAddress(addr);
                    285:                if (!name) {
                    286:                        continue;
                    287:                }
                    288:                count = data[*sort_arr].count;
                    289:                percentage = 100.0*count/cpu_profile.all_count;
                    290:                printf("0x%06x\t%.2f%%\t%d\t%s%s\n",
                    291:                       addr, percentage, count, name,
                    292:                       count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    293: 
                    294:                matched++;
                    295:                if (matched >= show || matched >= symbols) {
                    296:                        break;
                    297:                }
                    298:        }
                    299:        printf("%d CPU symbols listed.\n", matched);
                    300: }
                    301: 
                    302: 
                    303: /* ------------------ CPU profile control ----------------- */
                    304: 
                    305: /**
                    306:  * Initialize CPU profiling when necessary.  Return true if profiling.
                    307:  */
                    308: bool Profile_CpuStart(void)
                    309: {
                    310:        if (cpu_profile.sort_arr) {
                    311:                /* remove previous results */
                    312:                free(cpu_profile.sort_arr);
                    313:                free(cpu_profile.data);
                    314:                cpu_profile.sort_arr = NULL;
                    315:                cpu_profile.data = NULL;
                    316:                printf("Freed previous CPU profile buffers.\n");
                    317:        }
                    318:        if (!cpu_profile.enabled) {
                    319:                return false;
                    320:        }
                    321:        /* Shouldn't change within same debug session */
                    322: //     cpu_profile.size = (STRamEnd + 0x20000 + TosSize) / 2;
                    323: 
                    324:        /* Add one entry for catching invalid PC values */
                    325:        cpu_profile.data = calloc(cpu_profile.size+1, sizeof(*cpu_profile.data));
                    326:        if (cpu_profile.data) {
                    327:                printf("Allocated CPU profile buffer (%d MB).\n",
                    328:                       (int)sizeof(*cpu_profile.data)*cpu_profile.size/1024/1024);
                    329:        } else {
                    330:                perror("ERROR, new CPU profile buffer alloc failed");
                    331:                cpu_profile.enabled = false;
                    332:        }
                    333:        return cpu_profile.enabled;
                    334: }
                    335: 
                    336: 
                    337: /**
                    338:  * Update CPU cycle and count statistics for PC address.
                    339:  */
                    340: void Profile_CpuUpdate(void)
                    341: {
                    342: #if 0
                    343:        Uint32 idx, opcode, cycles;
                    344:        
                    345:        idx = address2index(M68000_GetPC());
                    346: 
                    347:        if (likely(cpu_profile.data[idx].count < MAX_PROFILE_VALUE)) {
                    348:                cpu_profile.data[idx].count++;
                    349:        }
                    350:        
                    351:        opcode = get_iword_prefetch (0);
                    352:        cycles = (*cpufunctbl[opcode])(opcode);
                    353:        
                    354:        if (likely(cpu_profile.data[idx].cycles < MAX_PROFILE_VALUE - cycles)) {
                    355:                        cpu_profile.data[idx].cycles += cycles;
                    356:        }
                    357: #endif
                    358: }
                    359: 
                    360: 
                    361: /**
                    362:  * Helper for collecting profile area statistics.
                    363:  */
                    364: static void update_area(Uint32 i, profile_item_t *item, profile_area_t *area)
                    365: {
                    366:        Uint32 cycles, count = item->count;
                    367:        if (!count) {
                    368:                return;
                    369:        }
                    370: 
                    371:        area->all_count += count;
                    372:        if (count > area->max_count) {
                    373:                area->max_count = count;
                    374:                area->max_count_addr = i;
                    375:        }
                    376: 
                    377:        cycles = item->cycles;
                    378:        area->all_cycles += cycles;
                    379:        if (cycles > area->max_cycles) {
                    380:                area->max_cycles = cycles;
                    381:                area->max_cycles_addr = i;
                    382:        }
                    383: 
                    384:        if (i < area->lowest) {
                    385:                area->lowest = i;
                    386:        }
                    387:        area->highest = i;
                    388: 
                    389:        area->active++;
                    390: }
                    391: 
                    392: 
                    393: /**
                    394:  * Stop and process the CPU profiling data; collect stats and
                    395:  * prepare for more optimal sorting.
                    396:  */
                    397: void Profile_CpuStop(void)
                    398: {
                    399:        profile_item_t *item;
                    400:        profile_area_t *area;
                    401:        Uint32 *sort_arr;
                    402:        Uint32 i, active;
                    403: 
                    404:        if (!cpu_profile.enabled) {
                    405:                return;
                    406:        }
                    407:        /* user didn't change RAM or TOS size in the meanwhile? */
                    408: //     assert(cpu_profile.size == (STRamEnd + 0x20000 + TosSize) / 2);
                    409: 
                    410:        /* find lowest and highest addresses executed... */
                    411:        item = cpu_profile.data;
                    412: 
                    413:        /* ...for normal RAM */
                    414:        area = &cpu_profile.ram;
                    415:        memset(area, 0, sizeof(profile_area_t));
                    416:        area->lowest = cpu_profile.size;
                    417: 
                    418: //     for (i = 0; i < STRamEnd/2; i++, item++) {
                    419: //             update_area(i, item, area);
                    420: //     }
                    421: 
                    422:        /* ... for Cartridge ROM */
                    423:        area = &cpu_profile.rom;
                    424:        memset(area, 0, sizeof(profile_area_t));
                    425:        area->lowest = cpu_profile.size;
                    426: 
                    427: //     for (; i < (STRamEnd + 0x20000)/2; i++, item++) {
                    428: //             update_area(i, item, area);
                    429: //     }
                    430: 
                    431:        /* ...for ROM TOS */
                    432:        area = &cpu_profile.tos;
                    433:        memset(area, 0, sizeof(profile_area_t));
                    434:        area->lowest = cpu_profile.size;
                    435: 
                    436:        for (i = 0; i < cpu_profile.size; i++, item++) {
                    437:                update_area(i, item, area);
                    438:        }
                    439: 
                    440:        cpu_profile.all_cycles = cpu_profile.ram.all_cycles + cpu_profile.rom.all_cycles + cpu_profile.tos.all_cycles;
                    441:        cpu_profile.all_count = cpu_profile.ram.all_count + cpu_profile.rom.all_count + cpu_profile.tos.all_count;
                    442: 
                    443:        /* allocate address array for sorting */
                    444:        active = cpu_profile.ram.active + cpu_profile.rom.active + cpu_profile.tos.active;
                    445:        sort_arr = calloc(active, sizeof(*sort_arr));
                    446: 
                    447:        if (!sort_arr) {
                    448:                perror("ERROR: allocating CPU profile address data");
                    449:                free(cpu_profile.data);
                    450:                cpu_profile.data = NULL;
                    451:                return;
                    452:        }
                    453:        printf("Allocated CPU profile address buffer (%d KB).\n",
                    454:               (int)sizeof(*sort_arr)*(active+512)/1024);
                    455:        cpu_profile.sort_arr = sort_arr;
                    456:        cpu_profile.active = active;
                    457: 
                    458:        /* and fill addresses for used instructions... */
                    459:        
                    460:        /* ...for normal RAM */
                    461:        area = &cpu_profile.ram;
                    462:        item = cpu_profile.data + area->lowest;
                    463:        for (i = area->lowest; i <= area->highest; i++, item++) {
                    464:                if (item->count) {
                    465:                        *sort_arr++ = i;
                    466:                }
                    467:        }
                    468: 
                    469:        /* ...for Cartridge ROM */
                    470:        area = &cpu_profile.rom;
                    471:        item = cpu_profile.data + area->lowest;
                    472:        for (i = area->lowest; i <= area->highest; i++, item++) {
                    473:                if (item->count) {
                    474:                        *sort_arr++ = i;
                    475:                }
                    476:        }
                    477: 
                    478:        /* ...for TOS ROM */
                    479:        area = &cpu_profile.tos;
                    480:        item = cpu_profile.data + area->lowest;
                    481:        for (i = area->lowest; i <= area->highest; i++, item++) {
                    482:                if (item->count) {
                    483:                        *sort_arr++ = i;
                    484:                }
                    485:        }
                    486:        //printf("%d/%d/%d\n", area->active, sort_arr-cpu_profile.sort_arr, active);
                    487: 
                    488:        Profile_CpuShowStats();
                    489:        return;
                    490: }
                    491: 
                    492: 
                    493: /* ------------------ DSP profile results ----------------- */
                    494: 
                    495: /**
                    496:  * Get DSP cycles & count for given address.
                    497:  * Return true if data was available and non-zero, false otherwise.
                    498:  */
                    499: bool Profile_DspAddressData(Uint16 addr, Uint32 *count, Uint32 *cycles)
                    500: {
                    501:        if (!dsp_profile.data) {
                    502:                return false;
                    503:        }
                    504:        *cycles = dsp_profile.data[addr].cycles;
                    505:        *count = dsp_profile.data[addr].count;
                    506:        return (*count > 0);
                    507: }
                    508: 
                    509: /**
                    510:  * show DSP specific profile statistics.
                    511:  */
                    512: void Profile_DspShowStats(void)
                    513: {
                    514:        profile_area_t *area = &dsp_profile.ram;
                    515:        fprintf(stderr, "DSP profile statistics (0x0-0xFFFF):\n");
                    516:        if (!area->active) {
                    517:                fprintf(stderr, "- no activity\n");
                    518:                return;
                    519:        }
                    520:        fprintf(stderr, "- active address range:\n  0x%04x-0x%04x\n",
                    521:                area->lowest, area->highest);
                    522:        fprintf(stderr, "- active instruction addresses:\n  %d\n",
                    523:                area->active);
                    524:        fprintf(stderr, "- executed instructions:\n  %"FMT_ll"u\n",
                    525:                area->all_count);
                    526:        fprintf(stderr, "- used cycles:\n  %"FMT_ll"u\n",
                    527:                area->all_cycles);
                    528:        fprintf(stderr, "- address with most cycles:\n  0x%04x, %d cycles (%.2f%% of all)\n",
                    529:                area->max_cycles_addr,
                    530:                area->max_cycles,
                    531:                (float)area->max_cycles/area->all_cycles*100);
                    532:        fprintf(stderr, "- address with most hits:\n  0x%04x, %d hits (%.2f%% of all)\n",
                    533:                area->max_count_addr,
                    534:                area->max_count,
                    535:                (float)area->max_count/area->all_count*100);
                    536:        if (area->max_cycles == MAX_PROFILE_VALUE) {
                    537:                fprintf(stderr, "- Counters OVERFLOW!\n");
                    538:        }
                    539: }
                    540: 
                    541: 
                    542: /**
                    543:  * compare function for qsort() to sort DSP profile data by descdending
                    544:  * address cycles counts.
                    545:  */
                    546: static int profile_by_dsp_cycles(const void *p1, const void *p2)
                    547: {
                    548:        Uint32 count1 = dsp_profile.data[*(const Uint16*)p1].cycles;
                    549:        Uint32 count2 = dsp_profile.data[*(const Uint16*)p2].cycles;
                    550:        if (count1 > count2) {
                    551:                return -1;
                    552:        }
                    553:        if (count1 < count2) {
                    554:                return 1;
                    555:        }
                    556:        return 0;
                    557: }
                    558: 
                    559: /**
                    560:  * Sort DSP profile data addresses by cycle counts and show the results.
                    561:  */
                    562: void Profile_DspShowCycles(unsigned int show)
                    563: {
                    564:        unsigned int active;
                    565:        Uint16 *sort_arr, *end, addr;
                    566:        profile_item_t *data = dsp_profile.data;
                    567:        float percentage;
                    568:        Uint32 count;
                    569: 
                    570:        if (!data) {
                    571:                fprintf(stderr, "ERROR: no DSP profiling data available!\n");
                    572:                return;
                    573:        }
                    574: 
                    575:        active = dsp_profile.ram.active;
                    576:        sort_arr = dsp_profile.sort_arr;
                    577:        qsort(sort_arr, active, sizeof(*sort_arr), profile_by_dsp_cycles);
                    578: 
                    579:        printf("addr:\tcycles:\n");
                    580:        show = (show < active ? show : active);
                    581:        for (end = sort_arr + show; sort_arr < end; sort_arr++) {
                    582:                addr = *sort_arr;
                    583:                count = data[addr].cycles;
                    584:                percentage = 100.0*count/dsp_profile.ram.all_cycles;
                    585:                printf("0x%04x\t%.2f%%\t%d%s\n", addr, percentage, count,
                    586:                       count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    587:        }
                    588:        printf("%d DSP addresses listed.\n", show);
                    589: }
                    590: 
                    591: 
                    592: /**
                    593:  * compare function for qsort() to sort DSP profile data by descdending
                    594:  * address access counts.
                    595:  */
                    596: static int profile_by_dsp_count(const void *p1, const void *p2)
                    597: {
                    598:        Uint32 count1 = dsp_profile.data[*(const Uint16*)p1].count;
                    599:        Uint32 count2 = dsp_profile.data[*(const Uint16*)p2].count;
                    600:        if (count1 > count2) {
                    601:                return -1;
                    602:        }
                    603:        if (count1 < count2) {
                    604:                return 1;
                    605:        }
                    606:        return 0;
                    607: }
                    608: 
                    609: /**
                    610:  * Sort DSP profile data addresses by call counts and show the results.
                    611:  * If symbols are requested and symbols are loaded, show (only) addresses
                    612:  * matching a symbol.
                    613:  */
                    614: void Profile_DspShowCounts(unsigned int show, bool only_symbols)
                    615: {
                    616:        profile_item_t *data = dsp_profile.data;
                    617:        unsigned int symbols, matched, active;
                    618:        Uint16 *sort_arr, *end, addr;
                    619:        const char *name;
                    620:        float percentage;
                    621:        Uint32 count;
                    622: 
                    623:        if (!data) {
                    624:                fprintf(stderr, "ERROR: no DSP profiling data available!\n");
                    625:                return;
                    626:        }
                    627:        active = dsp_profile.ram.active;
                    628:        show = (show < active ? show : active);
                    629: 
                    630:        sort_arr = dsp_profile.sort_arr;
                    631:        qsort(sort_arr, active, sizeof(*sort_arr), profile_by_dsp_count);
                    632: 
                    633:        if (!only_symbols) {
                    634:                printf("addr:\tcount:\n");
                    635:                for (end = sort_arr + show; sort_arr < end; sort_arr++) {
                    636:                        addr = *sort_arr;
                    637:                        count = data[addr].count;
                    638:                        percentage = 100.0*count/dsp_profile.ram.all_count;
                    639:                        printf("0x%04x\t%.2f%%\t%d%s\n",
                    640:                               addr, percentage, count,
                    641:                               count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    642:                }
                    643:                printf("%d DSP addresses listed.\n", show);
                    644:                return;
                    645:        }
                    646: 
                    647:        symbols = Symbols_DspCount();
                    648:        if (!symbols) {
                    649:                fprintf(stderr, "ERROR: no DSP symbols loaded!\n");
                    650:                return;
                    651:        }
                    652:        matched = 0;    
                    653: 
                    654:        printf("addr:\tcount:\t\tsymbol:\n");
                    655:        for (end = sort_arr + active; sort_arr < end; sort_arr++) {
                    656: 
                    657:                addr = *sort_arr;
                    658:                name = Symbols_GetByDspAddress(addr);
                    659:                if (!name) {
                    660:                        continue;
                    661:                }
                    662:                count = data[addr].count;
                    663:                percentage = 100.0*count/dsp_profile.ram.all_count;
                    664:                printf("0x%04x\t%.2f%%\t%d\t%s%s\n",
                    665:                       addr, percentage, count, name,
                    666:                       count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
                    667: 
                    668:                matched++;
                    669:                if (matched >= show || matched >= symbols) {
                    670:                        break;
                    671:                }
                    672:        }
                    673:        printf("%d DSP symbols listed.\n", matched);
                    674: }
                    675: 
                    676: 
                    677: /* ------------------ DSP profile control ----------------- */
                    678: 
                    679: /**
                    680:  * Initialize DSP profiling when necessary.  Return true if profiling.
                    681:  */
                    682: bool Profile_DspStart(void)
                    683: {
                    684:        if (dsp_profile.sort_arr) {
                    685:                /* remove previous results */
                    686:                free(dsp_profile.sort_arr);
                    687:                free(dsp_profile.data);
                    688:                dsp_profile.sort_arr = NULL;
                    689:                dsp_profile.data = NULL;
                    690:                printf("Freed previous DSP profile buffers.\n");
                    691:        }
                    692:        if (!dsp_profile.enabled) {
                    693:                return false;
                    694:        }
                    695: 
                    696:        dsp_profile.data = calloc(DSP_PROFILE_ARR_SIZE, sizeof(*dsp_profile.data));
                    697:        if (dsp_profile.data) {
                    698:                printf("Allocated DSP profile buffer (%d KB).\n",
                    699:                       (int)sizeof(*dsp_profile.data)*DSP_PROFILE_ARR_SIZE/1024);
                    700:        } else {
                    701:                perror("ERROR, new DSP profile buffer alloc failed");
                    702:                dsp_profile.enabled = false;
                    703:        }
                    704:        return dsp_profile.enabled;
                    705: }
                    706: 
                    707: /**
                    708:  * Update DSP cycle and count statistics for PC address.
                    709:  */
                    710: void Profile_DspUpdate(void)
                    711: {
                    712: //     Uint16 pc, cycles;
                    713: 
                    714: //     pc = DSP_GetPC();
                    715: //     if (likely(dsp_profile.data[pc].count < MAX_PROFILE_VALUE)) {
                    716: //             dsp_profile.data[pc].count++;
                    717: //     }
                    718: 
                    719: //     cycles = DSP_GetInstrCycles();
                    720: //     if (likely(dsp_profile.data[pc].cycles < MAX_PROFILE_VALUE - cycles)) {
                    721: //             dsp_profile.data[pc].cycles += cycles;
                    722: //     }
                    723: }
                    724: 
                    725: 
                    726: /**
                    727:  * Stop and process the DSP profiling data; collect stats and
                    728:  * prepare for more optimal sorting.
                    729:  */
                    730: void Profile_DspStop(void)
                    731: {
                    732:        profile_item_t *item;
                    733:        profile_area_t *area;
                    734:        Uint16 *sort_arr;
                    735:        Uint32 i;
                    736: 
                    737:        if (!dsp_profile.enabled) {
                    738:                return;
                    739:        }
                    740:        /* find lowest and highest  addresses executed */
                    741:        item = dsp_profile.data;
                    742:        area = &dsp_profile.ram;
                    743:        memset(area, 0, sizeof(profile_area_t));
                    744:        area->lowest = DSP_PROFILE_ARR_SIZE;
                    745: 
                    746:        for (i = 0; i < DSP_PROFILE_ARR_SIZE; i++, item++) {
                    747:                update_area(i, item, area);
                    748:        }
                    749: 
                    750:        /* allocate address array for sorting */
                    751:        sort_arr = calloc(dsp_profile.ram.active, sizeof(*sort_arr));
                    752: 
                    753:        if (!sort_arr) {
                    754:                perror("ERROR: allocating DSP profile address data");
                    755:                free(dsp_profile.data);
                    756:                dsp_profile.data = NULL;
                    757:                return;
                    758:        }
                    759:        printf("Allocated DSP profile address buffer (%d KB).\n",
                    760:               (int)sizeof(*sort_arr)*(dsp_profile.ram.active+512)/1024);
                    761:        dsp_profile.sort_arr = sort_arr;
                    762: 
                    763:        /* ...and fill addresses for used instructions... */
                    764:        area = &dsp_profile.ram;
                    765:        item = dsp_profile.data + area->lowest;
                    766:        for (i = area->lowest; i <= area->highest; i++, item++) {
                    767:                if (item->count) {
                    768:                        *sort_arr++ = i;
                    769:                }
                    770:        }
                    771:        //printf("%d/%d/%d\n", area->active, sort_arr-dsp_profile.sort_arr, active);
                    772: 
                    773:        Profile_DspShowStats();
                    774:        return;
                    775: }
                    776: 
                    777: 
                    778: /* ------------------- command parsing ---------------------- */
                    779: 
                    780: /**
                    781:  * Readline match callback to list profile subcommand names.
                    782:  * STATE = 0 -> different text from previous one.
                    783:  * Return next match or NULL if no matches.
                    784:  */
                    785: char *Profile_Match(const char *text, int state)
                    786: {
                    787:        static const char *names[] = {
                    788:                "on", "off", "counts", "cycles", "symbols", "stats"
                    789:        };
                    790:        static int i, len;
                    791:        
                    792:        if (!state)
                    793:        {
                    794:                /* first match */
                    795:                i = 0;
                    796:                len = strlen(text);
                    797:        }
                    798:        /* next match */
                    799:        while (i < ARRAYSIZE(names)) {
                    800:                if (strncasecmp(names[i++], text, len) == 0)
                    801:                        return (strdup(names[i-1]));
                    802:        }
                    803:        return NULL;
                    804: }
                    805: 
                    806: const char Profile_Description[] =
                    807:          "<on|off|counts|cycles|symbols|stats> [show count]\n"
                    808:          "\ton & off enable and disable profiling.  Data is collected\n"
                    809:          "\tuntil debugger is entered again after which you can view\n"
                    810:          "\tstatistics about the data or view PC addresses that took\n"
                    811:          "\tmost cycles or functions/symbols called most often.\n"
                    812:          "\tYou can specify how many items are shown at most.";
                    813: 
                    814: 
                    815: /**
                    816:  * Command: CPU/DSP profiling enabling, exec stats, cycle and call stats.
                    817:  * Return for succesful command and false for incorrect ones.
                    818:  */
                    819: bool Profile_Command(int nArgc, char *psArgs[], bool bForDsp)
                    820: {
                    821:        static int show = 16;
                    822:        bool *enabled;
                    823:        
                    824:        if (nArgc < 2) {
                    825:                DebugUI_PrintCmdHelp(psArgs[0]);
                    826:                return true;
                    827:        }
                    828:        if (nArgc > 2) {
                    829:                show = atoi(psArgs[2]);
                    830:        }
                    831:        
                    832:        if (bForDsp) {
                    833:                enabled = &dsp_profile.enabled;
                    834:        } else {
                    835:                enabled = &cpu_profile.enabled;
                    836:        }
                    837:        if (strcmp(psArgs[1], "on") == 0) {
                    838:                *enabled = true;
                    839:                fprintf(stderr, "Profiling enabled.\n");
                    840:                return true;
                    841:        }
                    842:        if (strcmp(psArgs[1], "off") == 0) {
                    843:                *enabled = false;
                    844:                fprintf(stderr, "Profiling disabled.\n");
                    845:                return true;
                    846:        }
                    847:        
                    848:        if (strcmp(psArgs[1], "stats") == 0) {
                    849:                if (bForDsp) {
                    850:                        Profile_DspShowStats();
                    851:                } else {
                    852:                        Profile_CpuShowStats();
                    853:                }
                    854:        } else if (strcmp(psArgs[1], "cycles") == 0) {
                    855:                if (bForDsp) {
                    856:                        Profile_DspShowCycles(show);
                    857:                } else {
                    858:                        Profile_CpuShowCycles(show);
                    859:                }
                    860:        } else if (strcmp(psArgs[1], "counts") == 0) {
                    861:                if (bForDsp) {
                    862:                        Profile_DspShowCounts(show, false);
                    863:                } else {
                    864:                        Profile_CpuShowCounts(show, false);
                    865:                }
                    866:        } else if (strcmp(psArgs[1], "symbols") == 0)   {
                    867:                if (bForDsp) {
                    868:                        Profile_DspShowCounts(show, true);
                    869:                } else {
                    870:                        Profile_CpuShowCounts(show, true);
                    871:                }
                    872:        } else {
                    873:                DebugUI_PrintCmdHelp(psArgs[0]);
                    874:                return false;
                    875:        }
                    876:        return true;
                    877: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.