Annotation of hatari/src/debug/profile.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * Hatari - profile.c
                      3:  * 
1.1.1.3 ! root        4:  * Copyright (C) 2010-2013 by Eero Tamminen
1.1       root        5:  *
1.1.1.3 ! root        6:  * This file is distributed under the GNU General Public License, version 2
        !             7:  * or at your option any later version. Read the file gpl.txt for details.
1.1       root        8:  *
1.1.1.3 ! root        9:  * profile.c - profile caller info handling and debugger parsing functions
1.1       root       10:  */
                     11: const char Profile_fileid[] = "Hatari profile.c : " __DATE__ " " __TIME__;
                     12: 
                     13: #include <stdio.h>
1.1.1.3 ! root       14: #include <assert.h>
        !            15: #include <inttypes.h>
1.1       root       16: #include "main.h"
1.1.1.3 ! root       17: #include "version.h"
        !            18: #include "debugui.h"
1.1       root       19: #include "debug_priv.h"
1.1.1.3 ! root       20: #include "configuration.h"
        !            21: #include "clocks_timings.h"
        !            22: #include "evaluate.h"
1.1       root       23: #include "profile.h"
1.1.1.3 ! root       24: #include "profile_priv.h"
1.1       root       25: #include "symbols.h"
                     26: 
                     27: 
1.1.1.3 ! root       28: /* ------------------ CPU/DSP caller information handling ----------------- */
1.1       root       29: 
1.1.1.3 ! root       30: static const struct {
        !            31:        char chr;
        !            32:        calltype_t bit;
        !            33:        const char *info;
        !            34: } flaginfo[] = {
        !            35:        { 'u', CALL_UNKNOWN,    "unknown PC change" },
        !            36:        { 'n', CALL_NEXT,       "PC moved to next instruction", },
        !            37:        { 'b', CALL_BRANCH,     "branch/jump" },
        !            38:        { 's', CALL_SUBROUTINE, "subroutine call" },
        !            39:        { 'r', CALL_SUBRETURN,  "return from subroutine" },
        !            40:        { 'e', CALL_EXCEPTION,  "exception" },
        !            41:        { 'x', CALL_EXCRETURN,  "return from exception" }
        !            42: };
        !            43: 
        !            44: /**
        !            45:  * compare function for qsort() to sort caller data by calls
        !            46:  */
        !            47: static int cmp_callers(const void *c1, const void *c2)
        !            48: {
        !            49:        Uint32 calls1 = ((const caller_t*)c1)->calls;
        !            50:        Uint32 calls2 = ((const caller_t*)c2)->calls;
        !            51:        if (calls1 > calls2) {
        !            52:                return -1;
1.1       root       53:        }
1.1.1.3 ! root       54:        if (calls1 < calls2) {
        !            55:                return 1;
1.1       root       56:        }
1.1.1.3 ! root       57:        return 0;
1.1       root       58: }
                     59: 
                     60: /**
1.1.1.3 ! root       61:  * output caller counter information
1.1       root       62:  */
1.1.1.3 ! root       63: static bool output_counter_info(FILE *fp, counters_t *counter)
1.1       root       64: {
1.1.1.3 ! root       65:        if (!counter->count) {
1.1       root       66:                return false;
                     67:        }
1.1.1.3 ! root       68:        /* number of calls needs to be first and rest must be in the same order as
        !            69:         * they're in the profile disassembly (count of instructions, etc...).
        !            70:         */
        !            71:        fprintf(fp, " %"PRIu64"/%"PRIu64"/%"PRIu64"",
        !            72:                counter->calls, counter->count, counter->cycles);
        !            73:        if (counter->misses) {
        !            74:                /* these are only with specific WinUAE CPU core */
        !            75:                fprintf(fp, "/%"PRIu64"", counter->misses);
        !            76:        }
        !            77:        return true;
1.1       root       78: }
                     79: 
                     80: /**
1.1.1.3 ! root       81:  * output caller call counts, call type(s) and costs
1.1       root       82:  */
1.1.1.3 ! root       83: static void output_caller_info(FILE *fp, caller_t *info, Uint32 *typeaddr)
1.1       root       84: {
1.1.1.3 ! root       85:        int k, typecount;
        !            86: 
        !            87:        fprintf(fp, "0x%x = %d", info->addr, info->calls);
        !            88:        if (info->flags) {      /* calltypes supported? */
        !            89:                fputc(' ', fp);
        !            90:                typecount = 0;
        !            91:                for (k = 0; k < ARRAYSIZE(flaginfo); k++) {
        !            92:                        if (info->flags & flaginfo[k].bit) {
        !            93:                                fputc(flaginfo[k].chr, fp);
        !            94:                                typecount++;
        !            95:                        }
        !            96:                }
        !            97:                if (typecount > 1) {
        !            98:                        *typeaddr = info->addr;
        !            99:                }
1.1       root      100:        }
1.1.1.3 ! root      101:        if (output_counter_info(fp, &(info->all))) {
        !           102:                output_counter_info(fp, &(info->own));
        !           103:                if (info->calls != info->own.calls) {
        !           104:                        fprintf(stderr, "WARNING: mismatch between function 0x%x call count %d and own call cost %"PRIu64"!\n",
        !           105:                               info->addr, info->calls, info->own.calls);
        !           106:                }
1.1       root      107:        }
1.1.1.3 ! root      108:        fputs(", ", fp);
1.1       root      109: }
                    110: 
