michael@0: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef spacetrace_h__ michael@0: #define spacetrace_h__ michael@0: michael@0: /* michael@0: ** spacetrace.h michael@0: ** michael@0: ** SpaceTrace is meant to take the output of trace-malloc and present michael@0: ** a picture of allocations over the run of the application. michael@0: */ michael@0: michael@0: /* michael@0: ** Required includes. michael@0: */ michael@0: #include michael@0: #include "nspr.h" michael@0: #include "prlock.h" michael@0: #include "prrwlock.h" michael@0: #include "nsTraceMalloc.h" michael@0: #include "tmreader.h" michael@0: #include "formdata.h" michael@0: michael@0: /* michael@0: ** Turn on to attempt adding support for graphs on your platform. michael@0: */ michael@0: #if defined(HAVE_BOUTELL_GD) michael@0: #define ST_WANT_GRAPHS 1 michael@0: #endif /* HAVE_BOUTELL_GD */ michael@0: #if !defined(ST_WANT_GRAPHS) michael@0: #define ST_WANT_GRAPHS 0 michael@0: #endif michael@0: michael@0: /* michael@0: ** REPORT_ERROR michael@0: ** REPORT_INFO michael@0: ** michael@0: ** Just report errors and stuff in a consistent manner. michael@0: */ michael@0: #define REPORT_ERROR(code, function) \ michael@0: PR_fprintf(PR_STDERR, "error(%d):\t%s\n", code, #function) michael@0: #define REPORT_ERROR_MSG(code, msg) \ michael@0: PR_fprintf(PR_STDERR, "error(%d):\t%s\n", code, msg) michael@0: #define REPORT_INFO(msg) \ michael@0: PR_fprintf(PR_STDOUT, "%s: %s\n", globals.mProgramName, (msg)) michael@0: michael@0: #if defined(DEBUG_blythe) && 1 michael@0: #define REPORT_blythe(code, msg) \ michael@0: PR_fprintf(PR_STDOUT, "gab(%d):\t%s\n", code, msg) michael@0: #else michael@0: #define REPORT_blythe(code, msg) michael@0: #endif /* DEBUG_blythe */ michael@0: michael@0: /* michael@0: ** CALLSITE_RUN michael@0: ** michael@0: ** How to get a callsite run. michael@0: ** Allows for further indirection if needed later. michael@0: */ michael@0: #define CALLSITE_RUN(callsite) \ michael@0: ((STRun*)((callsite)->data)) michael@0: michael@0: /* michael@0: ** ST_PERMS michael@0: ** ST_FLAGS michael@0: ** michael@0: ** File permissions we desire. michael@0: ** 0644 michael@0: */ michael@0: #define ST_PERMS (PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IROTH) michael@0: #define ST_FLAGS (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE) michael@0: michael@0: /* michael@0: ** Sorting order michael@0: */ michael@0: #define ST_WEIGHT 0 /* size * timeval */ michael@0: #define ST_SIZE 1 michael@0: #define ST_TIMEVAL 2 michael@0: #define ST_COUNT 3 michael@0: #define ST_HEAPCOST 4 michael@0: michael@0: /* michael@0: ** Callsite loop direction flags. michael@0: */ michael@0: #define ST_FOLLOW_SIBLINGS 0 michael@0: #define ST_FOLLOW_PARENTS 1 michael@0: michael@0: /* michael@0: ** Graph data. michael@0: */ michael@0: #define STGD_WIDTH 640 michael@0: #define STGD_HEIGHT 480 michael@0: #define STGD_MARGIN 75 michael@0: #define STGD_SPACE_X (STGD_WIDTH - (2 * STGD_MARGIN)) michael@0: #define STGD_SPACE_Y (STGD_HEIGHT - (2 * STGD_MARGIN)) michael@0: michael@0: /* michael@0: ** Minimum lifetime default, in seconds. michael@0: */ michael@0: #define ST_DEFAULT_LIFETIME_MIN 10 michael@0: michael@0: /* michael@0: ** Allocations fall to this boundry size by default. michael@0: ** Overhead is taken after alignment. michael@0: ** michael@0: ** The msvcrt malloc has an alignment of 16 with an overhead of 8. michael@0: ** The win32 HeapAlloc has an alignment of 8 with an overhead of 8. michael@0: */ michael@0: #define ST_DEFAULT_ALIGNMENT_SIZE 16 michael@0: #define ST_DEFAULT_OVERHEAD_SIZE 8 michael@0: michael@0: /* michael@0: ** Numer of substring match specifications to allow. michael@0: */ michael@0: #define ST_SUBSTRING_MATCH_MAX 5 michael@0: michael@0: /* michael@0: ** Max Number of patterns per rule michael@0: */ michael@0: #define ST_MAX_PATTERNS_PER_RULE 16 michael@0: michael@0: /* michael@0: ** Rule pointers and child pointers are allocated in steps of ST_ALLOC_STEP michael@0: */ michael@0: #define ST_ALLOC_STEP 16 michael@0: michael@0: /* michael@0: ** Name of the root category. Appears in UI. michael@0: */ michael@0: #define ST_ROOT_CATEGORY_NAME "All" michael@0: michael@0: /* michael@0: ** Size of our option string buffers. michael@0: */ michael@0: #define ST_OPTION_STRING_MAX 256 michael@0: michael@0: /* michael@0: ** Set the desired resolution of the timevals. michael@0: ** The resolution is just mimicking what is recorded in the trace-malloc michael@0: ** output, and that is currently milliseconds. michael@0: */ michael@0: #define ST_TIMEVAL_RESOLUTION 1000 michael@0: #define ST_TIMEVAL_FORMAT "%.3f" michael@0: #define ST_TIMEVAL_PRINTABLE(timeval) ((double)(timeval) / (double)ST_TIMEVAL_RESOLUTION) michael@0: #define ST_TIMEVAL_PRINTABLE64(timeval) ((double)((int64_t)(timeval)) / (double)ST_TIMEVAL_RESOLUTION) michael@0: #define ST_TIMEVAL_MAX ((uint32_t)-1 - ((uint32_t)-1 % ST_TIMEVAL_RESOLUTION)) michael@0: michael@0: #define ST_MICROVAL_RESOLUTION 1000000 michael@0: #define ST_MICROVAL_FORMAT "%.6f" michael@0: #define ST_MICROVAL_PRINTABLE(timeval) ((double)(timeval) / (double)ST_MICROVAL_RESOLUTION) michael@0: #define ST_MICROVAL_PRINTABLE64(timeval) ((double)((int64_t)(timeval)) / (double)ST_MICROVAL_RESOLUTION) michael@0: #define ST_MICROVAL_MAX ((uint32_t)-1 - ((uint32_t)-1 % ST_MICROVAL_RESOLUTION)) michael@0: michael@0: /* michael@0: ** Forward Declaration michael@0: */ michael@0: typedef struct __struct_STCategoryNode STCategoryNode; michael@0: typedef struct __struct_STCategoryRule STCategoryRule; michael@0: michael@0: michael@0: /* michael@0: ** STAllocEvent michael@0: ** michael@0: ** An event that happens to an allocation (malloc, free, et. al.) michael@0: */ michael@0: typedef struct __struct_STAllocEvent michael@0: { michael@0: /* michael@0: ** The type of allocation event. michael@0: ** This maps directly to the trace malloc events (i.e. TM_EVENT_MALLOC) michael@0: */ michael@0: char mEventType; michael@0: michael@0: /* michael@0: ** Each event, foremost, has a chronologically increasing ID in michael@0: ** relation to other allocation events. This is a time stamp michael@0: ** of sorts. michael@0: */ michael@0: uint32_t mTimeval; michael@0: michael@0: /* michael@0: ** Every event has a heap ID (pointer). michael@0: ** In the event of a realloc, this is the new heap ID. michael@0: ** In the event of a free, this is the previous heap ID value. michael@0: */ michael@0: uint32_t mHeapID; michael@0: michael@0: /* michael@0: ** Every event, along with the heap ID, tells of the size. michael@0: ** In the event of a realloc, this is the new size. michael@0: ** In th event of a free, this is the previous size. michael@0: */ michael@0: uint32_t mHeapSize; michael@0: michael@0: /* michael@0: ** Every event has a callsite/stack backtrace. michael@0: ** In the event of a realloc, this is the new callsite. michael@0: ** In the event of a free, this is the previous call site. michael@0: */ michael@0: tmcallsite* mCallsite; michael@0: } STAllocEvent; michael@0: michael@0: /* michael@0: ** STAllocation michael@0: ** michael@0: ** An allocation is a temporal entity in the heap. michael@0: ** It possibly lives under different heap IDs (pointers) and different michael@0: ** sizes during its given time. michael@0: ** An allocation is defined by the events during its lifetime. michael@0: ** An allocation's lifetime is defined by the range of event IDs it holds. michael@0: */ michael@0: typedef struct __struct_STAllocation michael@0: { michael@0: /* michael@0: ** The array of events. michael@0: */ michael@0: uint32_t mEventCount; michael@0: STAllocEvent* mEvents; michael@0: michael@0: /* michael@0: ** The lifetime/lifespan of the allocation. michael@0: */ michael@0: uint32_t mMinTimeval; michael@0: uint32_t mMaxTimeval; michael@0: michael@0: /* michael@0: ** Index of this allocation in the global run. michael@0: */ michael@0: uint32_t mRunIndex; michael@0: michael@0: /* michael@0: ** The runtime cost of heap events in this allocation. michael@0: ** The cost is defined as the number of time units recorded as being michael@0: ** spent in heap code (time of malloc, free, et al.). michael@0: ** We do not track individual event cost in order to save space. michael@0: */ michael@0: uint32_t mHeapRuntimeCost; michael@0: } STAllocation; michael@0: michael@0: /* michael@0: ** STCallsiteStats michael@0: ** michael@0: ** Stats regarding a run, kept mainly for callsite runs. michael@0: */ michael@0: typedef struct __struct_STCallsiteStats michael@0: { michael@0: /* michael@0: ** Sum timeval of the allocations. michael@0: ** Callsite runs total all allocations below the callsite. michael@0: */ michael@0: uint64_t mTimeval64; michael@0: michael@0: /* michael@0: ** Sum weight of the allocations. michael@0: ** Callsite runs total all allocations below the callsite. michael@0: */ michael@0: uint64_t mWeight64; michael@0: michael@0: /* michael@0: ** Sum size of the allocations. michael@0: ** Callsite runs total all allocations below the callsite. michael@0: */ michael@0: uint32_t mSize; michael@0: michael@0: /* michael@0: ** A stamp, indicated the relevance of the run. michael@0: ** If the stamp does not match the origin value, the michael@0: ** data contained here-in is considered invalid. michael@0: */ michael@0: uint32_t mStamp; michael@0: michael@0: /* michael@0: ** A sum total of allocations (note, not sizes) below the callsite. michael@0: ** This is NOT the same as STRun::mAllocationCount which michael@0: ** tracks the STRun::mAllocations array size. michael@0: */ michael@0: uint32_t mCompositeCount; michael@0: michael@0: /* michael@0: ** A sum total runtime cost of heap operations below the calliste. michael@0: ** The cost is defined as the number of time units recorded as being michael@0: ** spent in heap code (time of malloc, free, et al.). michael@0: */ michael@0: uint32_t mHeapRuntimeCost; michael@0: } STCallsiteStats; michael@0: michael@0: /* michael@0: ** STRun michael@0: ** michael@0: ** A run is a closed set of allocations. michael@0: ** Given a run, we can deduce information about the contained allocations. michael@0: ** We can also determine if an allocation lives beyond a run (leak). michael@0: ** michael@0: ** A run might be used to represent allocations for an entire application. michael@0: ** A run might also be used to represent allocations from a single callstack. michael@0: */ michael@0: typedef struct __struct_STRun michael@0: { michael@0: /* michael@0: ** The array of allocations. michael@0: */ michael@0: uint32_t mAllocationCount; michael@0: STAllocation** mAllocations; michael@0: michael@0: /* michael@0: ** Callsites like to keep some information. michael@0: ** As callsites are possibly shared between all contexts, each michael@0: ** different context needs to keep different stats. michael@0: */ michael@0: STCallsiteStats *mStats; michael@0: michael@0: } STRun; michael@0: michael@0: /* michael@0: ** Categorize allocations michael@0: ** michael@0: ** The objective is to have a tree of categories with each leaf node of the tree michael@0: ** matching a set of callsites that belong to the category. Each category can michael@0: ** signify a functional area like say css and hence the user can browse this michael@0: ** tree looking for how much of each of these are live at an instant. michael@0: */ michael@0: michael@0: /* michael@0: ** STCategoryNode michael@0: */ michael@0: michael@0: struct __struct_STCategoryNode michael@0: { michael@0: /* michael@0: ** Category name michael@0: */ michael@0: const char *categoryName; michael@0: michael@0: /* michael@0: ** Pointer to parent node. NULL for Root. michael@0: */ michael@0: STCategoryNode *parent; michael@0: michael@0: /* michael@0: ** For non-leaf nodes, an array of children node pointers. michael@0: ** NULL if leaf node. michael@0: */ michael@0: STCategoryNode** children; michael@0: uint32_t nchildren; michael@0: michael@0: /* michael@0: ** The Run(s). Valid for both leaf and parent nodes. michael@0: ** One run per --Context to handle multiple data sets. michael@0: ** The relevant index for the particular request will be michael@0: ** mIndex stored by the mContext of the request. michael@0: */ michael@0: STRun **runs; michael@0: }; michael@0: michael@0: michael@0: struct __struct_STCategoryRule michael@0: { michael@0: /* michael@0: ** The pattern for the rule. Patterns are an array of strings. michael@0: ** A callsite needs to pass substring match for all the strings. michael@0: */ michael@0: char* pats[ST_MAX_PATTERNS_PER_RULE]; michael@0: uint32_t patlen[ST_MAX_PATTERNS_PER_RULE]; michael@0: uint32_t npats; michael@0: michael@0: /* michael@0: ** Category name that this rule belongs to michael@0: */ michael@0: const char* categoryName; michael@0: michael@0: /* michael@0: ** The node this should be categorized into michael@0: */ michael@0: STCategoryNode* node; michael@0: }; michael@0: michael@0: michael@0: /* michael@0: ** CategoryName to Node mapping table michael@0: */ michael@0: typedef struct __struct_STCategoryMapEntry { michael@0: STCategoryNode* node; michael@0: const char * categoryName; michael@0: } STCategoryMapEntry; michael@0: michael@0: /* michael@0: ** Option genres. michael@0: ** michael@0: ** This helps to determine what functionality each option effects. michael@0: ** In specific, this will help use determine when and when not to michael@0: ** totally recaclulate the sorted run and categories. michael@0: ** Be very aware that adding things to a particular genre, or adding a genre, michael@0: ** may completely screw up the caching algorithms of SpaceTrace. michael@0: ** See contextLookup() or ask someone that knows if you are in doubt. michael@0: */ michael@0: typedef enum __enum_STOptionGenre michael@0: { michael@0: CategoryGenre = 0, michael@0: DataSortGenre, michael@0: DataSetGenre, michael@0: DataSizeGenre, michael@0: UIGenre, michael@0: ServerGenre, michael@0: BatchModeGenre, michael@0: michael@0: /* michael@0: ** Last one please. michael@0: */ michael@0: MaxGenres michael@0: } michael@0: STOptionGenre; michael@0: michael@0: /* michael@0: ** STOptions michael@0: ** michael@0: ** Structure containing the varios options for the code. michael@0: ** The definition of these options exists in a different file. michael@0: ** We access that definition via macros to inline our structure definition. michael@0: */ michael@0: #define ST_CMD_OPTION_BOOL(option_name, option_genre, option_help) PRBool m##option_name; michael@0: #define ST_CMD_OPTION_STRING(option_name, option_genre, default_value, option_help) char m##option_name[ST_OPTION_STRING_MAX]; michael@0: #define ST_CMD_OPTION_STRING_ARRAY(option_name, option_genre, array_size, option_help) char m##option_name[array_size][ST_OPTION_STRING_MAX]; michael@0: #define ST_CMD_OPTION_STRING_PTR_ARRAY(option_name, option_genre, option_help) const char** m##option_name; uint32_t m##option_name##Count; michael@0: #define ST_CMD_OPTION_UINT32(option_name, option_genre, default_value, multiplier, option_help) uint32_t m##option_name; michael@0: #define ST_CMD_OPTION_UINT64(option_name, option_genre, default_value, multiplier, option_help) uint64_t m##option_name##64; michael@0: michael@0: typedef struct __struct_STOptions michael@0: { michael@0: #include "stoptions.h" michael@0: } michael@0: STOptions; michael@0: michael@0: typedef struct __struct_STContext michael@0: /* michael@0: ** A per request, thread safe, manner of accessing the contained members. michael@0: ** A reader/writer lock ensures that the data is properly initialized before michael@0: ** readers of the data begin their work. michael@0: ** michael@0: ** mRWLock reader/writer lock. michael@0: ** writer lock is held to ensure initialization, though michael@0: ** others can be attempting to acquire read locks michael@0: ** at that time. michael@0: ** writer lock is also used in destruction to make sure michael@0: ** there are no more readers of data contained herein. michael@0: ** reader lock is to allow multiple clients to read the michael@0: ** data at the same time; implies is they must not michael@0: ** write anything. michael@0: ** mIndex Consider this much like thread private data or thread michael@0: ** local storage in a few places. michael@0: ** The index is specifically reserved for this context's michael@0: ** usage in other data structure array's provided michael@0: ** for the particular thread/client/context. michael@0: ** This should not be modified after initialization. michael@0: ** mSortedRun A pre sorted run taken from the global run, with our michael@0: ** options applied. michael@0: ** mImageLock An overly simplistic locking mechanism to protect the michael@0: ** shared image cache. michael@0: ** The proper implementation would have a reader/writer michael@0: ** lock per cached image data. michael@0: ** However, this will prove to be simpler for the time michael@0: ** being. michael@0: ** mFootprintCached Whether or not YData contains something useful. michael@0: ** mTimevalCached Whether or not YData contains something useful. michael@0: ** mLifespanCached Whether or not YData contains something useful. michael@0: ** mWeightCached Whether or not YData contains something useful. michael@0: ** mFootprintYData Precomputed cached graph data. michael@0: ** mTimevalYData Precomputed cached graph data. michael@0: ** mLifespanYData Precomputed cached graph data. michael@0: ** mWeightYData Precomputed cached graph data. michael@0: */ michael@0: { michael@0: PRRWLock* mRWLock; michael@0: uint32_t mIndex; michael@0: STRun* mSortedRun; michael@0: #if ST_WANT_GRAPHS michael@0: PRLock* mImageLock; michael@0: PRBool mFootprintCached; michael@0: PRBool mTimevalCached; michael@0: PRBool mLifespanCached; michael@0: PRBool mWeightCached; michael@0: uint32_t mFootprintYData[STGD_SPACE_X]; michael@0: uint32_t mTimevalYData[STGD_SPACE_X]; michael@0: uint32_t mLifespanYData[STGD_SPACE_X]; michael@0: uint64_t mWeightYData64[STGD_SPACE_X]; michael@0: #endif michael@0: } michael@0: STContext; michael@0: michael@0: michael@0: typedef struct __struct_STContextCacheItem michael@0: /* michael@0: ** This basically pools the common items that the context cache will michael@0: ** want to track on a per context basis. michael@0: ** michael@0: ** mOptions What options this item represents. michael@0: ** mContext State/data this cache item is wrapping. michael@0: ** mReferenceCount A count of clients currently using this item. michael@0: ** Should this item be 0, then the cache might michael@0: ** decide to evict this context. michael@0: ** Should this item not be 0, once it reaches michael@0: ** zero a condition variable in the context cache michael@0: ** will be signaled to notify the availability. michael@0: ** mLastAccessed A timestamp of when this item was last accessed/released. michael@0: ** Ignore this unless the reference count is 0, michael@0: ** This is used to evict the oldest unused item from michael@0: ** the context cache. michael@0: ** mInUse Mainly PR_FALSE only at the beginning of the process, michael@0: ** but this indicates that the item has not yet been michael@0: ** used at all, and thus shouldn't be evaluated for michael@0: ** a cache hit. michael@0: */ michael@0: { michael@0: STOptions mOptions; michael@0: STContext mContext; michael@0: int32_t mReferenceCount; michael@0: PRIntervalTime mLastAccessed; michael@0: PRBool mInUse; michael@0: } michael@0: STContextCacheItem; michael@0: michael@0: michael@0: typedef struct __struct_STContextCache michael@0: /* michael@0: ** A thread safe, possibly blocking, cache of context items. michael@0: ** michael@0: ** mLock Must hold the lock to read/access/write to this struct, as michael@0: ** well as any items it holds. michael@0: ** mCacheMiss All items are busy and there were no cache matches. michael@0: ** This condition variable is used to wait until an item becomes michael@0: ** "available" to be evicted from the cache. michael@0: ** mItems Array of items. michael@0: ** mItemCount Number of items in array. michael@0: ** This is generally the same as the global option's command line michael@0: ** mContexts.... michael@0: */ michael@0: { michael@0: PRLock* mLock; michael@0: PRCondVar* mCacheMiss; michael@0: STContextCacheItem* mItems; michael@0: uint32_t mItemCount; michael@0: } michael@0: STContextCache; michael@0: michael@0: michael@0: /* michael@0: ** STRequest michael@0: ** michael@0: ** Things specific to a request. michael@0: */ michael@0: typedef struct __struct_STRequest michael@0: { michael@0: /* michael@0: ** Sink/where to output. michael@0: */ michael@0: PRFileDesc* mFD; michael@0: michael@0: /* michael@0: ** The filename requested. michael@0: */ michael@0: const char* mGetFileName; michael@0: michael@0: /* michael@0: ** The GET form data, if any. michael@0: */ michael@0: const FormData* mGetData; michael@0: michael@0: /* michael@0: ** Options specific to this request. michael@0: */ michael@0: STOptions mOptions; michael@0: michael@0: /* michael@0: ** The context/data/state of the request. michael@0: */ michael@0: STContext* mContext; michael@0: } STRequest; michael@0: michael@0: michael@0: /* michael@0: ** STGlobals michael@0: ** michael@0: ** Various globals we keep around. michael@0: */ michael@0: typedef struct __struct_STGlobals michael@0: { michael@0: /* michael@0: ** The string which identifies this program. michael@0: */ michael@0: const char* mProgramName; michael@0: michael@0: /* michael@0: ** Options derived from the command line. michael@0: ** These are used as defaults, and should remain static during michael@0: ** the run of the application. michael@0: */ michael@0: STOptions mCommandLineOptions; michael@0: michael@0: /* michael@0: ** Context cache. michael@0: ** As clients come in, based on their options, a different context michael@0: ** will be used to service them. michael@0: */ michael@0: STContextCache mContextCache; michael@0: michael@0: /* michael@0: ** Various counters for different types of events. michael@0: */ michael@0: uint32_t mMallocCount; michael@0: uint32_t mCallocCount; michael@0: uint32_t mReallocCount; michael@0: uint32_t mFreeCount; michael@0: michael@0: /* michael@0: ** Total events, operation counter. michael@0: */ michael@0: uint32_t mOperationCount; michael@0: michael@0: /* michael@0: ** The "run" of the input. michael@0: */ michael@0: STRun mRun; michael@0: michael@0: /* michael@0: ** Operation minimum/maximum timevals. michael@0: ** So that we can determine the overall timeval of the run. michael@0: ** NOTE: These are NOT the options to control the data set. michael@0: */ michael@0: uint32_t mMinTimeval; michael@0: uint32_t mMaxTimeval; michael@0: michael@0: /* michael@0: ** Calculates peak allocation overall for all allocations. michael@0: */ michael@0: uint32_t mPeakMemoryUsed; michael@0: uint32_t mMemoryUsed; michael@0: michael@0: /* michael@0: ** A list of rules for categorization read in from the mCategoryFile michael@0: */ michael@0: STCategoryRule** mCategoryRules; michael@0: uint32_t mNRules; michael@0: michael@0: /* michael@0: ** CategoryName to Node mapping table michael@0: */ michael@0: STCategoryMapEntry** mCategoryMap; michael@0: uint32_t mNCategoryMap; michael@0: michael@0: /* michael@0: ** Categorized allocations. For now we support only one tree. michael@0: */ michael@0: STCategoryNode mCategoryRoot; michael@0: michael@0: /* michael@0: ** tmreader hash tables. michael@0: ** Moved into globals since we need to destroy these only after all michael@0: ** client threads are finishes (after PR_Cleanup). michael@0: */ michael@0: tmreader* mTMR; michael@0: } STGlobals; michael@0: michael@0: michael@0: /* michael@0: ** Function prototypes michael@0: */ michael@0: extern STRun* createRun(STContext* inContext, uint32_t aStamp); michael@0: extern void freeRun(STRun* aRun); michael@0: extern int initCategories(STGlobals* g); michael@0: extern int categorizeRun(STOptions* inOptions, STContext* inContext, const STRun* aRun, STGlobals* g); michael@0: extern STCategoryNode* findCategoryNode(const char *catName, STGlobals *g); michael@0: extern int freeCategories(STGlobals* g); michael@0: extern int displayCategoryReport(STRequest* inRequest, STCategoryNode *root, int depth); michael@0: michael@0: extern int recalculateAllocationCost(STOptions* inOptions, STContext* inContext, STRun* aRun, STAllocation* aAllocation, PRBool updateParent); michael@0: extern void htmlHeader(STRequest* inRequest, const char* aTitle); michael@0: extern void htmlFooter(STRequest* inRequest); michael@0: extern void htmlAnchor(STRequest* inRequest, michael@0: const char* aHref, michael@0: const char* aText, michael@0: const char* aTarget, michael@0: const char* aClass, michael@0: STOptions* inOptions); michael@0: extern char *FormatNumber(int32_t num); michael@0: michael@0: /* michael@0: ** shared globals michael@0: */ michael@0: extern STGlobals globals; michael@0: michael@0: #endif /* spacetrace_h__ */