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