tools/trace-malloc/tmstats.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

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 }

mercurial