uuUndo/QuickProfiler.c

1 line
10 KiB
C
Raw Normal View History

2015-02-06 08:56:41 +00:00
// // When __PROFILE is called, stack frame looks like this: // // sp+08 Caller's return address // sp+04 Address of function name string // sp Return address to start of function // // After we save registers and such, stack frame looks like this: // // sp+28 Caller's return address // sp+24 Address of function name string // sp+20 Return address to start of function // sp+16 saved A0 // sp+12 saved A1 // sp+08 saved D0 // sp+04 saved D1 // sp saved D2 // // Upon returning from __PROFILE, stack frame should look like this: // // sp Address of __PROFILEEND // // #include <Profiler.h> #include <Threads.h> #include <Timer.h> #include <stdio.h> #include <string.h> #pragma profile off #if defined(powerc) || defined(__powerc) extern void Profile_GetTime(UnsignedWide *time); #else #define Profile_GetTime(time) Microseconds(time) #endif #define THREAD_OFFSET 100 #define NAME_LENGTH 23 #define MAX_FUNCS 1000 #define MAX_THREADS 50 #define STACK_DEPTH 100 typedef struct { char name[NAME_LENGTH+1]; int calls; long address; UnsignedWide totalTime; } FunctionInfo; typedef struct { FunctionInfo *callerFunction; long returnAddress; } StackFrame; typedef struct { StackFrame stack[STACK_DEPTH]; StackFrame *stackPtr; FunctionInfo *currentFunction; UnsignedWide startTime; } ThreadInfo; static ThreadInfo gThread[MAX_THREADS]; static FunctionInfo gFunction[MAX_FUNCS]; static long gProfilerOn = false; static ThreadInfo *gCurrentThread; static FunctionInfo *gCallerFunction; static long gSaveArea[5]; static FunctionInfo *GetIndex(char *functionName:__A0, long address:__D0):__A0; static void StartTime(FunctionInfo *function:__A0, int call:__D0); static void StopTime(int index:__D0); static void GetThreadInfo(void); static void PushFrame(long returnAddress:__D0); static long PopFrame(void):__D0; static asm pascal void __PROFILEEND(void); #pragma parameter AddToWide(__A0, __A1) void AddToWide(UnsignedWide *a, UnsignedWide *b) = { 0x2011, // move.l 0(a1),d0 ;d0 = hi 0x2229, 0x0004, // move.l 4(a1),d1 ;d1 = lo 0x2410, // move.l 0(a0),d2 ;d2 = hi 0xD2A8, 0x0004, // add.l 4(a0),d1 ;add lo parts 0xD580, // addx.l d0,d2 ;add hi parts with carry 0x2082, // move.l d2,0(a0) ;store high result 0x2141, 0x0004 // move.l d1,4(a0) ;store low result }; #pragma parameter SubFromWide(__A1, __A0) void SubFromWide(UnsignedWide *a, UnsignedWide *b) = { 0x2011, // move.l 0(a1),d0 ;d0 = hi 0x2229, 0x0004, // move.l 4(a1),d1 ;d1 = lo 0x2410, // move.l 0(a0),d2 ;d2 = hi 0x92A8, 0x0004, // sub.l 4(a0),d1 ;add lo parts 0x9580, // subx.l d0,d2 ;add hi parts with carry 0x2082, // move.l d2,0(a0) ;store high result 0x2141, 0x0004 // move.l d1,4(a0) ;store low result }; pascal OSErr ProfilerInit(ProfilerCollectionMethod method, ProfilerTimeBase timeBase, short numFunctions, short stackDepth) { int i; // initialize the function table memset(gFunction, 0, sizeof(gFunction)); strcpy(gFunction[0].name, "Root_Function"); gFunction[0].address = -1; gFunction[0].calls = 1; // initialize the thread table memset(gThread, 0, sizeof(gThread)); for (i = 0; i < MAX_THREADS; i++) gThread[i].stackPtr = gThread[i].stack; Profile_GetTime(&gThread[0].startTime); gThread[0].currentFunction = gFunction; // make sure we're turned off gProfilerOn = false; return noErr; } pascal void ProfilerSetStatus(short on) { gProfilerOn = (on) ? true : false; } pascal OSErr ProfilerDump(StringPtr filename) { /* static char cfile[256]; FunctionInfo *function; double temp; FILE *f; int i; BlockMoveData(filename + 1, cfile, *filename); cfile[*filename] = 0; f = fopen(cfile, "w"); if (f) { for (i = 0, function = gFunction; i < MAX_FUNCS; i++, function++) if (function->address) { temp = ((double)function->totalTime.hi * 65536.0 * 65536.0) + (double)function->to