VirtualBox

source: kStuff/trunk/kProfiler2/prfreader.cpp.h@ 10

Last change on this file since 10 was 10, checked in by bird, 17 years ago

Corrected the calls from percentage.

  • Property svn:keywords set to Id Revision
File size: 56.7 KB
Line 
1/* $Id: prfreader.cpp.h 10 2008-04-20 04:06:12Z bird $ */
2/** @file
3 * kProfiler Mark 2 - Reader Code Template.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * This file is part of kProfiler.
10 *
11 * kProfiler is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * kProfiler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with kProfiler; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27
28/**
29 * Validates the non-header parts of a data-set.
30 *
31 * @returns true if valid.
32 * @returns false if invalid. (written description to pOut)
33 *
34 * @param pHdr Pointer to the data set.
35 * @param cb The size of the data set.
36 * @param pOut Where to write error messages.
37 */
38static bool KPRF_NAME(IsValid)(KPRF_TYPE(PC,HDR) pHdr, KU32 cb, FILE *pOut)
39{
40 KPRF_TYPE(,UPTR) uMaxPtr = ~(KPRF_TYPE(,UPTR))0 - pHdr->uBasePtr;
41
42 /*
43 * Iterate the module segments.
44 */
45 KU32 off = pHdr->offModSegs;
46 while (off < pHdr->offModSegs + pHdr->cbModSegs)
47 {
48 KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr);
49 KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
50 cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
51 if (cbCur + off > pHdr->offModSegs + pHdr->cbModSegs)
52 {
53 fprintf(pOut, "The module segment record at 0x%x is too long!\n", off);
54 return false;
55 }
56 if (pCur->uBasePtr > uMaxPtr)
57 fprintf(pOut, "warning: The module segment record at 0x%x has a too high base address.\n", off);
58
59 if (strlen(pCur->szPath) != pCur->cchPath)
60 {
61 fprintf(pOut, "The module segment record at 0x%x has an invalid path length 0x%x it the actual length is 0x%x\n",
62 pCur->cchPath, strlen(pCur->szPath));
63 return false;
64 }
65
66 /* next */
67 off += cbCur;
68 }
69
70
71 /*
72 * Iterate the functions.
73 */
74 KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr);
75 for (KU32 i = 0; i < pHdr->cFunctions; i++)
76 {
77 KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i];
78 if (pCur->uEntryPtr > uMaxPtr)
79 fprintf(pOut, "warning: Function 0x%x has a too high base address.\n", i);
80 if (pCur->offModSeg)
81 {
82 if ( pCur->offModSeg < pHdr->offModSegs
83 || pCur->offModSeg >= pHdr->offModSegs + pHdr->cbModSegs
84 || pCur->offModSeg != KPRF_ALIGN(pCur->offModSeg, sizeof(pCur->uEntryPtr))
85 )
86 {
87 fprintf(pOut, "Function 0x%x has an invalid offModSeg value (0x%x).\n", i, pCur->offModSeg);
88 return false;
89 }
90 /** @todo more validation here.. */
91 }
92 }
93
94
95 /*
96 * Validate the threads.
97 */
98 KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr);
99 for (KU32 i = 0; i < pHdr->cThreads; i++)
100 {
101 KPRF_TYPE(PC,THREAD) pCur = &paThreads[i];
102 if (pCur->uStackBasePtr > uMaxPtr)
103 fprintf(pOut, "warning: Thread 0x%x has a too high base address.\n", i);
104 switch (pCur->enmState)
105 {
106 case KPRF_TYPE(,THREADSTATE_ACTIVE):
107 case KPRF_TYPE(,THREADSTATE_SUSPENDED):
108 case KPRF_TYPE(,THREADSTATE_OVERFLOWED):
109 case KPRF_TYPE(,THREADSTATE_TERMINATED):
110 break;
111 default:
112 fprintf(pOut, "Thread 0x%x has an invalid state value (0x%x).\n", i, pCur->enmState);
113 return false;
114 }
115 }
116
117
118 return true;
119}
120
121
122/**
123 * Dumps a file of a particular format.
124 *
125 * @returns 0 on success. (you might want to check the pOut state)
126 * @returns -1 on failure.
127 *
128 * @param pHdr Pointer to the data set.
129 * @param pOut The output file. This is opened for text writing.
130 * @param pReader The reader object.
131 */
132static int KPRF_NAME(Dump)(KPRF_TYPE(PC,HDR) pHdr, FILE *pOut)
133{
134 /*
135 * Any commandline?
136 */
137 if (pHdr->offCommandLine)
138 fprintf(pOut,
139 "Commandline: %s (%d bytes)\n",
140 (char *)KPRF_OFF2PTR(PC,MODSEG, pHdr->offCommandLine, pHdr), /* stupid, stupid, type hacking. */
141 pHdr->cchCommandLine);
142
143 /*
144 * Dump the module segments.
145 */
146 fprintf(pOut,
147 "Module Segments: off=0x%x 0x%x/0x%x (bytes)\n"
148 "----------------\n",
149 pHdr->offModSegs, pHdr->cbModSegs, pHdr->cbMaxModSegs);
150 KU32 off = pHdr->offModSegs;
151 while (off < pHdr->offModSegs + pHdr->cbModSegs)
152 {
153 KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pHdr);
154 KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
155 cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
156
157 fprintf(pOut,
158 "0x%04x: iSegment=0x%08x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n",
159 off, pCur->iSegment, pCur->uBasePtr, pCur->szPath, pCur->cchPath);
160
161 /* next */
162 off += cbCur;
163 }
164 fprintf(pOut, "\n");
165
166 /*
167 * Dump the functions.
168 */
169 fprintf(pOut,
170 "Functions: off=0x%x 0x%x/0x%x\n"
171 "----------\n",
172 pHdr->offFunctions, pHdr->cFunctions, pHdr->cMaxFunctions);
173 KPRF_TYPE(PC,FUNC) paFuncs = KPRF_OFF2PTR(PC,FUNC, pHdr->offFunctions, pHdr);
174 for (KU32 i = 0; i < pHdr->cFunctions; i++)
175 {
176 KPRF_TYPE(PC,FUNC) pCur = &paFuncs[i];
177 fprintf(pOut, "0x%04x: uEntryPtr=%" KPRF_FMT_UPTR " cOnStack=0x%" KPRF_FMT_X64 " cCalls=0x%" KPRF_FMT_X64 "\n"
178 " OnStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n"
179 " OnTopOfStack={0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 ", 0x%" KPRF_FMT_X64 "}\n",
180 i, pCur->uEntryPtr, pCur->cOnStack, pCur->cCalls,
181 pCur->OnStack.MinTicks, pCur->OnStack.MaxTicks, pCur->OnStack.SumTicks,
182 pCur->OnTopOfStack.MinTicks, pCur->OnTopOfStack.MaxTicks, pCur->OnTopOfStack.SumTicks);
183 if (pCur->offModSeg)
184 {
185 KPRF_TYPE(PC,MODSEG) pModSeg = KPRF_OFF2PTR(PC,MODSEG, pCur->offModSeg, pHdr);
186 fprintf(pOut, " offModSeg=0x%08x iSegment=0x%02x uBasePtr=%" KPRF_FMT_UPTR " szPath='%s' (%d bytes)\n",
187 pCur->offModSeg, pModSeg->iSegment, pModSeg->uBasePtr, pModSeg->szPath, pModSeg->cchPath);
188
189#if 1
190 PKDBGMOD pMod;
191 int rc = kDbgModuleOpen(&pMod, pModSeg->szPath, NULL /* pLdrMod */);
192 if (!rc)
193 {
194 KDBGSYMBOL Sym;
195 rc = kDbgModuleQuerySymbol(pMod, pModSeg->iSegment, pCur->uEntryPtr - pModSeg->uBasePtr, &Sym);
196 if (!rc)
197 {
198 fprintf(pOut, " %s\n", Sym.szName);
199 }
200 kDbgModuleClose(pMod);
201 }
202#endif
203
204 }
205 }
206 fprintf(pOut, "\n");
207
208 /*
209 * Dump the threads.
210 */
211 fprintf(pOut,
212 "Threads: off=0x%x 0x%x/0x%x (Stacks=0x%x/0x%x cMaxStackFrames=0x%x)\n"
213 "--------\n",
214 pHdr->offThreads, pHdr->cThreads, pHdr->cMaxThreads, pHdr->cStacks, pHdr->cMaxStacks, pHdr->cMaxStackFrames);
215 KPRF_TYPE(PC,THREAD) paThreads = KPRF_OFF2PTR(PC,THREAD, pHdr->offThreads, pHdr);
216 for (KU32 i = 0; i < pHdr->cThreads; i++)
217 {
218 KPRF_TYPE(PC,THREAD) pCur = &paThreads[i];
219 fprintf(pOut,
220 "0x%02x: ThreadId=0x%08" KPRF_FMT_X64 " enmState=%d szName='%s'\n"
221 " uStackBasePtr=%" KPRF_FMT_UPTR " cbMaxStack=%" KPRF_FMT_UPTR "\n"
222 " cCalls=0x%" KPRF_FMT_X64 " cOverflows=0x%" KPRF_FMT_X64 " cStackSwitchRejects=0x%" KPRF_FMT_X64 "\n"
223 " cUnwinds=0x%" KPRF_FMT_X64 " ProfiledTicks=0x%" KPRF_FMT_X64 " OverheadTicks=0x%" KPRF_FMT_X64 "\n",
224 i, pCur->ThreadId, pCur->enmState, pCur->szName,
225 pCur->uStackBasePtr, pCur->cbMaxStack,
226 pCur->cCalls, pCur->cOverflows, pCur->cStackSwitchRejects,
227 pCur->cUnwinds, pCur->ProfiledTicks, pCur->OverheadTicks);
228 }
229
230 return 0;
231}
232
233
234/** Pointer to a report module.
235 * @internal */
236typedef struct KPRF_TYPE(,REPORTMOD) *KPRF_TYPE(P,REPORTMOD);
237/** Pointer to a report module segment.
238 * @internal */
239typedef struct KPRF_TYPE(,REPORTMODSEG) *KPRF_TYPE(P,REPORTMODSEG);
240
241
242/**
243 * A report module segment.
244 *
245 * @internal
246 */
247typedef struct KPRF_TYPE(,REPORTMODSEG)
248{
249 /** AVL node core. The key is the data set offset of the module segment record. */
250 KDBGADDR offSegment;
251 struct KPRF_TYPE(,REPORTMODSEG) *mpLeft; /**< AVL left branch. */
252 struct KPRF_TYPE(,REPORTMODSEG) *mpRight; /**< AVL rigth branch. */
253 /** Pointer to the next segment for the module. */
254 KPRF_TYPE(P,REPORTMODSEG) pNext;
255 /** Pointer to the module segment data in the data set. */
256 KPRF_TYPE(PC,MODSEG) pModSeg;
257 /** Pointer to the module this segment belongs to. */
258 KPRF_TYPE(P,REPORTMOD) pMod;
259 /** The time this segment has spent on the stack.. */
260 KU64 OnStackTicks;
261 /** The time this segment has spent on the top of the stack.. */
262 KU64 OnTopOfStackTicks;
263 /** The number of profiled functions from this segment. */
264 KU32 cFunctions;
265 KU8 mHeight; /**< AVL Subtree height. */
266} KPRF_TYPE(,REPORTMODSEG), *KPRF_TYPE(P,REPORTMODSEG);
267
268
269/**
270 * A report module segment.
271 *
272 * @internal
273 */
274typedef struct KPRF_TYPE(,REPORTMOD)
275{
276 /** The module number. */
277 KU32 iMod;
278 /** Pointer to the next module in the list. */
279 KPRF_TYPE(P,REPORTMOD) pNext;
280 /** Pointer to the list of segments belonging to this module. */
281 KPRF_TYPE(P,REPORTMODSEG) pFirstSeg;
282 /** The debug module handle. */
283 PKDBGMOD pDbgMod;
284 /** The time this segment has spent on the stack.. */
285 KU64 OnStackTicks;
286 /** The time this segment has spent on the top of the stack.. */
287 KU64 OnTopOfStackTicks;
288 /** The number of profiled functions from this segment. */
289 KU32 cFunctions;
290} KPRF_TYPE(,REPORTMOD), *KPRF_TYPE(P,REPORTMOD);
291
292
293/**
294 * A report function.
295 *
296 * @internal
297 */
298typedef struct KPRF_TYPE(,REPORTFUNC)
299{
300 /** Pointer to the function data in the data set. */
301 KPRF_TYPE(PC,FUNC) pFunc;
302 /** Pointer to the module segment this function belongs to. (can be NULL) */
303 KPRF_TYPE(P,REPORTMODSEG) pModSeg;
304 /** Pointer to the function symbol. */
305 PKDBGSYMBOL pSym;
306 /** Pointer to the function line number. */
307 PKDBGLINE pLine;
308} KPRF_TYPE(,REPORTFUNC), *KPRF_TYPE(P,REPORTFUNC);
309
310
311/**
312 * Compares two REPROTFUNC records to determin which has the higher on-stack time.
313 */
314static int KPRF_NAME(FuncCompareOnStack)(const void *pv1, const void *pv2)
315{
316 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
317 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
318 if (p1->OnStack.SumTicks > p2->OnStack.SumTicks)
319 return -1;
320 if (p1->OnStack.SumTicks < p2->OnStack.SumTicks)
321 return 1;
322 if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks)
323 return -1;
324 if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks)
325 return 1;
326 if (p1->OnStack.MinTicks > p2->OnStack.MinTicks)
327 return -1;
328 if (p1->OnStack.MinTicks < p2->OnStack.MinTicks)
329 return 1;
330 if (p1 < p2)
331 return -1;
332 return 1;
333}
334
335
336/**
337 * Compares two REPROTFUNC records to determin which has the higher on-stack average time.
338 */
339static int KPRF_NAME(FuncCompareOnStackAvg)(const void *pv1, const void *pv2)
340{
341 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
342 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
343 if (p1->OnStack.SumTicks / p1->cOnStack > p2->OnStack.SumTicks / p2->cOnStack)
344 return -1;
345 if (p1->OnStack.SumTicks / p1->cOnStack < p2->OnStack.SumTicks / p2->cOnStack)
346 return 1;
347 return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
348}
349
350
351/**
352 * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
353 */
354static int KPRF_NAME(FuncCompareOnStackMin)(const void *pv1, const void *pv2)
355{
356 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
357 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
358 if (p1->OnStack.MinTicks > p2->OnStack.MinTicks)
359 return -1;
360 if (p1->OnStack.MinTicks < p2->OnStack.MinTicks)
361 return 1;
362 return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
363}
364
365
366/**
367 * Compares two REPROTFUNC records to determin which has the higher on-stack max time.
368 */
369static int KPRF_NAME(FuncCompareOnStackMax)(const void *pv1, const void *pv2)
370{
371 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
372 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
373 if (p1->OnStack.MaxTicks > p2->OnStack.MaxTicks)
374 return -1;
375 if (p1->OnStack.MaxTicks < p2->OnStack.MaxTicks)
376 return 1;
377 return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
378}
379
380
381/**
382 * Compares two REPROTFUNC records to determin which has the higher on-stack time.
383 */
384static int KPRF_NAME(FuncCompareOnTopOfStack)(const void *pv1, const void *pv2)
385{
386 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
387 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
388 if (p1->OnTopOfStack.SumTicks > p2->OnTopOfStack.SumTicks)
389 return -1;
390 if (p1->OnTopOfStack.SumTicks < p2->OnTopOfStack.SumTicks)
391 return 1;
392 if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks)
393 return -1;
394 if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks)
395 return 1;
396 if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks)
397 return -1;
398 if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks)
399 return 1;
400 if (p1 < p2)
401 return -1;
402 return 1;
403}
404
405
406/**
407 * Compares two REPROTFUNC records to determin which has the higher on-stack average time.
408 */
409static int KPRF_NAME(FuncCompareOnTopOfStackAvg)(const void *pv1, const void *pv2)
410{
411 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
412 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
413 if (p1->OnTopOfStack.SumTicks / p1->cOnStack > p2->OnTopOfStack.SumTicks / p2->cOnStack)
414 return -1;
415 if (p1->OnTopOfStack.SumTicks / p1->cOnStack < p2->OnTopOfStack.SumTicks / p2->cOnStack)
416 return 1;
417 return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
418}
419
420
421/**
422 * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
423 */
424static int KPRF_NAME(FuncCompareOnTopOfStackMin)(const void *pv1, const void *pv2)
425{
426 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
427 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
428 if (p1->OnTopOfStack.MinTicks > p2->OnTopOfStack.MinTicks)
429 return -1;
430 if (p1->OnTopOfStack.MinTicks < p2->OnTopOfStack.MinTicks)
431 return 1;
432 return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
433}
434
435
436/**
437 * Compares two REPROTFUNC records to determin which has the higher on-stack min time.
438 */
439static int KPRF_NAME(FuncCompareOnTopOfStackMax)(const void *pv1, const void *pv2)
440{
441 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
442 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
443 if (p1->OnTopOfStack.MaxTicks > p2->OnTopOfStack.MaxTicks)
444 return -1;
445 if (p1->OnTopOfStack.MaxTicks < p2->OnTopOfStack.MaxTicks)
446 return 1;
447 return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
448}
449
450
451/**
452 * Compares two REPROTFUNC records to determin which has the higher call to count.
453 */
454static int KPRF_NAME(FuncCompareCallsTo)(const void *pv1, const void *pv2)
455{
456 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
457 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
458 if (p1->cOnStack > p2->cOnStack)
459 return -1;
460 if (p1->cOnStack < p2->cOnStack)
461 return 1;
462 return KPRF_NAME(FuncCompareOnStack)(pv1, pv2);
463}
464
465
466/**
467 * Compares two REPROTFUNC records to determin which has the higher call from count.
468 */
469static int KPRF_NAME(FuncCompareCallsFrom)(const void *pv1, const void *pv2)
470{
471 KPRF_TYPE(PC,FUNC) p1 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv1)->pFunc;
472 KPRF_TYPE(PC,FUNC) p2 = (*(KPRF_TYPE(P,REPORTFUNC) *)pv2)->pFunc;
473 if (p1->cCalls > p2->cCalls)
474 return -1;
475 if (p1->cCalls < p2->cCalls)
476 return 1;
477 return KPRF_NAME(FuncCompareOnTopOfStack)(pv1, pv2);
478}
479
480
481/**
482 * A report thread.
483 *
484 * @internal
485 */
486typedef struct KPRF_TYPE(,REPORTTHREAD)
487{
488 /** Pointer to the thread data in the data set. */
489 KPRF_TYPE(PC,THREAD) pThread;
490} KPRF_TYPE(,REPORTTHREAD), *KPRF_TYPE(P,REPORTTHREAD);
491
492
493/**
494 * Data-set analysis report.
495 *
496 * This is an internal structure to store temporary data between the
497 * analysis stage and the priting state.
498 *
499 * @internal
500 */
501typedef struct KPRF_TYPE(,REPORT)
502{
503 /** Pointer to the data set. */
504 KPRF_TYPE(PC,HDR) pHdr;
505
506 /** @name Data-set item wrappers.
507 * @{ */
508 /** Pointer to the array of threads. */
509 KPRF_TYPE(P,REPORTTHREAD) paThreads;
510 /** Pointer to the array of functions. */
511 KPRF_TYPE(P,REPORTFUNC) paFunctions;
512 /** Pointer to the head of the module list. */
513 KPRF_TYPE(P,REPORTMOD) pFirstMod;
514 /** The number of modules in the list. */
515 KU32 cMods;
516 /** The module segment tree. (Only kAvl cares about this.) */
517 KPRF_TYPE(P,REPORTMODSEG) pModSegTree;
518 /** The number of module segments in the tree. */
519 KU32 cModSegs;
520 /** @} */
521
522 /** @name Sorting.
523 * @{ */
524 /** Pointer to the array of threads. */
525 KPRF_TYPE(P,REPORTTHREAD) *papSortedThreads;
526 /** Pointer to the array of functions. */
527 KPRF_TYPE(P,REPORTFUNC) *papSortedFunctions;
528 /** @} */
529
530 /** @name Accumulated Thread Data.
531 * @{ */
532 /** Sum of the profiled ticks. */
533 KU64 ProfiledTicks;
534 /** Sum of the overhead ticks. */
535 KU64 OverheadTicks;
536 /** Sum of the sleep ticks. */
537 KU64 SleepTicks;
538 /** Sum of calls performed. */
539 KU64 cCalls;
540 /** @} */
541
542} KPRF_TYPE(,REPORT), *KPRF_TYPE(P,REPORT), **KPRF_TYPE(PP,REPORT);
543
544
545/* Instantiate the AVL tree code. */
546#define KAVL_CHECK_FOR_EQUAL_INSERT
547#define KAVL_MAX_STACK 32
548#define KAVL_STD_KEY_COMP
549#define mKey offSegment
550#define KAVLKEY KDBGADDR
551#define KAVLNODE KPRF_TYPE(,REPORTMODSEG)
552#define mpRoot pModSegTree
553#define KAVLROOT KPRF_TYPE(,REPORT)
554#define KAVL_FN(name) KPRF_NAME(ReportTree ## name)
555#define KAVL_TYPE(prefix,name) KPRF_TYPE(prefix, REPORTMODESEG ## name)
556#define KAVL_INT(name) KPRF_NAME(REPORTMODESEGINT ## name)
557#define KAVL_DECL(type) K_DECL_INLINE(type)
558#include <k/kAvlTmpl/kAvlBase.h>
559#include <k/kAvlTmpl/kAvlDestroy.h>
560#include <k/kAvlTmpl/kAvlGet.h>
561#include <k/kAvlTmpl/kAvlUndef.h>
562
563
564/**
565 * Allocates and initializes a report.
566 *
567 * @returns Pointer to the report on success.
568 * @returns NULL on failure.
569 */
570static KPRF_TYPE(P,REPORT) KPRF_NAME(NewReport)(KPRF_TYPE(PC,HDR) pHdr)
571{
572 /*
573 * Allocate memory for the report.
574 * Everything but the mods and modsegs is allocated in the same block as the report.
575 */
576 KSIZE cb = KPRF_ALIGN(KPRF_SIZEOF(REPORT), 32);
577 KUPTR offThreads = cb;
578 cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTTHREAD) * pHdr->cThreads, 32);
579 KUPTR offFunctions = cb;
580 cb += KPRF_ALIGN(KPRF_SIZEOF(REPORTFUNC) * pHdr->cFunctions, 32);
581 KUPTR offSortedThreads = cb;
582 cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTTHREAD)) * pHdr->cThreads, 32);
583 KUPTR offSortedFunctions = cb;
584 cb += KPRF_ALIGN(sizeof(KPRF_TYPE(P,REPORTFUNC)) * pHdr->cFunctions, 32);
585 KPRF_TYPE(P,REPORT) pReport = (KPRF_TYPE(P,REPORT))malloc(cb);
586 if (!pReport)
587 return NULL;
588
589 /*
590 * Initialize it.
591 */
592 pReport->pHdr = pHdr;
593 pReport->paThreads = (KPRF_TYPE(P,REPORTTHREAD))((KU8 *)pReport + offThreads);
594 pReport->paFunctions = (KPRF_TYPE(P,REPORTFUNC))((KU8 *)pReport + offFunctions);
595 pReport->pFirstMod = NULL;
596 pReport->cMods = 0;
597 KPRF_NAME(ReportTreeInit)(pReport);
598 pReport->cModSegs = 0;
599 pReport->papSortedThreads = (KPRF_TYPE(P,REPORTTHREAD) *)((KU8 *)pReport + offSortedThreads);
600 pReport->papSortedFunctions = (KPRF_TYPE(P,REPORTFUNC) *)((KU8 *)pReport + offSortedFunctions);
601 pReport->ProfiledTicks = 0;
602 pReport->OverheadTicks = 0;
603 pReport->SleepTicks = 0;
604 pReport->cCalls = 0;
605
606 return pReport;
607}
608
609
610/**
611 * AVL callback for deleting a module segment node.
612 *
613 * @returns 0
614 * @param pCore The tree node to delete.
615 * @param pvParam User parameter, ignored.
616 */
617static int KPRF_NAME(DeleteModSeg)(KPRF_TYPE(P,REPORTMODSEG) pCore, void *pvParam)
618{
619 free(pCore);
620 return 0;
621}
622
623
624/**
625 * Releases all the resources held be a report.
626 *
627 * @param pReport The report to delete.
628 */
629static void KPRF_NAME(DeleteReport)(KPRF_TYPE(P,REPORT) pReport)
630{
631 /*
632 * The list and AVL.
633 */
634 while (pReport->pFirstMod)
635 {
636 KPRF_TYPE(P,REPORTMOD) pFree = pReport->pFirstMod;
637 pReport->pFirstMod = pFree->pNext;
638 kDbgModuleClose(pFree->pDbgMod);
639 free(pFree);
640 }
641
642 KPRF_NAME(ReportTreeDestroy)(pReport, KPRF_NAME(DeleteModSeg), NULL);
643
644 /*
645 * The function debug info.
646 */
647 KU32 i = pReport->pHdr->cFunctions;
648 while (i-- > 0)
649 {
650 kDbgSymbolFree(pReport->paFunctions[i].pSym);
651 kDbgLineFree(pReport->paFunctions[i].pLine);
652 }
653
654 /*
655 * The report it self.
656 */
657 pReport->pHdr = NULL;
658 free(pReport);
659}
660
661
662/**
663 * Builds the module segment tree and the list of modules.
664 *
665 * @returns 0 on success.
666 * @returns -1 on failure.
667 * @param pReport The report to work on.
668 */
669static int KPRF_NAME(AnalyzeModSegs)(KPRF_TYPE(P,REPORT) pReport)
670{
671 const KU32 offEnd = pReport->pHdr->offModSegs + pReport->pHdr->cbModSegs;
672 KU32 off = pReport->pHdr->offModSegs;
673 while (off < offEnd)
674 {
675 KPRF_TYPE(PC,MODSEG) pCur = KPRF_OFF2PTR(PC,MODSEG, off, pReport->pHdr);
676 KU32 cbCur = KPRF_OFFSETOF(MODSEG, szPath[pCur->cchPath + 1]);
677 cbCur = KPRF_ALIGN(cbCur, KPRF_SIZEOF(UPTR));
678
679 /*
680 * Create a new modseg record.
681 */
682 KPRF_TYPE(P,REPORTMODSEG) pSeg = (KPRF_TYPE(P,REPORTMODSEG))malloc(sizeof(*pSeg));
683 if (!pSeg)
684 return -1;
685
686 pSeg->offSegment = off;
687 pSeg->pModSeg = pCur;
688 pSeg->pMod = NULL; /* below */
689 pSeg->OnStackTicks = 0;
690 pSeg->OnTopOfStackTicks = 0;
691 pSeg->cFunctions = 0;
692
693 if (!KPRF_NAME(ReportTreeInsert)(pReport, pSeg))
694 {
695 free(pSeg);
696 return -1;
697 }
698 pReport->cModSegs++;
699
700 /*
701 * Search for the module record.
702 */
703 KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod;
704 while ( pMod
705 && ( pMod->pFirstSeg->pModSeg->cchPath != pCur->cchPath
706 || memcmp(pMod->pFirstSeg->pModSeg->szPath, pCur->szPath, pCur->cchPath)))
707 pMod = pMod->pNext;
708 if (pMod)
709 {
710 /** @todo sort segments */
711 pSeg->pMod = pMod;
712 pSeg->pNext = pMod->pFirstSeg;
713 pMod->pFirstSeg = pSeg;
714 }
715 else
716 {
717 KPRF_TYPE(P,REPORTMOD) pMod = (KPRF_TYPE(P,REPORTMOD))malloc(sizeof(*pMod) + pCur->cchPath);
718 if (!pMod)
719 return -1;
720 pSeg->pMod = pMod;
721 pSeg->pNext = NULL;
722 pMod->iMod = pReport->cMods++;
723 pMod->pNext = pReport->pFirstMod;
724 pReport->pFirstMod = pMod;
725 pMod->pFirstSeg = pSeg;
726 pMod->pDbgMod = NULL;
727 pMod->OnStackTicks = 0;
728 pMod->OnTopOfStackTicks = 0;
729 pMod->cFunctions = 0;
730
731 int rc = kDbgModuleOpen(&pMod->pDbgMod, pSeg->pModSeg->szPath, NULL /* kLdrMod */);
732 if (rc)
733 pMod->pDbgMod = NULL;
734 }
735
736 /* next */
737 off += cbCur;
738 }
739
740 return 0;
741}
742
743
744/**
745 * Initializes the function arrays.
746 *
747 * @returns 0 on success.
748 * @returns -1 on failure.
749 * @param pReport The report to work on.
750 */
751static int KPRF_NAME(AnalyseFunctions)(KPRF_TYPE(P,REPORT) pReport)
752{
753 KU32 iFunc = pReport->pHdr->cFunctions;
754 KPRF_TYPE(PC,FUNC) pFunc = KPRF_OFF2PTR(PC,FUNC, pReport->pHdr->offFunctions + iFunc * sizeof(*pFunc), pReport->pHdr);
755 KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc];
756 while (iFunc-- > 0)
757 {
758 pFunc--;
759 pReportFunc--;
760
761 pReport->papSortedFunctions[iFunc] = pReportFunc;
762 pReportFunc->pFunc = pFunc;
763 pReportFunc->pModSeg = KPRF_NAME(ReportTreeGet)(pReport, pFunc->offModSeg);
764 pReportFunc->pSym = NULL;
765 pReportFunc->pLine = NULL;
766 if (pReportFunc->pModSeg)
767 {
768 /* Collect module segment and module statistics. */
769 KPRF_TYPE(P,REPORTMODSEG) pModSeg = pReportFunc->pModSeg;
770 pModSeg->cFunctions++;
771 pModSeg->OnStackTicks += pFunc->OnStack.SumTicks;
772 pModSeg->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks;
773
774 KPRF_TYPE(P,REPORTMOD) pMod = pModSeg->pMod;
775 pMod->cFunctions++;
776 pMod->OnStackTicks += pFunc->OnStack.SumTicks;
777 pMod->OnTopOfStackTicks += pFunc->OnTopOfStack.SumTicks;
778
779 /* Get debug info. */
780 KDBGADDR offSegment = pFunc->uEntryPtr - pModSeg->pModSeg->uBasePtr;
781 int rc = kDbgModuleQuerySymbolA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pSym);
782 /** @todo check displacement! */
783 if (rc)
784 pReportFunc->pSym = NULL;
785 rc = kDbgModuleQueryLineA(pMod->pDbgMod, pModSeg->pModSeg->iSegment, offSegment, &pReportFunc->pLine);
786 if (rc)
787 pReportFunc->pLine = NULL;
788 }
789 }
790 return 0;
791}
792
793
794/**
795 * Initializes the thread arrays.
796 *
797 * @returns 0 on success.
798 * @returns -1 on failure.
799 * @param pReport The report to work on.
800 */
801static int KPRF_NAME(AnalyseThreads)(KPRF_TYPE(P,REPORT) pReport)
802{
803 KU32 iThread = pReport->pHdr->cThreads;
804 KPRF_TYPE(PC,THREAD) pThread = KPRF_OFF2PTR(PC,THREAD, pReport->pHdr->offThreads + iThread * sizeof(*pThread), pReport->pHdr);
805 KPRF_TYPE(P,REPORTTHREAD) pReportThread = &pReport->paThreads[iThread];
806 while (iThread-- > 0)
807 {
808 pThread--;
809 pReportThread--;
810
811 pReport->papSortedThreads[iThread] = pReportThread;
812 pReportThread->pThread = pThread;
813
814 /* collect statistics */
815 pReport->ProfiledTicks += pThread->ProfiledTicks;
816 pReport->OverheadTicks += pThread->OverheadTicks;
817 pReport->SleepTicks += pThread->SleepTicks;
818 pReport->cCalls += pThread->cCalls;
819
820 }
821 return 0;
822}
823
824
825/**
826 * Analyses the data set, producing a report.
827 *
828 * @returns 0 on success.
829 * @returns -1 on failure.
830 *
831 * @param pHdr The data set.
832 * @param ppReport Where to store the report.
833 */
834static int KPRF_NAME(Analyse)(KPRF_TYPE(PC,HDR) pHdr, KPRF_TYPE(PP,REPORT) ppReport)
835{
836 *ppReport = NULL;
837
838 /* allocate it */
839 KPRF_TYPE(P,REPORT) pReport = KPRF_NAME(NewReport)(pHdr);
840 if (!pReport)
841 return -1;
842
843 /* read module segments */
844 int rc = KPRF_NAME(AnalyzeModSegs)(pReport);
845 if (!rc)
846 {
847 /* read functions. */
848 rc = KPRF_NAME(AnalyseFunctions)(pReport);
849 if (!rc)
850 {
851 /* read threads */
852 rc = KPRF_NAME(AnalyseThreads)(pReport);
853 if (!rc)
854 {
855 *ppReport = pReport;
856 return 0;
857 }
858 }
859 }
860
861 KPRF_NAME(DeleteReport)(pReport);
862 return rc;
863}
864
865
866/**
867 * Writes row with 32-bit value.
868 * @internal
869 */
870static void KPRF_NAME(HtmlWriteRowU32X32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit)
871{
872 fprintf(pOut,
873 " <tr>\n"
874 " <th>%s</th>\n"
875 " <td colspan=\"6\">%u (0x%x)%s%s</td>\n"
876 " </tr>\n",
877 pszName,
878 u32, u32, pszUnit ? " " : "", pszUnit ? pszUnit : "");
879}
880
881
882/**
883 * Writes row with 32-bit value.
884 * @internal
885 */
886static void KPRF_NAME(HtmlWriteRowU32)(FILE *pOut, const char *pszName, KU32 u32, const char *pszUnit)
887{
888 fprintf(pOut,
889 " <tr>\n"
890 " <th>%s</th>\n"
891 " <td colspan=\"6\">%u%s%s</td>\n"
892 " </tr>\n",
893 pszName,
894 u32, pszUnit ? " " : "", pszUnit ? pszUnit : "");
895}
896
897
898/**
899 * Writes row with 64-bit value.
900 * @internal
901 */
902static void KPRF_NAME(HtmlWriteRowU64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit)
903{
904 fprintf(pOut,
905 " <tr>\n"
906 " <th>%s</th>\n"
907 " <td colspan=\"6\">% " KPRF_FMT_U64 " (0x%" KPRF_FMT_X64 ")%s%s</td>\n"
908 " </tr>\n",
909 pszName,
910 u64, u64, pszUnit ? " " : "", pszUnit ? pszUnit : "");
911}
912
913
914/**
915 * Writes row with 64-bit hex value.
916 * @internal
917 */
918static void KPRF_NAME(HtmlWriteRowX64)(FILE *pOut, const char *pszName, KU64 u64, const char *pszUnit)
919{
920 fprintf(pOut,
921 " <tr>\n"
922 " <th>%s</th>\n"
923 " <td colspan=\"6\">0x%" KPRF_FMT_X64 "%s%s</td>\n"
924 " </tr>\n",
925 pszName,
926 u64, pszUnit ? " " : "", pszUnit ? pszUnit : "");
927}
928
929
930/**
931 * Writes a ticks.
932 */
933static void KPRF_NAME(HtmlWriteParts)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks)
934{
935 /** U+2030 PER MILLE SIGN */
936 static const KU8 s_szPerMilleSignUtf8[4] = { 0xe2, 0x80, 0xb0, 0};
937
938 if (cTicks * 100 / cTotalTicks)
939 {
940 KU32 u = (KU32)((cTicks * 1000) / cTotalTicks);
941 fprintf(pOut, "%u.%01u%%", u / 10, u %10);
942 }
943 else //if (cTicks * 100000 / cTotalTicks)
944 {
945 KU32 u = (KU32)((cTicks * 100000) / cTotalTicks);
946 fprintf(pOut, "%u.%02u%s", u / 100, u % 100, s_szPerMilleSignUtf8);
947 }
948 /*
949 else if (cTicks * 1000000 / cTotalTicks)
950 fprintf(pOut, "%u ppm", (unsigned)((cTicks * 1000000) / cTotalTicks));
951 else
952 fprintf(pOut, "%u ppb", (unsigned)((cTicks * 1000000000) / cTotalTicks));
953 */
954}
955
956
957/**
958 * Writes a ticks.
959 */
960static void KPRF_NAME(HtmlWriteTicks)(FILE *pOut, KU64 cTicks, KU64 cTotalTicks)
961{
962 fprintf(pOut, "%" KPRF_FMT_U64 "", cTicks);
963 if (cTotalTicks)
964 {
965 fprintf(pOut, "</td><td class=\"PartsRow\">");
966 KPRF_NAME(HtmlWriteParts)(pOut, cTicks, cTotalTicks);
967 }
968}
969
970
971/**
972 * Writes row with ticks value.
973 *
974 * @param pOut Where to write.
975 * @aaran pszName The row name.
976 * @param cTicks The tick count.
977 * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks.
978 * @internal
979 */
980static void KPRF_NAME(HtmlWriteRowTicks)(FILE *pOut, const char *pszName, KU64 cTicks, KU64 cTotalTicks)
981{
982 fprintf(pOut,
983 " <tr>\n"
984 " <th class=\"TicksRow\">%s</th>\n"
985 " <td class=\"TicksRow\">",
986 pszName);
987 KPRF_NAME(HtmlWriteTicks)(pOut, cTicks, cTotalTicks);
988 fprintf(pOut,
989 "</td><td colspan=\"%d\"/>\n"
990 " </tr>\n",
991 cTotalTicks ? 4 : 5);
992}
993
994
995/**
996 * Writes row with a time stat value.
997 *
998 * @param pOut Where to write.
999 * @aaran pszName The row name.
1000 * @param cTicks The tick count.
1001 * @param cTotalTicks If non-zero, this is used for cTicks / cTotalTicks.
1002 * @internal
1003 */
1004static void KPRF_NAME(HtmlWriteRowTimeStat)(FILE *pOut, const char *pszName, KPRF_TYPE(PC,TIMESTAT) pTimeStat, KU64 cTotalTicks)
1005{
1006 fprintf(pOut,
1007 " <tr>\n"
1008 " <th class=\"TicksRow\">%s</th>\n"
1009 " <td class=\"TicksRow\">",
1010 pszName);
1011 KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->SumTicks, cTotalTicks);
1012 fprintf(pOut, "</td>\n"
1013 " <td class=\"MinMaxTicksRow\">");
1014 KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MinTicks, cTotalTicks);
1015 fprintf(pOut, "</td>\n"
1016 " <td class=\"MinMaxTicksRow\">");
1017 KPRF_NAME(HtmlWriteTicks)(pOut, pTimeStat->MaxTicks, cTotalTicks);
1018 fprintf(pOut, "</td>\n"
1019 " </tr>\n");
1020}
1021
1022
1023/**
1024 * Writes row with calls value.
1025 *
1026 * @param pOut Where to write.
1027 * @aaran pszName The row name.
1028 * @param cCalls The call count.
1029 * @param cTotalCalls This is used for cCalls / cTotalCalls.
1030 * @internal
1031 */
1032static void KPRF_NAME(HtmlWriteRowCalls)(FILE *pOut, const char *pszName, KU64 cCalls, KU64 cTotalCalls)
1033{
1034 fprintf(pOut,
1035 " <tr>\n"
1036 " <th class=\"CallsRow\">%s</th>\n"
1037 " <td class=\"CallsRow\">%" KPRF_FMT_U64"</td><td class=\"PartsRow\">",
1038 pszName, cCalls);
1039 KPRF_NAME(HtmlWriteParts)(pOut, cCalls, cTotalCalls);
1040 fprintf(pOut, "</td><td colspan=4></td>"
1041 " </tr>\n");
1042}
1043
1044
1045/**
1046 * Writes row with pointer value.
1047 * @internal
1048 */
1049static void KPRF_NAME(HtmlWriteRowUPTR)(FILE *pOut, const char *pszName, KPRF_TYPE(,UPTR) uPtr, const char *pszUnit)
1050{
1051 fprintf(pOut,
1052 " <tr>\n"
1053 " <th>%s</th>\n"
1054 " <td colspan=\"6\">%" KPRF_FMT_UPTR "%s%s</td>\n"
1055 " </tr>\n",
1056 pszName,
1057 uPtr, pszUnit ? " " : "", pszUnit ? pszUnit : "");
1058}
1059
1060
1061/**
1062 * Writes row with string value.
1063 * @internal
1064 */
1065static void KPRF_NAME(HtmlWriteRowString)(FILE *pOut, const char *pszName, const char *pszClass, const char *pszFormat, ...)
1066{
1067 fprintf(pOut,
1068 " <tr>\n"
1069 " <th>%s</th>\n"
1070 " <td%s%s%s colspan=\"6\">",
1071 pszName,
1072 pszClass ? " class=\"" : "", pszClass ? pszClass : "", pszClass ? "\"" : "");
1073 va_list va;
1074 va_start(va, pszFormat);
1075 vfprintf(pOut, pszFormat, va);
1076 va_end(va);
1077 fprintf(pOut, "</td>\n"
1078 " </tr>\n");
1079}
1080
1081
1082/**
1083 * The first column
1084 */
1085typedef enum KPRF_TYPE(,FIRSTCOLUMN)
1086{
1087 KPRF_TYPE(,FIRSTCOLUMN_ON_STACK) = 0,
1088 KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK),
1089 KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO),
1090 KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM),
1091 KPRF_TYPE(,FIRSTCOLUMN_MAX)
1092} KPRF_TYPE(,FIRSTCOLUMN);
1093
1094
1095/**
1096 * Prints the table with the sorted functions.
1097 * The tricky bit is that the sorted column should be to the left of the function name.
1098 */
1099static void KPRF_NAME(HtmlWriteSortedFunctions)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut, const char *pszName,
1100 const char *pszTitle, KPRF_TYPE(,FIRSTCOLUMN) enmFirst)
1101{
1102 fprintf(pOut,
1103 "<h2><a name=\"%s\">%s</a></h2>\n"
1104 "\n",
1105 pszName, pszTitle);
1106
1107 fprintf(pOut,
1108 "<table class=\"FunctionsSorted\">\n"
1109 " <tr>\n"
1110 " <th/>\n");
1111 static const char *s_pszHeaders[KPRF_TYPE(,FIRSTCOLUMN_MAX) * 2] =
1112 {
1113 " <th colspan=8><a href=\"#Functions-TimeOnStack\">Time On Stack</a> (ticks)</th>\n",
1114 " <th colspan=2><a href=\"#Functions-TimeOnStack\">Sum</a></th>\n"
1115 " <th colspan=2><a href=\"#Functions-TimeOnStack-Min\">Min</a></th>\n"
1116 " <th colspan=2><a href=\"#Functions-TimeOnStack-Avg\">Average</a></th>\n"
1117 " <th colspan=2><a href=\"#Functions-TimeOnStack-Max\">Max</a></th>\n",
1118
1119 " <th colspan=8><a href=\"#Functions-TimeOnTopOfStack\">Time On To Top</a> (ticks)</th>\n",
1120 " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack\">Sum</a></th>\n"
1121 " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Min\">Min</a></th>\n"
1122 " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Avg\">Average</a></th>\n"
1123 " <th colspan=2><a href=\"#Functions-TimeOnTopOfStack-Max\">Max</a></th>\n",
1124
1125 " <th colspan=2><a href=\"#Functions-CallsTo\">Calls To</a></th>\n",
1126 " <th/><th/>\n",
1127
1128 " <th colspan=2><a href=\"#Functions-CallsFrom\">Calls From</a></th>\n",
1129 " <th/><th/>\n",
1130 };
1131
1132 fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2]);
1133 fprintf(pOut, " <th>Function</th>\n");
1134 for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX))
1135 fprintf(pOut, "%s", s_pszHeaders[i * 2]);
1136 fprintf(pOut,
1137 " </tr>\n"
1138 " <tr>\n"
1139 " <th/>\n");
1140 fprintf(pOut, "%s", s_pszHeaders[enmFirst * 2 + 1]);
1141 fprintf(pOut, " <th/>\n");
1142 for (unsigned i = (enmFirst + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX); i != enmFirst; i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX))
1143 fprintf(pOut, "%s", s_pszHeaders[i * 2 + 1]);
1144 fprintf(pOut,
1145 " </tr>\n");
1146
1147 for (KU32 iFunc = 0; iFunc < pReport->pHdr->cFunctions; iFunc++)
1148 {
1149 KPRF_TYPE(P,REPORTFUNC) pReportFunc = pReport->papSortedFunctions[iFunc];
1150 KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc;
1151 fprintf(pOut,
1152 " <tr>\n"
1153 " <td>%u</td>\n",
1154 iFunc);
1155
1156 unsigned i = enmFirst;
1157 do
1158 {
1159 switch (i)
1160 {
1161 case KPRF_TYPE(,FIRSTCOLUMN_ON_STACK):
1162 fprintf(pOut,
1163 " <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1164 pFunc->OnStack.SumTicks);
1165 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.SumTicks, pReport->ProfiledTicks);
1166 fprintf(pOut, "</td>\n"
1167 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1168 pFunc->OnStack.MinTicks);
1169 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
1170 fprintf(pOut, "</td>\n"
1171 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1172 pFunc->OnStack.SumTicks / pFunc->cOnStack);
1173 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MinTicks, pReport->ProfiledTicks);
1174 fprintf(pOut, "</td>\n"
1175 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1176 pFunc->OnStack.MaxTicks);
1177 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnStack.MaxTicks, pReport->ProfiledTicks);
1178 fprintf(pOut, "</td>\n");
1179 break;
1180
1181 case KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK):
1182 fprintf(pOut,
1183 " <td class=\"Ticks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1184 pFunc->OnTopOfStack.SumTicks);
1185 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.SumTicks, pReport->ProfiledTicks);
1186 fprintf(pOut, "</td>\n"
1187 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1188 pFunc->OnTopOfStack.MinTicks);
1189 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
1190 fprintf(pOut, "</td>\n"
1191 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1192 pFunc->OnTopOfStack.SumTicks / pFunc->cOnStack);
1193 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MinTicks, pReport->ProfiledTicks);
1194 fprintf(pOut, "</td>\n"
1195 " <td class=\"MinMaxTicks\">%" KPRF_FMT_U64 "</td><td class=\"Parts\">",
1196 pFunc->OnTopOfStack.MaxTicks);
1197 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->OnTopOfStack.MaxTicks, pReport->ProfiledTicks);
1198 fprintf(pOut, "</td>\n");
1199 break;
1200
1201 case KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO):
1202 fprintf(pOut,
1203 " <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
1204 pFunc->cOnStack);
1205 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cOnStack, pReport->cCalls);
1206 fprintf(pOut, "</td>\n");
1207 break;
1208
1209 case KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM):
1210 fprintf(pOut,
1211 " <td class=\"Calls\">%" KPRF_FMT_U64 "</td><td Class=\"Parts\">",
1212 pFunc->cCalls);
1213 KPRF_NAME(HtmlWriteParts)(pOut, pFunc->cCalls, pReport->cCalls);
1214 fprintf(pOut, "</td>\n");
1215 break;
1216
1217 default:
1218 break;
1219 }
1220
1221 /* inject the function column */
1222 if (i == enmFirst)
1223 {
1224 fprintf(pOut,
1225 " <td><a href=\"#Func-%u\">",
1226 pReportFunc - pReport->paFunctions);
1227 if (pReportFunc->pSym)
1228 fprintf(pOut, "%s</a></td>\n", pReportFunc->pSym->szName);
1229 else
1230 fprintf(pOut, "%" KPRF_FMT_UPTR "</a></td>\n", pFunc->uEntryPtr);
1231 }
1232
1233 /* next */
1234 i = (i + 1) % KPRF_TYPE(,FIRSTCOLUMN_MAX);
1235 } while (i != enmFirst);
1236
1237 fprintf(pOut,
1238 " </tr>\n");
1239 }
1240 fprintf(pOut,
1241 "</table>\n"
1242 "\n");
1243
1244}
1245
1246
1247/**
1248 * Writes an HTML report.
1249 *
1250 * @returns 0 on success.
1251 * @returns -1 on failure.
1252 * @param pReport The report to put into HTML.
1253 * @param pOut The file stream to write the HTML to.
1254 */
1255static int KPRF_NAME(WriteHtmlReport)(KPRF_TYPE(P,REPORT) pReport, FILE *pOut)
1256{
1257 KPRF_TYPE(PC,HDR) pHdr = pReport->pHdr;
1258
1259 /*
1260 * Write the standard html.
1261 */
1262 fprintf(pOut,
1263 "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
1264 "<html>\n"
1265 "<head>\n"
1266 " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n"
1267 " <title>kProfiler 2 - %s</title>\n"
1268 "</head>\n"
1269 "<style>\n"
1270 "table\n"
1271 "{\n"
1272// " width: 90%%;\n"
1273 " background: #999999;\n"
1274// " margin-top: .6em;\n"
1275// " margin-bottom: .3em;\n"
1276 "}\n"
1277 "th\n"
1278 "{\n"
1279 " padding: 1px 4px;\n"
1280 " background: #cccccc;\n"
1281// " text-align: left;\n"
1282 " font-size: 90%%;\n"
1283 //" width: 30%%;\n"
1284 "}\n"
1285 "td\n"
1286 "{\n"
1287 " padding: 1px 4px;\n"
1288 " background: #ffffff;\n"
1289 " font-size: 90%%;\n"
1290 "}\n"
1291 "td.Ticks\n"
1292 "{\n"
1293 " text-align: right;\n"
1294 "}\n"
1295 "td.TicksRow\n"
1296 "{\n"
1297 " text-align: right;\n"
1298 "}\n"
1299 "td.MinMaxTicks\n"
1300 "{\n"
1301 " text-align: right;\n"
1302 "}\n"
1303 "td.MinMaxTicksRow\n"
1304 "{\n"
1305 " text-align: right;\n"
1306 "}\n"
1307 "td.Parts\n"
1308 "{\n"
1309 " text-align: right;\n"
1310 "}\n"
1311 "td.PartsRow\n"
1312 "{\n"
1313 " text-align: left;\n"
1314 "}\n"
1315 "td.Calls\n"
1316 "{\n"
1317 " text-align: right;\n"
1318 "}\n"
1319 "td.CallsRow\n"
1320 "{\n"
1321 " text-align: right;\n"
1322 "}\n"
1323 "td.BlankRow\n"
1324 "{\n"
1325 " background: #e0e0e0;\n"
1326 "}\n"
1327 "td.Name\n"
1328 "{\n"
1329 " font-weight: bold;\n"
1330 "}\n"
1331 "table.Summary th\n"
1332 "{\n"
1333 " width:200px;\n"
1334 "}\n"
1335 "table.Thread\n"
1336 "{\n"
1337 " min-width:60%%\n"
1338 "}\n"
1339 "table.Thread th\n"
1340 "{\n"
1341 " width:200px;\n"
1342 "}\n"
1343 "table.Functions\n"
1344 "{\n"
1345 " width:60%%;\n"
1346 "}\n"
1347 "table.Functions th\n"
1348 "{\n"
1349 " width:200px;\n"
1350 "}\n"
1351 "table.Modules\n"
1352 "{\n"
1353 " width:60%%;\n"
1354 "}\n"
1355 "table.Modules th\n"
1356 "{\n"
1357 " width:200px;\n"
1358 "}\n"
1359 "table.FunctionsSorted\n"
1360 "{\n"
1361 "}\n"
1362 "</style>\n"
1363 "<body topmargin=\"0\">\n"
1364 ,
1365 pHdr->offCommandLine
1366 ? (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr)
1367 : ""
1368 );
1369
1370 /*
1371 * Table of contents.
1372 */
1373 fprintf(pOut,
1374 "<h2>Table of Contents</h2>\n"
1375 "\n"
1376 "<ul>\n"
1377 " <li><a href=\"#Summary\" >1.0 Summary</a></li>\n"
1378 " <li><a href=\"#Functions\">2.0 Functions</a></li>\n"
1379 " <ul>\n"
1380 " <li><a href=\"#Functions-TimeOnStack\" >2.1 Time On Stack</a></li>\n"
1381 " <ul>\n"
1382 " <li><a href=\"#Functions-TimeOnStack-Avg\" >2.2.1 Time On Stack - Average</a></li>\n"
1383 " <li><a href=\"#Functions-TimeOnStack-Min\" >2.2.1 Time On Stack - Min</a></li>\n"
1384 " <li><a href=\"#Functions-TimeOnStack-Max\" >2.2.2 Time On Stack - Max</a></li>\n"
1385 " </ul>\n"
1386 " <li><a href=\"#Functions-TimeOnTopOfStack\">2.3 Time On Top Of Stack</a></li>\n"
1387 " <ul>\n"
1388 " <li><a href=\"#Functions-TimeOnTopOfStack-Avg\">2.3.1 Time On Top Of Stack - Average</a></li>\n"
1389 " <li><a href=\"#Functions-TimeOnTopOfStack-Min\">2.3.2 Time On Top Of Stack - Min</a></li>\n"
1390 " <li><a href=\"#Functions-TimeOnTopOfStack-Max\">2.3.3 Time On Top Of Stack - Max</a></li>\n"
1391 " </ul>\n"
1392 " <li><a href=\"#Functions-CallsTo\" >2.3 Calls To</a></li>\n"
1393 " <li><a href=\"#Functions-CallsFrom\" >2.4 Calls From</a></li>\n"
1394 " <li><a href=\"#Function-Details\" >2.5 Function Details</a></li>\n"
1395 " </ul>\n"
1396 " <li><a href=\"#Threads\" >3.0 Threads</a></li>\n"
1397 " <li><a href=\"#Modules\" >4.0 Modules</a></li>\n"
1398 "</ul>\n"
1399 "\n"
1400 "\n");
1401
1402 /*
1403 * Summary.
1404 */
1405 fprintf(pOut,
1406 "<h2><a name=\"Summary\">1.0 Summary</a></h2>\n"
1407 "\n"
1408 "<p>\n"
1409 "<table class=\"Summary\">\n");
1410 if (pHdr->offCommandLine)
1411 KPRF_NAME(HtmlWriteRowString)(pOut, "Command Line", NULL, "%s", (const char *)KPRF_OFF2PTR(P,FUNC, pHdr->offCommandLine, pHdr));
1412 KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Threads", pHdr->cThreads, NULL);
1413 KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Modules", pReport->cMods, NULL);
1414 KPRF_NAME(HtmlWriteRowU32X32)(pOut, "Functions", pHdr->cFunctions, NULL);
1415 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pReport->ProfiledTicks, pReport->ProfiledTicks);
1416 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pReport->SleepTicks, pReport->ProfiledTicks);
1417 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pReport->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks);
1418 KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pReport->cCalls, pReport->cCalls);
1419 fprintf(pOut, "<tr><td class=\"BlankRow\" colspan=7>&nbsp;</td></tr>\n");
1420 KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Version ", NULL, "Mark 2 Alpha 1");
1421 KPRF_NAME(HtmlWriteRowString)(pOut, "kProfiler Build Time ", NULL, __DATE__ " " __TIME__);
1422 fprintf(pOut,
1423 "</table>\n"
1424 "</p>\n"
1425 "\n"
1426 "\n");
1427
1428 /*
1429 * Functions.
1430 */
1431 fprintf(pOut,
1432 "<h2><a name=\"Functions\">2.0 Functions</a></h2>\n"
1433 "\n");
1434
1435 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStack));
1436 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack", "2.1 Time On Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
1437 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackAvg));
1438 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Avg", "2.2.1 Time On Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
1439 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMin));
1440 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Min", "2.2.2 Time On Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
1441 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnStackMax));
1442 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnStack-Max", "2.2.3 Time On Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_STACK));
1443
1444 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStack));
1445 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack", "2.2 Time On Top Of Stack", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
1446 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackAvg));
1447 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Avg","2.2.1 Time On Top Of Stack - Average", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
1448 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMin));
1449 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Min","2.2.2 Time On Top Of Stack - Min", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
1450 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareOnTopOfStackMax));
1451 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-TimeOnTopOfStack-Max","2.2.3 Time On Top Of Stack - Max", KPRF_TYPE(,FIRSTCOLUMN_ON_TOP_OF_STACK));
1452
1453 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsTo));
1454 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsTo", "2.4 Calls To", KPRF_TYPE(,FIRSTCOLUMN_CALLS_TO));
1455
1456 qsort(&pReport->papSortedFunctions[0], pHdr->cFunctions, sizeof(pReport->papSortedFunctions[0]), KPRF_NAME(FuncCompareCallsFrom));
1457 KPRF_NAME(HtmlWriteSortedFunctions)(pReport, pOut, "Functions-CallsFrom", "2.5 Calls From", KPRF_TYPE(,FIRSTCOLUMN_CALLS_FROM));
1458
1459 fprintf(pOut,
1460 "<h2><a name=\"Function-Details\">2.5 Function Details</a></h2>\n"
1461 "\n"
1462 "<p>\n"
1463 "<table class=\"Functions\">\n");
1464 for (KU32 iFunc = 0; iFunc < pHdr->cFunctions; iFunc++)
1465 {
1466 KPRF_TYPE(P,REPORTFUNC) pReportFunc = &pReport->paFunctions[iFunc];
1467 KPRF_TYPE(PC,FUNC) pFunc = pReportFunc->pFunc;
1468
1469 fprintf(pOut,
1470 "<tr><td class=\"BlankRow\" colspan=7><a name=\"Func-%u\">&nbsp;</a></td></tr>\n",
1471 iFunc);
1472 KPRF_NAME(HtmlWriteRowU32)(pOut, "Function No.", iFunc, NULL);
1473 if (pReportFunc->pSym)
1474 KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pReportFunc->pSym->szName);
1475 if (pReportFunc->pLine)
1476 KPRF_NAME(HtmlWriteRowString)(pOut, "Location", NULL, "<a href=\"file:///%s\">%s</a> Line #%d",
1477 pReportFunc->pLine->szFile, pReportFunc->pLine->szFile, pReportFunc->pLine->iLine);
1478 if (pReportFunc->pModSeg)
1479 {
1480 KPRF_NAME(HtmlWriteRowString)(pOut, "Module", NULL, "<a href=\"#Mod-%u\">%s</a>",
1481 pReportFunc->pModSeg->pMod->iMod, pReportFunc->pModSeg->pModSeg->szPath);
1482 KPRF_NAME(HtmlWriteRowString)(pOut, "Segment:Offset", NULL, "%x:%" KPRF_FMT_UPTR,
1483 pReportFunc->pModSeg->pModSeg->iSegment,
1484 pFunc->uEntryPtr - pReportFunc->pModSeg->pModSeg->uBasePtr);
1485 }
1486 KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Address", pFunc->uEntryPtr, NULL);
1487
1488 KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Stack", &pFunc->OnStack, pReport->ProfiledTicks);
1489 KPRF_NAME(HtmlWriteRowTimeStat)(pOut, "On Top Of Stack", &pFunc->OnTopOfStack, pReport->ProfiledTicks);
1490 KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls To", pFunc->cOnStack, pReport->cCalls);
1491 KPRF_NAME(HtmlWriteRowCalls)(pOut, "Calls From", pFunc->cCalls, pReport->cCalls);
1492
1493 fprintf(pOut,
1494 "\n");
1495 }
1496 fprintf(pOut,
1497 "</table>\n"
1498 "</p>\n"
1499 "\n");
1500
1501 /*
1502 * Threads.
1503 */
1504 fprintf(pOut,
1505 "<h2><a name=\"Threads\">3.0 Threads</a></h2>\n"
1506 "\n"
1507 "<p>\n"
1508 "<table class=\"Threads\">\n");
1509
1510 for (KU32 iThread = 0; iThread < pHdr->cThreads; iThread++)
1511 {
1512 KPRF_TYPE(PC,THREAD) pThread = pReport->paThreads[iThread].pThread;
1513
1514 fprintf(pOut,
1515 "<tr><td class=\"BlankRow\" colspan=7><a name=\"Thread-%u\">&nbsp;</a></td></tr>\n",
1516 iThread);
1517 KPRF_NAME(HtmlWriteRowU32)(pOut, "Thread No.", iThread, NULL);
1518 KPRF_NAME(HtmlWriteRowX64)(pOut, "Thread Id", pThread->ThreadId, NULL);
1519 if (pThread->szName[0])
1520 KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pThread->szName);
1521 KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Stack Base Address", pThread->uStackBasePtr, NULL);
1522 KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cbMaxStack, "bytes");
1523 //KPRF_NAME(HtmlWriteRowUPTR)(pOut, "Max Stack Depth", pThread->cMaxFrames, "frames"); /** @todo max stack frames! */
1524 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Profiled", pThread->ProfiledTicks, pReport->ProfiledTicks);
1525 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Sleep", pThread->SleepTicks, pReport->ProfiledTicks);
1526 KPRF_NAME(HtmlWriteRowTicks)(pOut, "Overhead", pThread->OverheadTicks, pReport->ProfiledTicks + pReport->OverheadTicks);
1527 KPRF_NAME(HtmlWriteRowCalls)(pOut, "Recorded Calls", pThread->cCalls, pReport->cCalls);
1528 KPRF_NAME(HtmlWriteRowU64)(pOut, "Unwinds", pThread->cUnwinds, NULL);
1529 KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Overflows", pThread->cOverflows, NULL);
1530 KPRF_NAME(HtmlWriteRowU64)(pOut, "Profiler Stack Switch Rejects", pThread->cStackSwitchRejects, NULL);
1531
1532 fprintf(pOut,
1533 "\n");
1534 }
1535 fprintf(pOut,
1536 "</table>\n"
1537 "</p>\n"
1538 "\n");
1539
1540
1541 /*
1542 * Modules.
1543 */
1544 fprintf(pOut,
1545 "<h2><a name=\"Modules\">4.0 Modules</a></h2>\n"
1546 "\n"
1547 "<p>\n"
1548 "<table class=\"Modules\">\n");
1549
1550 KPRF_TYPE(P,REPORTMOD) pMod = pReport->pFirstMod;
1551 KU32 iMod = 0;
1552 while (pMod)
1553 {
1554 fprintf(pOut,
1555 "<a name=\"Mod-%u\">\n"
1556 "<tr><td class=\"BlankRow\" colspan=7><a name=\"Module-%u\">&nbsp;</a></td></tr>\n",
1557 iMod);
1558 KPRF_NAME(HtmlWriteRowU32)(pOut, "Module No.", iMod, NULL);
1559 KPRF_NAME(HtmlWriteRowString)(pOut, "Name", "Name", "%s", pMod->pFirstSeg->pModSeg->szPath);
1560
1561 for (KPRF_TYPE(P,REPORTMODSEG) pSeg = pMod->pFirstSeg; pSeg; pSeg = pSeg->pNext)
1562 {
1563 char szName[64];
1564 sprintf(szName, "Segment No.%u - Base", pSeg->pModSeg->iSegment);
1565 KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName, pSeg->pModSeg->uBasePtr, NULL);
1566 sprintf(szName, "Segment No.%u - Size", pSeg->pModSeg->iSegment);
1567 KPRF_NAME(HtmlWriteRowUPTR)(pOut, szName,
1568 pSeg->pModSeg->cbSegmentMinusOne + 1 > pSeg->pModSeg->cbSegmentMinusOne
1569 ? pSeg->pModSeg->cbSegmentMinusOne + 1
1570 : pSeg->pModSeg->cbSegmentMinusOne,
1571 NULL);
1572 }
1573
1574 KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Stack", pMod->OnStackTicks, pReport->ProfiledTicks);
1575 KPRF_NAME(HtmlWriteRowTicks)(pOut, "On Top Of Stack", pMod->OnTopOfStackTicks, pReport->ProfiledTicks);
1576 KPRF_NAME(HtmlWriteRowU32)(pOut, "Functions", pMod->cFunctions, NULL);
1577
1578 fprintf(pOut,
1579 "\n");
1580
1581 /* next */
1582 iMod++;
1583 pMod = pMod->pNext;
1584 }
1585 fprintf(pOut,
1586 "</table>\n"
1587 "</p>\n"
1588 "\n");
1589
1590
1591 /*
1592 * The End.
1593 */
1594 fprintf(pOut,
1595 "</body>\n"
1596 "</html>\n");
1597 return 0;
1598}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette