VirtualBox

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

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

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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

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