|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.