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