source: branches/gcc-kmk/src/kernel32/perfview.cpp@ 21837

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

Use pid instead of the ordinal number in log file names.

This in particular fixes the problem when WGSS50 writes to the log
before the ordinal is correctly initialized by KERNEL32 which resulted
into two processes writing to the same log file.

This also guarantees that a subsequent re-run will not vanish the
previous log file which is also useful sometimes.

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 <process.h>
31
32#include <ccollection.h>
33#include <winbase.h>
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;
45 unsigned long int nMinimumTicks;
46 unsigned long int nMaximumTicks;
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;
53static unsigned long int tsCompensation = 0;
54
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
90// register a call to a function
91void _Optlink PerfView_RegisterCall(char* pszCallerName,
92 char* pszFunctionName,
93 unsigned long int nTicks)
94{
95 // don't record call if currently locked
96 if (flagLock)
97 return;
98
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.
102 if (tsCompensation < nTicks)
103 nTicks -= tsCompensation;
104 else
105 nTicks = 0;
106
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;
116 p->nMinimumTicks = 0xffffffff;
117 p->nMaximumTicks = 0;
118
119 // add to the hashtable
120 pProfileMap->addElement(pszFunctionName, p);
121 }
122
123 // update statistical data
124 p->nCalled++;
125 p->nTotalTicks += nTicks;
126
127 if (nTicks < p->nMinimumTicks)
128 p->nMinimumTicks = nTicks;
129
130 if (nTicks > p->nMaximumTicks)
131 p->nMaximumTicks = nTicks;
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 }
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
226 int iEntries = pProfileMap->getNumberOfElements();
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
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
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"
248 "Ticks ---- Called --- Average -- Minimum -- Maximum -- Function -----------\n");
249 for(int i = 0;
250 i < iEntries;
251 i++)
252 {
253 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
254 fprintf(file,
255 "%10d %10d %10d %10d %10d %s\n",
256 p->nTotalTicks,
257 p->nCalled,
258 p->nTotalTicks / p->nCalled,
259 p->nMinimumTicks,
260 p->nMaximumTicks,
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
351 sprintf(szFilename, "perf_%d.log", getpid());
352 _privateLogFile = fopen(szFilename, "w");
353
354 if(_privateLogFile == NULL)
355 {
356 sprintf(szFilename, "%sperf_%d.log", kernel32Path, getpid());
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.