1.1.1.3 ! root      111: /*
        !           112:  * Show collected CPU/DSP callee/caller information.
        !           113:  *
        !           114:  * Hint: As caller info list is based on number of loaded symbols,
        !           115:  * load only text symbols to save memory & make things faster...
1.1       root      116:  */
1.1.1.3 ! root      117: void Profile_ShowCallers(FILE *fp, int sites, callee_t *callsite, const char * (*addr2name)(Uint32, Uint64 *))
1.1       root      118: {
1.1.1.3 ! root      119:        int i, j, countissues, countdiff;
        !           120:        const char *name;
        !           121:        caller_t *info;
        !           122:        Uint64 total;
        !           123:        Uint32 addr, typeaddr;
        !           124: 
        !           125:        /* legend */
        !           126:        fputs("# <callee>: <caller1> = <calls> <types>[ <inclusive/totals>[ <exclusive/totals>]], <caller2> ..., <callee name>", fp);
        !           127:        fputs("\n# types: ", fp);
        !           128:        for (i = 0; i < ARRAYSIZE(flaginfo); i++) {
        !           129:                fprintf(fp, "%c = %s, ", flaginfo[i].chr, flaginfo[i].info);
        !           130:        }
        !           131:        fputs("\n# totals: calls/instructions/cycles/misses\n", fp);
        !           132: 
        !           133:        countdiff = 0;
        !           134:        countissues = 0;
        !           135:        for (i = 0; i < sites; i++, callsite++) {
        !           136:                addr = callsite->addr;
        !           137:                if (!addr) {
        !           138:                        continue;
        !           139:                }
        !           140:                name = addr2name(addr, &total);
        !           141:                fprintf(fp, "0x%x: ", callsite->addr);
        !           142: 
        !           143:                typeaddr = 0;
        !           144:                info = callsite->callers;
        !           145:                qsort(info, callsite->count, sizeof(*info), cmp_callers);
        !           146:                for (j = 0; j < callsite->count; j++, info++) {
        !           147:                        if (!info->calls) {
        !           148:                                break;
        !           149:                        }
        !           150:                        total -= info->calls;
        !           151:                        output_caller_info(fp, info, &typeaddr);
        !           152:                }
        !           153:                if (name) {
        !           154:                        fprintf(fp, "%s", name);
        !           155:                }
        !           156:                fputs("\n", fp);
        !           157:                if (total) {
        !           158: #if DEBUG
        !           159:                        fprintf(stderr, "WARNING: %llu differences in call and instruction counts for '%s'!\n", total, name);
        !           160: #endif
        !           161:                        countdiff += total;
        !           162:                        countissues++;
        !           163:                }
        !           164:                if (typeaddr) {
        !           165:                        fprintf(stderr, "WARNING: different types of calls (at least) from 0x%x (to 0x%x),\n\t has its codechanged during profiling?\n",
        !           166:                                typeaddr, callsite->addr);
        !           167:                }
        !           168:        }
        !           169:        if (countissues) {
        !           170:                if (countdiff <= 2 && countissues == countdiff) {
        !           171:                        fprintf(stderr, "WARNING: callcount mismatches (%d calls) with address instruction\n\t counts in %d cases, most likely profile start & end.\n",
        !           172:                                countdiff, countissues);
        !           173:                } else {
        !           174:                        /* profiler bug: some (address?) mismatch in recording instruction counts and call counts */
        !           175:                        fprintf(stderr, "ERROR: callcount mismatches with address instruction counts\n\t(%d in total) detected in %d cases!\n",
        !           176:                                countdiff, countissues);
        !           177:                }
1.1       root      178:        }
                    179: }
                    180: 
                    181: 
                    182: /**
1.1.1.3 ! root      183:  * add second counter values to first counters
1.1       root      184:  */
1.1.1.3 ! root      185: static void add_counter_costs(counters_t *dst, counters_t *src)
1.1       root      186: {
1.1.1.3 ! root      187:        dst->calls += src->calls;
        !           188:        dst->count += src->count;
        !           189:        dst->cycles += src->cycles;
        !           190:        dst->misses += src->misses;
1.1       root      191: }
                    192: 
                    193: /**
1.1.1.3 ! root      194:  * set first counter values to their difference from a reference value
1.1       root      195:  */
1.1.1.3 ! root      196: static void set_counter_diff(counters_t *dst, counters_t *ref)
1.1       root      197: {
1.1.1.3 ! root      198:        dst->calls = ref->calls - dst->calls;
        !           199:        dst->count = ref->count - dst->count;
        !           200:        dst->cycles = ref->cycles - dst->cycles;
        !           201:        dst->misses = ref->misses - dst->misses;
1.1       root      202: }
                    203: 
                    204: /**
1.1.1.3 ! root      205:  * add called (callee) function costs to caller information
1.1       root      206:  */
1.1.1.3 ! root      207: static void add_callee_cost(callee_t *callsite, callstack_t *stack)
1.1       root      208: {
1.1.1.3 ! root      209:        caller_t *info = callsite->callers;
        !           210:        counters_t owncost;
        !           211:        int i;
1.1       root      212: 
1.1.1.3 ! root      213:        for (i = 0; i < callsite->count; i++, info++) {
        !           214:                if (info->addr == stack->caller_addr) {
        !           215:                        /* own cost for callee is its child (out) costs
        !           216:                         * deducted from full (all) costs
        !           217:                         */
        !           218:                        owncost = stack->out;
        !           219:                        set_counter_diff(&owncost, &(stack->all));
        !           220:                        add_counter_costs(&(info->own), &owncost);
        !           221:                        add_counter_costs(&(info->all), &(stack->all));
        !           222:                        return;
        !           223:                }
1.1       root      224:        }
1.1.1.3 ! root      225:        /* cost is only added for updated callers,
        !           226:         * so they should always exist
        !           227:         */
        !           228:        fprintf(stderr, "ERROR: trying to add costs to non-existing 0x%x caller of 0x%x!\n",
        !           229:                stack->caller_addr, callsite->addr);
        !           230:        assert(0);
1.1       root      231: }
                    232: 
                    233: 
