00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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