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

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

improvement of profiler

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