source: trunk/kProfile/kPrf2Read.cpp@ 3524

Last change on this file since 3524 was 3524, checked in by bird, 18 years ago

kProfile Mark II. Some early/old code.

File size: 14.8 KB
Line 
1/* $Id: $ */
2/** @file
3 *
4 * kProfiler Mark 2 - The reader and statistics producer.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-src-spam@anduin.net.de>
7 *
8 *
9 * This file is part of kLIBC.
10 *
11 * kLIBC is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLIBC 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
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLIBC; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdarg.h>
36
37/* iprt dependencies */
38#include <iprt/types.h>
39#include <iprt/err.h>
40#include <iprt/avl.h>
41#include "dbg.h"
42#if 1
43# include <iprt/alloc.h>
44# define malloc(cb) RTMemAlloc(cb)
45# define free(pv) RTMemFree(pv)
46#endif
47
48
49/** @def KPRF_OFF2PTR
50 * Internal helper for converting a offset to a pointer.
51 * @internal
52 */
53#define KPRF_OFF2PTR(TypePrefix, TypeName, off, pHdr) \
54 ( (KPRF_TYPE(TypePrefix, TypeName)) ((off) + (uintptr_t)pHdr) )
55
56/** @def KPRF_ALIGN
57 * The usual align macro.
58 * @internal
59 */
60#define KPRF_ALIGN(n, align) ( ((n) + ( (align) - 1)) & ~((align) - 1) )
61
62/** @def KPRF_OFFSETOF
63 * My usual extended OFFSETOF macro, except this returns uint32_t and mangles the type name.
64 * @internal
65 */
66#define KPRF_OFFSETOF(kPrfType, Member) ( (uint32_t)(uintptr_t)&((KPRF_TYPE(P,kPrfType))0)->Member )
67
68/** @def PRF_SIZEOF
69 * Size of a kPrf type.
70 * @internal
71 */
72#define KPRF_SIZEOF(kPrfType) sizeof(KPRF_TYPE(,kPrfType))
73
74#ifdef _MSC_VER
75# define KPRF_FMT_U64 "I64u"
76# define KPRF_FMT_X64 "I64x"
77# define KPRF_FMT_I64 "I64d"
78#else
79# define KPRF_FMT_X64 "llx"
80# define KPRF_FMT_U64 "llu"
81# define KPRF_FMT_I64 "lld"
82#endif
83
84
85/*
86 * Instantiate the readers.
87 */
88/* 32-bit */
89#define KPRF_NAME(Suffix) KPrf32##Suffix
90#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF32##Suffix
91#define KPRF_BITS 32
92#define KPRF_FMT_UPTR "#010x"
93
94#include "prfcore.h.h"
95#include "prfreader.cpp.h"
96
97#undef KPRF_FMT_UPTR
98#undef KPRF_NAME
99#undef KPRF_TYPE
100#undef KPRF_BITS
101
102/* 64-bit */
103#define KPRF_NAME(Suffix) KPrf64##Suffix
104#define KPRF_TYPE(Prefix,Suffix) Prefix##KPRF64##Suffix
105#define KPRF_BITS 64
106#ifdef _MSC_VER
107# define KPRF_FMT_UPTR "#018I64x"
108#else
109# define KPRF_FMT_UPTR "#018llx"
110#endif
111
112#include "prfcore.h.h"
113#include "prfreader.cpp.h"
114
115#undef KPRF_FMT_UPTR
116#undef KPRF_NAME
117#undef KPRF_TYPE
118#undef KPRF_BITS
119
120
121/*******************************************************************************
122* Structures and Typedefs *
123*******************************************************************************/
124/**
125 * Header union type.
126 */
127typedef union KPRFHDR
128{
129 KPRF32HDR Hdr32;
130 KPRF64HDR Hdr64;
131} KPRFHDR;
132typedef KPRFHDR *PKPRFHDR;
133typedef const KPRFHDR *PCKPRFHDR;
134
135
136
137/**
138 * Read the data set into memory.
139 *
140 * @returns Pointer to the loaded data set. (release using free()).
141 *
142 * @param pszFilename The path to the profiler data set.
143 * @param pcb Where to store the size of the data set.
144 * @param pOut Where to write errors.
145 */
146PKPRFHDR kPrfLoad(const char *pszFilename, uint32_t *pcb, FILE *pOut)
147{
148 FILE *pFile = fopen(pszFilename, "rb");
149 if (!pFile)
150 {
151 fprintf(pOut, "Cannot open '%s' for reading!\n", pszFilename);
152 return NULL;
153 }
154
155 /*
156 * Read the file into memory.
157 */
158 long cbFile;
159 if ( !fseek(pFile, 0, SEEK_END)
160 && (cbFile = ftell(pFile)) >= 0
161 && !fseek(pFile, 0, SEEK_SET)
162 )
163 {
164 if (pcb)
165 *pcb = cbFile;
166
167 void *pvData = malloc(cbFile);
168 if (pvData)
169 {
170 if (fread(pvData, cbFile, 1, pFile))
171 {
172
173 fclose(pFile);
174 return (PKPRFHDR)pvData;
175 }
176 fprintf(pOut, "Failed reading '%s' into memory!\n", pszFilename);
177 free(pvData);
178 }
179 else
180 fprintf(pOut, "Failed to allocate %ld bytes of memory for reading the file '%s' into!\n", cbFile, pszFilename);
181 }
182 else
183 fprintf(pOut, "Failed to determin the size of '%s'!\n", pszFilename);
184
185 fclose(pFile);
186 return NULL;
187}
188
189
190/**
191 * Validates the data set
192 *
193 * @returns true if valid.
194 * @returns false if invalid.
195 *
196 * @param pHdr Pointer to the data set.
197 * @param cb The size of the data set.
198 * @param pOut Where to write error messages.
199 */
200static bool kPrfIsValidate(PCKPRFHDR pHdr, uint32_t cb, FILE *pOut)
201{
202 /*
203 * We ASSUMES that the header is identicial with the exception
204 * of the uBasePtr size. (this is padded out and the upper bits are all zero)
205 */
206
207 if ( pHdr->Hdr32.u32Magic != KPRF32HDR_MAGIC
208 && pHdr->Hdr32.u32Magic != KPRF64HDR_MAGIC)
209 {
210 fprintf(pOut, "Invalid magic %#x\n", pHdr->Hdr32.u32Magic);
211 return false;
212 }
213
214 if ( pHdr->Hdr32.cFormatBits != 32
215 && pHdr->Hdr32.cFormatBits != 64)
216 {
217 fprintf(pOut, "Invalid/Unsupported bit count %u\n", pHdr->Hdr32.cFormatBits);
218 return false;
219 }
220
221 if (pHdr->Hdr32.cb > cb)
222 {
223 fprintf(pOut, "Data set size mismatch. Header say %#x, input is %#x\n", pHdr->Hdr32.cb, cb);
224 return false;
225 }
226
227#define KPRF_VALIDATE_SIZE(MemBaseName, cb32, cb64) do {\
228 if (pHdr->Hdr32.cb##MemBaseName > (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64)) \
229 { \
230 fprintf(pOut, "cb" #MemBaseName " was expected to be %#x but is %#x. Probably a format change, rebuild.\n", \
231 (pHdr->Hdr32.cFormatBits == 32 ? cb32 : cb64), pHdr->Hdr32.cb##MemBaseName); \
232 return false; \
233 }\
234 } while (0)
235
236 KPRF_VALIDATE_SIZE(Function, sizeof(KPRF32FUNC), sizeof(KPRF64FUNC));
237 KPRF_VALIDATE_SIZE(Thread, sizeof(KPRF32THREAD), sizeof(KPRF64THREAD));
238 KPRF_VALIDATE_SIZE(Stack,
239 (uint32_t)&((PKPRF32STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames],
240 (uint32_t)&((PKPRF64STACK)0)->aFrames[pHdr->Hdr32.cMaxStackFrames]);
241
242 uintptr_t cbHeader = (uintptr_t)&pHdr->Hdr32.aiFunctions[pHdr->Hdr32.cFunctions] - (uintptr_t)pHdr;
243 if ( cbHeader != (uint32_t)cbHeader
244 || cbHeader >= cb)
245 {
246 fprintf(pOut, "cFunctions (%#x) is too large to fit the lookup table inside the data set.\n",
247 pHdr->Hdr32.cFunctions);
248 return false;
249 }
250
251 /* The space assignment is hereby required to be equal to the member order in the header. */
252 uint32_t offMin = cbHeader;
253#define KPRF_VALIDATE_OFF(off, name) do {\
254 if ( off > 0 \
255 && off < offMin) \
256 { \
257 fprintf(pOut, #name " (%#x) is overlapping with other element or invalid space assignment order.\n", off); \
258 return false; \
259 }\
260 if (off >= cb) \
261 { \
262 fprintf(pOut, #name " (%#x) is outside the data set (%#x)\n", off, cb); \
263 return false; \
264 }\
265 } while (0)
266#define KPRF_VALIDATE_MEM(MemBaseName) do {\
267 KPRF_VALIDATE_OFF(pHdr->Hdr32.off##MemBaseName##s, off##MemBaseName##s); \
268 if ( pHdr->Hdr32.off##MemBaseName##s \
269 && ( pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s > cb \
270 || pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s < pHdr->Hdr32.off##MemBaseName##s)\
271 ) \
272 { \
273 fprintf(pOut, #MemBaseName " (%#x) is outside the data set (%#x)\n", \
274 pHdr->Hdr32.off##MemBaseName##s + pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s, cb); \
275 return false; \
276 }\
277 if (pHdr->Hdr32.c##MemBaseName##s > pHdr->Hdr32.cMax##MemBaseName##s) \
278 { \
279 fprintf(pOut, "c" #MemBaseName " (%#x) higher than the max (%#x)\n", \
280 pHdr->Hdr32.c##MemBaseName##s, pHdr->Hdr32.cMax##MemBaseName##s); \
281 return false; \
282 } \
283 if (pHdr->Hdr32.off##MemBaseName##s) \
284 offMin += pHdr->Hdr32.cb##MemBaseName * pHdr->Hdr32.cMax##MemBaseName##s; \
285 } while (0)
286
287 KPRF_VALIDATE_MEM(Function);
288 KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs, offModSegs);
289 if (pHdr->Hdr32.offModSegs)
290 KPRF_VALIDATE_OFF(pHdr->Hdr32.offModSegs + pHdr->Hdr32.cbMaxModSegs, cbMaxModSegs);
291 if (pHdr->Hdr32.cbModSegs > pHdr->Hdr32.cbMaxModSegs)
292 {
293 fprintf(pOut, "ccbModSegs (%#x) higher than the max (%#x)\n",
294 pHdr->Hdr32.cbModSegs, pHdr->Hdr32.cbMaxModSegs);
295 return false;
296 }
297 if (pHdr->Hdr32.offModSegs) \
298 offMin += pHdr->Hdr32.cbMaxModSegs; \
299 KPRF_VALIDATE_MEM(Thread);
300 KPRF_VALIDATE_MEM(Stack);
301 KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine, offCommandLine);
302 KPRF_VALIDATE_OFF(pHdr->Hdr32.offCommandLine + pHdr->Hdr32.cchCommandLine, cchCommandLine);
303
304 /*
305 * Validate the function lookup table
306 */
307 for (uint32_t i = 0; i < pHdr->Hdr32.cFunctions; i++)
308 if (pHdr->Hdr32.aiFunctions[i] >= pHdr->Hdr32.cFunctions)
309 {
310 fprintf(pOut, "Function lookup entry %#x is invalid: index %#x, max is %#x\n",
311 i, pHdr->Hdr32.aiFunctions[i], pHdr->Hdr32.cFunctions);
312 return false;
313 }
314
315 /*
316 * Validate the functions.
317 */
318 switch (pHdr->Hdr32.cFormatBits)
319 {
320 case 32:
321 return KPrf32IsValid(&pHdr->Hdr32, cb, pOut);
322
323 case 64:
324 return KPrf64IsValid(&pHdr->Hdr64, cb, pOut);
325 }
326 return false;
327#undef KPRF_VALIDATE_SIZE
328#undef KPRF_VALIDATE_MEM
329#undef KPRF_VALIDATE_OFF
330}
331
332
333/**
334 * Dumps a kProfiler 2 format file.
335 *
336 * @returns 0 on success.
337 * @returns -1 on failure.
338 *
339 * @param pszFilename The path to the profiler data set.
340 * @param pOut Where to write the output.
341 */
342int KPrfDumpFile(const char *pszFilename, FILE *pOut)
343{
344 /*
345 * Load and validate the data set.
346 */
347 uint32_t cb;
348 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
349 if (!pHdr)
350 return -1;
351 if (!kPrfIsValidate(pHdr, cb, pOut))
352 return -1;
353
354 /*
355 * Switch to the appropirate dumper routine.
356 */
357 int rc;
358 switch (pHdr->Hdr32.cFormatBits)
359 {
360 case 32:
361 rc = KPrf32Dump(&pHdr->Hdr32, pOut);
362 break;
363
364 case 64:
365 rc = KPrf64Dump(&pHdr->Hdr64, pOut);
366 break;
367
368 default:
369 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
370 rc = -1;
371 break;
372 }
373
374 return rc;
375}
376
377
378/**
379 * Creates a HTML report from a kProfiler 2 format file.
380 *
381 * @returns 0 on success.
382 * @returns -1 on failure.
383 *
384 * @param pszFilename The path to the profiler data set.
385 * @param pOut Where to write the output.
386 */
387int KPrfHtmlReport(const char *pszFilename, FILE *pOut)
388{
389 /*
390 * Load and validate the data set.
391 */
392 uint32_t cb;
393 PKPRFHDR pHdr = kPrfLoad(pszFilename, &cb, pOut);
394 if (!pHdr)
395 return -1;
396 if (!kPrfIsValidate(pHdr, cb, pOut))
397 return -1;
398
399 /*
400 * Switch to the appropirate dumper routine.
401 */
402 int rc;
403 switch (pHdr->Hdr32.cFormatBits)
404 {
405 case 32:
406 {
407 PKPRF32REPORT pReport;
408 rc = KPrf32Analyse(&pHdr->Hdr32, &pReport);
409 if (!rc)
410 {
411 rc = KPrf32WriteHtmlReport(pReport, pOut);
412 if (rc)
413 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
414 KPrf32DeleteReport(pReport);
415 }
416 else
417 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
418 break;
419 }
420
421 case 64:
422 {
423 PKPRF64REPORT pReport;
424 rc = KPrf64Analyse(&pHdr->Hdr64, &pReport);
425 if (!rc)
426 {
427 rc = KPrf64WriteHtmlReport(pReport, pOut);
428 if (rc)
429 fprintf(stderr, "Error while writing HTML report for '%s'\n", pszFilename);
430 KPrf64DeleteReport(pReport);
431 }
432 else
433 fprintf(stderr, "Analysis of '%s' failed!\n", pszFilename);
434 break;
435 }
436
437 default:
438 fprintf(stderr, "Unsupported bit count %d\n", pHdr->Hdr32.cFormatBits);
439 rc = -1;
440 break;
441 }
442
443 return rc;
444}
445
446
447
448/**
449 * Prints the usage.
450 */
451static int Usage(void)
452{
453 printf("kProfiler MK2 - Reader & Producer of Statistics\n"
454 "usage: kPrf2Read [-r|-d] <file1> [[-r|-d] file2 []]\n"
455 );
456 return 1;
457}
458
459
460int main(int argc, char **argv)
461{
462 /*
463 * Parse arguments.
464 */
465 if (argc <= 1)
466 return Usage();
467 enum { OP_DUMP, OP_HTML } enmOp = OP_DUMP;
468 for (int i = 1; i < argc; i++)
469 {
470 if (argv[i][0] == '-')
471 {
472 switch (argv[i][1])
473 {
474 case 'h':
475 case 'H':
476 case '?':
477 case '-':
478 return Usage();
479
480 case 'd':
481 enmOp = OP_DUMP;
482 break;
483
484 case 'r':
485 enmOp = OP_HTML;
486 break;
487
488 default:
489 printf("Syntax error: Unknown argument '%s'\n", argv[i]);
490 return 1;
491 }
492 }
493 else
494 {
495 int rc;
496 switch (enmOp)
497 {
498 case OP_DUMP:
499 rc = KPrfDumpFile(argv[i], stdout);
500 break;
501 case OP_HTML:
502 rc = KPrfHtmlReport(argv[i], stdout);
503 break;
504 }
505 if (rc)
506 return rc;
507 }
508 }
509
510 return 0;
511}
Note: See TracBrowser for help on using the repository browser.