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

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

heap acceleration

File size: 8.4 KB
Line 
1/* $Id: perfview.cpp,v 1.3 2001-10-12 03:48:06 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 if (tsCompensation < nTicks)
100 nTicks -= tsCompensation;
101 else
102 nTicks = 0;
103
104 // check if that particular function is registered already
105 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)pProfileMap->getElement(pszFunctionName);
106 if (NULL == p)
107 {
108 // new function call
109 p = (PPERFVIEW_FUNCTION)malloc( sizeof( PERFVIEW_FUNCTION ) );
110 p->pszFunctionName = strdup( pszFunctionName );
111 p->nCalled = 0;
112 p->nTotalTicks = 0;
113 p->nMinimumTicks = 0xffffffff;
114 p->nMaximumTicks = 0;
115
116 // add to the hashtable
117 pProfileMap->addElement(pszFunctionName, p);
118 }
119
120 // update statistical data
121 p->nCalled++;
122 p->nTotalTicks += nTicks;
123
124 if (nTicks < p->nMinimumTicks)
125 p->nMinimumTicks = nTicks;
126
127 if (nTicks > p->nMaximumTicks)
128 p->nMaximumTicks = nTicks;
129}
130
131
132int _Optlink sortHashtableEntries0(const void *arg1,const void *arg2)
133{
134 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
135 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
136
137 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
138 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
139
140 return strcmp(p1->pszFunctionName, p2->pszFunctionName);
141}
142
143int _Optlink sortHashtableEntries1(const void *arg1,const void *arg2)
144{
145 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
146 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
147
148 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
149 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
150
151 // return strcmp(pHTE1->pszName, pHTE2->pszName);
152 return p1->nTotalTicks - p2->nTotalTicks;
153}
154
155int _Optlink sortHashtableEntries2(const void *arg1,const void *arg2)
156{
157 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
158 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
159
160 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
161 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
162
163 return p1->nCalled - p2->nCalled;
164}
165
166int _Optlink sortHashtableEntries3(const void *arg1,const void *arg2)
167{
168 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
169 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
170
171 PPERFVIEW_FUNCTION p1 = (PPERFVIEW_FUNCTION)pHTE1->pObject;
172 PPERFVIEW_FUNCTION p2 = (PPERFVIEW_FUNCTION)pHTE2->pObject;
173
174 unsigned long int iAvg1 = p1->nTotalTicks / p1->nCalled;
175 unsigned long int iAvg2 = p2->nTotalTicks / p2->nCalled;
176
177 return iAvg1 - iAvg2;
178}
179
180
181// dump the collected profile to the specified file
182void _Optlink PerfView_DumpProfile(FILE *file)
183{
184 flagLock = TRUE; // lock recording
185
186 int iEntries = pProfileMap->getSize();
187
188 // get a list of all entries of the hashtable
189 PHASHTABLEENTRY arrEntries = (PHASHTABLEENTRY)malloc( iEntries * sizeof(HASHTABLEENTRY) );
190 iEntries = pProfileMap->getElementMap(arrEntries);
191
192 fprintf(file,
193 "ODIN Performance Analysis\n"
194 "%d entries available, compensated measure overhead is %d ticks.\n\n",
195 iEntries,
196 tsCompensation);
197
198
199 // sort the list by function name
200 qsort(arrEntries,
201 iEntries,
202 sizeof( HASHTABLEENTRY ),
203 sortHashtableEntries0);
204
205 // write to file
206 fprintf(file,
207 "Sorted by function name\n"
208 "Ticks ---- Called --- Average -- Minimum -- Maximum -- Function -----------\n");
209 for(int i = 0;
210 i < iEntries;
211 i++)
212 {
213 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
214 fprintf(file,
215 "%10d %10d %10d %10d %10d %s\n",
216 p->nTotalTicks,
217 p->nCalled,
218 p->nTotalTicks / p->nCalled,
219 p->nMinimumTicks,
220 p->nMaximumTicks,
221 p->pszFunctionName);
222 }
223
224
225 // sort the list by nTotalTicks
226 qsort(arrEntries,
227 iEntries,
228 sizeof( HASHTABLEENTRY ),
229 sortHashtableEntries1);
230
231 // write to file
232 fprintf(file,
233 "\nSorted by total call time\n"
234 "Ticks ---- Called --- Average -- Function ---------------------------------\n");
235 for(i = 0;
236 i < iEntries;
237 i++)
238 {
239 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
240 fprintf(file,
241 "%10d %10d %10d %s\n",
242 p->nTotalTicks,
243 p->nCalled,
244 p->nTotalTicks / p->nCalled,
245 p->pszFunctionName);
246 }
247
248
249 // sort the list by nCalled
250 qsort(arrEntries,
251 iEntries,
252 sizeof( HASHTABLEENTRY ),
253 sortHashtableEntries2);
254
255 // write to file
256 fprintf(file,
257 "\nSorted by total calls\n"
258 "Called --- Ticks ---- Average -- Function ---------------------------------\n");
259 for(i = 0;
260 i < iEntries;
261 i++)
262 {
263 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
264 fprintf(file,
265 "%10d %10d %10d %s\n",
266 p->nCalled,
267 p->nTotalTicks,
268 p->nTotalTicks / p->nCalled,
269 p->pszFunctionName);
270 }
271
272
273 // sort the list by average call time
274 qsort(arrEntries,
275 iEntries,
276 sizeof( HASHTABLEENTRY ),
277 sortHashtableEntries3);
278
279 // write to file
280 fprintf(file,
281 "\nSorted by average call time\n"
282 "Average -- Calls ---- Ticks ---- Function ---------------------------------\n");
283 for(i = 0;
284 i < iEntries;
285 i++)
286 {
287 PPERFVIEW_FUNCTION p = (PPERFVIEW_FUNCTION)arrEntries[i].pObject;
288 fprintf(file,
289 "%10d %10d %10d %s\n",
290 p->nTotalTicks / p->nCalled,
291 p->nCalled,
292 p->nTotalTicks,
293 p->pszFunctionName);
294 }
295
296
297 flagLock = FALSE; // lock recording
298}
299
300
301//use a different logfile
302#define PRIVATE_LOGGING
303#include <misc.h>
304
305
306void PerfView_Write()
307{
308 FILE* _privateLogFile;
309 char szFilename[260];
310
311 sprintf(szFilename, "perf_%d.log", loadNr);
312 _privateLogFile = fopen(szFilename, "w");
313
314 if(_privateLogFile == NULL)
315 {
316 sprintf(szFilename, "%sperf_%d.log", kernel32Path, loadNr);
317 _privateLogFile = fopen(szFilename, "w");
318 }
319
320 dprintfGlobal(("PE PERFFILE : %s", szFilename));
321
322 // dump the gathered data
323 PerfView_DumpProfile(_privateLogFile);
324
325 if(_privateLogFile)
326 {
327 fclose(_privateLogFile);
328 _privateLogFile = NULL;
329 }
330}
331
332
333
334#endif /* PROFILE */
Note: See TracBrowser for help on using the repository browser.