kDefs.h: Added risc-v to the K_ARCH_XXX defines.
[kstuff-mirror.git] / kProfiler2 / kPrf2Read.cpp
blob49e7a134b2bf5f9a8138995e4c7c45d3106c9b35
1 /* $Id$ */
2 /** @file
3 * kProfiler Mark 2 - The reader and producer of statistics.
4 */
6 /*
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
16 * conditions:
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 /*******************************************************************************
32 * Header Files *
33 *******************************************************************************/
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <k/kDbg.h>
41 /** @def KPRF_OFF2PTR
42 * Internal helper for converting a offset to a pointer.
43 * @internal
45 #define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
46 ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (KUPTR)pHdr) )
48 /** @def KPRF_ALIGN
49 * The usual align macro.
50 * @internal
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.
56 * @internal
58 #define KPRF_OFFSETOF(kPrfType, Member) ( (KU32)(KUPTR)&((KPRF_TYPE(P,kPrfType))0)->Member )
60 /** @def PRF_SIZEOF
61 * Size of a kPrf type.
62 * @internal
64 #define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType))
66 #ifdef _MSC_VER
67 # define KPRF_FMT_U64 "I64u"
68 # define KPRF_FMT_X64 "I64x"
69 # define KPRF_FMT_I64 "I64d"
70 #else
71 # define KPRF_FMT_X64 "llx"
72 # define KPRF_FMT_U64 "llu"
73 # define KPRF_FMT_I64 "lld"
74 #endif
78 * Instantiate the readers.
80 /* 32-bit */
81 #define KPRF_NAME(Suffix) KPrf32##Suffix
82 #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix
83 #define KPRF_BITS 32
84 #define KPRF_FMT_UPTR "#010x"
86 #include "prfcore.h.h"
87 #include "prfreader.cpp.h"
89 #undef KPRF_FMT_UPTR
90 #undef KPRF_NAME
91 #undef KPRF_TYPE
92 #undef KPRF_BITS
94 /* 64-bit */
95 #define KPRF_NAME(Suffix) KPrf64##Suffix
96 #define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix
97 #define KPRF_BITS 64
98 #ifdef _MSC_VER
99 # define KPRF_FMT_UPTR "#018I64x"
100 #else
101 # define KPRF_FMT_UPTR "#018llx"
102 #endif
104 #include "prfcore.h.h"
105 #include "prfreader.cpp.h"
107 #undef KPRF_FMT_UPTR
108 #undef KPRF_NAME
109 #undef KPRF_TYPE
110 #undef KPRF_BITS
113 /*******************************************************************************
114 * Structures and Typedefs *
115 *******************************************************************************/
117 * Header union type.
119 typedef union KPRFHDR
121 KPRF32HDR Hdr32;
122 KPRF64HDR Hdr64;
123 } 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");
141 if (!pFile)
143 fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename);
144 return NULL;
148 * Read the file into memory.
150 long cbFile;
151 if ( !fseek(pFile, 0, SEEK_END)
152 && (cbFile = ftell(pFile)) >= 0
153 && !fseek(pFile, 0, SEEK_SET)
156 if (pcb)
157 *pcb = cbFile;
159 void *pvData = malloc(cbFile);
160 if (pvData)
162 if (fread(pvData, cbFile, 1, pFile))
165 fclose(pFile);
166 return (PKPRFHDR)pvData;
168 fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename);
169 free(pvData);
171 else
172 fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename);
174 else
175 fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename);
177 fclose(pFile);
178 return NULL;
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);
203 return false;
206 if ( pHdr->Hdr32.cFormatBits != 32
207 && pHdr->Hdr32.cFormatBits != 64)
209 fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits);
210 return false;
213 if (pHdr->Hdr32.cb > cb)
215 fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb);
216 return false;
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); \
224 return false; \
226 } while (0)
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
236 || cbHeader >= cb)
238 fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n",
239 pHdr->Hdr32.cFunctions);
240 return false;
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 {\
246 if ( off > 0 \
247 && off < offMin) \
249 fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \
250 return false; \
252 if (off >= cb) \
254 fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \
255 return false; \
257 } while (0)
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); \
267 return false; \
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); \
273 return false; \
275 if (pHdr->Hdr32.off##MemBaseName##s) \
276 offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \
277 } while (0)
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);
287 return false;
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);
304 return false;
308 * Validate the functions.
310 switch (pHdr->Hdr32.cFormatBits)
312 case 32:
313 return KPrf32IsValid(&pHdr->Hdr32, cb, pOut);
315 case 64:
316 return KPrf64IsValid(&pHdr->Hdr64, cb, pOut);
318 return false;
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.
339 KU32 cb;
340 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
341 if (!pHdr)
342 return -1;
343 if (!kPrfIsValidate(pHdr, cb, pOut))
344 return -1;
347 * Switch to the appropirate dumper routine.
349 int rc;
350 switch (pHdr->Hdr32.cFormatBits)
352 case 32:
353 rc = KPrf32Dump(&pHdr->Hdr32, pOut);
354 break;
356 case 64:
357 rc = KPrf64Dump(&pHdr->Hdr64, pOut);
358 break;
360 default:
361 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
362 rc = -1;
363 break;
366 return rc;
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.
384 KU32 cb;
385 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
386 if (!pHdr)
387 return -1;
388 if (!kPrfIsValidate(pHdr, cb, pOut))
389 return -1;
392 * Switch to the appropirate dumper routine.
394 int rc;
395 switch (pHdr->Hdr32.cFormatBits)
397 case 32:
399 PKPRF32REPORT pReport;
400 rc = KPrf32Analyse(&pHdr->Hdr32, &pReport);
401 if (!rc)
403 rc = KPrf32WriteHtmlReport(pReport, pOut);
404 if (rc)
405 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
406 KPrf32DeleteReport(pReport);
408 else
409 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
410 break;
413 case 64:
415 PKPRF64REPORT pReport;
416 rc = KPrf64Analyse(&pHdr->Hdr64, &pReport);
417 if (!rc)
419 rc = KPrf64WriteHtmlReport(pReport, pOut);
420 if (rc)
421 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
422 KPrf64DeleteReport(pReport);
424 else
425 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
426 break;
429 default:
430 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
431 rc = -1;
432 break;
435 return rc;
441 * Prints the usage.
443 static int Usage(void)
445 printf("kProfiler MK2 - Reader & Producer of Statistics\n"
446 "usage: kPrf2Read [-r|-d] <file1> [[-r|-d] file2 []]\n"
448 return 1;
452 int main(int argc, char **argv)
455 * Parse arguments.
457 if (argc <= 1)
458 return Usage();
459 enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP;
460 for (int i = 1; i < argc; i++)
462 if (argv[i][0] == '-')
464 switch (argv[i][1])
466 case 'h':
467 case 'H':
468 case '?':
469 case '-':
470 return Usage();
472 case 'd':
473 enmOp = OP_DUMP;
474 break;
476 case 'r':
477 enmOp = OP_HTML;
478 break;
480 default:
481 printf("Syntax error: Unknown argument '%s'\n", argv[i]);
482 return 1;
485 else
487 int rc;
488 switch (enmOp)
490 case OP_DUMP:
491 rc = KPrfDumpFile(argv[i], stdout);
492 break;
493 case OP_HTML:
494 rc = KPrfHtmlReport(argv[i], stdout);
495 break;
497 if (rc)
498 return rc;
502 return 0;