CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / tools / trace-malloc / tmstats.c
blobead484ac5af1c3dd29d06c68f52e5e1d6ad2e917
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
14 * License.
16 * The Original Code is tmstats.c code, released
17 * Oct 25, 2002.
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.
24 * Contributor(s):
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 ***** */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <time.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <math.h>
49 #include "nspr.h"
50 #include "tmreader.h"
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.
67 ** Default is stdout.
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;
78 char* mInputName;
79 FILE* mOutput;
80 char* mOutputName;
81 int mHelp;
82 unsigned mOverhead;
83 unsigned mAlignment;
84 int mAverages;
85 int mDeviances;
86 int mRunLength;
88 Options;
91 typedef struct __struct_Switch
93 ** Command line options.
96 const char* mLongName;
97 const char* mShortName;
98 int mHasValue;
99 const char* mValue;
100 const char* mDescription;
102 Switch;
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[] = {
116 &gInputSwitch,
117 &gOutputSwitch,
118 &gAlignmentSwitch,
119 &gOverheadSwitch,
120 &gAveragesSwitch,
121 &gDeviationsSwitch,
122 &gRunLengthSwitch,
123 &gHelpSwitch
127 typedef struct _struct_VarianceState
129 ** State for a single pass variance calculation.
132 unsigned mCount;
133 PRUint64 mSum;
134 PRUint64 mSquaredSum;
136 VarianceState;
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.
172 Options* mOptions;
173 unsigned uMemoryInUse;
174 unsigned uPeakMemory;
175 unsigned uObjectsInUse;
176 unsigned uPeakObjects;
177 unsigned uMallocs;
178 unsigned uCallocs;
179 unsigned uReallocs;
180 unsigned uFrees;
182 unsigned uMallocSize;
183 unsigned uCallocSize;
184 unsigned uReallocSize;
185 unsigned uFreeSize;
186 VarianceState mMallocSizeVar;
187 VarianceState mCallocSizeVar;
188 VarianceState mReallocSizeVar;
189 VarianceState mFreeSizeVar;
191 unsigned uMallocCost;
192 unsigned uCallocCost;
193 unsigned uReallocCost;
194 unsigned uFreeCost;
195 VarianceState mMallocCostVar;
196 VarianceState mCallocCostVar;
197 VarianceState mReallocCostVar;
198 VarianceState mFreeCostVar;
200 unsigned uMinTicks;
201 unsigned uMaxTicks;
203 TMStats;
206 int initOptions(Options* outOptions, int inArgc, char** inArgv)
208 ** returns int 0 if successful.
211 int retval = 0;
212 int loop = 0;
213 int switchLoop = 0;
214 int match = 0;
215 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
216 Switch* current = NULL;
219 ** Set any defaults.
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)
231 retval = __LINE__;
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++)
240 match = 0;
241 current = NULL;
243 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
245 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
247 match = __LINE__;
249 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
251 match = __LINE__;
254 if(match)
256 if(gSwitches[switchLoop]->mHasValue)
259 ** Attempt to absorb next option to fullfill value.
261 if(loop + 1 < inArgc)
263 loop++;
265 current = gSwitches[switchLoop];
266 current->mValue = inArgv[loop];
269 else
271 current = gSwitches[switchLoop];
274 break;
278 if(0 == match)
280 outOptions->mHelp = __LINE__;
281 retval = __LINE__;
282 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
284 else if(NULL == current)
286 outOptions->mHelp = __LINE__;
287 retval = __LINE__;
288 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
290 else
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)
301 retval = __LINE__;
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)
317 retval = __LINE__;
318 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
320 else
322 outOptions->mOutputName = strdup(current->mValue);
323 if(NULL == outOptions->mOutputName)
325 retval = __LINE__;
326 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
330 else if(current == &gHelpSwitch)
332 outOptions->mHelp = __LINE__;
334 else if(current == &gAlignmentSwitch)
336 unsigned arg = 0;
337 char* endScan = NULL;
339 errno = 0;
340 arg = strtoul(current->mValue, &endScan, 0);
341 if(0 == errno && endScan != current->mValue)
343 outOptions->mAlignment = arg;
345 else
347 retval = __LINE__;
348 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
351 else if(current == &gOverheadSwitch)
353 unsigned arg = 0;
354 char* endScan = NULL;
356 errno = 0;
357 arg = strtoul(current->mValue, &endScan, 0);
358 if(0 == errno && endScan != current->mValue)
360 outOptions->mOverhead = arg;
362 else
364 retval = __LINE__;
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__;
381 else
383 retval = __LINE__;
384 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
389 return retval;
393 void cleanOptions(Options* inOptions)
395 ** Clean up any open handles.
398 unsigned loop = 0;
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.
416 int loop = 0;
417 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
418 const char* valueText = NULL;
420 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
421 printf("\n");
422 printf("arguments:\n");
424 for(loop = 0; loop < switchCount; loop++)
426 if(gSwitches[loop]->mHasValue)
428 valueText = " <value>";
430 else
432 valueText = "";
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.
450 PRUint64 squared;
451 PRUint64 bigValue;
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)
473 PRFloat64 count;
474 PRFloat64 sum;
475 PRInt64 isum;
478 ** Avoids a compiler error (not impl) under MSVC.
480 isum = inVariance->mSum;
482 count = (PRFloat64)inVariance->mCount;
483 LL_L2F(sum, isum);
485 retval = sum / count;
488 return retval;
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)
501 PRFloat64 count;
502 PRFloat64 squaredSum;
503 PRFloat64 avg;
504 PRFloat64 squaredAvg;
505 PRInt64 isquaredSum;
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);
521 return retval;
525 PRFloat64 getStdDev(VarianceState* inVariance)
527 ** Determine the standard deviation based on the given state.
530 PRFloat64 retval = 0.0;
531 PRFloat64 variance;
533 variance = getVariance(inVariance);
534 retval = sqrt(variance);
536 return retval;
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).
546 if(0 != retval)
548 unsigned eval = 0;
549 unsigned over = 0;
551 eval = retval - 1;
552 if(0 != inOptions->mAlignment)
554 over = eval % inOptions->mAlignment;
556 retval = eval + inOptions->mOverhead + inOptions->mAlignment - over;
559 return retval;
563 PRUint32 ticks2xsec(tmreader* aReader, PRUint32 aTicks, PRUint32 aResolution)
565 ** Convert platform specific ticks to second units
566 ** Returns 0 on success.
569 PRUint32 retval = 0;
570 PRUint64 bigone;
571 PRUint64 tmp64;
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);
580 return retval;
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.
625 switch(type)
627 case TM_EVENT_MALLOC:
628 stats->uMallocs++;
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);
636 break;
638 case TM_EVENT_CALLOC:
639 stats->uCallocs++;
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);
647 break;
649 case TM_EVENT_REALLOC:
650 stats->uReallocs++;
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);
665 else
667 addVariance(&stats->mReallocSizeVar, actualOldSize - actualSize);
669 addVariance(&stats->mReallocCostVar, inEvent->u.alloc.cost);
670 break;
672 case TM_EVENT_FREE:
673 stats->uFrees++;
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);
681 break;
683 default:
685 ** Don't care.
687 break;
690 switch(type)
692 case TM_EVENT_MALLOC:
693 case TM_EVENT_CALLOC:
694 case TM_EVENT_REALLOC:
696 ** Check the peaks.
698 if(stats->uMemoryInUse > stats->uPeakMemory)
700 stats->uPeakMemory = stats->uMemoryInUse;
702 if(stats->uObjectsInUse > stats->uPeakObjects)
704 stats->uPeakObjects = stats->uObjectsInUse;
708 ** Falling through.
711 case TM_EVENT_FREE:
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;
724 break;
726 default:
728 ** Don't care.
730 break;
735 int report_stats(Options* inOptions, TMStats* inStats)
737 int retval = 0;
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");
812 return retval;
816 int tmstats(Options* inOptions)
818 ** As quick as possible, load the input file and report stats.
821 int retval = 0;
822 tmreader* tmr = NULL;
823 TMStats stats;
825 memset(&stats, 0, sizeof(stats));
826 stats.mOptions = inOptions;
827 stats.uMinTicks = 0xFFFFFFFFU;
830 ** Need a tmreader.
832 tmr = tmreader_new(inOptions->mProgramName, &stats);
833 if(NULL != tmr)
835 int tmResult = 0;
837 tmResult = tmreader_eventloop(tmr, inOptions->mInputName, tmEventHandler);
838 if(0 == tmResult)
840 retval = __LINE__;
841 ERROR_REPORT(retval, inOptions->mInputName, "Problem reading trace-malloc data.");
844 tmreader_destroy(tmr);
845 tmr = NULL;
847 if(0 == retval)
849 retval = report_stats(inOptions, &stats);
852 else
854 retval = __LINE__;
855 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to obtain tmreader.");
858 return retval;
862 int main(int inArgc, char** inArgv)
864 int retval = 0;
865 Options options;
867 retval = initOptions(&options, inArgc, inArgv);
868 if(options.mHelp)
870 showHelp(&options);
872 else if(0 == retval)
874 retval = tmstats(&options);
877 cleanOptions(&options);
878 return retval;