1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is tmstats.c code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2002
22 * the Initial Developer. All Rights Reserved.
25 * Garrett Arch Blythe, 25-October-2002
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
52 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
53 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
56 #define COST_RESOLUTION 1000
57 #define COST_PRINTABLE(cost) ((PRFloat64)(cost) / (PRFloat64)COST_RESOLUTION)
60 typedef struct __struct_Options
62 ** Options to control how we perform.
64 ** mProgramName Used in help text.
65 ** mInputName Name of the file.
66 ** mOutput Output file, append.
68 ** mOutputName Name of the file.
69 ** mHelp Whether or not help should be shown.
70 ** mOverhead How much overhead an allocation will have.
71 ** mAlignment What boundry will the end of an allocation line up on.
72 ** mAverages Whether or not to display averages.
73 ** mDeviances Whether or not to display standard deviations.
74 ** mRunLength Whether or not to display run length.
77 const char* mProgramName
;
91 typedef struct __struct_Switch
93 ** Command line options.
96 const char* mLongName
;
97 const char* mShortName
;
100 const char* mDescription
;
104 #define DESC_NEWLINE "\n\t\t"
106 static Switch gInputSwitch
= {"--input", "-i", 1, NULL
, "Specify input file." DESC_NEWLINE
"stdin is default."};
107 static Switch gOutputSwitch
= {"--output", "-o", 1, NULL
, "Specify output file." DESC_NEWLINE
"Appends if file exists." DESC_NEWLINE
"stdout is default."};
108 static Switch gHelpSwitch
= {"--help", "-h", 0, NULL
, "Information on usage."};
109 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."};
110 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."};
111 static Switch gAveragesSwitch
= {"--averages", "-avg", 0, NULL
, "Display averages."};
112 static Switch gDeviationsSwitch
= {"--deviations", "-dev", 0, NULL
, "Display standard deviations from the average." DESC_NEWLINE
"Implies --averages."};
113 static Switch gRunLengthSwitch
= {"--run-length", "-rl", 0, NULL
, "Display the run length in seconds."};
115 static Switch
* gSwitches
[] = {
127 typedef struct _struct_VarianceState
129 ** State for a single pass variance calculation.
134 PRUint64 mSquaredSum
;
139 typedef struct __struct_TMStats
141 ** Stats we are trying to calculate.
143 ** mOptions Obilgatory options pointer.
144 ** uMemoryInUse Current tally of memory in use.
145 ** uPeakMemory Heap topped out at this byte level.
146 ** uObjectsInUse Different allocations outstanding.
147 ** uPeakObjects Highest object count.
148 ** uMallocs Number of malloc calls.
149 ** uCallocs Number of calloc calls.
150 ** uReallocs Number of realloc calls.
151 ** uFrees Number of free calls.
152 ** uMallocSize Bytes from malloc.
153 ** uCallocSize Bytes from calloc.
154 ** uReallocSize Bytes from realloc.
155 ** uFreeSize Bytes from free.
156 ** mMallocSizeVar Variance of bytes.
157 ** mCallocSizeVar Variance of bytes.
158 ** mReallocSizeVar Variance of bytes.
159 ** mFreeSizeVar Variance of bytes.
160 ** uMallocCost Time of mallocs.
161 ** uCallocCost Time of callocs.
162 ** uReallocCost Time of reallocs.
163 ** uFreeCost Time of frees.
164 ** mMallocCostVar Variance of cost.
165 ** mCallocCostVar Variance of cost.
166 ** mReallocCostVar Variance of cost.
167 ** mFreeCostVar Variance of cost.
168 ** uMinTicks Start of run.
169 ** uMaxTicks End of run.
173 unsigned uMemoryInUse
;
174 unsigned uPeakMemory
;
175 unsigned uObjectsInUse
;
176 unsigned uPeakObjects
;
182 unsigned uMallocSize
;
183 unsigned uCallocSize
;
184 unsigned uReallocSize
;
186 VarianceState mMallocSizeVar
;
187 VarianceState mCallocSizeVar
;
188 VarianceState mReallocSizeVar
;
189 VarianceState mFreeSizeVar
;
191 unsigned uMallocCost
;
192 unsigned uCallocCost
;
193 unsigned uReallocCost
;
195 VarianceState mMallocCostVar
;
196 VarianceState mCallocCostVar
;
197 VarianceState mReallocCostVar
;
198 VarianceState mFreeCostVar
;
206 int initOptions(Options
* outOptions
, int inArgc
, char** inArgv
)
208 ** returns int 0 if successful.
215 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
216 Switch
* current
= NULL
;
221 memset(outOptions
, 0, sizeof(Options
));
222 outOptions
->mProgramName
= inArgv
[0];
223 outOptions
->mInputName
= strdup("-");
224 outOptions
->mOutput
= stdout
;
225 outOptions
->mOutputName
= strdup("stdout");
226 outOptions
->mAlignment
= 16;
227 outOptions
->mOverhead
= 8;
229 if(NULL
== outOptions
->mOutputName
|| NULL
== outOptions
->mInputName
)
232 ERROR_REPORT(retval
, "stdin/stdout", "Unable to strdup.");
236 ** Go through and attempt to do the right thing.
238 for(loop
= 1; loop
< inArgc
&& 0 == retval
; loop
++)
243 for(switchLoop
= 0; switchLoop
< switchCount
&& 0 == retval
; switchLoop
++)
245 if(0 == strcmp(gSwitches
[switchLoop
]->mLongName
, inArgv
[loop
]))
249 else if(0 == strcmp(gSwitches
[switchLoop
]->mShortName
, inArgv
[loop
]))
256 if(gSwitches
[switchLoop
]->mHasValue
)
259 ** Attempt to absorb next option to fullfill value.
261 if(loop
+ 1 < inArgc
)
265 current
= gSwitches
[switchLoop
];
266 current
->mValue
= inArgv
[loop
];
271 current
= gSwitches
[switchLoop
];
280 outOptions
->mHelp
= __LINE__
;
282 ERROR_REPORT(retval
, inArgv
[loop
], "Unknown command line switch.");
284 else if(NULL
== current
)
286 outOptions
->mHelp
= __LINE__
;
288 ERROR_REPORT(retval
, inArgv
[loop
], "Command line switch requires a value.");
293 ** Do something based on address/swtich.
295 if(current
== &gInputSwitch
)
297 CLEANUP(outOptions
->mInputName
);
298 outOptions
->mInputName
= strdup(current
->mValue
);
299 if(NULL
== outOptions
->mInputName
)
302 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
305 else if(current
== &gOutputSwitch
)
307 CLEANUP(outOptions
->mOutputName
);
308 if(NULL
!= outOptions
->mOutput
&& stdout
!= outOptions
->mOutput
)
310 fclose(outOptions
->mOutput
);
311 outOptions
->mOutput
= NULL
;
314 outOptions
->mOutput
= fopen(current
->mValue
, "a");
315 if(NULL
== outOptions
->mOutput
)
318 ERROR_REPORT(retval
, current
->mValue
, "Unable to open output file.");
322 outOptions
->mOutputName
= strdup(current
->mValue
);
323 if(NULL
== outOptions
->mOutputName
)
326 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
330 else if(current
== &gHelpSwitch
)
332 outOptions
->mHelp
= __LINE__
;
334 else if(current
== &gAlignmentSwitch
)
337 char* endScan
= NULL
;
340 arg
= strtoul(current
->mValue
, &endScan
, 0);
341 if(0 == errno
&& endScan
!= current
->mValue
)
343 outOptions
->mAlignment
= arg
;
348 ERROR_REPORT(retval
, current
->mValue
, "Unable to convert to a number.");
351 else if(current
== &gOverheadSwitch
)
354 char* endScan
= NULL
;
357 arg
= strtoul(current
->mValue
, &endScan
, 0);
358 if(0 == errno
&& endScan
!= current
->mValue
)
360 outOptions
->mOverhead
= arg
;
365 ERROR_REPORT(retval
, current
->mValue
, "Unable to convert to a number.");
368 else if(current
== &gAveragesSwitch
)
370 outOptions
->mAverages
= __LINE__
;
372 else if(current
== &gDeviationsSwitch
)
374 outOptions
->mAverages
= __LINE__
;
375 outOptions
->mDeviances
= __LINE__
;
377 else if(current
== &gRunLengthSwitch
)
379 outOptions
->mRunLength
= __LINE__
;
384 ERROR_REPORT(retval
, current
->mLongName
, "No handler for command line switch.");
393 void cleanOptions(Options
* inOptions
)
395 ** Clean up any open handles.
400 CLEANUP(inOptions
->mInputName
);
401 CLEANUP(inOptions
->mOutputName
);
402 if(NULL
!= inOptions
->mOutput
&& stdout
!= inOptions
->mOutput
)
404 fclose(inOptions
->mOutput
);
407 memset(inOptions
, 0, sizeof(Options
));
411 void showHelp(Options
* inOptions
)
413 ** Show some simple help text on usage.
417 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
418 const char* valueText
= NULL
;
420 printf("usage:\t%s [arguments]\n", inOptions
->mProgramName
);
422 printf("arguments:\n");
424 for(loop
= 0; loop
< switchCount
; loop
++)
426 if(gSwitches
[loop
]->mHasValue
)
428 valueText
= " <value>";
435 printf("\t%s%s\n", gSwitches
[loop
]->mLongName
, valueText
);
436 printf("\t %s%s", gSwitches
[loop
]->mShortName
, valueText
);
437 printf(DESC_NEWLINE
"%s\n\n", gSwitches
[loop
]->mDescription
);
440 printf("This tool reports simple heap usage and allocation call counts.\n");
441 printf("Useful for eyeballing trace-malloc numbers quickly.\n");
445 void addVariance(VarianceState
* inVariance
, unsigned inValue
)
447 ** Add a value to a variance state.
453 LL_UI2L(bigValue
, inValue
);
455 LL_ADD(inVariance
->mSum
, inVariance
->mSum
, bigValue
);
457 LL_MUL(squared
, bigValue
, bigValue
);
458 LL_ADD(inVariance
->mSquaredSum
, inVariance
->mSquaredSum
, squared
);
460 inVariance
->mCount
++;
464 PRFloat64
getAverage(VarianceState
* inVariance
)
466 ** Determine the mean/average based on the given state.
469 PRFloat64 retval
= 0.0;
471 if(NULL
!= inVariance
&& 0 < inVariance
->mCount
)
478 ** Avoids a compiler error (not impl) under MSVC.
480 isum
= inVariance
->mSum
;
482 count
= (PRFloat64
)inVariance
->mCount
;
485 retval
= sum
/ count
;
492 PRFloat64
getVariance(VarianceState
* inVariance
)
494 ** Determine the variance based on the given state.
497 PRFloat64 retval
= 0.0;
499 if(NULL
!= inVariance
&& 1 < inVariance
->mCount
)
502 PRFloat64 squaredSum
;
504 PRFloat64 squaredAvg
;
508 ** Avoids a compiler error (not impl) under MSVC.
510 isquaredSum
= inVariance
->mSquaredSum
;
512 count
= (PRFloat64
)inVariance
->mCount
;
513 LL_L2F(squaredSum
, isquaredSum
);
515 avg
= getAverage(inVariance
);
516 squaredAvg
= avg
* avg
;
518 retval
= (squaredSum
- (count
* squaredAvg
)) / (count
- 1.0);
525 PRFloat64
getStdDev(VarianceState
* inVariance
)
527 ** Determine the standard deviation based on the given state.
530 PRFloat64 retval
= 0.0;
533 variance
= getVariance(inVariance
);
534 retval
= sqrt(variance
);
540 unsigned actualByteSize(Options
* inOptions
, unsigned retval
)
542 ** Apply alignment and overhead to size to figure out actual byte size.
543 ** This by default mimics spacetrace with default options (msvc crt heap).
552 if(0 != inOptions
->mAlignment
)
554 over
= eval
% inOptions
->mAlignment
;
556 retval
= eval
+ inOptions
->mOverhead
+ inOptions
->mAlignment
- over
;
563 PRUint32
ticks2xsec(tmreader
* aReader
, PRUint32 aTicks
, PRUint32 aResolution
)
565 ** Convert platform specific ticks to second units
566 ** Returns 0 on success.
573 LL_UI2L(bigone
, aResolution
);
574 LL_UI2L(tmp64
, aTicks
);
575 LL_MUL(bigone
, bigone
, tmp64
);
576 LL_UI2L(tmp64
, aReader
->ticksPerSec
);
577 LL_DIV(bigone
, bigone
, tmp64
);
578 LL_L2UI(retval
, bigone
);
582 #define ticks2msec(reader, ticks) ticks2xsec((reader), (ticks), 1000)
585 void tmEventHandler(tmreader
* inReader
, tmevent
* inEvent
)
587 ** Callback from the tmreader_eventloop.
588 ** Keep it simple in here, this is where we'll spend the most time.
589 ** The goal is to be fast.
592 TMStats
* stats
= (TMStats
*)inReader
->data
;
593 Options
* options
= (Options
*)stats
->mOptions
;
594 char type
= inEvent
->type
;
595 unsigned size
= inEvent
->u
.alloc
.size
;
596 unsigned actualSize
= 0;
597 unsigned actualOldSize
= 0;
598 PRUint32 interval
= 0;
601 ** To match spacetrace stats, reallocs of size zero are frees.
602 ** Adjust the size to match what free expects.
604 if(TM_EVENT_REALLOC
== type
&& 0 == size
)
606 type
= TM_EVENT_FREE
;
607 if(0 != inEvent
->u
.alloc
.oldserial
)
609 size
= inEvent
->u
.alloc
.oldsize
;
614 ** Adjust the size due to the options.
616 actualSize
= actualByteSize(options
, size
);
617 if(TM_EVENT_REALLOC
== type
&& 0 != inEvent
->u
.alloc
.oldserial
)
619 actualOldSize
= actualByteSize(options
, inEvent
->u
.alloc
.oldsize
);
623 ** Modify event specific data.
627 case TM_EVENT_MALLOC
:
629 stats
->uMallocSize
+= actualSize
;
630 stats
->uMallocCost
+= ticks2msec(inReader
, inEvent
->u
.alloc
.cost
);
631 stats
->uMemoryInUse
+= actualSize
;
632 stats
->uObjectsInUse
++;
634 addVariance(&stats
->mMallocSizeVar
, actualSize
);
635 addVariance(&stats
->mMallocCostVar
, inEvent
->u
.alloc
.cost
);
638 case TM_EVENT_CALLOC
:
640 stats
->uCallocSize
+= actualSize
;
641 stats
->uCallocCost
+= ticks2msec(inReader
, inEvent
->u
.alloc
.cost
);
642 stats
->uMemoryInUse
+= actualSize
;
643 stats
->uObjectsInUse
++;
645 addVariance(&stats
->mCallocSizeVar
, actualSize
);
646 addVariance(&stats
->mCallocCostVar
, inEvent
->u
.alloc
.cost
);
649 case TM_EVENT_REALLOC
:
651 stats
->uReallocSize
-= actualOldSize
;
652 stats
->uReallocSize
+= actualSize
;
653 stats
->uReallocCost
+= ticks2msec(inReader
, inEvent
->u
.alloc
.cost
);
654 stats
->uMemoryInUse
-= actualOldSize
;
655 stats
->uMemoryInUse
+= actualSize
;
656 if(0 == inEvent
->u
.alloc
.oldserial
)
658 stats
->uObjectsInUse
++;
661 if(actualSize
> actualOldSize
)
663 addVariance(&stats
->mReallocSizeVar
, actualSize
- actualOldSize
);
667 addVariance(&stats
->mReallocSizeVar
, actualOldSize
- actualSize
);
669 addVariance(&stats
->mReallocCostVar
, inEvent
->u
.alloc
.cost
);
674 stats
->uFreeSize
+= actualSize
;
675 stats
->uFreeCost
+= ticks2msec(inReader
, inEvent
->u
.alloc
.cost
);
676 stats
->uMemoryInUse
-= actualSize
;
677 stats
->uObjectsInUse
--;
679 addVariance(&stats
->mFreeSizeVar
, actualSize
);
680 addVariance(&stats
->mFreeCostVar
, inEvent
->u
.alloc
.cost
);
692 case TM_EVENT_MALLOC
:
693 case TM_EVENT_CALLOC
:
694 case TM_EVENT_REALLOC
:
698 if(stats
->uMemoryInUse
> stats
->uPeakMemory
)
700 stats
->uPeakMemory
= stats
->uMemoryInUse
;
702 if(stats
->uObjectsInUse
> stats
->uPeakObjects
)
704 stats
->uPeakObjects
= stats
->uObjectsInUse
;
713 ** Check the overall time.
715 interval
= ticks2msec(inReader
, inEvent
->u
.alloc
.interval
);
716 if(stats
->uMinTicks
> interval
)
718 stats
->uMinTicks
= interval
;
720 if(stats
->uMaxTicks
< interval
)
722 stats
->uMaxTicks
= interval
;
735 int report_stats(Options
* inOptions
, TMStats
* inStats
)
739 fprintf(inOptions
->mOutput
, "Peak Memory Usage: %11d\n", inStats
->uPeakMemory
);
740 fprintf(inOptions
->mOutput
, "Memory Leaked: %11d\n", inStats
->uMemoryInUse
);
741 fprintf(inOptions
->mOutput
, "\n");
743 fprintf(inOptions
->mOutput
, "Peak Object Count: %11d\n", inStats
->uPeakObjects
);
744 fprintf(inOptions
->mOutput
, "Objects Leaked: %11d\n", inStats
->uObjectsInUse
);
745 if(0 != inOptions
->mAverages
&& 0 != inStats
->uObjectsInUse
)
747 fprintf(inOptions
->mOutput
, "Average Leaked Object Size: %11.4f\n", (PRFloat64
)inStats
->uMemoryInUse
/ (PRFloat64
)inStats
->uObjectsInUse
);
749 fprintf(inOptions
->mOutput
, "\n");
751 fprintf(inOptions
->mOutput
, "Call Total: %11d\n", inStats
->uMallocs
+ inStats
->uCallocs
+ inStats
->uReallocs
+ inStats
->uFrees
);
752 fprintf(inOptions
->mOutput
, " malloc: %11d\n", inStats
->uMallocs
);
753 fprintf(inOptions
->mOutput
, " calloc: %11d\n", inStats
->uCallocs
);
754 fprintf(inOptions
->mOutput
, " realloc: %11d\n", inStats
->uReallocs
);
755 fprintf(inOptions
->mOutput
, " free: %11d\n", inStats
->uFrees
);
756 fprintf(inOptions
->mOutput
, "\n");
758 fprintf(inOptions
->mOutput
, "Byte Total (sans free): %11d\n", inStats
->uMallocSize
+ inStats
->uCallocSize
+ inStats
->uReallocSize
);
759 fprintf(inOptions
->mOutput
, " malloc: %11d\n", inStats
->uMallocSize
);
760 fprintf(inOptions
->mOutput
, " calloc: %11d\n", inStats
->uCallocSize
);
761 fprintf(inOptions
->mOutput
, " realloc: %11d\n", inStats
->uReallocSize
);
762 fprintf(inOptions
->mOutput
, " free: %11d\n", inStats
->uFreeSize
);
763 if(0 != inOptions
->mAverages
)
765 fprintf(inOptions
->mOutput
, "Byte Averages:\n");
766 fprintf(inOptions
->mOutput
, " malloc: %11.4f\n", getAverage(&inStats
->mMallocSizeVar
));
767 fprintf(inOptions
->mOutput
, " calloc: %11.4f\n", getAverage(&inStats
->mCallocSizeVar
));
768 fprintf(inOptions
->mOutput
, " realloc: %11.4f\n", getAverage(&inStats
->mReallocSizeVar
));
769 fprintf(inOptions
->mOutput
, " free: %11.4f\n", getAverage(&inStats
->mFreeSizeVar
));
771 if(0 != inOptions
->mDeviances
)
773 fprintf(inOptions
->mOutput
, "Byte Standard Deviations:\n");
774 fprintf(inOptions
->mOutput
, " malloc: %11.4f\n", getStdDev(&inStats
->mMallocSizeVar
));
775 fprintf(inOptions
->mOutput
, " calloc: %11.4f\n", getStdDev(&inStats
->mCallocSizeVar
));
776 fprintf(inOptions
->mOutput
, " realloc: %11.4f\n", getStdDev(&inStats
->mReallocSizeVar
));
777 fprintf(inOptions
->mOutput
, " free: %11.4f\n", getStdDev(&inStats
->mFreeSizeVar
));
779 fprintf(inOptions
->mOutput
, "\n");
781 fprintf(inOptions
->mOutput
, "Overhead Total: %11.4f\n", COST_PRINTABLE(inStats
->uMallocCost
) + COST_PRINTABLE(inStats
->uCallocCost
) + COST_PRINTABLE(inStats
->uReallocCost
) + COST_PRINTABLE(inStats
->uFreeCost
));
782 fprintf(inOptions
->mOutput
, " malloc: %11.4f\n", COST_PRINTABLE(inStats
->uMallocCost
));
783 fprintf(inOptions
->mOutput
, " calloc: %11.4f\n", COST_PRINTABLE(inStats
->uCallocCost
));
784 fprintf(inOptions
->mOutput
, " realloc: %11.4f\n", COST_PRINTABLE(inStats
->uReallocCost
));
785 fprintf(inOptions
->mOutput
, " free: %11.4f\n", COST_PRINTABLE(inStats
->uFreeCost
));
786 if(0 != inOptions
->mAverages
)
788 fprintf(inOptions
->mOutput
, "Overhead Averages:\n");
789 fprintf(inOptions
->mOutput
, " malloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats
->mMallocCostVar
)));
790 fprintf(inOptions
->mOutput
, " calloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats
->mCallocCostVar
)));
791 fprintf(inOptions
->mOutput
, " realloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats
->mReallocCostVar
)));
792 fprintf(inOptions
->mOutput
, " free: %11.4f\n", COST_PRINTABLE(getAverage(&inStats
->mFreeCostVar
)));
794 if(0 != inOptions
->mDeviances
)
796 fprintf(inOptions
->mOutput
, "Overhead Standard Deviations:\n");
797 fprintf(inOptions
->mOutput
, " malloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats
->mMallocCostVar
)));
798 fprintf(inOptions
->mOutput
, " calloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats
->mCallocCostVar
)));
799 fprintf(inOptions
->mOutput
, " realloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats
->mReallocCostVar
)));
800 fprintf(inOptions
->mOutput
, " free: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats
->mFreeCostVar
)));
802 fprintf(inOptions
->mOutput
, "\n");
804 if(0 != inOptions
->mRunLength
)
806 unsigned length
= inStats
->uMaxTicks
- inStats
->uMinTicks
;
808 fprintf(inOptions
->mOutput
, "Run Length: %11.4f\n", COST_PRINTABLE(length
));
809 fprintf(inOptions
->mOutput
, "\n");
816 int tmstats(Options
* inOptions
)
818 ** As quick as possible, load the input file and report stats.
822 tmreader
* tmr
= NULL
;
825 memset(&stats
, 0, sizeof(stats
));
826 stats
.mOptions
= inOptions
;
827 stats
.uMinTicks
= 0xFFFFFFFFU
;
832 tmr
= tmreader_new(inOptions
->mProgramName
, &stats
);
837 tmResult
= tmreader_eventloop(tmr
, inOptions
->mInputName
, tmEventHandler
);
841 ERROR_REPORT(retval
, inOptions
->mInputName
, "Problem reading trace-malloc data.");
844 tmreader_destroy(tmr
);
849 retval
= report_stats(inOptions
, &stats
);
855 ERROR_REPORT(retval
, inOptions
->mProgramName
, "Unable to obtain tmreader.");
862 int main(int inArgc
, char** inArgv
)
867 retval
= initOptions(&options
, inArgc
, inArgv
);
874 retval
= tmstats(&options
);
877 cleanOptions(&options
);