diff options
Diffstat (limited to 'src/gallium/auxiliary/util/p_debug_prof.c')
-rw-r--r-- | src/gallium/auxiliary/util/p_debug_prof.c | 269 |
1 files changed, 207 insertions, 62 deletions
diff --git a/src/gallium/auxiliary/util/p_debug_prof.c b/src/gallium/auxiliary/util/p_debug_prof.c index 958f99c327..5f9772ef91 100644 --- a/src/gallium/auxiliary/util/p_debug_prof.c +++ b/src/gallium/auxiliary/util/p_debug_prof.c @@ -46,15 +46,86 @@ #include "util/u_string.h" -#define PROFILE_FILE_SIZE 4*1024*1024 +#define PROFILE_TABLE_SIZE (1024*1024) #define FILE_NAME_SIZE 256 -static WCHAR wFileName[FILE_NAME_SIZE]; +struct debug_profile_entry +{ + uintptr_t caller; + uintptr_t callee; + uint64_t samples; +}; + +static unsigned long enabled = 0; + +static WCHAR wFileName[FILE_NAME_SIZE] = L"\\??\\c:\\00000000.prof"; static ULONG_PTR iFile = 0; -static void *pMap = NULL; -static void *pMapEnd = NULL; + +static struct debug_profile_entry *table = NULL; +static unsigned long free_table_entries = 0; +static unsigned long max_table_entries = 0; + +uint64_t start_stamp = 0; +uint64_t end_stamp = 0; + + +static void +debug_profile_entry(uintptr_t caller, uintptr_t callee, uint64_t samples) +{ + unsigned hash = ( caller + callee ) & PROFILE_TABLE_SIZE - 1; + + while(1) { + if(table[hash].caller == 0 && table[hash].callee == 0) { + table[hash].caller = caller; + table[hash].callee = callee; + table[hash].samples = samples; + --free_table_entries; + break; + } + else if(table[hash].caller == caller && table[hash].callee == callee) { + table[hash].samples += samples; + break; + } + else { + ++hash; + } + } +} + + +static uintptr_t caller_stack[1024]; +static unsigned last_caller = 0; + + +static int64_t delta(void) { + int64_t result = end_stamp - start_stamp; + if(result > UINT64_C(0xffffffff)) + result = 0; + return result; +} + + +static void __cdecl +debug_profile_enter(uintptr_t callee) +{ + uintptr_t caller = last_caller ? caller_stack[last_caller - 1] : 0; + + if (caller) + debug_profile_entry(caller, 0, delta()); + debug_profile_entry(caller, callee, 1); + caller_stack[last_caller++] = callee; +} +static void __cdecl +debug_profile_exit(uintptr_t callee) +{ + debug_profile_entry(callee, 0, delta()); + if(last_caller) + --last_caller; +} + + /** * Called at the start of every method or function. * @@ -63,27 +134,49 @@ static void *pMapEnd = NULL; void __declspec(naked) __cdecl _penter(void) { _asm { - push ebx - mov ebx, [pMap] - test ebx, ebx - jz done - cmp ebx, [pMapEnd] - je done push eax + mov eax, [enabled] + test eax, eax + jz skip + push edx - mov eax, [esp+12] - and eax, 0xfffffffe - mov [ebx], eax - add ebx, 4 + rdtsc - mov [ebx], eax - add ebx, 4 - mov [pMap], ebx + mov dword ptr [end_stamp], eax + mov dword ptr [end_stamp+4], edx + + xor eax, eax + mov [enabled], eax + + mov eax, [esp+8] + + push ebx + push ecx + push ebp + push edi + push esi + + push eax + call debug_profile_enter + add esp, 4 + + pop esi + pop edi + pop ebp + pop ecx + pop ebx + + mov eax, 1 + mov [enabled], eax + + rdtsc + mov dword ptr [start_stamp], eax + mov dword ptr [start_stamp+4], edx + pop edx +skip: pop eax -done: - pop ebx - ret + ret } } @@ -96,46 +189,60 @@ done: void __declspec(naked) __cdecl _pexit(void) { _asm { - push ebx - mov ebx, [pMap] - test ebx, ebx - jz done - cmp ebx, [pMapEnd] - je done push eax + mov eax, [enabled] + test eax, eax + jz skip + push edx - mov eax, [esp+12] - or eax, 0x00000001 - mov [ebx], eax - add ebx, 4 + rdtsc - mov [ebx], eax - add ebx, 4 - mov [pMap], ebx - pop edx - pop eax -done: + mov dword ptr [end_stamp], eax + mov dword ptr [end_stamp+4], edx + + xor eax, eax + mov [enabled], eax + + mov eax, [esp+8] + + push ebx + push ecx + push ebp + push edi + push esi + + push eax + call debug_profile_exit + add esp, 4 + + pop esi + pop edi + pop ebp + pop ecx pop ebx - ret - } -} + mov eax, 1 + mov [enabled], eax -void __declspec(naked) -__debug_profile_reference1(void) { - _asm { - call _penter - call _pexit + rdtsc + mov dword ptr [start_stamp], eax + mov dword ptr [start_stamp+4], edx + + pop edx +skip: + pop eax ret } } +/** + * Reference function for calibration. + */ void __declspec(naked) -__debug_profile_reference2(void) { +__debug_profile_reference(void) { _asm { call _penter - call __debug_profile_reference1 call _pexit ret } @@ -145,31 +252,69 @@ __debug_profile_reference2(void) { void debug_profile_start(void) { - static unsigned no = 0; - char filename[FILE_NAME_SIZE]; - unsigned i; + WCHAR *p; - util_snprintf(filename, sizeof(filename), "\\??\\c:\\%03u.prof", ++no); - for(i = 0; i < FILE_NAME_SIZE; ++i) - wFileName[i] = (WCHAR)filename[i]; - - pMap = EngMapFile(wFileName, PROFILE_FILE_SIZE, &iFile); - if(pMap) { - pMapEnd = (unsigned char*)pMap + PROFILE_FILE_SIZE; - /* reference functions for calibration purposes */ - __debug_profile_reference2(); + // increment starting from the less significant digit + p = &wFileName[14]; + while(1) { + if(*p == '9') { + *p-- = '0'; + } + else { + *p += 1; + break; + } + } + + table = EngMapFile(wFileName, + PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry), + &iFile); + if(table) { + unsigned i; + + free_table_entries = max_table_entries = PROFILE_TABLE_SIZE; + memset(table, 0, PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry)); + + table[0].caller = (uintptr_t)&__debug_profile_reference; + table[0].callee = 0; + table[0].samples = 0; + --free_table_entries; + + _asm { + push edx + push eax + + rdtsc + mov dword ptr [start_stamp], eax + mov dword ptr [start_stamp+4], edx + + pop edx + pop eax + } + + last_caller = 0; + + enabled = 1; + + for(i = 0; i < 8; ++i) { + _asm { + call __debug_profile_reference + } + } } } + void debug_profile_stop(void) { - if(iFile) { + enabled = 0; + + if(iFile) EngUnmapFile(iFile); - /* TODO: truncate file */ - } iFile = 0; - pMapEnd = pMap = NULL; + table = NULL; + free_table_entries = max_table_entries = 0; } #endif /* PROFILE */ |