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