Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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"
19 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
20 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
23 #define ticks2msec(reader, ticks) ticks2xsec((reader), (ticks), 1000)
24 #define ticks2usec(reader, ticks) ticks2xsec((reader), (ticks), 1000000)
25 #define TICK_RESOLUTION 1000
26 #define TICK_PRINTABLE(timeval) ((double)(timeval) / (double)ST_TIMEVAL_RESOLUTION)
29 typedef struct __struct_Options
30 /*
31 ** Options to control how we perform.
32 **
33 ** mProgramName Used in help text.
34 ** mInputName Name of the file.
35 ** mOutput Output file, append.
36 ** Default is stdout.
37 ** mOutputName Name of the file.
38 ** mHelp Whether or not help should be shown.
39 ** mOverhead How much overhead an allocation will have.
40 ** mAlignment What boundry will the end of an allocation line up on.
41 ** mPageSize Controls the page size. A page containing only fragments
42 ** is not fragmented. A page containing any life memory
43 ** costs mPageSize in bytes.
44 */
45 {
46 const char* mProgramName;
47 char* mInputName;
48 FILE* mOutput;
49 char* mOutputName;
50 int mHelp;
51 unsigned mOverhead;
52 unsigned mAlignment;
53 unsigned mPageSize;
54 }
55 Options;
58 typedef struct __struct_Switch
59 /*
60 ** Command line options.
61 */
62 {
63 const char* mLongName;
64 const char* mShortName;
65 int mHasValue;
66 const char* mValue;
67 const char* mDescription;
68 }
69 Switch;
71 #define DESC_NEWLINE "\n\t\t"
73 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
74 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
75 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
76 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."};
77 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."};
78 static Switch gPageSizeSwitch = {"--page-size", "-ps", 1, NULL, "Sets the page size which aids the identification of fragmentation." DESC_NEWLINE "Closer to actual heap conditions; set to 4294967295 for true sizes." DESC_NEWLINE "Default value is 4096."};
80 static Switch* gSwitches[] = {
81 &gInputSwitch,
82 &gOutputSwitch,
83 &gAlignmentSwitch,
84 &gOverheadSwitch,
85 &gPageSizeSwitch,
86 &gHelpSwitch
87 };
90 typedef struct __struct_AnyArray
91 /*
92 ** Variable sized item array.
93 **
94 ** mItems The void pointer items.
95 ** mItemSize Size of each different item.
96 ** mCount The number of items in the array.
97 ** mCapacity How many more items we can hold before reallocing.
98 ** mGrowBy How many items we allocate when we grow.
99 */
100 {
101 void* mItems;
102 unsigned mItemSize;
103 unsigned mCount;
104 unsigned mCapacity;
105 unsigned mGrowBy;
106 }
107 AnyArray;
110 typedef int (*arrayMatchFunc)(void* inContext, AnyArray* inArray, void* inItem, unsigned inItemIndex)
111 /*
112 ** Callback function for the arrayIndexFn function.
113 ** Used to determine an item match by customizable criteria.
114 **
115 ** inContext The criteria and state of the search.
116 ** User specified/created.
117 ** inArray The array the item is in.
118 ** inItem The item to evaluate for match.
119 ** inItemIndex The index of this particular item in the array.
120 **
121 ** return int 0 to specify a match.
122 ** !0 to continue the search performed by arrayIndexFn.
123 */
124 ;
127 typedef enum __enum_HeapEventType
128 /*
129 ** Simple heap events are really one of two things.
130 */
131 {
132 FREE,
133 ALLOC
134 }
135 HeapEventType;
138 typedef enum __enum_HeapObjectType
139 /*
140 ** The various types of heap objects we track.
141 */
142 {
143 ALLOCATION,
144 FRAGMENT
145 }
146 HeapObjectType;
149 typedef struct __struct_HeapObject HeapObject;
150 typedef struct __struct_HeapHistory
151 /*
152 ** A marker as to what has happened.
153 **
154 ** mTimestamp When history occurred.
155 ** mTMRSerial The historical state as known to the tmreader.
156 ** mObjectIndex Index to the object that was before or after this event.
157 ** The index as in the index according to all heap objects
158 ** kept in the TMState structure.
159 ** We use an index instead of a pointer as the array of
160 ** objects can change location in the heap.
161 */
162 {
163 unsigned mTimestamp;
164 unsigned mTMRSerial;
165 unsigned mObjectIndex;
166 }
167 HeapHistory;
170 struct __struct_HeapObject
171 /*
172 ** An object in the heap.
173 **
174 ** A special case should be noted here. If either the birth or death
175 ** history leads to an object of the same type, then this object
176 ** is the same as that object, but was modified somehow.
177 ** Also note that multiple objects may have the same birth object,
178 ** as well as the same death object.
179 **
180 ** mUniqueID Each object is unique.
181 ** mType Either allocation or fragment.
182 ** mHeapOffset Where in the heap the object is.
183 ** mSize How much of the heap the object takes.
184 ** mBirth History about the birth event.
185 ** mDeath History about the death event.
186 */
187 {
188 unsigned mUniqueID;
190 HeapObjectType mType;
191 unsigned mHeapOffset;
192 unsigned mSize;
194 HeapHistory mBirth;
195 HeapHistory mDeath;
196 };
199 typedef struct __struct_TMState
200 /*
201 ** State of our current operation.
202 ** Stats we are trying to calculate.
203 **
204 ** mOptions Obilgatory options pointer.
205 ** mTMR The tmreader, used in tmreader API calls.
206 ** mLoopExitTMR Set to non zero in order to quickly exit from tmreader
207 ** input loop. This will also result in an error.
208 ** uMinTicks Start of run, milliseconds.
209 ** uMaxTicks End of run, milliseconds.
210 */
211 {
212 Options* mOptions;
213 tmreader* mTMR;
215 int mLoopExitTMR;
217 unsigned uMinTicks;
218 unsigned uMaxTicks;
219 }
220 TMState;
223 int initOptions(Options* outOptions, int inArgc, char** inArgv)
224 /*
225 ** returns int 0 if successful.
226 */
227 {
228 int retval = 0;
229 int loop = 0;
230 int switchLoop = 0;
231 int match = 0;
232 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
233 Switch* current = NULL;
235 /*
236 ** Set any defaults.
237 */
238 memset(outOptions, 0, sizeof(Options));
239 outOptions->mProgramName = inArgv[0];
240 outOptions->mInputName = strdup("-");
241 outOptions->mOutput = stdout;
242 outOptions->mOutputName = strdup("stdout");
243 outOptions->mAlignment = 16;
244 outOptions->mOverhead = 8;
246 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
247 {
248 retval = __LINE__;
249 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
250 }
252 /*
253 ** Go through and attempt to do the right thing.
254 */
255 for(loop = 1; loop < inArgc && 0 == retval; loop++)
256 {
257 match = 0;
258 current = NULL;
260 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
261 {
262 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
263 {
264 match = __LINE__;
265 }
266 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
267 {
268 match = __LINE__;
269 }
271 if(match)
272 {
273 if(gSwitches[switchLoop]->mHasValue)
274 {
275 /*
276 ** Attempt to absorb next option to fullfill value.
277 */
278 if(loop + 1 < inArgc)
279 {
280 loop++;
282 current = gSwitches[switchLoop];
283 current->mValue = inArgv[loop];
284 }
285 }
286 else
287 {
288 current = gSwitches[switchLoop];
289 }
291 break;
292 }
293 }
295 if(0 == match)
296 {
297 outOptions->mHelp = __LINE__;
298 retval = __LINE__;
299 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
300 }
301 else if(NULL == current)
302 {
303 outOptions->mHelp = __LINE__;
304 retval = __LINE__;
305 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
306 }
307 else
308 {
309 /*
310 ** Do something based on address/swtich.
311 */
312 if(current == &gInputSwitch)
313 {
314 CLEANUP(outOptions->mInputName);
315 outOptions->mInputName = strdup(current->mValue);
316 if(NULL == outOptions->mInputName)
317 {
318 retval = __LINE__;
319 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
320 }
321 }
322 else if(current == &gOutputSwitch)
323 {
324 CLEANUP(outOptions->mOutputName);
325 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
326 {
327 fclose(outOptions->mOutput);
328 outOptions->mOutput = NULL;
329 }
331 outOptions->mOutput = fopen(current->mValue, "a");
332 if(NULL == outOptions->mOutput)
333 {
334 retval = __LINE__;
335 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
336 }
337 else
338 {
339 outOptions->mOutputName = strdup(current->mValue);
340 if(NULL == outOptions->mOutputName)
341 {
342 retval = __LINE__;
343 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
344 }
345 }
346 }
347 else if(current == &gHelpSwitch)
348 {
349 outOptions->mHelp = __LINE__;
350 }
351 else if(current == &gAlignmentSwitch)
352 {
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)
359 {
360 outOptions->mAlignment = arg;
361 }
362 else
363 {
364 retval = __LINE__;
365 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
366 }
367 }
368 else if(current == &gOverheadSwitch)
369 {
370 unsigned arg = 0;
371 char* endScan = NULL;
373 errno = 0;
374 arg = strtoul(current->mValue, &endScan, 0);
375 if(0 == errno && endScan != current->mValue)
376 {
377 outOptions->mOverhead = arg;
378 }
379 else
380 {
381 retval = __LINE__;
382 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
383 }
384 }
385 else if(current == &gPageSizeSwitch)
386 {
387 unsigned arg = 0;
388 char* endScan = NULL;
390 errno = 0;
391 arg = strtoul(current->mValue, &endScan, 0);
392 if(0 == errno && endScan != current->mValue)
393 {
394 outOptions->mPageSize = arg;
395 }
396 else
397 {
398 retval = __LINE__;
399 ERROR_REPORT(retval, current->mValue, "Unable to convert to a number.");
400 }
401 }
402 else
403 {
404 retval = __LINE__;
405 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
406 }
407 }
408 }
410 return retval;
411 }
414 uint32_t ticks2xsec(tmreader* aReader, uint32_t aTicks, uint32_t aResolution)
415 /*
416 ** Convert platform specific ticks to second units
417 */
418 {
419 return (uint32)((aResolution * aTicks) / aReader->ticksPerSec);
420 }
423 void cleanOptions(Options* inOptions)
424 /*
425 ** Clean up any open handles.
426 */
427 {
428 unsigned loop = 0;
430 CLEANUP(inOptions->mInputName);
431 CLEANUP(inOptions->mOutputName);
432 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
433 {
434 fclose(inOptions->mOutput);
435 }
437 memset(inOptions, 0, sizeof(Options));
438 }
441 void showHelp(Options* inOptions)
442 /*
443 ** Show some simple help text on usage.
444 */
445 {
446 int loop = 0;
447 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
448 const char* valueText = NULL;
450 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
451 printf("\n");
452 printf("arguments:\n");
454 for(loop = 0; loop < switchCount; loop++)
455 {
456 if(gSwitches[loop]->mHasValue)
457 {
458 valueText = " <value>";
459 }
460 else
461 {
462 valueText = "";
463 }
465 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
466 printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
467 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
468 }
470 printf("This tool reports heap fragmentation stats from a trace-malloc log.\n");
471 }
474 AnyArray* arrayCreate(unsigned inItemSize, unsigned inGrowBy)
475 /*
476 ** Create an array container object.
477 */
478 {
479 AnyArray* retval = NULL;
481 if(0 != inGrowBy && 0 != inItemSize)
482 {
483 retval = (AnyArray*)calloc(1, sizeof(AnyArray));
484 retval->mItemSize = inItemSize;
485 retval->mGrowBy = inGrowBy;
486 }
488 return retval;
489 }
492 void arrayDestroy(AnyArray* inArray)
493 /*
494 ** Release the memory the array contains.
495 ** This will release the items as well.
496 */
497 {
498 if(NULL != inArray)
499 {
500 if(NULL != inArray->mItems)
501 {
502 free(inArray->mItems);
503 }
504 free(inArray);
505 }
506 }
509 unsigned arrayAlloc(AnyArray* inArray, unsigned inItems)
510 /*
511 ** Resize the item array capcity to a specific number of items.
512 ** This could possibly truncate the array, so handle that as well.
513 **
514 ** returns unsigned <= inArray->mCapacity on success.
515 */
516 {
517 unsigned retval = (unsigned)-1;
519 if(NULL != inArray)
520 {
521 void* moved = NULL;
523 moved = realloc(inArray->mItems, inItems * inArray->mItemSize);
524 if(NULL != moved)
525 {
526 inArray->mItems = moved;
527 inArray->mCapacity = inItems;
528 if(inArray->mCount > inItems)
529 {
530 inArray->mCount = inItems;
531 }
533 retval = inItems;
534 }
535 }
537 return retval;
538 }
541 void* arrayItem(AnyArray* inArray, unsigned inIndex)
542 /*
543 ** Return the array item at said index.
544 ** Zero based index.
545 **
546 ** returns void* NULL on failure.
547 */
548 {
549 void* retval = NULL;
551 if(NULL != inArray && inIndex < inArray->mCount)
552 {
553 retval = (void*)((char*)inArray->mItems + (inArray->mItemSize * inIndex));
554 }
556 return retval;
557 }
560 unsigned arrayIndex(AnyArray* inArray, void* inItem, unsigned inStartIndex)
561 /*
562 ** Go through the array from the index specified looking for an item
563 ** match based on byte for byte comparison.
564 ** We allow specifying the start index in order to handle arrays with
565 ** duplicate items.
566 **
567 ** returns unsigned >= inArray->mCount on failure.
568 */
569 {
570 unsigned retval = (unsigned)-1;
572 if(NULL != inArray && NULL != inItem && inStartIndex < inArray->mCount)
573 {
574 void* curItem = NULL;
576 for(retval = inStartIndex; retval < inArray->mCount; retval++)
577 {
578 curItem = arrayItem(inArray, retval);
579 if(0 == memcmp(inItem, curItem, inArray->mItemSize))
580 {
581 break;
582 }
583 }
584 }
587 return retval;
588 }
591 unsigned arrayIndexFn(AnyArray* inArray, arrayMatchFunc inFunc, void* inFuncContext, unsigned inStartIndex)
592 /*
593 ** Go through the array from the index specified looking for an item
594 ** match based upon the return value of inFunc (0, Zero, is a match).
595 ** We allow specifying the start index in order to facilitate looping over
596 ** the array which could have multiple matches.
597 **
598 ** returns unsigned >= inArray->mCount on failure.
599 */
600 {
601 unsigned retval = (unsigned)-1;
603 if(NULL != inArray && NULL != inFunc && inStartIndex < inArray->mCount)
604 {
605 void* curItem = NULL;
607 for(retval = inStartIndex; retval < inArray->mCount; retval++)
608 {
609 curItem = arrayItem(inArray, retval);
610 if(0 == inFunc(inFuncContext, inArray, curItem, retval))
611 {
612 break;
613 }
614 }
615 }
617 return retval;
618 }
621 unsigned arrayAddItem(AnyArray* inArray, void* inItem)
622 /*
623 ** Add a new item to the array.
624 ** This is done by copying the item.
625 **
626 ** returns unsigned < inArray->mCount on success.
627 */
628 {
629 unsigned retval = (unsigned)-1;
631 if(NULL != inArray && NULL != inItem)
632 {
633 int noCopy = 0;
635 /*
636 ** See if the array should grow.
637 */
638 if(inArray->mCount == inArray->mCapacity)
639 {
640 unsigned allocRes = 0;
642 allocRes = arrayAlloc(inArray, inArray->mCapacity + inArray->mGrowBy);
643 if(allocRes > inArray->mCapacity)
644 {
645 noCopy = __LINE__;
646 }
647 }
649 if(0 == noCopy)
650 {
651 retval = inArray->mCount;
653 inArray->mCount++;
654 memcpy(arrayItem(inArray, retval), inItem, inArray->mItemSize);
655 }
656 }
658 return retval;
659 }
662 HeapObject* initHeapObject(HeapObject* inObject)
663 /*
664 ** Function to init the heap object just right.
665 ** Sets the unique ID to something unique.
666 */
667 {
668 HeapObject* retval = inObject;
670 if(NULL != inObject)
671 {
672 static unsigned uniqueGenerator = 0;
674 memset(inObject, -1, sizeof(HeapObject));
676 inObject->mUniqueID = uniqueGenerator;
677 uniqueGenerator++;
678 }
680 return retval;
681 }
684 int simpleHeapEvent(TMState* inStats, HeapEventType inType, unsigned mTimestamp, unsigned inSerial, unsigned inHeapID, unsigned inSize)
685 /*
686 ** A new heap event will cause the creation of a new heap object.
687 ** The new heap object will displace, or replace, a heap object of a different type.
688 */
689 {
690 int retval = 0;
691 HeapObject newObject;
693 /*
694 ** Set the most basic object details.
695 */
696 initHeapObject(&newObject);
697 newObject.mHeapOffset = inHeapID;
698 newObject.mSize = inSize;
699 if(FREE == inType)
700 {
701 newObject.mType = FRAGMENT;
702 }
703 else if(ALLOC == inType)
704 {
705 newObject.mType = ALLOCATION;
706 }
708 /*
709 ** Add it to the heap object array.
710 */
712 /*
713 ** TODO GAB
714 **
715 ** First thing to do is to add the new object to the heap in order to
716 ** obtain a valid index.
717 **
718 ** Next, find all matches to this range of heap memory that this event
719 ** refers to, that are alive during this timestamp (no death yet).
720 ** Fill in the death event of those objects.
721 ** If the objects contain some portions outside of the range, then
722 ** new objects for those ranges need to be created that carry on
723 ** the same object type, have the index of the old object for birth,
724 ** and the serial of the old object, new timestamp of course.
725 ** The old object's death points to the new object, which tells why the
726 ** fragmentation took place.
727 ** The new object birth points to the old object only if a fragment.
728 ** An allocation only has a birth object when it is a realloc (complex)
729 ** heap event.
730 **
731 ** I believe this give us enough information to look up particular
732 ** details of the heap at any given time.
733 */
735 return retval;
736 }
739 int complexHeapEvent(TMState* inStats, unsigned mTimestamp, unsigned inOldSerial, unsigned inOldHeapID, unsigned inOSize, unsigned inNewSerial, unsigned inNewHeapID, unsigned inNewSize)
740 /*
741 ** Generally, this event intends to chain one old heap object to a newer heap object.
742 ** Otherwise, the functionality should recognizable ala simpleHeapEvent.
743 */
744 {
745 int retval = 0;
747 /*
748 ** TODO GAB
749 */
751 return retval;
752 }
755 unsigned actualByteSize(Options* inOptions, unsigned retval)
756 /*
757 ** Apply alignment and overhead to size to figure out actual byte size.
758 ** This by default mimics spacetrace with default options (msvc crt heap).
759 */
760 {
761 if(0 != retval)
762 {
763 unsigned eval = 0;
764 unsigned over = 0;
766 eval = retval - 1;
767 if(0 != inOptions->mAlignment)
768 {
769 over = eval % inOptions->mAlignment;
770 }
771 retval = eval + inOptions->mOverhead + inOptions->mAlignment - over;
772 }
774 return retval;
775 }
778 void tmEventHandler(tmreader* inReader, tmevent* inEvent)
779 /*
780 ** Callback from the tmreader_eventloop.
781 ** Build up our fragmentation information herein.
782 */
783 {
784 char type = inEvent->type;
785 TMState* stats = (TMState*)inReader->data;
787 /*
788 ** Only intersted in handling events of a particular type.
789 */
790 switch(type)
791 {
792 default:
793 return;
795 case TM_EVENT_MALLOC:
796 case TM_EVENT_CALLOC:
797 case TM_EVENT_REALLOC:
798 case TM_EVENT_FREE:
799 break;
800 }
802 /*
803 ** Should we even try to look?
804 ** Set mLoopExitTMR to non-zero to abort the read loop faster.
805 */
806 if(0 == stats->mLoopExitTMR)
807 {
808 Options* options = (Options*)stats->mOptions;
809 unsigned timestamp = ticks2msec(stats->mTMR, inEvent->u.alloc.interval);
810 unsigned actualSize = actualByteSize(options, inEvent->u.alloc.size);
811 unsigned heapID = inEvent->u.alloc.ptr;
812 unsigned serial = inEvent->serial;
814 /*
815 ** Check the timestamp range of our overall state.
816 */
817 if(stats->uMinTicks > timestamp)
818 {
819 stats->uMinTicks = timestamp;
820 }
821 if(stats->uMaxTicks < timestamp)
822 {
823 stats->uMaxTicks = timestamp;
824 }
826 /*
827 ** Realloc in general deserves some special attention if dealing
828 ** with an old allocation (not new memory).
829 */
830 if(TM_EVENT_REALLOC == type && 0 != inEvent->u.alloc.oldserial)
831 {
832 unsigned oldActualSize = actualByteSize(options, inEvent->u.alloc.oldsize);
833 unsigned oldHeapID = inEvent->u.alloc.oldptr;
834 unsigned oldSerial = inEvent->u.alloc.oldserial;
836 if(0 == actualSize)
837 {
838 /*
839 ** Reallocs of size zero are to become free events.
840 */
841 stats->mLoopExitTMR = simpleHeapEvent(stats, FREE, timestamp, serial, oldHeapID, oldActualSize);
842 }
843 else if(heapID != oldHeapID || actualSize != oldActualSize)
844 {
845 /*
846 ** Reallocs which moved generate two events.
847 ** Reallocs which changed size generate two events.
848 **
849 ** One event to free the old memory area.
850 ** Another event to allocate the new memory area.
851 ** They are to be linked to one another, so the history
852 ** and true origin can be tracked.
853 */
854 stats->mLoopExitTMR = complexHeapEvent(stats, timestamp, oldSerial, oldHeapID, oldActualSize, serial, heapID, actualSize);
855 }
856 else
857 {
858 /*
859 ** The realloc is not considered an operation and is skipped.
860 ** It is not an operation, because it did not move or change
861 ** size; this can happen if a realloc falls within the
862 ** alignment of an allocation.
863 ** Say if you realloc a 1 byte allocation to 2 bytes, it will
864 ** not really change heap impact unless you have 1 set as
865 ** the alignment of your allocations.
866 */
867 }
868 }
869 else if(TM_EVENT_FREE == type)
870 {
871 /*
872 ** Generate a free event to create a fragment.
873 */
874 stats->mLoopExitTMR = simpleHeapEvent(stats, FREE, timestamp, serial, heapID, actualSize);
875 }
876 else
877 {
878 /*
879 ** Generate an allocation event to clear fragments.
880 */
881 stats->mLoopExitTMR = simpleHeapEvent(stats, ALLOC, timestamp, serial, heapID, actualSize);
882 }
883 }
884 }
887 int tmfrags(Options* inOptions)
888 /*
889 ** Load the input file and report stats.
890 */
891 {
892 int retval = 0;
893 TMState stats;
895 memset(&stats, 0, sizeof(stats));
896 stats.mOptions = inOptions;
897 stats.uMinTicks = 0xFFFFFFFFU;
899 /*
900 ** Need a tmreader.
901 */
902 stats.mTMR = tmreader_new(inOptions->mProgramName, &stats);
903 if(NULL != stats.mTMR)
904 {
905 int tmResult = 0;
907 tmResult = tmreader_eventloop(stats.mTMR, inOptions->mInputName, tmEventHandler);
908 if(0 == tmResult)
909 {
910 retval = __LINE__;
911 ERROR_REPORT(retval, inOptions->mInputName, "Problem reading trace-malloc data.");
912 }
913 if(0 != stats.mLoopExitTMR)
914 {
915 retval = stats.mLoopExitTMR;
916 ERROR_REPORT(retval, inOptions->mInputName, "Aborted trace-malloc input loop.");
917 }
919 tmreader_destroy(stats.mTMR);
920 stats.mTMR = NULL;
921 }
922 else
923 {
924 retval = __LINE__;
925 ERROR_REPORT(retval, inOptions->mProgramName, "Unable to obtain tmreader.");
926 }
928 return retval;
929 }
932 int main(int inArgc, char** inArgv)
933 {
934 int retval = 0;
935 Options options;
937 retval = initOptions(&options, inArgc, inArgv);
938 if(options.mHelp)
939 {
940 showHelp(&options);
941 }
942 else if(0 == retval)
943 {
944 retval = tmfrags(&options);
945 }
947 cleanOptions(&options);
948 return retval;
949 }