1.1.1.3 ! root      234: static void add_caller(callee_t *callsite, Uint32 pc, Uint32 prev_pc, calltype_t flag)
1.1       root      235: {
1.1.1.3 ! root      236:        caller_t *info;
        !           237:        int i, count;
1.1       root      238: 
1.1.1.3 ! root      239:        /* need to store real call addresses as symbols can change
        !           240:         * after profiling has been stopped
        !           241:         */
        !           242:        info = callsite->callers;
        !           243:        if (!info) {
        !           244:                info = calloc(1, sizeof(*info));
        !           245:                if (!info) {
        !           246:                        fprintf(stderr, "ERROR: caller info alloc failed!\n");
        !           247:                        return;
1.1       root      248:                }
1.1.1.3 ! root      249:                /* first call to this address, save address */
        !           250:                callsite->addr = pc;
        !           251:                callsite->callers = info;
        !           252:                callsite->count = 1;
1.1       root      253:        }
1.1.1.3 ! root      254:        /* how many caller slots are currently allocated? */
        !           255:        count = callsite->count;
        !           256:        for (;;) {
        !           257:                for (i = 0; i < count; i++, info++) {
        !           258:                        if (info->addr == prev_pc) {
        !           259:                                info->flags |= flag;
        !           260:                                info->calls++;
        !           261:                                return;
        !           262:                        }
        !           263:                        if (!info->addr) {
        !           264:                                /* empty slot */
        !           265:                                info->addr = prev_pc;
        !           266:                                info->flags |= flag;
        !           267:                                info->calls = 1;
        !           268:                                return;
        !           269:                        }
1.1       root      270:                }
1.1.1.3 ! root      271:                /* not enough, double caller slots */
        !           272:                count *= 2;
        !           273:                info = realloc(callsite->callers, count * sizeof(*info));
        !           274:                if (!info) {
        !           275:                        fprintf(stderr, "ERROR: caller info alloc failed!\n");
        !           276:                        return;
1.1       root      277:                }
1.1.1.3 ! root      278:                memset(info + callsite->count, 0, callsite->count * sizeof(*info));
        !           279:                callsite->callers = info;
        !           280:                callsite->count = count;
1.1       root      281:        }
                    282: }
                    283: 
                    284: /**
1.1.1.3 ! root      285:  * Add information about called symbol, and if it was subroutine
        !           286:  * call, add it to stack of functions which total costs are tracked.
        !           287:  * callinfo.return_pc needs to be set before invoking this if the call
        !           288:  * is of type CALL_SUBROUTINE.
1.1       root      289:  */
1.1.1.3 ! root      290: void Profile_CallStart(int idx, callinfo_t *callinfo, Uint32 prev_pc, calltype_t flag, Uint32 pc, counters_t *totalcost)
1.1       root      291: {
1.1.1.3 ! root      292:        callstack_t *stack;
        !           293:        int count;
1.1       root      294: 
1.1.1.3 ! root      295:        if (unlikely(idx >= callinfo->sites)) {
        !           296:                fprintf(stderr, "ERROR: number of symbols increased during profiling (%d > %d)!\n", idx, callinfo->sites);
1.1       root      297:                return;
                    298:        }
                    299: 
1.1.1.3 ! root      300:        add_caller(callinfo->site + idx, pc, prev_pc, flag);
1.1       root      301: 
1.1.1.3 ! root      302:        /* subroutine call which will return? */
        !           303:        if (flag != CALL_SUBROUTINE) {
        !           304:                /* no, some other call type */
1.1       root      305:                return;
                    306:        }
1.1.1.3 ! root      307:        /* yes, add it to call stack */
1.1       root      308: 
1.1.1.3 ! root      309:        if (unlikely(!callinfo->count)) {
        !           310:                /* initial stack alloc, can be a bit larger */
        !           311:                count = 8;
        !           312:                stack = calloc(count, sizeof(*stack));
        !           313:                if (!stack) {
        !           314:                        fputs("ERROR: callstack alloc failed!\n", stderr);
        !           315:                        return;
1.1       root      316:                }
1.1.1.3 ! root      317:                callinfo->stack = stack;
        !           318:                callinfo->count = count;
1.1       root      319: 
1.1.1.3 ! root      320:        } else if (unlikely(callinfo->depth+1 >= callinfo->count)) {
        !           321:                /* need to alloc more stack space for new call? */
        !           322:                count = callinfo->count * 2;
        !           323:                stack = realloc(callinfo->stack, count * sizeof(*stack));
        !           324:                if (!stack) {
        !           325:                        fputs("ERROR: callstack alloc failed!\n", stderr);
        !           326:                        return;
1.1       root      327:                }
1.1.1.3 ! root      328:                memset(stack + callinfo->count, 0, callinfo->count * sizeof(*stack));
        !           329:                callinfo->stack = stack;
        !           330:                callinfo->count = count;
1.1       root      331:        }
                    332: 
1.1.1.3 ! root      333:        /* only first instruction can be undefined */
        !           334:        assert(callinfo->return_pc != PC_UNDEFINED || !callinfo->depth);
1.1       root      335: 
1.1.1.3 ! root      336:        /* called function */
        !           337:        stack = &(callinfo->stack[callinfo->depth++]);
1.1       root      338: 
1.1.1.3 ! root      339:        /* store current running totals & zero subcall costs */
        !           340:        stack->all = *totalcost;
        !           341:        memset(&(stack->out), 0, sizeof(stack->out));
1.1       root      342: 
1.1.1.3 ! root      343:        /* set subroutine call information */
        !           344:        stack->ret_addr = callinfo->return_pc;
        !           345:        stack->callee_idx = idx;
        !           346:        stack->caller_addr = prev_pc;
        !           347:        stack->callee_addr = pc;
1.1       root      348: 
1.1.1.3 ! root      349:        /* record call to this into costs... */
        !           350:        totalcost->calls++;
1.1       root      351: }
                    352: 
                    353: /**
1.1.1.3 ! root      354:  * If it really was subcall (function) return, store returned function
        !           355:  * costs and update callinfo->return_pc value.  Return address of
        !           356:  * the instruction which did the returned call.
1.1       root      357:  */
1.1.1.3 ! root      358: Uint32 Profile_CallEnd(callinfo_t *callinfo, counters_t *totalcost)
1.1       root      359: {
1.1.1.3 ! root      360:        callstack_t *stack;
1.1       root      361: 
1.1.1.3 ! root      362:        assert(callinfo->depth);
1.1       root      363: 
1.1.1.3 ! root      364:        /* remove call info from stack */
        !           365:        callinfo->depth--;
1.1       root      366: 
1.1.1.3 ! root      367:        /* callinfo->depth points now to to-be removed item */
        !           368:        stack = &(callinfo->stack[callinfo->depth]);
1.1       root      369: 
1.1.1.3 ! root      370:        if (unlikely(stack->caller_addr == PC_UNDEFINED)) {
        !           371:                /* return address can be undefined only for
        !           372:                 * first profiled instruction, i.e. only for
        !           373:                 * function at top of stack
        !           374:                 */
        !           375:                assert(!callinfo->depth);
        !           376:        } else {
        !           377:                /* full cost is original global cost (in ->all)
        !           378:                 * deducted from current global (total) cost
        !           379:                 */
        !           380:                set_counter_diff(&(stack->all), totalcost);
        !           381:                add_callee_cost(callinfo->site + stack->callee_idx, stack);
1.1       root      382:        }
                    383: 
1.1.1.3 ! root      384:        /* if current function had a parent:
        !           385:         * - start tracking that
        !           386:         * - add full cost of current function to parent's outside costs
        !           387:         */
        !           388:        if (callinfo->depth) {
        !           389:                callstack_t *parent = stack - 1;
        !           390:                callinfo->return_pc = parent->ret_addr;
        !           391:                add_counter_costs(&(parent->out), &(stack->all));
        !           392:        } else {
        !           393:                callinfo->return_pc = PC_UNDEFINED;
1.1       root      394:        }
                    395: 
1.1.1.3 ! root      396:        /* where the returned function was called from */
        !           397:        return stack->caller_addr;
        !           398: }
