source: trunk/src/kernel32/perfview.cpp

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 9.5 KB
RevLine 
[7413]1/* $Id: perfview.cpp,v 1.5 2001-11-21 16:02:14 phaller Exp $ */
[7021]2
3/*
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 * Win32 performance measurement and self-profiling API functions
7 *
8 * Copyright 2001 Patrick Haller <patrick.haller@innotek.de>
9 */
10
11/****************************************************************************
12 * includes
13 ****************************************************************************/
14#include "perfview.h"
15
16
17#ifndef PROFILE
18
19// insert "nullified" dummies here to save space in the executable image
[7025]20void PerfView_Initialize(void) {}
[7326]21void PerfView_RegisterCall(char* pszCallerName,
22 char* pszFunctionName,
[7021]23 unsigned long int nTicks) {}
24
25void PerfView_DumpProfile(FILE *file) {}
26void PerfView_Write() {}
27
28#else
29
[21916]30#include <process.h>
31
[7021]32#include <ccollection.h>
[7025]33#include <winbase.h>
[7021]34
35// imported from the kernel loader (initterm)
36extern char kernel32Path[];
37
38
39
40typedef struct tagFUNCTION
41{
42 char* pszFunctionName;
43 unsigned long int nCalled;
44 unsigned long int nTotalTicks;
[7025]45 unsigned long int nMinimumTicks;
46 unsigned long int nMaximumTicks;
[7021]47} PERFVIEW_FUNCTION, *PPERFVIEW_FUNCTION;
48
49
50// the map keeps track of all called methods and functions
51static CHashtableLookup* pProfileMap = new CHashtableLookup(1021);
52static BOOL flagLock = FALSE;
[7025]53static unsigned long int tsCompensation = 0;
[7021]54
[7025]55
56// measure the measurement overhead itself
57void PerfView_Initialize(void)
58{
59#define CALIBRATION_RUNS 100
60
61 LARGE_INTEGER liStart;
62 LARGE_INTEGER liEnd;
63 unsigned long ulElapsed;
64
65 // initialize this
66 tsCompensation = 0;
67
68 for (int i = 0;
69 i < CALIBRATION_RUNS;
70 i++)
71 {
72 QueryPerformanceCounter(&liStart);
73 QueryPerformanceCounter(&liEnd);
74
75 if (liStart.LowPart > liEnd.LowPart)
76 ulElapsed = 0xFFFFFFFF - liStart.LowPart + liEnd.LowPart;
77 else
78 ulElapsed = liEnd.LowPart - liStart.LowPart;
79
80 // save the determined amount of elapsed ticks
81 // as compensatory factor
82 tsCompensation += ulElapsed;
83 }
84
85 // now calculate back to real value
86 tsCompensation /= CALIBRATION_RUNS;
87}
88
89
[7021]90// register a call to a function
[7326]91void _Optlink PerfView_RegisterCall(char* pszCallerName,
92 char* pszFunctionName,
[7021]93 unsigned long int nTicks)
94{
95 // don't record call if currently locked
96 if (flagLock)
97 return;
98
[7025]99 // subtract the measurement overhead factor.
100 // Note: this should rather be done where the times are taken,
101 // however this would spread the code just too far.
[7027]102 if (tsCompensation < nTicks)
103 nTicks -= tsCompensation;
104 else
105 nTicks = 0;
[7025]106
[7021]107 // check if that particular function is registered already
108 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)pProfileMap->getElement(pszFunctionName);
109 if (NULL == p)
110 {
111 // new function call
112 p = (PPERFVIEW_FUNCTION)malloc( sizeof( PERFVIEW_FUNCTION ) );
113 p->pszFunctionName = strdup( pszFunctionName );
114 p->nCalled = 0;
115 p->nTotalTicks = 0;
[7025]116 p->nMinimumTicks = 0xffffffff;
117 p->nMaximumTicks = 0;
[7021]118
119 // add to the hashtable
120 pProfileMap->addElement(pszFunctionName, p);
121 }
122
123 // update statistical data
124 p->nCalled++;
125 p->nTotalTicks += nTicks;
[7025]126
127 if (nTicks < p->nMinimumTicks)
128 p->nMinimumTicks = nTicks;
129
130 if (nTicks > p->nMaximumTicks)
131 p->nMaximumTicks = nTicks;
[7326]132
133
134 // add call-path tracing
135 if (NULL != pszCallerName)
136 {
137 // build path name
138 char szBuf[256];
139 strcpy(szBuf, pszCallerName);
140 strcat(szBuf, "->");
141 strcat(szBuf, pszFunctionName);
142
143 // check if that particular callpath is registered already
144 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pProfileMap->getElement(szBuf);
145 if (NULL == p2)
146 {
147 // new function call
148 p2 = (PPERFVIEW_FUNCTION)malloc( sizeof( PERFVIEW_FUNCTION ) );
149 p2->pszFunctionName = strdup( szBuf );
150 p2->nCalled = 0;
151 p2->nTotalTicks = 0;
152 p2->nMinimumTicks = 0xffffffff;
153 p2->nMaximumTicks = 0;
154
155 // add to the hashtable
156 pProfileMap->addElement(p2->pszFunctionName, p2);
157 }
158
159 // update statistical data
160 p2->nCalled++;
161 p2->nTotalTicks += nTicks;
162
163 if (nTicks < p2->nMinimumTicks)
164 p2->nMinimumTicks = nTicks;
165
166 if (nTicks > p2->nMaximumTicks)
167 p2->nMaximumTicks = nTicks;
168 }
[7021]169}
170
171
172int _Optlink sortHashtableEntries0(const void *arg1,const void *arg2)
173{
174 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
175 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
176
177 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
178 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
179
180 return strcmp(p1->pszFunctionName, p2->pszFunctionName);
181}
182
183int _Optlink sortHashtableEntries1(const void *arg1,const void *arg2)
184{
185 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
186 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
187
188 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
189 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
190
191 // return strcmp(pHTE1->pszName, pHTE2->pszName);
192 return p1->nTotalTicks - p2->nTotalTicks;
193}
194
195int _Optlink sortHashtableEntries2(const void *arg1,const void *arg2)
196{
197 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
198 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
199
200 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
201 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
202
203 return p1->nCalled - p2->nCalled;
204}
205
206int _Optlink sortHashtableEntries3(const void *arg1,const void *arg2)
207{
208 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
209 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
210
211 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
212 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
213
214 unsigned long int iAvg1 = p1->nTotalTicks / p1->nCalled;
215 unsigned long int iAvg2 = p2->nTotalTicks / p2->nCalled;
216
217 return iAvg1 - iAvg2;
218}
219
220
221// dump the collected profile to the specified file
222void _Optlink PerfView_DumpProfile(FILE *file)
223{
224 flagLock = TRUE; // lock recording
225
[7413]226 int iEntries = pProfileMap->getNumberOfElements();
[7021]227
228 // get a list of all entries of the hashtable
229 PHASHTABLEENTRY arrEntries = (PHASHTABLEENTRY)malloc( iEntries * sizeof(HASHTABLEENTRY) );
230 iEntries = pProfileMap->getElementMap(arrEntries);
231
[7025]232 fprintf(file,
233 "ODIN Performance Analysis\n"
234 "%d entries available, compensated measure overhead is %d ticks.\n\n",
235 iEntries,
236 tsCompensation);
237
238
[7021]239 // sort the list by function name
240 qsort(arrEntries,
241 iEntries,
242 sizeof( HASHTABLEENTRY ),
243 sortHashtableEntries0);
244
245 // write to file
246 fprintf(file,
247 "Sorted by function name\n"
[7025]248 "Ticks ---- Called --- Average -- Minimum -- Maximum -- Function -----------\n");
[7021]249 for(int i = 0;
250 i < iEntries;
251 i++)
252 {
253 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
254 fprintf(file,
[7025]255 "%10d %10d %10d %10d %10d %s\n",
[7021]256 p->nTotalTicks,
257 p->nCalled,
258 p->nTotalTicks / p->nCalled,
[7025]259 p->nMinimumTicks,
260 p->nMaximumTicks,
[7021]261 p->pszFunctionName);
262 }
263
264
265 // sort the list by nTotalTicks
266 qsort(arrEntries,
267 iEntries,
268 sizeof( HASHTABLEENTRY ),
269 sortHashtableEntries1);
270
271 // write to file
272 fprintf(file,
273 "\nSorted by total call time\n"
274 "Ticks ---- Called --- Average -- Function ---------------------------------\n");
275 for(i = 0;
276 i < iEntries;
277 i++)
278 {
279 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
280 fprintf(file,
281 "%10d %10d %10d %s\n",
282 p->nTotalTicks,
283 p->nCalled,
284 p->nTotalTicks / p->nCalled,
285 p->pszFunctionName);
286 }
287
288
289 // sort the list by nCalled
290 qsort(arrEntries,
291 iEntries,
292 sizeof( HASHTABLEENTRY ),
293 sortHashtableEntries2);
294
295 // write to file
296 fprintf(file,
297 "\nSorted by total calls\n"
298 "Called --- Ticks ---- Average -- Function ---------------------------------\n");
299 for(i = 0;
300 i < iEntries;
301 i++)
302 {
303 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
304 fprintf(file,
305 "%10d %10d %10d %s\n",
306 p->nCalled,
307 p->nTotalTicks,
308 p->nTotalTicks / p->nCalled,
309 p->pszFunctionName);
310 }
311
312
313 // sort the list by average call time
314 qsort(arrEntries,
315 iEntries,
316 sizeof( HASHTABLEENTRY ),
317 sortHashtableEntries3);
318
319 // write to file
320 fprintf(file,
321 "\nSorted by average call time\n"
322 "Average -- Calls ---- Ticks ---- Function ---------------------------------\n");
323 for(i = 0;
324 i < iEntries;
325 i++)
326 {
327 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
328 fprintf(file,
329 "%10d %10d %10d %s\n",
330 p->nTotalTicks / p->nCalled,
331 p->nCalled,
332 p->nTotalTicks,
333 p->pszFunctionName);
334 }
335
336
337 flagLock = FALSE; // lock recording
338}
339
340
341//use a different logfile
342#define PRIVATE_LOGGING
343#include <misc.h>
344
345
346void PerfView_Write()
347{
348 FILE* _privateLogFile;
349 char szFilename[260];
350
[21916]351 sprintf(szFilename, "perf_%d.log", getpid());
[7021]352 _privateLogFile = fopen(szFilename, "w");
353
354 if(_privateLogFile == NULL)
355 {
[21916]356 sprintf(szFilename, "%sperf_%d.log", kernel32Path, getpid());
[7021]357 _privateLogFile = fopen(szFilename, "w");
358 }
359
360 dprintfGlobal(("PE PERFFILE : %s", szFilename));
361
362 // dump the gathered data
363 PerfView_DumpProfile(_privateLogFile);
364
365 if(_privateLogFile)
366 {
367 fclose(_privateLogFile);
368 _privateLogFile = NULL;
369 }
370}
371
372
373
374#endif /* PROFILE */
Note: See TracBrowser for help on using the repository browser.