Annotation of previous/src/debug/profile.c, revision 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.