radeon/r200/r300: cleanup some of the renderbuffer code
[mesa.git] / src / gallium / auxiliary / util / p_debug_prof.c
1 /**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * @file
30 * Poor-man profiling.
31 *
32 * @author José Fonseca <jrfonseca@tungstengraphics.com>
33 *
34 * @sa http://blogs.msdn.com/joshpoley/archive/2008/03/12/poor-man-s-profiler.aspx
35 * @sa http://www.johnpanzer.com/aci_cuj/index.html
36 */
37
38 #include "pipe/p_config.h"
39
40 #if defined(PROFILE) && defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY)
41
42 #include <windows.h>
43 #include <winddi.h>
44
45 #include "pipe/p_debug.h"
46 #include "util/u_string.h"
47
48
49 #define PROFILE_TABLE_SIZE (1024*1024)
50 #define FILE_NAME_SIZE 256
51
52 struct debug_profile_entry
53 {
54 uintptr_t caller;
55 uintptr_t callee;
56 uint64_t samples;
57 };
58
59 static unsigned long enabled = 0;
60
61 static WCHAR wFileName[FILE_NAME_SIZE] = L"\\??\\c:\\00000000.prof";
62 static ULONG_PTR iFile = 0;
63
64 static struct debug_profile_entry *table = NULL;
65 static unsigned long free_table_entries = 0;
66 static unsigned long max_table_entries = 0;
67
68 uint64_t start_stamp = 0;
69 uint64_t end_stamp = 0;
70
71
72 static void
73 debug_profile_entry(uintptr_t caller, uintptr_t callee, uint64_t samples)
74 {
75 unsigned hash = ( caller + callee ) & PROFILE_TABLE_SIZE - 1;
76
77 while(1) {
78 if(table[hash].caller == 0 && table[hash].callee == 0) {
79 table[hash].caller = caller;
80 table[hash].callee = callee;
81 table[hash].samples = samples;
82 --free_table_entries;
83 break;
84 }
85 else if(table[hash].caller == caller && table[hash].callee == callee) {
86 table[hash].samples += samples;
87 break;
88 }
89 else {
90 ++hash;
91 }
92 }
93 }
94
95
96 static uintptr_t caller_stack[1024];
97 static unsigned last_caller = 0;
98
99
100 static int64_t delta(void) {
101 int64_t result = end_stamp - start_stamp;
102 if(result > UINT64_C(0xffffffff))
103 result = 0;
104 return result;
105 }
106
107
108 static void __cdecl
109 debug_profile_enter(uintptr_t callee)
110 {
111 uintptr_t caller = last_caller ? caller_stack[last_caller - 1] : 0;
112
113 if (caller)
114 debug_profile_entry(caller, 0, delta());
115 debug_profile_entry(caller, callee, 1);
116 caller_stack[last_caller++] = callee;
117 }
118
119
120 static void __cdecl
121 debug_profile_exit(uintptr_t callee)
122 {
123 debug_profile_entry(callee, 0, delta());
124 if(last_caller)
125 --last_caller;
126 }
127
128
129 /**
130 * Called at the start of every method or function.
131 *
132 * @sa http://msdn.microsoft.com/en-us/library/c63a9b7h.aspx
133 */
134 void __declspec(naked) __cdecl
135 _penter(void) {
136 _asm {
137 push eax
138 mov eax, [enabled]
139 test eax, eax
140 jz skip
141
142 push edx
143
144 rdtsc
145 mov dword ptr [end_stamp], eax
146 mov dword ptr [end_stamp+4], edx
147
148 xor eax, eax
149 mov [enabled], eax
150
151 mov eax, [esp+8]
152
153 push ebx
154 push ecx
155 push ebp
156 push edi
157 push esi
158
159 push eax
160 call debug_profile_enter
161 add esp, 4
162
163 pop esi
164 pop edi
165 pop ebp
166 pop ecx
167 pop ebx
168
169 mov eax, 1
170 mov [enabled], eax
171
172 rdtsc
173 mov dword ptr [start_stamp], eax
174 mov dword ptr [start_stamp+4], edx
175
176 pop edx
177 skip:
178 pop eax
179 ret
180 }
181 }
182
183
184 /**
185 * Called at the end of Calls the end of every method or function.
186 *
187 * @sa http://msdn.microsoft.com/en-us/library/xc11y76y.aspx
188 */
189 void __declspec(naked) __cdecl
190 _pexit(void) {
191 _asm {
192 push eax
193 mov eax, [enabled]
194 test eax, eax
195 jz skip
196
197 push edx
198
199 rdtsc
200 mov dword ptr [end_stamp], eax
201 mov dword ptr [end_stamp+4], edx
202
203 xor eax, eax
204 mov [enabled], eax
205
206 mov eax, [esp+8]
207
208 push ebx
209 push ecx
210 push ebp
211 push edi
212 push esi
213
214 push eax
215 call debug_profile_exit
216 add esp, 4
217
218 pop esi
219 pop edi
220 pop ebp
221 pop ecx
222 pop ebx
223
224 mov eax, 1
225 mov [enabled], eax
226
227 rdtsc
228 mov dword ptr [start_stamp], eax
229 mov dword ptr [start_stamp+4], edx
230
231 pop edx
232 skip:
233 pop eax
234 ret
235 }
236 }
237
238
239 /**
240 * Reference function for calibration.
241 */
242 void __declspec(naked)
243 __debug_profile_reference(void) {
244 _asm {
245 call _penter
246 call _pexit
247 ret
248 }
249 }
250
251
252 void
253 debug_profile_start(void)
254 {
255 WCHAR *p;
256
257 // increment starting from the less significant digit
258 p = &wFileName[14];
259 while(1) {
260 if(*p == '9') {
261 *p-- = '0';
262 }
263 else {
264 *p += 1;
265 break;
266 }
267 }
268
269 table = EngMapFile(wFileName,
270 PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry),
271 &iFile);
272 if(table) {
273 unsigned i;
274
275 free_table_entries = max_table_entries = PROFILE_TABLE_SIZE;
276 memset(table, 0, PROFILE_TABLE_SIZE*sizeof(struct debug_profile_entry));
277
278 table[0].caller = (uintptr_t)&__debug_profile_reference;
279 table[0].callee = 0;
280 table[0].samples = 0;
281 --free_table_entries;
282
283 _asm {
284 push edx
285 push eax
286
287 rdtsc
288 mov dword ptr [start_stamp], eax
289 mov dword ptr [start_stamp+4], edx
290
291 pop edx
292 pop eax
293 }
294
295 last_caller = 0;
296
297 enabled = 1;
298
299 for(i = 0; i < 8; ++i) {
300 _asm {
301 call __debug_profile_reference
302 }
303 }
304 }
305 }
306
307
308 void
309 debug_profile_stop(void)
310 {
311 enabled = 0;
312
313 if(iFile)
314 EngUnmapFile(iFile);
315 iFile = 0;
316 table = NULL;
317 free_table_entries = max_table_entries = 0;
318 }
319
320 #endif /* PROFILE */