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

unix.superglobalmegacorp.com

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