1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/trace-malloc/tmstats.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,830 @@ 1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <stdio.h> 1.11 +#include <stdlib.h> 1.12 +#include <string.h> 1.13 +#include <time.h> 1.14 +#include <ctype.h> 1.15 +#include <errno.h> 1.16 +#include <math.h> 1.17 + 1.18 +#include "nspr.h" 1.19 +#include "tmreader.h" 1.20 + 1.21 +#define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg)); 1.22 +#define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0) 1.23 + 1.24 + 1.25 +#define COST_RESOLUTION 1000 1.26 +#define COST_PRINTABLE(cost) ((double)(cost) / (double)COST_RESOLUTION) 1.27 + 1.28 + 1.29 +typedef struct __struct_Options 1.30 +/* 1.31 +** Options to control how we perform. 1.32 +** 1.33 +** mProgramName Used in help text. 1.34 +** mInputName Name of the file. 1.35 +** mOutput Output file, append. 1.36 +** Default is stdout. 1.37 +** mOutputName Name of the file. 1.38 +** mHelp Whether or not help should be shown. 1.39 +** mOverhead How much overhead an allocation will have. 1.40 +** mAlignment What boundry will the end of an allocation line up on. 1.41 +** mAverages Whether or not to display averages. 1.42 +** mDeviances Whether or not to display standard deviations. 1.43 +** mRunLength Whether or not to display run length. 1.44 +*/ 1.45 +{ 1.46 + const char* mProgramName; 1.47 + char* mInputName; 1.48 + FILE* mOutput; 1.49 + char* mOutputName; 1.50 + int mHelp; 1.51 + unsigned mOverhead; 1.52 + unsigned mAlignment; 1.53 + int mAverages; 1.54 + int mDeviances; 1.55 + int mRunLength; 1.56 +} 1.57 +Options; 1.58 + 1.59 + 1.60 +typedef struct __struct_Switch 1.61 +/* 1.62 +** Command line options. 1.63 +*/ 1.64 +{ 1.65 + const char* mLongName; 1.66 + const char* mShortName; 1.67 + int mHasValue; 1.68 + const char* mValue; 1.69 + const char* mDescription; 1.70 +} 1.71 +Switch; 1.72 + 1.73 +#define DESC_NEWLINE "\n\t\t" 1.74 + 1.75 +static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."}; 1.76 +static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."}; 1.77 +static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."}; 1.78 +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."}; 1.79 +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."}; 1.80 +static Switch gAveragesSwitch = {"--averages", "-avg", 0, NULL, "Display averages."}; 1.81 +static Switch gDeviationsSwitch = {"--deviations", "-dev", 0, NULL, "Display standard deviations from the average." DESC_NEWLINE "Implies --averages."}; 1.82 +static Switch gRunLengthSwitch = {"--run-length", "-rl", 0, NULL, "Display the run length in seconds."}; 1.83 + 1.84 +static Switch* gSwitches[] = { 1.85 + &gInputSwitch, 1.86 + &gOutputSwitch, 1.87 + &gAlignmentSwitch, 1.88 + &gOverheadSwitch, 1.89 + &gAveragesSwitch, 1.90 + &gDeviationsSwitch, 1.91 + &gRunLengthSwitch, 1.92 + &gHelpSwitch 1.93 +}; 1.94 + 1.95 + 1.96 +typedef struct _struct_VarianceState 1.97 +/* 1.98 +** State for a single pass variance calculation. 1.99 +*/ 1.100 +{ 1.101 + unsigned mCount; 1.102 + uint64_t mSum; 1.103 + uint64_t mSquaredSum; 1.104 +} 1.105 +VarianceState; 1.106 + 1.107 + 1.108 +typedef struct __struct_TMStats 1.109 +/* 1.110 +** Stats we are trying to calculate. 1.111 +** 1.112 +** mOptions Obilgatory options pointer. 1.113 +** uMemoryInUse Current tally of memory in use. 1.114 +** uPeakMemory Heap topped out at this byte level. 1.115 +** uObjectsInUse Different allocations outstanding. 1.116 +** uPeakObjects Highest object count. 1.117 +** uMallocs Number of malloc calls. 1.118 +** uCallocs Number of calloc calls. 1.119 +** uReallocs Number of realloc calls. 1.120 +** uFrees Number of free calls. 1.121 +** uMallocSize Bytes from malloc. 1.122 +** uCallocSize Bytes from calloc. 1.123 +** uReallocSize Bytes from realloc. 1.124 +** uFreeSize Bytes from free. 1.125 +** mMallocSizeVar Variance of bytes. 1.126 +** mCallocSizeVar Variance of bytes. 1.127 +** mReallocSizeVar Variance of bytes. 1.128 +** mFreeSizeVar Variance of bytes. 1.129 +** uMallocCost Time of mallocs. 1.130 +** uCallocCost Time of callocs. 1.131 +** uReallocCost Time of reallocs. 1.132 +** uFreeCost Time of frees. 1.133 +** mMallocCostVar Variance of cost. 1.134 +** mCallocCostVar Variance of cost. 1.135 +** mReallocCostVar Variance of cost. 1.136 +** mFreeCostVar Variance of cost. 1.137 +** uMinTicks Start of run. 1.138 +** uMaxTicks End of run. 1.139 +*/ 1.140 +{ 1.141 + Options* mOptions; 1.142 + unsigned uMemoryInUse; 1.143 + unsigned uPeakMemory; 1.144 + unsigned uObjectsInUse; 1.145 + unsigned uPeakObjects; 1.146 + unsigned uMallocs; 1.147 + unsigned uCallocs; 1.148 + unsigned uReallocs; 1.149 + unsigned uFrees; 1.150 + 1.151 + unsigned uMallocSize; 1.152 + unsigned uCallocSize; 1.153 + unsigned uReallocSize; 1.154 + unsigned uFreeSize; 1.155 + VarianceState mMallocSizeVar; 1.156 + VarianceState mCallocSizeVar; 1.157 + VarianceState mReallocSizeVar; 1.158 + VarianceState mFreeSizeVar; 1.159 + 1.160 + unsigned uMallocCost; 1.161 + unsigned uCallocCost; 1.162 + unsigned uReallocCost; 1.163 + unsigned uFreeCost; 1.164 + VarianceState mMallocCostVar; 1.165 + VarianceState mCallocCostVar; 1.166 + VarianceState mReallocCostVar; 1.167 + VarianceState mFreeCostVar; 1.168 + 1.169 + unsigned uMinTicks; 1.170 + unsigned uMaxTicks; 1.171 +} 1.172 +TMStats; 1.173 + 1.174 + 1.175 +int initOptions(Options* outOptions, int inArgc, char** inArgv) 1.176 +/* 1.177 +** returns int 0 if successful. 1.178 +*/ 1.179 +{ 1.180 + int retval = 0; 1.181 + int loop = 0; 1.182 + int switchLoop = 0; 1.183 + int match = 0; 1.184 + const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); 1.185 + Switch* current = NULL; 1.186 + 1.187 + /* 1.188 + ** Set any defaults. 1.189 + */ 1.190 + memset(outOptions, 0, sizeof(Options)); 1.191 + outOptions->mProgramName = inArgv[0]; 1.192 + outOptions->mInputName = strdup("-"); 1.193 + outOptions->mOutput = stdout; 1.194 + outOptions->mOutputName = strdup("stdout"); 1.195 + outOptions->mAlignment = 16; 1.196 + outOptions->mOverhead = 8; 1.197 + 1.198 + if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName) 1.199 + { 1.200 + retval = __LINE__; 1.201 + ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup."); 1.202 + } 1.203 + 1.204 + /* 1.205 + ** Go through and attempt to do the right thing. 1.206 + */ 1.207 + for(loop = 1; loop < inArgc && 0 == retval; loop++) 1.208 + { 1.209 + match = 0; 1.210 + current = NULL; 1.211 + 1.212 + for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++) 1.213 + { 1.214 + if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop])) 1.215 + { 1.216 + match = __LINE__; 1.217 + } 1.218 + else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop])) 1.219 + { 1.220 + match = __LINE__; 1.221 + } 1.222 + 1.223 + if(match) 1.224 + { 1.225 + if(gSwitches[switchLoop]->mHasValue) 1.226 + { 1.227 + /* 1.228 + ** Attempt to absorb next option to fullfill value. 1.229 + */ 1.230 + if(loop + 1 < inArgc) 1.231 + { 1.232 + loop++; 1.233 + 1.234 + current = gSwitches[switchLoop]; 1.235 + current->mValue = inArgv[loop]; 1.236 + } 1.237 + } 1.238 + else 1.239 + { 1.240 + current = gSwitches[switchLoop]; 1.241 + } 1.242 + 1.243 + break; 1.244 + } 1.245 + } 1.246 + 1.247 + if(0 == match) 1.248 + { 1.249 + outOptions->mHelp = __LINE__; 1.250 + retval = __LINE__; 1.251 + ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch."); 1.252 + } 1.253 + else if(NULL == current) 1.254 + { 1.255 + outOptions->mHelp = __LINE__; 1.256 + retval = __LINE__; 1.257 + ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value."); 1.258 + } 1.259 + else 1.260 + { 1.261 + /* 1.262 + ** Do something based on address/swtich. 1.263 + */ 1.264 + if(current == &gInputSwitch) 1.265 + { 1.266 + CLEANUP(outOptions->mInputName); 1.267 + outOptions->mInputName = strdup(current->mValue); 1.268 + if(NULL == outOptions->mInputName) 1.269 + { 1.270 + retval = __LINE__; 1.271 + ERROR_REPORT(retval, current->mValue, "Unable to strdup."); 1.272 + } 1.273 + } 1.274 + else if(current == &gOutputSwitch) 1.275 + { 1.276 + CLEANUP(outOptions->mOutputName); 1.277 + if(NULL != outOptions->mOutput && stdout != outOptions->mOutput) 1.278 + { 1.279 + fclose(outOptions->mOutput); 1.280 + outOptions->mOutput = NULL; 1.281 + } 1.282 + 1.283 + outOptions->mOutput = fopen(current->mValue, "a"); 1.284 + if(NULL == outOptions->mOutput) 1.285 + { 1.286 + retval = __LINE__; 1.287 + ERROR_REPORT(retval, current->mValue, "Unable to open output file."); 1.288 + } 1.289 + else 1.290 + { 1.291 + outOptions->mOutputName = strdup(current->mValue); 1.292 + if(NULL == outOptions->mOutputName) 1.293 + { 1.294 + retval = __LINE__; 1.295 + ERROR_REPORT(retval, current->mValue, "Unable to strdup."); 1.296 + } 1.297 + } 1.298 + } 1.299 + else if(current == &gHelpSwitch) 1.300 + { 1.301 + outOptions->mHelp = __LINE__; 1.302 + } 1.303 + else if(current == &gAlignmentSwitch) 1.304 + { 1.305 + unsigned arg = 0; 1.306 + char* endScan = NULL; 1.307 + 1.308 + errno = 0; 1.309 + arg = strtoul(current->mValue, &endScan, 0); 1.310 + if(0 == errno && endScan != current->mValue) 1.311 + { 1.312 + outOptions->mAlignment = arg; 1.313 + } 1.314 + else 1.315 + { 1.316 + retval = __LINE__; 1.317 + ERROR_REPORT(retval, current->mValue, "Unable to convert to a number."); 1.318 + } 1.319 + } 1.320 + else if(current == &gOverheadSwitch) 1.321 + { 1.322 + unsigned arg = 0; 1.323 + char* endScan = NULL; 1.324 + 1.325 + errno = 0; 1.326 + arg = strtoul(current->mValue, &endScan, 0); 1.327 + if(0 == errno && endScan != current->mValue) 1.328 + { 1.329 + outOptions->mOverhead = arg; 1.330 + } 1.331 + else 1.332 + { 1.333 + retval = __LINE__; 1.334 + ERROR_REPORT(retval, current->mValue, "Unable to convert to a number."); 1.335 + } 1.336 + } 1.337 + else if(current == &gAveragesSwitch) 1.338 + { 1.339 + outOptions->mAverages = __LINE__; 1.340 + } 1.341 + else if(current == &gDeviationsSwitch) 1.342 + { 1.343 + outOptions->mAverages = __LINE__; 1.344 + outOptions->mDeviances = __LINE__; 1.345 + } 1.346 + else if(current == &gRunLengthSwitch) 1.347 + { 1.348 + outOptions->mRunLength = __LINE__; 1.349 + } 1.350 + else 1.351 + { 1.352 + retval = __LINE__; 1.353 + ERROR_REPORT(retval, current->mLongName, "No handler for command line switch."); 1.354 + } 1.355 + } 1.356 + } 1.357 + 1.358 + return retval; 1.359 +} 1.360 + 1.361 + 1.362 +void cleanOptions(Options* inOptions) 1.363 +/* 1.364 +** Clean up any open handles. 1.365 +*/ 1.366 +{ 1.367 + unsigned loop = 0; 1.368 + 1.369 + CLEANUP(inOptions->mInputName); 1.370 + CLEANUP(inOptions->mOutputName); 1.371 + if(NULL != inOptions->mOutput && stdout != inOptions->mOutput) 1.372 + { 1.373 + fclose(inOptions->mOutput); 1.374 + } 1.375 + 1.376 + memset(inOptions, 0, sizeof(Options)); 1.377 +} 1.378 + 1.379 + 1.380 +void showHelp(Options* inOptions) 1.381 +/* 1.382 +** Show some simple help text on usage. 1.383 +*/ 1.384 +{ 1.385 + int loop = 0; 1.386 + const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]); 1.387 + const char* valueText = NULL; 1.388 + 1.389 + printf("usage:\t%s [arguments]\n", inOptions->mProgramName); 1.390 + printf("\n"); 1.391 + printf("arguments:\n"); 1.392 + 1.393 + for(loop = 0; loop < switchCount; loop++) 1.394 + { 1.395 + if(gSwitches[loop]->mHasValue) 1.396 + { 1.397 + valueText = " <value>"; 1.398 + } 1.399 + else 1.400 + { 1.401 + valueText = ""; 1.402 + } 1.403 + 1.404 + printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText); 1.405 + printf("\t %s%s", gSwitches[loop]->mShortName, valueText); 1.406 + printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription); 1.407 + } 1.408 + 1.409 + printf("This tool reports simple heap usage and allocation call counts.\n"); 1.410 + printf("Useful for eyeballing trace-malloc numbers quickly.\n"); 1.411 +} 1.412 + 1.413 + 1.414 +void addVariance(VarianceState* inVariance, unsigned inValue) 1.415 +/* 1.416 +** Add a value to a variance state. 1.417 +*/ 1.418 +{ 1.419 + uint64_t squared; 1.420 + uint64_t bigValue; 1.421 + 1.422 + bigValue = inValue; 1.423 + inVariance->mSum += bigValue; 1.424 + 1.425 + squared = bigValue * bigValue; 1.426 + inVariance->mSquaredSum += squared; 1.427 + 1.428 + inVariance->mCount++; 1.429 +} 1.430 + 1.431 + 1.432 +double getAverage(VarianceState* inVariance) 1.433 +/* 1.434 +** Determine the mean/average based on the given state. 1.435 +*/ 1.436 +{ 1.437 + double retval = 0.0; 1.438 + 1.439 + if(NULL != inVariance && 0 < inVariance->mCount) 1.440 + { 1.441 + double count; 1.442 + int64_t isum; 1.443 + 1.444 + /* 1.445 + ** Avoids a compiler error (not impl) under MSVC. 1.446 + */ 1.447 + isum = inVariance->mSum; 1.448 + 1.449 + count = (double)inVariance->mCount; 1.450 + 1.451 + retval = (double)isum / count; 1.452 + } 1.453 + 1.454 + return retval; 1.455 +} 1.456 + 1.457 + 1.458 +double getVariance(VarianceState* inVariance) 1.459 +/* 1.460 +** Determine the variance based on the given state. 1.461 +*/ 1.462 +{ 1.463 + double retval = 0.0; 1.464 + 1.465 + if(NULL != inVariance && 1 < inVariance->mCount) 1.466 + { 1.467 + double count; 1.468 + double avg; 1.469 + double squaredAvg; 1.470 + int64_t isquaredSum; 1.471 + 1.472 + /* 1.473 + ** Avoids a compiler error (not impl) under MSVC. 1.474 + */ 1.475 + isquaredSum = inVariance->mSquaredSum; 1.476 + 1.477 + count = (double)inVariance->mCount; 1.478 + 1.479 + avg = getAverage(inVariance); 1.480 + squaredAvg = avg * avg; 1.481 + 1.482 + retval = ((double)isquaredSum - (count * squaredAvg)) / (count - 1.0); 1.483 + } 1.484 + 1.485 + return retval; 1.486 +} 1.487 + 1.488 + 1.489 +double getStdDev(VarianceState* inVariance) 1.490 +/* 1.491 +** Determine the standard deviation based on the given state. 1.492 +*/ 1.493 +{ 1.494 + double retval = 0.0; 1.495 + double variance; 1.496 + 1.497 + variance = getVariance(inVariance); 1.498 + retval = sqrt(variance); 1.499 + 1.500 + return retval; 1.501 +} 1.502 + 1.503 + 1.504 +unsigned actualByteSize(Options* inOptions, unsigned retval) 1.505 +/* 1.506 +** Apply alignment and overhead to size to figure out actual byte size. 1.507 +** This by default mimics spacetrace with default options (msvc crt heap). 1.508 +*/ 1.509 +{ 1.510 + if(0 != retval) 1.511 + { 1.512 + unsigned eval = 0; 1.513 + unsigned over = 0; 1.514 + 1.515 + eval = retval - 1; 1.516 + if(0 != inOptions->mAlignment) 1.517 + { 1.518 + over = eval % inOptions->mAlignment; 1.519 + } 1.520 + retval = eval + inOptions->mOverhead + inOptions->mAlignment - over; 1.521 + } 1.522 + 1.523 + return retval; 1.524 +} 1.525 + 1.526 + 1.527 +uint32_t ticks2xsec(tmreader* aReader, uint32_t aTicks, uint32_t aResolution) 1.528 +/* 1.529 +** Convert platform specific ticks to second units 1.530 +** Returns 0 on success. 1.531 +*/ 1.532 +{ 1.533 + return (uint32_t)((aResolution * aTicks) / aReader->ticksPerSec); 1.534 +} 1.535 +#define ticks2msec(reader, ticks) ticks2xsec((reader), (ticks), 1000) 1.536 + 1.537 + 1.538 +void tmEventHandler(tmreader* inReader, tmevent* inEvent) 1.539 +/* 1.540 +** Callback from the tmreader_eventloop. 1.541 +** Keep it simple in here, this is where we'll spend the most time. 1.542 +** The goal is to be fast. 1.543 +*/ 1.544 +{ 1.545 + TMStats* stats = (TMStats*)inReader->data; 1.546 + Options* options = (Options*)stats->mOptions; 1.547 + char type = inEvent->type; 1.548 + unsigned size = inEvent->u.alloc.size; 1.549 + unsigned actualSize = 0; 1.550 + unsigned actualOldSize = 0; 1.551 + uint32_t interval = 0; 1.552 + 1.553 + /* 1.554 + ** To match spacetrace stats, reallocs of size zero are frees. 1.555 + ** Adjust the size to match what free expects. 1.556 + */ 1.557 + if(TM_EVENT_REALLOC == type && 0 == size) 1.558 + { 1.559 + type = TM_EVENT_FREE; 1.560 + if(0 != inEvent->u.alloc.oldserial) 1.561 + { 1.562 + size = inEvent->u.alloc.oldsize; 1.563 + } 1.564 + } 1.565 + 1.566 + /* 1.567 + ** Adjust the size due to the options. 1.568 + */ 1.569 + actualSize = actualByteSize(options, size); 1.570 + if(TM_EVENT_REALLOC == type && 0 != inEvent->u.alloc.oldserial) 1.571 + { 1.572 + actualOldSize = actualByteSize(options, inEvent->u.alloc.oldsize); 1.573 + } 1.574 + 1.575 + /* 1.576 + ** Modify event specific data. 1.577 + */ 1.578 + switch(type) 1.579 + { 1.580 + case TM_EVENT_MALLOC: 1.581 + stats->uMallocs++; 1.582 + stats->uMallocSize += actualSize; 1.583 + stats->uMallocCost += ticks2msec(inReader, inEvent->u.alloc.cost); 1.584 + stats->uMemoryInUse += actualSize; 1.585 + stats->uObjectsInUse++; 1.586 + 1.587 + addVariance(&stats->mMallocSizeVar, actualSize); 1.588 + addVariance(&stats->mMallocCostVar, inEvent->u.alloc.cost); 1.589 + break; 1.590 + 1.591 + case TM_EVENT_CALLOC: 1.592 + stats->uCallocs++; 1.593 + stats->uCallocSize += actualSize; 1.594 + stats->uCallocCost += ticks2msec(inReader, inEvent->u.alloc.cost); 1.595 + stats->uMemoryInUse += actualSize; 1.596 + stats->uObjectsInUse++; 1.597 + 1.598 + addVariance(&stats->mCallocSizeVar, actualSize); 1.599 + addVariance(&stats->mCallocCostVar, inEvent->u.alloc.cost); 1.600 + break; 1.601 + 1.602 + case TM_EVENT_REALLOC: 1.603 + stats->uReallocs++; 1.604 + stats->uReallocSize -= actualOldSize; 1.605 + stats->uReallocSize += actualSize; 1.606 + stats->uReallocCost += ticks2msec(inReader, inEvent->u.alloc.cost); 1.607 + stats->uMemoryInUse -= actualOldSize; 1.608 + stats->uMemoryInUse += actualSize; 1.609 + if(0 == inEvent->u.alloc.oldserial) 1.610 + { 1.611 + stats->uObjectsInUse++; 1.612 + } 1.613 + 1.614 + if(actualSize > actualOldSize) 1.615 + { 1.616 + addVariance(&stats->mReallocSizeVar, actualSize - actualOldSize); 1.617 + } 1.618 + else 1.619 + { 1.620 + addVariance(&stats->mReallocSizeVar, actualOldSize - actualSize); 1.621 + } 1.622 + addVariance(&stats->mReallocCostVar, inEvent->u.alloc.cost); 1.623 + break; 1.624 + 1.625 + case TM_EVENT_FREE: 1.626 + stats->uFrees++; 1.627 + stats->uFreeSize += actualSize; 1.628 + stats->uFreeCost += ticks2msec(inReader, inEvent->u.alloc.cost); 1.629 + stats->uMemoryInUse -= actualSize; 1.630 + stats->uObjectsInUse--; 1.631 + 1.632 + addVariance(&stats->mFreeSizeVar, actualSize); 1.633 + addVariance(&stats->mFreeCostVar, inEvent->u.alloc.cost); 1.634 + break; 1.635 + 1.636 + default: 1.637 + /* 1.638 + ** Don't care. 1.639 + */ 1.640 + break; 1.641 + } 1.642 + 1.643 + switch(type) 1.644 + { 1.645 + case TM_EVENT_MALLOC: 1.646 + case TM_EVENT_CALLOC: 1.647 + case TM_EVENT_REALLOC: 1.648 + /* 1.649 + ** Check the peaks. 1.650 + */ 1.651 + if(stats->uMemoryInUse > stats->uPeakMemory) 1.652 + { 1.653 + stats->uPeakMemory = stats->uMemoryInUse; 1.654 + } 1.655 + if(stats->uObjectsInUse > stats->uPeakObjects) 1.656 + { 1.657 + stats->uPeakObjects = stats->uObjectsInUse; 1.658 + } 1.659 + 1.660 + /* 1.661 + ** Falling through. 1.662 + */ 1.663 + 1.664 + case TM_EVENT_FREE: 1.665 + /* 1.666 + ** Check the overall time. 1.667 + */ 1.668 + interval = ticks2msec(inReader, inEvent->u.alloc.interval); 1.669 + if(stats->uMinTicks > interval) 1.670 + { 1.671 + stats->uMinTicks = interval; 1.672 + } 1.673 + if(stats->uMaxTicks < interval) 1.674 + { 1.675 + stats->uMaxTicks = interval; 1.676 + } 1.677 + break; 1.678 + 1.679 + default: 1.680 + /* 1.681 + ** Don't care. 1.682 + */ 1.683 + break; 1.684 + } 1.685 + 1.686 +} 1.687 + 1.688 +int report_stats(Options* inOptions, TMStats* inStats) 1.689 +{ 1.690 + int retval = 0; 1.691 + 1.692 + fprintf(inOptions->mOutput, "Peak Memory Usage: %11d\n", inStats->uPeakMemory); 1.693 + fprintf(inOptions->mOutput, "Memory Leaked: %11d\n", inStats->uMemoryInUse); 1.694 + fprintf(inOptions->mOutput, "\n"); 1.695 + 1.696 + fprintf(inOptions->mOutput, "Peak Object Count: %11d\n", inStats->uPeakObjects); 1.697 + fprintf(inOptions->mOutput, "Objects Leaked: %11d\n", inStats->uObjectsInUse); 1.698 + if(0 != inOptions->mAverages && 0 != inStats->uObjectsInUse) 1.699 + { 1.700 + fprintf(inOptions->mOutput, "Average Leaked Object Size: %11.4f\n", (double)inStats->uMemoryInUse / (double)inStats->uObjectsInUse); 1.701 + } 1.702 + fprintf(inOptions->mOutput, "\n"); 1.703 + 1.704 + fprintf(inOptions->mOutput, "Call Total: %11d\n", inStats->uMallocs + inStats->uCallocs + inStats->uReallocs + inStats->uFrees); 1.705 + fprintf(inOptions->mOutput, " malloc: %11d\n", inStats->uMallocs); 1.706 + fprintf(inOptions->mOutput, " calloc: %11d\n", inStats->uCallocs); 1.707 + fprintf(inOptions->mOutput, " realloc: %11d\n", inStats->uReallocs); 1.708 + fprintf(inOptions->mOutput, " free: %11d\n", inStats->uFrees); 1.709 + fprintf(inOptions->mOutput, "\n"); 1.710 + 1.711 + fprintf(inOptions->mOutput, "Byte Total (sans free): %11d\n", inStats->uMallocSize + inStats->uCallocSize + inStats->uReallocSize); 1.712 + fprintf(inOptions->mOutput, " malloc: %11d\n", inStats->uMallocSize); 1.713 + fprintf(inOptions->mOutput, " calloc: %11d\n", inStats->uCallocSize); 1.714 + fprintf(inOptions->mOutput, " realloc: %11d\n", inStats->uReallocSize); 1.715 + fprintf(inOptions->mOutput, " free: %11d\n", inStats->uFreeSize); 1.716 + if(0 != inOptions->mAverages) 1.717 + { 1.718 + fprintf(inOptions->mOutput, "Byte Averages:\n"); 1.719 + fprintf(inOptions->mOutput, " malloc: %11.4f\n", getAverage(&inStats->mMallocSizeVar)); 1.720 + fprintf(inOptions->mOutput, " calloc: %11.4f\n", getAverage(&inStats->mCallocSizeVar)); 1.721 + fprintf(inOptions->mOutput, " realloc: %11.4f\n", getAverage(&inStats->mReallocSizeVar)); 1.722 + fprintf(inOptions->mOutput, " free: %11.4f\n", getAverage(&inStats->mFreeSizeVar)); 1.723 + } 1.724 + if(0 != inOptions->mDeviances) 1.725 + { 1.726 + fprintf(inOptions->mOutput, "Byte Standard Deviations:\n"); 1.727 + fprintf(inOptions->mOutput, " malloc: %11.4f\n", getStdDev(&inStats->mMallocSizeVar)); 1.728 + fprintf(inOptions->mOutput, " calloc: %11.4f\n", getStdDev(&inStats->mCallocSizeVar)); 1.729 + fprintf(inOptions->mOutput, " realloc: %11.4f\n", getStdDev(&inStats->mReallocSizeVar)); 1.730 + fprintf(inOptions->mOutput, " free: %11.4f\n", getStdDev(&inStats->mFreeSizeVar)); 1.731 + } 1.732 + fprintf(inOptions->mOutput, "\n"); 1.733 + 1.734 + fprintf(inOptions->mOutput, "Overhead Total: %11.4f\n", COST_PRINTABLE(inStats->uMallocCost) + COST_PRINTABLE(inStats->uCallocCost) + COST_PRINTABLE(inStats->uReallocCost) + COST_PRINTABLE(inStats->uFreeCost)); 1.735 + fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(inStats->uMallocCost)); 1.736 + fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(inStats->uCallocCost)); 1.737 + fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(inStats->uReallocCost)); 1.738 + fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(inStats->uFreeCost)); 1.739 + if(0 != inOptions->mAverages) 1.740 + { 1.741 + fprintf(inOptions->mOutput, "Overhead Averages:\n"); 1.742 + fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mMallocCostVar))); 1.743 + fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mCallocCostVar))); 1.744 + fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mReallocCostVar))); 1.745 + fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(getAverage(&inStats->mFreeCostVar))); 1.746 + } 1.747 + if(0 != inOptions->mDeviances) 1.748 + { 1.749 + fprintf(inOptions->mOutput, "Overhead Standard Deviations:\n"); 1.750 + fprintf(inOptions->mOutput, " malloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mMallocCostVar))); 1.751 + fprintf(inOptions->mOutput, " calloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mCallocCostVar))); 1.752 + fprintf(inOptions->mOutput, " realloc: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mReallocCostVar))); 1.753 + fprintf(inOptions->mOutput, " free: %11.4f\n", COST_PRINTABLE(getStdDev(&inStats->mFreeCostVar))); 1.754 + } 1.755 + fprintf(inOptions->mOutput, "\n"); 1.756 + 1.757 + if(0 != inOptions->mRunLength) 1.758 + { 1.759 + unsigned length = inStats->uMaxTicks - inStats->uMinTicks; 1.760 + 1.761 + fprintf(inOptions->mOutput, "Run Length: %11.4f\n", COST_PRINTABLE(length)); 1.762 + fprintf(inOptions->mOutput, "\n"); 1.763 + } 1.764 + 1.765 + return retval; 1.766 +} 1.767 + 1.768 + 1.769 +int tmstats(Options* inOptions) 1.770 +/* 1.771 +** As quick as possible, load the input file and report stats. 1.772 +*/ 1.773 +{ 1.774 + int retval = 0; 1.775 + tmreader* tmr = NULL; 1.776 + TMStats stats; 1.777 + 1.778 + memset(&stats, 0, sizeof(stats)); 1.779 + stats.mOptions = inOptions; 1.780 + stats.uMinTicks = 0xFFFFFFFFU; 1.781 + 1.782 + /* 1.783 + ** Need a tmreader. 1.784 + */ 1.785 + tmr = tmreader_new(inOptions->mProgramName, &stats); 1.786 + if(NULL != tmr) 1.787 + { 1.788 + int tmResult = 0; 1.789 + 1.790 + tmResult = tmreader_eventloop(tmr, inOptions->mInputName, tmEventHandler); 1.791 + if(0 == tmResult) 1.792 + { 1.793 + retval = __LINE__; 1.794 + ERROR_REPORT(retval, inOptions->mInputName, "Problem reading trace-malloc data."); 1.795 + } 1.796 + 1.797 + tmreader_destroy(tmr); 1.798 + tmr = NULL; 1.799 + 1.800 + if(0 == retval) 1.801 + { 1.802 + retval = report_stats(inOptions, &stats); 1.803 + } 1.804 + } 1.805 + else 1.806 + { 1.807 + retval = __LINE__; 1.808 + ERROR_REPORT(retval, inOptions->mProgramName, "Unable to obtain tmreader."); 1.809 + } 1.810 + 1.811 + return retval; 1.812 +} 1.813 + 1.814 + 1.815 +int main(int inArgc, char** inArgv) 1.816 +{ 1.817 + int retval = 0; 1.818 + Options options; 1.819 + 1.820 + retval = initOptions(&options, inArgc, inArgv); 1.821 + if(options.mHelp) 1.822 + { 1.823 + showHelp(&options); 1.824 + } 1.825 + else if(0 == retval) 1.826 + { 1.827 + retval = tmstats(&options); 1.828 + } 1.829 + 1.830 + cleanOptions(&options); 1.831 + return retval; 1.832 +} 1.833 +