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