1.1       root      399: 
                    400: /**
1.1.1.3 ! root      401:  * Add costs to all functions still in call stack
1.1       root      402:  */
1.1.1.3 ! root      403: void Profile_FinalizeCalls(callinfo_t *callinfo, counters_t *totalcost, const char* (*get_symbol)(Uint32 addr))
1.1       root      404: {
1.1.1.3 ! root      405:        Uint32 addr;
        !           406:        if (!callinfo->depth) {
1.1       root      407:                return;
                    408:        }
1.1.1.3 ! root      409:        fprintf(stderr, "Finalizing costs for %d non-returned functions:\n", callinfo->depth);
        !           410:        while (callinfo->depth > 0) {
        !           411:                Profile_CallEnd(callinfo, totalcost);
        !           412:                addr = callinfo->stack[callinfo->depth].callee_addr;
        !           413:                fprintf(stderr, "- 0x%x: %s (return = 0x%x)\n", addr, get_symbol(addr),
        !           414:                        callinfo->stack[callinfo->depth].ret_addr);
1.1       root      415:        }
                    416: }
                    417: 
                    418: /**
1.1.1.3 ! root      419:  * Show current profile stack
1.1       root      420:  */
1.1.1.3 ! root      421: static void Profile_ShowStack(bool forDsp)
1.1       root      422: {
1.1.1.3 ! root      423:        int i;
        !           424:        Uint32 addr;
        !           425:        callinfo_t *callinfo;
        !           426:        const char* (*get_symbol)(Uint32 addr);
        !           427: 
        !           428:        if (forDsp) {
        !           429:                Profile_DspGetCallinfo(&callinfo, &get_symbol);
        !           430:        } else {
        !           431:                Profile_CpuGetCallinfo(&callinfo, &get_symbol);
1.1       root      432:        }
1.1.1.3 ! root      433:        if (!callinfo->depth) {
        !           434:                fprintf(stderr, "Empty stack.\n");
        !           435:                return;
1.1       root      436:        }
                    437: 
1.1.1.3 ! root      438:        for (i = 0; i < callinfo->depth; i++) {
        !           439:                addr = callinfo->stack[i].callee_addr;
        !           440:                fprintf(stderr, "- 0x%x: %s (return = 0x%x)\n", addr,
        !           441:                        get_symbol(addr), callinfo->stack[i].ret_addr);
1.1       root      442:        }
                    443: }
                    444: 
                    445: /**
1.1.1.3 ! root      446:  * Allocate & set initial callinfo structure information
1.1       root      447:  */
1.1.1.3 ! root      448: int Profile_AllocCallinfo(callinfo_t *callinfo, int count, const char *name)
1.1       root      449: {
1.1.1.3 ! root      450:        callinfo->sites = count;
        !           451:        if (count) {
        !           452:                /* alloc & clear new data */
        !           453:                callinfo->site = calloc(count, sizeof(callee_t));
        !           454:                if (callinfo->site) {
        !           455:                        printf("Allocated %s profile callsite buffer for %d symbols.\n", name, count);
        !           456:                        callinfo->prev_pc = callinfo->return_pc = PC_UNDEFINED;
        !           457:                } else {
        !           458:                        fprintf(stderr, "ERROR: callesite buffer alloc failed!\n");
        !           459:                        callinfo->sites = 0;
        !           460:                }
1.1       root      461:        }
1.1.1.3 ! root      462:        return callinfo->sites;
1.1       root      463: }
                    464: 
                    465: /**
1.1.1.3 ! root      466:  * Free all callinfo structure information
1.1       root      467:  */
1.1.1.3 ! root      468: void Profile_FreeCallinfo(callinfo_t *callinfo)
1.1       root      469: {
1.1.1.3 ! root      470:        int i;
        !           471:        if (callinfo->sites) {
        !           472:                callee_t *site = callinfo->site;
        !           473:                for (i = 0; i < callinfo->sites; i++, site++) {
        !           474:                        if (site->callers) {
        !           475:                                free(site->callers);
        !           476:                        }
1.1       root      477:                }
1.1.1.3 ! root      478:                free(callinfo->site);
        !           479:                if (callinfo->stack) {
        !           480:                        free(callinfo->stack);
        !           481:                }
        !           482:                memset(callinfo, 0, sizeof(*callinfo));
1.1       root      483:        }
                    484: }
                    485: 
                    486: 
                    487: /* ------------------- command parsing ---------------------- */
                    488: 
                    489: /**
                    490:  * Readline match callback to list profile subcommand names.
                    491:  * STATE = 0 -> different text from previous one.
                    492:  * Return next match or NULL if no matches.
                    493:  */
                    494: char *Profile_Match(const char *text, int state)
                    495: {
                    496:        static const char *names[] = {
1.1.1.3 ! root      497:                "addresses", "callers", "counts", "cycles", "misses",
        !           498:                "off", "on", "save", "stack", "stats", "symbols"
1.1       root      499:        };
                    500:        static int i, len;
                    501:        
                    502:        if (!state)
                    503:        {
                    504:                /* first match */
                    505:                i = 0;
                    506:                len = strlen(text);
                    507:        }
                    508:        /* next match */
                    509:        while (i < ARRAYSIZE(names)) {
                    510:                if (strncasecmp(names[i++], text, len) == 0)
                    511:                        return (strdup(names[i-1]));
                    512:        }
                    513:        return NULL;
                    514: }
                    515: 
                    516: const char Profile_Description[] =
