source: trunk/src/kernel32/perfview.cpp@ 7413

Last change on this file since 7413 was 7413, checked in by phaller, 24 years ago

bugfix when dumping table

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