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.

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

mercurial