|
|
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.