1.1.1.3 ! root      517:        "<on|off|stats|counts|cycles|misses|symbols|callers|stack|addresses|save> [count|address|file]\n"
        !           518:        "\t'on' & 'off' enable and disable profiling.  Data is collected\n"
        !           519:        "\tuntil debugger is entered again at which point you get profiling\n"
        !           520:        "\tstatistics ('stats') summary.\n"
        !           521:        "\n"
        !           522:        "\tThen you can ask for list of the PC addresses, sorted either by\n"
        !           523:        "\texecution 'counts', used 'cycles' or cache 'misses'. First can\n"
        !           524:        "\tbe limited just to named addresses with 'symbols'.  Optional\n"
        !           525:        "\tcount will limit how many items will be shown.\n"
        !           526:        "\n"
        !           527:        "\t'addresses' lists the profiled addresses in order, with the\n"
        !           528:        "\tinstructions (currently) residing at them.  By default this\n"
        !           529:        "\tstarts from the first executed instruction, or you can\n"
        !           530:        "\tspecify the starting address.\n"
        !           531:        "\n"
        !           532:        "\t'callers' shows (raw) caller information for addresses which\n"
        !           533:        "\thad symbol(s) associated with them.  'stack' shows the currect\n"
        !           534:        "\tprofile stack, this is useful only with :noinit breakpoints.\n"
        !           535:        "\n"
        !           536:        "\tProfile information can be saved with 'save'.";
