3 * kProfiler Mark 2 - The reader and producer of statistics.
7 * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
31 /*******************************************************************************
33 *******************************************************************************/
42 * Internal helper for converting a offset to a pointer.
45 #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
46 ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) )
49 * The usual align macro.
52 #define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) )
54 /** @def KPRF_OFFSETOF
55 * My usual extended offsetof macro, except this returns KU32 and mangles the type name.
58 #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member )
61 * Size of a kPrf type.
64 #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType))
67 # define KPRF_FMT_U64 "I64u"
68 # define KPRF_FMT_X64 "I64x"
69 # define KPRF_FMT_I64 "I64d"
71 # define KPRF_FMT_X64 "llx"
72 # define KPRF_FMT_U64 "llu"
73 # define KPRF_FMT_I64 "lld"
78 * Instantiate the readers.
81 #define KPRF_NAME(Suffix) KPrf32##Suffix
82 #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix
84 #define KPRF_FMT_UPTR "#010x"
86 #include "prfcore.h.h"
87 #include "prfreader.cpp.h"
95 #define KPRF_NAME(Suffix) KPrf64##Suffix
96 #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix
99 # define KPRF_FMT_UPTR "#018I64x"
101 # define KPRF_FMT_UPTR "#018llx"
104 #include "prfcore.h.h"
105 #include "prfreader.cpp.h"
113 /*******************************************************************************
114 * Structures and Typedefs *
115 *******************************************************************************/
119 typedef union KPRFHDR
124 typedef KPRFHDR
*PKPRFHDR
;
125 typedef const KPRFHDR
*PCKPRFHDR
;
130 * Read the data set into memory.
132 * @returns Pointer to the loaded data set. (release using free()).
134 * @param pszFilename The path to the profiler data set.
135 * @param pcb Where to store the size of the data set.
136 * @param pOut Where to write errors.
138 PKPRFHDR
kPrfLoad(const char *pszFilename
, KU32
*pcb
, FILE *pOut
)
140 FILE *pFile
= fopen(pszFilename
, "rb");
143 fprintf(pOut
, "Cannot open '%s' for reading!\n", pszFilename
);
148 * Read the file into memory.
151 if ( !fseek(pFile
, 0, SEEK_END
)
152 && (cbFile
= ftell(pFile
)) >= 0
153 && !fseek(pFile
, 0, SEEK_SET
)
159 void *pvData
= malloc(cbFile
);
162 if (fread(pvData
, cbFile
, 1, pFile
))
166 return (PKPRFHDR
)pvData
;
168 fprintf(pOut
, "Failed reading '%s' into memory!\n", pszFilename
);
172 fprintf(pOut
, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile
, pszFilename
);
175 fprintf(pOut
, "Failed to determin the size of '%s'!\n", pszFilename
);
183 * Validates the data set
185 * @returns true if valid.
186 * @returns false if invalid.
188 * @param pHdr Pointer to the data set.
189 * @param cb The size of the data set.
190 * @param pOut Where to write error messages.
192 static bool kPrfIsValidate(PCKPRFHDR pHdr
, KU32 cb
, FILE *pOut
)
195 * We ASSUMES that the header is identicial with the exception
196 * of the uBasePtr size. (this is padded out and the upper bits are all zero)
199 if ( pHdr
->Hdr32
.u32Magic
!= KPRF32HDR_MAGIC
200 && pHdr
->Hdr32
.u32Magic
!= KPRF64HDR_MAGIC
)
202 fprintf(pOut
, "Invalid magic %#x\n", pHdr
->Hdr32
.u32Magic
);
206 if ( pHdr
->Hdr32
.cFormatBits
!= 32
207 && pHdr
->Hdr32
.cFormatBits
!= 64)
209 fprintf(pOut
, "Invalid/Unsupported bit count %u\n", pHdr
->Hdr32
.cFormatBits
);
213 if (pHdr
->Hdr32
.cb
> cb
)
215 fprintf(pOut
, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr
->Hdr32
.cb
, cb
);
219 #define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\
220 if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \
222 fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \
223 (unsigned)(pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \
228 KPRF_VALIDATE_SIZE(Function
, sizeof(KPRF32FUNC
), sizeof(KPRF64FUNC
));
229 KPRF_VALIDATE_SIZE(Thread
, sizeof(KPRF32THREAD
), sizeof(KPRF64THREAD
));
230 KPRF_VALIDATE_SIZE(Stack
,
231 (KU32
)&((PKPRF32STACK
)0)->aFrames
[pHdr
->Hdr32
.cMaxStackFrames
],
232 (KU32
)&((PKPRF64STACK
)0)->aFrames
[pHdr
->Hdr32
.cMaxStackFrames
]);
234 KUPTR cbHeader
= (KUPTR
)&pHdr
->Hdr32
.aiFunctions
[pHdr
->Hdr32
.cFunctions
] - (KUPTR
)pHdr
;
235 if ( cbHeader
!= (KU32
)cbHeader
238 fprintf(pOut
, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n",
239 pHdr
->Hdr32
.cFunctions
);
243 /* The space assignment is hereby required to be equal to the member order in the header. */
244 KU32 offMin
= cbHeader
;
245 #define KPRF_VALIDATE_OFF(off, name) do {\
249 fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \
254 fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \
258 #define KPRF_VALIDATE_MEM(MemBaseName) do {\
259 KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \
260 if ( pHdr->Hdr32.off##MemBaseName##s \
261 && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \
262 || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\
265 fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \
266 pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \
269 if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \
271 fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \
272 pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \
275 if (pHdr->Hdr32.off##MemBaseName##s) \
276 offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \
279 KPRF_VALIDATE_MEM(Function
);
280 KPRF_VALIDATE_OFF(pHdr
->Hdr32
.offModSegs
, offModSegs
);
281 if (pHdr
->Hdr32
.offModSegs
)
282 KPRF_VALIDATE_OFF(pHdr
->Hdr32
.offModSegs
+ pHdr
->Hdr32
.cbMaxModSegs
, cbMaxModSegs
);
283 if (pHdr
->Hdr32
.cbModSegs
> pHdr
->Hdr32
.cbMaxModSegs
)
285 fprintf(pOut
, "ccbModSegs (%#x) higher than the max (%#x)\n",
286 pHdr
->Hdr32
.cbModSegs
, pHdr
->Hdr32
.cbMaxModSegs
);
289 if (pHdr
->Hdr32
.offModSegs
) \
290 offMin
+= pHdr
->Hdr32
.cbMaxModSegs
; \
291 KPRF_VALIDATE_MEM(Thread
);
292 KPRF_VALIDATE_MEM(Stack
);
293 KPRF_VALIDATE_OFF(pHdr
->Hdr32
.offCommandLine
, offCommandLine
);
294 KPRF_VALIDATE_OFF(pHdr
->Hdr32
.offCommandLine
+ pHdr
->Hdr32
.cchCommandLine
, cchCommandLine
);
297 * Validate the function lookup table
299 for (KU32 i
= 0; i
< pHdr
->Hdr32
.cFunctions
; i
++)
300 if (pHdr
->Hdr32
.aiFunctions
[i
] >= pHdr
->Hdr32
.cFunctions
)
302 fprintf(pOut
, "Function lookup entry %#x is invalid: index %#x, max is %#x\n",
303 i
, pHdr
->Hdr32
.aiFunctions
[i
], pHdr
->Hdr32
.cFunctions
);
308 * Validate the functions.
310 switch (pHdr
->Hdr32
.cFormatBits
)
313 return KPrf32IsValid(&pHdr
->Hdr32
, cb
, pOut
);
316 return KPrf64IsValid(&pHdr
->Hdr64
, cb
, pOut
);
319 #undef KPRF_VALIDATE_SIZE
320 #undef KPRF_VALIDATE_MEM
321 #undef KPRF_VALIDATE_OFF
326 * Dumps a kProfiler 2 format file.
328 * @returns 0 on success.
329 * @returns -1 on failure.
331 * @param pszFilename The path to the profiler data set.
332 * @param pOut Where to write the output.
334 int KPrfDumpFile(const char *pszFilename
, FILE *pOut
)
337 * Load and validate the data set.
340 PKPRFHDR pHdr
= kPrfLoad(pszFilename
, &cb
, pOut
);
343 if (!kPrfIsValidate(pHdr
, cb
, pOut
))
347 * Switch to the appropirate dumper routine.
350 switch (pHdr
->Hdr32
.cFormatBits
)
353 rc
= KPrf32Dump(&pHdr
->Hdr32
, pOut
);
357 rc
= KPrf64Dump(&pHdr
->Hdr64
, pOut
);
361 fprintf(stderr
, "Unsupported bit count %d\n", pHdr
->Hdr32
.cFormatBits
);
371 * Creates a HTML report from a kProfiler 2 format file.
373 * @returns 0 on success.
374 * @returns -1 on failure.
376 * @param pszFilename The path to the profiler data set.
377 * @param pOut Where to write the output.
379 int KPrfHtmlReport(const char *pszFilename
, FILE *pOut
)
382 * Load and validate the data set.
385 PKPRFHDR pHdr
= kPrfLoad(pszFilename
, &cb
, pOut
);
388 if (!kPrfIsValidate(pHdr
, cb
, pOut
))
392 * Switch to the appropirate dumper routine.
395 switch (pHdr
->Hdr32
.cFormatBits
)
399 PKPRF32REPORT pReport
;
400 rc
= KPrf32Analyse(&pHdr
->Hdr32
, &pReport
);
403 rc
= KPrf32WriteHtmlReport(pReport
, pOut
);
405 fprintf(stderr
, "Error while writing HTML report for '%s'\n", pszFilename
);
406 KPrf32DeleteReport(pReport
);
409 fprintf(stderr
, "Analysis of '%s' failed!\n", pszFilename
);
415 PKPRF64REPORT pReport
;
416 rc
= KPrf64Analyse(&pHdr
->Hdr64
, &pReport
);
419 rc
= KPrf64WriteHtmlReport(pReport
, pOut
);
421 fprintf(stderr
, "Error while writing HTML report for '%s'\n", pszFilename
);
422 KPrf64DeleteReport(pReport
);
425 fprintf(stderr
, "Analysis of '%s' failed!\n", pszFilename
);
430 fprintf(stderr
, "Unsupported bit count %d\n", pHdr
->Hdr32
.cFormatBits
);
443 static int Usage(void)
445 printf("kProfiler MK2 - Reader & Producer of Statistics\n"
446 "usage: kPrf2Read [-r|-d] <file1> [[-r|-d] file2 []]\n"
452 int main(int argc
, char **argv
)
459 enum { OP_DUMP
, OP_HTML
} enmOp
= OP_DUMP
;
460 for (int i
= 1; i
< argc
; i
++)
462 if (argv
[i
][0] == '-')
481 printf("Syntax error: Unknown argument '%s'\n", argv
[i
]);
491 rc
= KPrfDumpFile(argv
[i
], stdout
);
494 rc
= KPrfHtmlReport(argv
[i
], stdout
);