Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <math.h>
15 #include "nspr.h"
16 #include "tmreader.h"
18 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
19 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
22 #define COST_RESOLUTION 1000
23 #define COST_PRINTABLE(cost) ((double)(cost) / (double)COST_RESOLUTION)
26 typedef struct __struct_Options
27 /*
28 ** Options to control how we perform.
29 **
30 ** mProgramName Used in help text.
31 ** mInputName Name of the file.
32 ** mOutput Output file, append.
33 ** Default is stdout.
34 ** mOutputName Name of the file.
35 ** mHelp Whether or not help should be shown.
36 ** mOverhead How much overhead an allocation will have.
37 ** mAlignment What boundry will the end of an allocation line up on.
38 ** mAverages Whether or not to display averages.
39 ** mDeviances Whether or not to display standard deviations.
40 ** mRunLength Whether or not to display run length.
41 */
42 {
43 const char* mProgramName;
44 char* mInputName;
45 FILE* mOutput;
46 char* mOutputName;
47 int mHelp;
48 unsigned mOverhead;
49 unsigned mAlignment;
50 int mAverages;
51 int mDeviances;
52 int mRunLength;
53 }
54 Options;
57 typedef struct __struct_Switch
58 /*
59 ** Command line options.
60 */
61 {
62 const char* mLongName;
63 const char* mShortName;
64 int mHasValue;
65 const char* mValue;
66 const char* mDescription;
67 }
68 Switch;
70 #define DESC_NEWLINE "\n\t\t"
72 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
73 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
74 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
75 static Switch gAlignmentSwitch = {"--alignment", "-al", 1, NULL, "All allocation sizes are made to be a multiple of this number." DESC_NEWLINE "Closer to actual heap conditions; set to 1 for true sizes." DESC_NEWLINE "Default value is 16."};
76 static Switch gOverheadSwitch = {"--overhead", "-ov", 1, NULL, "After alignment, all allocations are made to increase by this number." DESC_NEWLINE "Closer to actual heap conditions; set to 0 for true sizes." DESC_NEWLINE "Default value is 8."};
77 static Switch gAveragesSwitch = {"--averages", "-avg", 0, NULL, "Display averages."};
78 static Switch gDeviationsSwitch = {"--deviations", "-dev", 0, NULL, "Display standard deviations from the average." DESC_NEWLINE "Implies --averages."};
79 static Switch gRunLengthSwitch = {"--run-length", "-rl", 0, NULL, "Display the run length in seconds."};
81 static Switch* gSwitches[] = {
82 &gInputSwitch,
83 &gOutputSwitch,
84 &gAlignmentSwitch,
85 &gOverheadSwitch,
86 &gAveragesSwitch,
87 &gDeviationsSwitch,
88 &gRunLengthSwitch,
89 &gHelpSwitch
90 };
93 typedef struct _struct_VarianceState
94 /*
95 ** State for a single pass variance calculation.
96 */
97 {
98 unsigned mCount;
99 uint64_t mSum;
100 uint64_t mSquaredSum;
101 }
102 VarianceState;
105 typedef struct __struct_TMStats
106 /*
107 ** Stats we are trying to calculate.
108 **
109 ** mOptions Obilgatory options pointer.
110 ** uMemoryInUse Current tally of memory in use.
111 ** uPeakMemory Heap topped out at this byte level.
112 ** uObjectsInUse Different allocations outstanding.
113 ** uPeakObjects Highest object count.
114 ** uMallocs Number of malloc calls.
115 ** uCallocs Number of calloc calls.
116 ** uReallocs Number of realloc calls.
117 ** uFrees Number of free calls.
118 ** uMallocSize Bytes from malloc.
119 ** uCallocSize Bytes from calloc.
120 ** uReallocSize Bytes from realloc.
121 ** uFreeSize Bytes from free.
122 ** mMallocSizeVar Variance of bytes.
123 ** mCallocSizeVar Variance of bytes.
124 ** mReallocSizeVar Variance of bytes.
125 ** mFreeSizeVar Variance of bytes.
126 ** uMallocCost Time of mallocs.
127 ** uCallocCost Time of callocs.
128 ** uReallocCost Time of reallocs.
129 ** uFreeCost Time of frees.
130 ** mMallocCostVar Variance of cost.
131 ** mCallocCostVar Variance of cost.
132 ** mReallocCostVar Variance of cost.
133 ** mFreeCostVar Variance of cost.
134 ** uMinTicks Start of run.
135 ** uMaxTicks End of run.
136 */
137 {
138 Options* mOptions;
139 unsigned uMemoryInUse;
140 unsigned uPeakMemory;
141 unsigned uObjectsInUse;
142 unsigned uPeakObjects;
143 unsigned uMallocs;
144 unsigned uCallocs;
145 unsigned uReallocs;
146 unsigned uFrees;
148 unsigned uMallocSize;
149 unsigned uCallocSize;
150 unsigned uReallocSize;
151 unsigned uFreeSize;
152 VarianceState mMallocSizeVar;
153 VarianceState mCallocSizeVar;
154 VarianceState mReallocSizeVar;
155 VarianceState mFreeSizeVar;
157 unsigned uMallocCost;
158 unsigned uCallocCost;
159 unsigned uReallocCost;
160 unsigned uFreeCost;
161 VarianceState mMallocCostVar;
162 VarianceState mCallocCostVar;
163 VarianceState mReallocCostVar;
164 VarianceState mFreeCostVar;
166 unsigned uMinTicks;
167 unsigned uMaxTicks;
168 }
169 TMStats;
172 int initOptions(Options* outOptions, int inArgc, char** inArgv)
173 /*
174 ** returns int 0 if successful.
175 */
176 {
177 int retval = 0;
178 int loop = 0;
179 int switchLoop = 0;
180 int match = 0;
181 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
182 Switch* current = NULL;
184 /*
185 ** Set any defaults.
186 */
187 memset(outOptions, 0, sizeof(Options));
188 outOptions->mProgramName = inArgv[0];
189 outOptions->mInputName = strdup("-");
190 outOptions->mOutput = stdout;
191 outOptions->mOutputName = strdup("stdout");
192 outOptions->mAlignment = 16;
193 outOptions->mOverhead = 8;
195 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
196 {
197 retval = __LINE__;
198 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
199 }
201 /*
202 ** Go through and attempt to do the right thing.
203 */
204 for(loop = 1; loop < inArgc && 0 == retval; loop++)
205 {
206 match = 0;
207 current = NULL;
209 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
210 {
211 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
212 {
213 match = __LINE__;
214 }
215 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
216 {
217 match = __LINE__;
218 }
220 if(match)
221 {
222 if(gSwitches[switchLoop]->mHasValue)
223 {
224 /*
225 ** Attempt to absorb next option to fullfill value.
226 */
227 if(loop + 1 < inArgc)
228 {
229 loop++;
231 current = gSwitches[switchLoop];
232 current->mValue = inArgv[loop];
233 }
234 }
235 else
236 {
237 current = gSwitches[switchLoop];
238 }
240 break;
241 }
242 }
244 if(0 == match)
245 {
246 outOptions->mHelp = __LINE__;
247 retval = __LINE__;
248 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
249 }
250 else if(NULL == current)
251 {
252 outOptions->mHelp = __LINE__;
253 retval = __LINE__;
254 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
255 }
256 else
257 {
258 /*
259 ** Do something based on address/swtich.
260 */
261 if(current == &gInputSwitch)
262 {
263 CLEANUP(outOptions->mInputName);
264 outOptions->mInputName = strdup(current->mValue);
265 if(NULL == outOptions->mInputName)
266 {
267 retval = __LINE__;
268 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
269 }
270 }
271 else if(current == &gOutputSwitch)
272 {
273 CLEANUP(outOptions->mOutputName);
274 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
275 {
276 fclose(outOptions->mOutput);
277 outOptions->mOutput = NULL;
278 }
280 outOptions->mOutput = fopen(current->mValue, "a");
281 if(NULL == outOptions->mOutput)
282 {
283 retval = __LINE__;
284 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
285 }
286 else
287 {
288 outOptions->mOutputName = strdup(current->mValue);
289 if(NULL == outOptions->mOutputName)
290 {
291 retval = __LINE__;
292 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
293 }
294 }
295 }
296 else if(current == &gHelpSwitch)
297 {
298 outOptions->mHelp = __LINE__;
299 }
300 else if(current == &gAlignmentSwitch)
301 {
302 unsigned arg = 0;
303 char* endScan = NULL;
305 errno = 0;
306 arg = strtoul(current->mValue, &endScan, 0);
307 if(0 == errno && endScan != current->mValue)
308 {
309 outOptions->mAlignment = arg;
310 }
311 else
312 {
313 retval = __LINE__;
314 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
315 }
316 }
317 else if(current == &gOverheadSwitch)
318 {
319 unsigned arg = 0;
320 char* endScan = NULL;
322 errno = 0;
323 arg = strtoul(current->mValue, &endScan, 0);
324 if(0 == errno && endScan != current->mValue)
325 {
326 outOptions->mOverhead = arg;
327 }
328 else
329 {
330 retval = __LINE__;
331 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
332 }
333 }
334 else if(current == &gAveragesSwitch)
335 {
336 outOptions->mAverages = __LINE__;
337 }
338 else if(current == &gDeviationsSwitch)
339 {
340 outOptions->mAverages = __LINE__;
341 outOptions->mDeviances = __LINE__;
342 }
343 else if(current == &gRunLengthSwitch)
344 {
345 outOptions->mRunLength = __LINE__;
346 }
347 else
348 {
349 retval = __LINE__;
350 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
351 }
352 }
353 }
355 return retval;
356 }
359 void cleanOptions(Options* inOptions)
360 /*
361 ** Clean up any open handles.
362 */
363 {
364 unsigned loop = 0;
366 CLEANUP(inOptions->mInputName);
367 CLEANUP(inOptions->mOutputName);
368 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
369 {
370 fclose(inOptions->mOutput);
371 }
373 memset(inOptions, 0, sizeof(Options));
374 }
377 void showHelp(Options* inOptions)
378 /*
379 ** Show some simple help text on usage.
380 */
381 {
382 int loop = 0;
383 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
384 const char* valueText = NULL;
386 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
387 printf("\n");
388 printf("arguments:\n");
390 for(loop = 0; loop < switchCount; loop++)
391 {
392 if(gSwitches[loop]->mHasValue)
393 {
394 valueText = " <value>";
395 }
396 else
397 {
398 valueText = "";
399 }
401 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
402 printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
403 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
404 }
406 printf("This tool reports simple heap usage and allocation call counts.\n");
407 printf("Useful for eyeballing trace-malloc numbers quickly.\n");
408 }
411 void addVariance(VarianceState* inVariance, unsigned inValue)
412 /*
413 ** Add a value to a variance state.
414 */
415 {
416 uint64_t squared;
417 uint64_t bigValue;
419 bigValue = inValue;
420 inVariance->mSum += bigValue;
422 squared = bigValue * bigValue;
423 inVariance->mSquaredSum += squared;
425 inVariance->mCount++;
426 }
429 double getAverage(VarianceState* inVariance)
430 /*
431 ** Determine the mean/average based on the given state.
432 */
433 {
434 double retval = 0.0;
436 if(NULL != inVariance && 0 < inVariance->mCount)
437 {
438 double count;
439 int64_t isum;
441 /*
442 ** Avoids a compiler error (not impl) under MSVC.
443 */
444 isum = inVariance->mSum;
446 count = (double)inVariance->mCount;
448 retval = (double)isum / count;
449 }
451 return retval;
452 }
455 double getVariance(VarianceState* inVariance)
456 /*
457 ** Determine the variance based on the given state.
458 */
459 {
460 double retval = 0.0;
462 if(NULL != inVariance && 1 < inVariance->mCount)
463 {
464 double count;
465 double avg;
466 double squaredAvg;
467 int64_t isquaredSum;
469 /*
470 ** Avoids a compiler error (not impl) under MSVC.
471 */
472 isquaredSum = inVariance->mSquaredSum;
474 count = (double)inVariance->mCount;
476 avg = getAverage(inVariance);
477 squaredAvg = avg * avg;
479 retval = ((double)isquaredSum - (count * squaredAvg)) / (count - 1.0);
480 }
482 return retval;
483 }
486 double getStdDev(VarianceState* inVariance)
487 /*
488 ** Determine the standard deviation based on the given state.
489 */
490 {
491 double retval = 0.0;
492 double variance;
494 variance = getVariance(inVariance);
495 retval = sqrt(variance);
497 return retval;
498 }
501 unsigned actualByteSize(Options* inOptions, unsigned retval)
502 /*
503 ** Apply alignment and overhead to size to figure out actual byte size.
504 ** This by default mimics spacetrace with default options (msvc crt heap).
505 */
506 {
507 if(0 != retval)
508 {
509 unsigned eval = 0;
510 unsigned over = 0;
512 eval = retval - 1;
513 if(0 != inOptions->mAlignment)
514 {
515 over = eval % inOptions->mAlignment;
516 }
517 retval = eval + inOptions->mOverhead + inOptions->mAlignment - over;
518 }
520 return retval;
521 }
524 uint32_t ticks2xsec(tmreader* aReader, uint32_t aTicks, uint32_t aResolution)
525 /*
526 ** Convert platform specific ticks to second units
527 ** Returns 0 on success.
528 */
529 {
530 return (uint32_t)((aResolution * aTicks) / aReader->ticksPerSec);
531 }
532 #define ticks2msec(reader, ticks) ticks2xsec((reader), (ticks), 1000)
535 void tmEventHandler(tmreader* inReader, tmevent* inEvent)
536 /*
537 ** Callback from the tmreader_eventloop.
538 ** Keep it simple in here, this is where we'll spend the most time.
539 ** The goal is to be fast.
540 */
541 {
542 TMStats* stats = (TMStats*)inReader->data;
543 Options* options = (Options*)stats->mOptions;
544 char type = inEvent->type;
545 unsigned size = inEvent->u.alloc.size;
546 unsigned actualSize = 0;
547 unsigned actualOldSize = 0;
548 uint32_t interval = 0;
550 /*
551 ** To match spacetrace stats, reallocs of size zero are frees.
552 ** Adjust the size to match what free expects.
553 */
554 if(TM_EVENT_REALLOC == type && 0 == size)
555 {
556 type = TM_EVENT_FREE;
557 if(0 != inEvent->u.alloc.oldserial)
558 {
559 size = inEvent->u.alloc.oldsize;
560 }
561 }
563 /*
564 ** Adjust the size due to the options.
565 */
566 actualSize = actualByteSize(options, size);
567 if(TM_EVENT_REALLOC == type && 0 != inEvent->u.alloc.oldserial)
568 {
569 actualOldSize = actualByteSize(options, inEvent->u.alloc.oldsize);
570 }
572 /*
573 ** Modify event specific data.
574 */
575 switch(type)
576 {
577 case TM_EVENT_MALLOC:
578 stats->uMallocs++;
579 stats->uMallocSize += actualSize;
580 stats->uMallocCost += ticks2msec(inReader, inEvent->u.alloc.cost);
581 stats->uMemoryInUse += actualSize;
582 stats->uObjectsInUse++;
584 addVariance(&stats->mMallocSizeVar, actualSize);
585 addVariance(&stats->mMallocCostVar, inEvent->u.alloc.cost);
586 break;
588 case TM_EVENT_CALLOC:
589 stats->uCallocs++;
590 stats->uCallocSize += actualSize;
591 stats->uCallocCost += ticks2msec(inReader, inEvent->u.alloc.cost);
592 stats->uMemoryInUse += actualSize;
593 stats->uObjectsInUse++;
595 addVariance(&stats->mCallocSizeVar, actualSize);
596 addVariance(&stats->mCallocCostVar, inEvent->u.alloc.cost);
597 break;
599 case TM_EVENT_REALLOC:
600 stats->uReallocs++;
601 stats->uReallocSize -= actualOldSize;
602 stats->uReallocSize += actualSize;
603 stats->uReallocCost += ticks2msec(inReader, inEvent->u.alloc.cost);
604 stats->uMemoryInUse -= actualOldSize;
605 stats->uMemoryInUse += actualSize;
606 if(0 == inEvent->u.alloc.oldserial)
607 {
608 stats->uObjectsInUse++;
609 }
611 if(actualSize > actualOldSize)
612 {
613 addVariance(&stats->mReallocSizeVar, actualSize - actualOldSize);
614 }
615 else
616 {
617 addVariance(&stats->mReallocSizeVar, actualOldSize - actualSize);
618 }
619 addVariance(&stats->mReallocCostVar, inEvent->u.alloc.cost);
620 break;
622 case TM_EVENT_FREE:
623 stats->uFrees++;
624 stats->uFreeSize += actualSize;
625 stats->uFreeCost += ticks2msec(inReader, inEvent->u.alloc.cost);
626 stats->uMemoryInUse -= actualSize;
627 stats->uObjectsInUse--;
629 addVariance(&stats->mFreeSizeVar, actualSize);
630 addVariance(&stats->mFreeCostVar, inEvent->u.alloc.cost);
631 break;
633 default:
634 /*
635 ** Don't care.
636 */
637 break;
638 }
640 switch(type)
641 {
642 case TM_EVENT_MALLOC:
643 case TM_EVENT_CALLOC:
644 case TM_EVENT_REALLOC:
645 /*
646 ** Check the peaks.
647 */
648 if(stats->uMemoryInUse > stats->uPeakMemory)
649 {
650 stats->uPeakMemory = stats->uMemoryInUse;
651 }
652 if(stats->uObjectsInUse > stats->uPeakObjects)
653 {
654 stats->uPeakObjects = stats->uObjectsInUse;
655 }
657 /*
658 ** Falling through.
659 */
661 case TM_EVENT_FREE:
662 /*
663 ** Check the overall time.
664 */
665 interval = ticks2msec(inReader, inEvent->u.alloc.interval);
666 if(stats->uMinTicks > interval)
667 {
668 stats->uMinTicks = interval;
669 }
670 if(stats->uMaxTicks < interval)
671 {
672 stats->uMaxTicks = interval;
673 }
674 break;
676 default:
677 /*
678 ** Don't care.
679 */
680 break;
681 }
683 }
685 int report_stats(Options* inOptions, TMStats* inStats)
686 {
687 int retval = 0;
689 fprintf(inOptions->mOutput, "Peak Memory Usage: %11d\n", inStats->uPeakMemory);
690 fprintf(inOptions->mOutput, "Memory Leaked: %11d\n", inStats->uMemoryInUse);
691 fprintf(inOptions->mOutput, "\n");
693 fprintf(inOptions->mOutput, "Peak Object Count: %11d\n", inStats->uPeakObjects);
694 fprintf(inOptions->mOutput, "Objects Leaked: %11d\n", inStats->uObjectsInUse);
695 if(0 != inOptions->mAverages && 0 != inStats->uObjectsInUse)
696 {
697 fprintf(inOptions->mOutput, "Average Leaked Object Size: %11.4f\n", (double)inStats->uMemoryInUse / (double)inStats->uObjectsInUse);
698 }
699 fprintf(inOptions->mOutput, "\n");
701 fprintf(inOptions->mOutput, "Call Total: %11d\n", inStats->uMallocs + inStats->uCallocs + inStats->uReallocs + inStats->uFrees);
702 fprintf(inOptions->mOutput, " malloc: %11d\n", inStats->uMallocs);
703 fprintf(inOptions->mOutput, " calloc: %11d\n", inStats->uCallocs);
704 fprintf(inOptions->mOutput, " realloc: %11d\n", inStats->uReallocs);
705 fprintf(inOptions->mOutput, " free: %11d\n", inStats->uFrees);
706 fprintf(inOptions->mOutput, "\n");
708 fprintf(inOptions->mOutput, "Byte Total (sans free): %11d\n", inStats->uMallocSize + inStats->uCallocSize + inStats->uReallocSize);
709 fprintf(inOptions->mOutput, " malloc: %11d\n", inStats->uMallocSize);
710 fprintf(inOptions->mOutput, " calloc: %11d\n", inStats->uCallocSize);
711 fprintf(inOptions->mOutput, " realloc: %11d\n", inStats->uReallocSize);
712 fprintf(inOptions->mOutput, " free: %11d\n", inStats->uFreeSize);
713 if(0 != inOptions->mAverages)
714 {
715 fprintf(inOptions->mOutput, "Byte Averages:\n");
716 fprintf(inOptions->mOutput, " malloc: %11.4f\n", getAverage(&inStats->mMallocSizeVar));
717 fprintf(inOptions->mOutput, " calloc: %11.4f\n", getAverage(&inStats->mCallocSizeVar));
718 fprintf(inOptions->mOutput, " realloc: %11.4f\n", getAverage(&inStats->mReallocSizeVar));
719 fprintf(inOptions->mOutput, " free: %11.4f\n", getAverage(&inStats->mFreeSizeVar));
720 }
721 if(0 != inOptions->mDeviances)
722 {
723 fprintf(inOptions->mOutput, "Byte Standard Deviations:\n");
724 fprintf(inOptions->mOutput, " malloc: %11.4f\n", getStdDev(&inStats->mMallocSizeVar));
725 fprintf(inOptions->mOutput, " calloc: %11.4f\n", getStdDev(&inStats->mCallocSizeVar));
726 fprintf(inOptions->mOutput, " realloc: %11.4f\n", getStdDev(&inStats->mReallocSizeVar));
727 fprintf(inOptions->mOutput, " free: %11.4f\n", getStdDev(&inStats->mFreeSizeVar));
728 }
729 fprintf(inOptions->mOutput, "\n");
731 fprintf(inOptions->mOutput, "Overhead Total: %11.4f\n", COST_PRINTABLE(inStats->uMallocCost) + COST_PRINTABLE(inStats->uCallocCost) + COST_PRINTABLE(inStats->uReallocCost) + COST_PRINTABLE(inStats->uFreeCost));
732 fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(inStats->uMallocCost));
733 fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(inStats->uCallocCost));
734 fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(inStats->uReallocCost));
735 fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(inStats->uFreeCost));
736 if(0 != inOptions->mAverages)
737 {
738 fprintf(inOptions->mOutput, "Overhead Averages:\n");
739 fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mMallocCostVar)));
740 fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mCallocCostVar)));
741 fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mReallocCostVar)));
742 fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mFreeCostVar)));
743 }
744 if(0 != inOptions->mDeviances)
745 {
746 fprintf(inOptions->mOutput, "Overhead Standard Deviations:\n");
747 fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mMallocCostVar)));
748 fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mCallocCostVar)));
749 fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mReallocCostVar)));
750 fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mFreeCostVar)));
751 }
752 fprintf(inOptions->mOutput, "\n");
754 if(0 != inOptions->mRunLength)
755 {
756 unsigned length = inStats->uMaxTicks - inStats->uMinTicks;
758 fprintf(inOptions->mOutput, "Run Length: %11.4f\n", COST_PRINTABLE(length));
759 fprintf(inOptions->mOutput, "\n");
760 }
762 return retval;
763 }
766 int tmstats(Options* inOptions)
767 /*
768 ** As quick as possible, load the input file and report stats.
769 */
770 {
771 int retval = 0;
772 tmreader* tmr = NULL;
773 TMStats stats;
775 memset(&stats, 0, sizeof(stats));
776 stats.mOptions = inOptions;
777 stats.uMinTicks = 0xFFFFFFFFU;
779 /*
780 ** Need a tmreader.
781 */
782 tmr = tmreader_new(inOptions->mProgramName, &stats);
783 if(NULL != tmr)
784 {
785 int tmResult = 0;
787 tmResult = tmreader_eventloop(tmr, inOptions->mInputName, tmEventHandler);
788 if(0 == tmResult)
789 {
790 retval = __LINE__;
791 ERROR_REPORT(retval, inOptions->mInputName, "Problem reading trace-malloc data.");
792 }
794 tmreader_destroy(tmr);
795 tmr = NULL;
797 if(0 == retval)
798 {
799 retval = report_stats(inOptions, &stats);
800 }
801 }
802 else
803 {
804 retval = __LINE__;
805 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to obtain tmreader.");
806 }
808 return retval;
809 }
812 int main(int inArgc, char** inArgv)
813 {
814 int retval = 0;
815 Options options;
817 retval = initOptions(&options, inArgc, inArgv);
818 if(options.mHelp)
819 {
820 showHelp(&options);
821 }
822 else if(0 == retval)
823 {
824 retval = tmstats(&options);
825 }
827 cleanOptions(&options);
828 return retval;
829 }