1.1       root      537: 
                    538: 
                    539: /**
1.1.1.3 ! root      540:  * Save profiling information for CPU or DSP.
        !           541:  */
        !           542: static bool Profile_Save(const char *fname, bool bForDsp)
        !           543: {
        !           544:        FILE *out;
        !           545:        Uint32 freq;
        !           546:        const char *proc, *core;
        !           547:        if (!(out = fopen(fname, "w"))) {
        !           548:                fprintf(stderr, "ERROR: opening '%s' for writing failed!\n", fname);
        !           549:                perror(NULL);
        !           550:                return false;
        !           551:        }
        !           552:        if (bForDsp) {
        !           553:                freq = MachineClocks.DSP_Freq;
        !           554:                proc = "DSP";
        !           555:        } else {
        !           556:                freq = MachineClocks.CPU_Freq;
        !           557:                proc = "CPU";
        !           558:        }
        !           559: #if ENABLE_WINUAE_CPU
        !           560:        core = "WinUAE";
        !           561: #else
        !           562:        core = "OldUAE";
        !           563: #endif
        !           564:        fprintf(out, "Hatari %s profile (%s, %s CPU core)\n", proc, PROG_NAME, core);
        !           565:        fprintf(out, "Cycles/second:\t%u\n", freq);
        !           566:        if (bForDsp) {
        !           567:                Profile_DspSave(out);
        !           568:        } else {
        !           569:                Profile_CpuSave(out);
        !           570:        }
        !           571:        fclose(out);
        !           572:        return true;
        !           573: }
        !           574: 
        !           575: /**
1.1       root      576:  * Command: CPU/DSP profiling enabling, exec stats, cycle and call stats.
1.1.1.3 ! root      577:  * Returns DEBUGGER_CMDDONE or DEBUGGER_CMDCONT.
1.1       root      578:  */
1.1.1.3 ! root      579: int Profile_Command(int nArgc, char *psArgs[], bool bForDsp)
1.1       root      580: {
                    581:        static int show = 16;
1.1.1.3 ! root      582:        Uint32 *disasm_addr;
1.1       root      583:        bool *enabled;
1.1.1.3 ! root      584: 
1.1       root      585:        if (nArgc > 2) {
                    586:                show = atoi(psArgs[2]);
1.1.1.3 ! root      587:        }       
1.1       root      588:        if (bForDsp) {
1.1.1.3 ! root      589:                Profile_DspGetPointers(&enabled, &disasm_addr);
1.1       root      590:        } else {
1.1.1.3 ! root      591:                Profile_CpuGetPointers(&enabled, &disasm_addr);
1.1       root      592:        }
1.1.1.3 ! root      593: 
        !           594:        /* continue or explicit addresses command? */
        !           595:        if (nArgc < 2 || strcmp(psArgs[1], "addresses") == 0) {
        !           596:                Uint32 lower, upper = 0;
        !           597:                if (nArgc > 2) {
        !           598:                        if (Eval_Range(psArgs[2], &lower, &upper, false) < 0) {
        !           599:                                return DEBUGGER_CMDDONE;
        !           600:                        }
        !           601:                } else {
        !           602:                        lower = *disasm_addr;
        !           603:                }
        !           604:                if (bForDsp) {
        !           605:                        *disasm_addr = Profile_DspShowAddresses(lower, upper, stdout);
        !           606:                } else {
        !           607:                        *disasm_addr = Profile_CpuShowAddresses(lower, upper, stdout);
        !           608:                }
        !           609:                return DEBUGGER_CMDCONT;
        !           610: 
        !           611:        } else if (strcmp(psArgs[1], "on") == 0) {
1.1       root      612:                *enabled = true;
                    613:                fprintf(stderr, "Profiling enabled.\n");
1.1.1.3 ! root      614: 
        !           615:        } else if (strcmp(psArgs[1], "off") == 0) {
1.1       root      616:                *enabled = false;
                    617:                fprintf(stderr, "Profiling disabled.\n");
                    618:        
1.1.1.3 ! root      619:        } else if (strcmp(psArgs[1], "stats") == 0) {
1.1       root      620:                if (bForDsp) {
                    621:                        Profile_DspShowStats();
                    622:                } else {
                    623:                        Profile_CpuShowStats();
                    624:                }
1.1.1.3 ! root      625:        } else if (strcmp(psArgs[1], "misses") == 0) {
        !           626:                if (bForDsp) {
        !           627:                        fprintf(stderr, "Cache misses are recorded only for CPU, not DSP.\n");
        !           628:                } else {
        !           629:                        Profile_CpuShowMisses(show);
        !           630:                }
1.1       root      631:        } else if (strcmp(psArgs[1], "cycles") == 0) {
                    632:                if (bForDsp) {
                    633:                        Profile_DspShowCycles(show);
                    634:                } else {
                    635:                        Profile_CpuShowCycles(show);
                    636:                }
                    637:        } else if (strcmp(psArgs[1], "counts") == 0) {
                    638:                if (bForDsp) {
                    639:                        Profile_DspShowCounts(show, false);
                    640:                } else {
                    641:                        Profile_CpuShowCounts(show, false);
                    642:                }
1.1.1.3 ! root      643:        } else if (strcmp(psArgs[1], "symbols") == 0) {
1.1       root      644:                if (bForDsp) {
                    645:                        Profile_DspShowCounts(show, true);
                    646:                } else {
                    647:                        Profile_CpuShowCounts(show, true);
                    648:                }
1.1.1.3 ! root      649:        } else if (strcmp(psArgs[1], "callers") == 0) {
        !           650:                if (bForDsp) {
        !           651:                        Profile_DspShowCallers(stdout);
        !           652:                } else {
        !           653:                        Profile_CpuShowCallers(stdout);
        !           654:                }
        !           655:        } else if (strcmp(psArgs[1], "stack") == 0) {
        !           656:                Profile_ShowStack(bForDsp);
        !           657:        } else if (strcmp(psArgs[1], "save") == 0) {
        !           658:                Profile_Save(psArgs[2], bForDsp);
1.1       root      659:        } else {
                    660:                DebugUI_PrintCmdHelp(psArgs[0]);
                    661:        }
1.1.1.3 ! root      662:        return DEBUGGER_CMDDONE;
1.1       root      663: }

unix.superglobalmegacorp.com

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