p_debug_prof.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00038 #include "pipe/p_config.h" 
00039 
00040 #if defined(PROFILE) && defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
00041 
00042 #include <windows.h>
00043 #include <winddi.h>
00044 
00045 #include "pipe/p_debug.h" 
00046 #include "util/u_string.h" 
00047 
00048 
00049 #define PROFILE_TABLE_SIZE (1024*1024)
00050 #define FILE_NAME_SIZE 256
00051 
00052 struct debug_profile_entry
00053 {
00054    uintptr_t caller;
00055    uintptr_t callee;
00056    uint64_t samples;
00057 };
00058 
00059 static unsigned long enabled = 0;
00060 
00061 static WCHAR wFileName[FILE_NAME_SIZE] = L"\\??\\c:\\00000000.prof";
00062 static ULONG_PTR iFile = 0;
00063 
00064 static struct debug_profile_entry *table = NULL;
00065 static unsigned long free_table_entries = 0;
00066 static unsigned long max_table_entries = 0;
00067 
00068 uint64_t start_stamp = 0;
00069 uint64_t end_stamp = 0;
00070 
00071 
00072 static void
00073 debug_profile_entry(uintptr_t caller, uintptr_t callee, uint64_t samples)
00074 {
00075    unsigned hash = ( caller + callee ) & PROFILE_TABLE_SIZE - 1;
00076    
00077    while(1) {
00078       if(table[hash].caller == 0 && table[hash].callee == 0) {
00079          table[hash].caller = caller;
00080          table[hash].callee = callee;
00081          table[hash].samples = samples;
00082          --free_table_entries;
00083          break;
00084       }
00085       else if(table[hash].caller == caller && table[hash].callee == callee) {
00086          table[hash].samples += samples;
00087          break;
00088       }
00089       else {
00090          ++hash;
00091       }
00092    }
00093 }
00094 
00095 
00096 static uintptr_t caller_stack[1024];
00097 static unsigned last_caller = 0;
00098 
00099 
00100 static int64_t delta(void) {
00101    int64_t result = end_stamp - start_stamp;
00102    if(result > UINT64_C(0xffffffff))
00103       result = 0;
00104    return result;
00105 }
00106 
00107 
00108 static void __cdecl 
00109 debug_profile_enter(uintptr_t callee)
00110 {
00111    uintptr_t caller = last_caller ? caller_stack[last_caller - 1] : 0;
00112                 
00113    if (caller)
00114       debug_profile_entry(caller, 0, delta());
00115    debug_profile_entry(caller, callee, 1);
00116    caller_stack[last_caller++] = callee;
00117 }
00118 
00119 
00120 static void __cdecl
00121 debug_profile_exit(uintptr_t callee)
00122 {
00123    debug_profile_entry(callee, 0, delta());
00124    if(last_caller)
00125       --last_caller;
00126 }
00127    
00128    
00134 void __declspec(naked) __cdecl 
00135 _penter(void) {
00136    _asm {
00137       push eax
00138       mov eax, [enabled]
00139       test eax, eax
00140       jz skip
00141 
00142       push edx
00143       
00144       rdtsc
00145       mov dword ptr [end_stamp], eax
00146       mov dword ptr [end_stamp+4], edx
00147 
00148       xor eax, eax
00149       mov [enabled], eax
00150 
00151       mov eax, [esp+8]
00152 
00153       push ebx
00154       push ecx
00155       push ebp
00156       push edi
00157       push esi
00158 
00159       push eax
00160       call debug_profile_enter
00161       add esp, 4
00162 
00163       pop esi
00164       pop edi
00165       pop ebp
00166       pop ecx
00167       pop ebx
00168 
00169       mov eax, 1
00170       mov [enabled], eax 
00171 
00172       rdtsc
00173       mov dword ptr [start_stamp], eax
00174       mov dword ptr [start_stamp+4], edx
00175       
00176       pop edx
00177 skip:
00178       pop eax
00179       ret
00180    }
00181 }
00182 
00183 
00189 void __declspec(naked) __cdecl 
00190 _pexit(void) {
00191    _asm {
00192       push eax
00193       mov eax, [enabled]
00194       test eax, eax
00195       jz skip
00196 
00197       push edx
00198       
00199       rdtsc
00200       mov dword ptr [end_stamp], eax
00201       mov dword ptr [end_stamp+4], edx
00202 
00203       xor eax, eax
00204       mov [enabled], eax
00205 
00206       mov eax, [esp+8]
00207 
00208       push ebx
00209       push ecx
00210       push ebp
00211       push edi
00212       push esi
00213 
00214       push eax
00215       call debug_profile_exit
00216       add esp, 4
00217 
00218       pop esi
00219       pop edi
00220       pop ebp
00221       pop ecx
00222       pop ebx
00223 
00224       mov eax, 1
00225       mov [enabled], eax 
00226 
00227       rdtsc
00228       mov dword ptr [start_stamp], eax
00229       mov dword ptr [start_stamp+4], edx
00230       
00231       pop edx
00232 skip:
00233       pop eax
00234       ret
00235    }
00236 }
00237 
00238 
00242 void __declspec(naked) 
00243 __debug_profile_reference(void) {
00244    _asm {
00245       call _penter
00246       call _pexit
00247       ret
00248    }
00249 }
00250 
00251 
00252 void
00253 debug_profile_start(void)
00254 {
00255    WCHAR *p;
00256 
00257    // increment starting from the less significant digit
00258    p = &wFileName[14];
00259    while(1) {
00260       if(*p == '9') {
00261          *p-- = '0';
00262       }
00263       else {
00264          *p += 1;
00265          break;
00266       }
00267    }
00268 
00269    table = EngMapFile(wFileName, 
00270                       PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry), 
00271                       &iFile);
00272    if(table) {
00273       unsigned i;
00274       
00275       free_table_entries = max_table_entries = PROFILE_TABLE_SIZE;
00276       memset(table, 0, PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry));
00277       
00278       table[0].caller = (uintptr_t)&__debug_profile_reference;
00279       table[0].callee = 0;
00280       table[0].samples = 0;
00281       --free_table_entries;
00282 
00283       _asm {
00284          push edx
00285          push eax
00286       
00287          rdtsc
00288          mov dword ptr [start_stamp], eax
00289          mov dword ptr [start_stamp+4], edx
00290          
00291          pop edx
00292          pop eax
00293       }
00294 
00295       last_caller = 0;
00296       
00297       enabled = 1;
00298 
00299       for(i = 0; i < 8; ++i) {
00300          _asm {
00301             call __debug_profile_reference
00302          }
00303       }
00304    }
00305 }
00306 
00307 
00308 void 
00309 debug_profile_stop(void)
00310 {
00311    enabled = 0;
00312 
00313    if(iFile)
00314       EngUnmapFile(iFile);
00315    iFile = 0;
00316    table = NULL;
00317    free_table_entries = max_table_entries = 0;
00318 }
00319 
00320 #endif /* PROFILE */

Generated on Tue Sep 29 06:25:15 2009 for Gallium3D by  doxygen 1.5.4