|
|
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: {
1.1.1.2 ! root 354: Uint32 idx, cycles;
1.1 root 355: idx = address2index(M68000_GetPC());
1.1.1.2 ! root 356: assert(idx < cpu_profile.size);
1.1 root 357:
358: if (likely(cpu_profile.data[idx].count < MAX_PROFILE_VALUE)) {
359: cpu_profile.data[idx].count++;
360: }
1.1.1.2 ! root 361: cycles = CurrentInstrCycles + nWaitStateCycles;
1.1 root 362: if (likely(cpu_profile.data[idx].cycles < MAX_PROFILE_VALUE - cycles)) {
363: cpu_profile.data[idx].cycles += cycles;
364: }
365: }
366:
367:
368: /**
369: * Helper for collecting profile area statistics.
370: */
371: static void update_area(Uint32 i, profile_item_t *item, profile_area_t *area)
372: {
373: Uint32 cycles, count = item->count;
374: if (!count) {
375: return;
376: }
377:
378: area->all_count += count;
379: if (count > area->max_count) {
380: area->max_count = count;
381: area->max_count_addr = i;
382: }
383:
384: cycles = item->cycles;
385: area->all_cycles += cycles;
386: if (cycles > area->max_cycles) {
387: area->max_cycles = cycles;
388: area->max_cycles_addr = i;
389: }
390:
391: if (i < area->lowest) {
392: area->lowest = i;
393: }
394: area->highest = i;
395:
396: area->active++;
397: }
398:
399:
400: /**
401: * Stop and process the CPU profiling data; collect stats and
402: * prepare for more optimal sorting.
403: */
404: void Profile_CpuStop(void)
405: {
406: profile_item_t *item;
407: profile_area_t *area;
408: Uint32 *sort_arr;
409: Uint32 i, active;
410:
411: if (!cpu_profile.enabled) {
412: return;
413: }
414: /* user didn't change RAM or TOS size in the meanwhile? */
415: assert(cpu_profile.size == (STRamEnd + 0x20000 + TosSize) / 2);
416:
417: /* find lowest and highest addresses executed... */
418: item = cpu_profile.data;
419:
420: /* ...for normal RAM */
421: area = &cpu_profile.ram;
422: memset(area, 0, sizeof(profile_area_t));
423: area->lowest = cpu_profile.size;
424:
425: for (i = 0; i < STRamEnd/2; i++, item++) {
426: update_area(i, item, area);
427: }
428:
429: /* ... for Cartridge ROM */
430: area = &cpu_profile.rom;
431: memset(area, 0, sizeof(profile_area_t));
432: area->lowest = cpu_profile.size;
433:
434: for (; i < (STRamEnd + 0x20000)/2; i++, item++) {
435: update_area(i, item, area);
436: }
437:
438: /* ...for ROM TOS */
439: area = &cpu_profile.tos;
440: memset(area, 0, sizeof(profile_area_t));
441: area->lowest = cpu_profile.size;
442:
443: for (; i < cpu_profile.size; i++, item++) {
444: update_area(i, item, area);
445: }
446:
447: cpu_profile.all_cycles = cpu_profile.ram.all_cycles + cpu_profile.rom.all_cycles + cpu_profile.tos.all_cycles;
448: cpu_profile.all_count = cpu_profile.ram.all_count + cpu_profile.rom.all_count + cpu_profile.tos.all_count;
449:
450: /* allocate address array for sorting */
451: active = cpu_profile.ram.active + cpu_profile.rom.active + cpu_profile.tos.active;
452: sort_arr = calloc(active, sizeof(*sort_arr));
453:
454: if (!sort_arr) {
455: perror("ERROR: allocating CPU profile address data");
456: free(cpu_profile.data);
457: cpu_profile.data = NULL;
458: return;
459: }
460: printf("Allocated CPU profile address buffer (%d KB).\n",
461: (int)sizeof(*sort_arr)*(active+512)/1024);
462: cpu_profile.sort_arr = sort_arr;
463: cpu_profile.active = active;
464:
465: /* and fill addresses for used instructions... */
466:
467: /* ...for normal RAM */
468: area = &cpu_profile.ram;
469: item = cpu_profile.data + area->lowest;
470: for (i = area->lowest; i <= area->highest; i++, item++) {
471: if (item->count) {
472: *sort_arr++ = i;
473: }
474: }
475:
476: /* ...for Cartridge ROM */
477: area = &cpu_profile.rom;
478: item = cpu_profile.data + area->lowest;
479: for (i = area->lowest; i <= area->highest; i++, item++) {
480: if (item->count) {
481: *sort_arr++ = i;
482: }
483: }
484:
485: /* ...for TOS ROM */
486: area = &cpu_profile.tos;
487: item = cpu_profile.data + area->lowest;
488: for (i = area->lowest; i <= area->highest; i++, item++) {
489: if (item->count) {
490: *sort_arr++ = i;
491: }
492: }
493: //printf("%d/%d/%d\n", area->active, sort_arr-cpu_profile.sort_arr, active);
494:
495: Profile_CpuShowStats();
496: return;
497: }
498:
499:
500: /* ------------------ DSP profile results ----------------- */
501:
502: /**
503: * Get DSP cycles & count for given address.
504: * Return true if data was available and non-zero, false otherwise.
505: */
506: bool Profile_DspAddressData(Uint16 addr, Uint32 *count, Uint32 *cycles)
507: {
508: if (!dsp_profile.data) {
509: return false;
510: }
511: *cycles = dsp_profile.data[addr].cycles;
512: *count = dsp_profile.data[addr].count;
513: return (*count > 0);
514: }
515:
516: /**
517: * show DSP specific profile statistics.
518: */
519: void Profile_DspShowStats(void)
520: {
521: profile_area_t *area = &dsp_profile.ram;
522: fprintf(stderr, "DSP profile statistics (0x0-0xFFFF):\n");
523: if (!area->active) {
524: fprintf(stderr, "- no activity\n");
525: return;
526: }
527: fprintf(stderr, "- active address range:\n 0x%04x-0x%04x\n",
528: area->lowest, area->highest);
529: fprintf(stderr, "- active instruction addresses:\n %d\n",
530: area->active);
531: fprintf(stderr, "- executed instructions:\n %llu\n",
532: area->all_count);
533: fprintf(stderr, "- used cycles:\n %llu\n",
534: area->all_cycles);
535: fprintf(stderr, "- address with most cycles:\n 0x%04x, %d cycles (%.2f%% of all)\n",
536: area->max_cycles_addr,
537: area->max_cycles,
538: (float)area->max_cycles/area->all_cycles*100);
539: fprintf(stderr, "- address with most hits:\n 0x%04x, %d hits (%.2f%% of all)\n",
540: area->max_count_addr,
541: area->max_count,
542: (float)area->max_count/area->all_count*100);
543: if (area->max_cycles == MAX_PROFILE_VALUE) {
544: fprintf(stderr, "- Counters OVERFLOW!\n");
545: }
546: }
547:
548:
549: /**
550: * compare function for qsort() to sort DSP profile data by descdending
551: * address cycles counts.
552: */
553: static int profile_by_dsp_cycles(const void *p1, const void *p2)
554: {
555: Uint32 count1 = dsp_profile.data[*(const Uint16*)p1].cycles;
556: Uint32 count2 = dsp_profile.data[*(const Uint16*)p2].cycles;
557: if (count1 > count2) {
558: return -1;
559: }
560: if (count1 < count2) {
561: return 1;
562: }
563: return 0;
564: }
565:
566: /**
567: * Sort DSP profile data addresses by cycle counts and show the results.
568: */
569: void Profile_DspShowCycles(unsigned int show)
570: {
571: unsigned int active;
572: Uint16 *sort_arr, *end, addr;
573: profile_item_t *data = dsp_profile.data;
574: float percentage;
575: Uint32 count;
576:
577: if (!data) {
578: fprintf(stderr, "ERROR: no DSP profiling data available!\n");
579: return;
580: }
581:
582: active = dsp_profile.ram.active;
583: sort_arr = dsp_profile.sort_arr;
584: qsort(sort_arr, active, sizeof(*sort_arr), profile_by_dsp_cycles);
585:
586: printf("addr:\tcycles:\n");
587: show = (show < active ? show : active);
588: for (end = sort_arr + show; sort_arr < end; sort_arr++) {
589: addr = *sort_arr;
590: count = data[addr].cycles;
591: percentage = 100.0*count/dsp_profile.ram.all_cycles;
592: printf("0x%04x\t%.2f%%\t%d%s\n", addr, percentage, count,
593: count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
594: }
595: printf("%d DSP addresses listed.\n", show);
596: }
597:
598:
599: /**
600: * compare function for qsort() to sort DSP profile data by descdending
601: * address access counts.
602: */
603: static int profile_by_dsp_count(const void *p1, const void *p2)
604: {
605: Uint32 count1 = dsp_profile.data[*(const Uint16*)p1].count;
606: Uint32 count2 = dsp_profile.data[*(const Uint16*)p2].count;
607: if (count1 > count2) {
608: return -1;
609: }
610: if (count1 < count2) {
611: return 1;
612: }
613: return 0;
614: }
615:
616: /**
617: * Sort DSP profile data addresses by call counts and show the results.
618: * If symbols are requested and symbols are loaded, show (only) addresses
619: * matching a symbol.
620: */
621: void Profile_DspShowCounts(unsigned int show, bool only_symbols)
622: {
623: profile_item_t *data = dsp_profile.data;
624: unsigned int symbols, matched, active;
625: Uint16 *sort_arr, *end, addr;
626: const char *name;
627: float percentage;
628: Uint32 count;
629:
630: if (!data) {
631: fprintf(stderr, "ERROR: no DSP profiling data available!\n");
632: return;
633: }
634: active = dsp_profile.ram.active;
635: show = (show < active ? show : active);
636:
637: sort_arr = dsp_profile.sort_arr;
638: qsort(sort_arr, active, sizeof(*sort_arr), profile_by_dsp_count);
639:
640: if (!only_symbols) {
641: printf("addr:\tcount:\n");
642: for (end = sort_arr + show; sort_arr < end; sort_arr++) {
643: addr = *sort_arr;
644: count = data[addr].count;
645: percentage = 100.0*count/dsp_profile.ram.all_count;
646: printf("0x%04x\t%.2f%%\t%d%s\n",
647: addr, percentage, count,
648: count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
649: }
650: printf("%d DSP addresses listed.\n", show);
651: return;
652: }
653:
654: symbols = Symbols_DspCount();
655: if (!symbols) {
656: fprintf(stderr, "ERROR: no DSP symbols loaded!\n");
657: return;
658: }
659: matched = 0;
660:
661: printf("addr:\tcount:\t\tsymbol:\n");
662: for (end = sort_arr + active; sort_arr < end; sort_arr++) {
663:
664: addr = *sort_arr;
665: name = Symbols_GetByDspAddress(addr);
666: if (!name) {
667: continue;
668: }
669: count = data[addr].count;
670: percentage = 100.0*count/dsp_profile.ram.all_count;
671: printf("0x%04x\t%.2f%%\t%d\t%s%s\n",
672: addr, percentage, count, name,
673: count == MAX_PROFILE_VALUE ? " (OVERFLOW)" : "");
674:
675: matched++;
676: if (matched >= show || matched >= symbols) {
677: break;
678: }
679: }
680: printf("%d DSP symbols listed.\n", matched);
681: }
682:
683:
684: /* ------------------ DSP profile control ----------------- */
685:
686: /**
687: * Initialize DSP profiling when necessary. Return true if profiling.
688: */
689: bool Profile_DspStart(void)
690: {
691: if (dsp_profile.sort_arr) {
692: /* remove previous results */
693: free(dsp_profile.sort_arr);
694: free(dsp_profile.data);
695: dsp_profile.sort_arr = NULL;
696: dsp_profile.data = NULL;
697: printf("Freed previous DSP profile buffers.\n");
698: }
699: if (!dsp_profile.enabled) {
700: return false;
701: }
702:
703: dsp_profile.data = calloc(DSP_PROFILE_ARR_SIZE, sizeof(*dsp_profile.data));
704: if (dsp_profile.data) {
705: printf("Allocated DSP profile buffer (%d KB).\n",
706: (int)sizeof(*dsp_profile.data)*DSP_PROFILE_ARR_SIZE/1024);
707: } else {
708: perror("ERROR, new DSP profile buffer alloc failed");
709: dsp_profile.enabled = false;
710: }
711: return dsp_profile.enabled;
712: }
713:
714: /**
715: * Update DSP cycle and count statistics for PC address.
716: */
717: void Profile_DspUpdate(void)
718: {
719: Uint16 pc, cycles;
720:
721: pc = DSP_GetPC();
722: if (likely(dsp_profile.data[pc].count < MAX_PROFILE_VALUE)) {
723: dsp_profile.data[pc].count++;
724: }
725:
726: cycles = DSP_GetInstrCycles();
727: if (likely(dsp_profile.data[pc].cycles < MAX_PROFILE_VALUE - cycles)) {
728: dsp_profile.data[pc].cycles += cycles;
729: }
730: }
731:
732:
733: /**
734: * Stop and process the DSP profiling data; collect stats and
735: * prepare for more optimal sorting.
736: */
737: void Profile_DspStop(void)
738: {
739: profile_item_t *item;
740: profile_area_t *area;
741: Uint16 *sort_arr;
742: Uint32 i;
743:
744: if (!dsp_profile.enabled) {
745: return;
746: }
747: /* find lowest and highest addresses executed */
748: item = dsp_profile.data;
749: area = &dsp_profile.ram;
750: memset(area, 0, sizeof(profile_area_t));
751: area->lowest = DSP_PROFILE_ARR_SIZE;
752:
753: for (i = 0; i < DSP_PROFILE_ARR_SIZE; i++, item++) {
754: update_area(i, item, area);
755: }
756:
757: /* allocate address array for sorting */
758: sort_arr = calloc(dsp_profile.ram.active, sizeof(*sort_arr));
759:
760: if (!sort_arr) {
761: perror("ERROR: allocating DSP profile address data");
762: free(dsp_profile.data);
763: dsp_profile.data = NULL;
764: return;
765: }
766: printf("Allocated DSP profile address buffer (%d KB).\n",
767: (int)sizeof(*sort_arr)*(dsp_profile.ram.active+512)/1024);
768: dsp_profile.sort_arr = sort_arr;
769:
770: /* ...and fill addresses for used instructions... */
771: area = &dsp_profile.ram;
772: item = dsp_profile.data + area->lowest;
773: for (i = area->lowest; i <= area->highest; i++, item++) {
774: if (item->count) {
775: *sort_arr++ = i;
776: }
777: }
778: //printf("%d/%d/%d\n", area->active, sort_arr-dsp_profile.sort_arr, active);
779:
780: Profile_DspShowStats();
781: return;
782: }
783:
784:
785: /* ------------------- command parsing ---------------------- */
786:
787: /**
788: * Readline match callback to list profile subcommand names.
789: * STATE = 0 -> different text from previous one.
790: * Return next match or NULL if no matches.
791: */
792: char *Profile_Match(const char *text, int state)
793: {
794: static const char *names[] = {
795: "on", "off", "counts", "cycles", "symbols", "stats"
796: };
797: static int i, len;
798:
799: if (!state)
800: {
801: /* first match */
802: i = 0;
803: len = strlen(text);
804: }
805: /* next match */
806: while (i < ARRAYSIZE(names)) {
807: if (strncasecmp(names[i++], text, len) == 0)
808: return (strdup(names[i-1]));
809: }
810: return NULL;
811: }
812:
813: const char Profile_Description[] =
814: "<on|off|counts|cycles|symbols|stats> [show count]\n"
815: "\ton & off enable and disable profiling. Data is collected\n"
816: "\tuntil debugger is entered again after which you can view\n"
817: "\tstatistics about the data or view PC addresses that took\n"
818: "\tmost cycles or functions/symbols called most often.\n"
819: "\tYou can specify how many items are shown at most.";
820:
821:
822: /**
823: * Command: CPU/DSP profiling enabling, exec stats, cycle and call stats.
824: * Return for succesful command and false for incorrect ones.
825: */
826: bool Profile_Command(int nArgc, char *psArgs[], bool bForDsp)
827: {
828: static int show = 16;
829: bool *enabled;
830:
831: if (nArgc < 2) {
832: DebugUI_PrintCmdHelp(psArgs[0]);
833: return true;
834: }
835: if (nArgc > 2) {
836: show = atoi(psArgs[2]);
837: }
838:
839: if (bForDsp) {
840: enabled = &dsp_profile.enabled;
841: } else {
842: enabled = &cpu_profile.enabled;
843: }
844: if (strcmp(psArgs[1], "on") == 0) {
845: *enabled = true;
846: fprintf(stderr, "Profiling enabled.\n");
847: return true;
848: }
849: if (strcmp(psArgs[1], "off") == 0) {
850: *enabled = false;
851: fprintf(stderr, "Profiling disabled.\n");
852: return true;
853: }
854:
855: if (strcmp(psArgs[1], "stats") == 0) {
856: if (bForDsp) {
857: Profile_DspShowStats();
858: } else {
859: Profile_CpuShowStats();
860: }
861: } else if (strcmp(psArgs[1], "cycles") == 0) {
862: if (bForDsp) {
863: Profile_DspShowCycles(show);
864: } else {
865: Profile_CpuShowCycles(show);
866: }
867: } else if (strcmp(psArgs[1], "counts") == 0) {
868: if (bForDsp) {
869: Profile_DspShowCounts(show, false);
870: } else {
871: Profile_CpuShowCounts(show, false);
872: }
873: } else if (strcmp(psArgs[1], "symbols") == 0) {
874: if (bForDsp) {
875: Profile_DspShowCounts(show, true);
876: } else {
877: Profile_CpuShowCounts(show, true);
878: }
879: } else {
880: DebugUI_PrintCmdHelp(psArgs[0]);
881: return false;
882: }
883: return true;
884: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.