spacetrace updates (not part of build)

- use arenas for hashtable allocation - reduces spacetrace's mem usage tremendously for large files
- code cleanup & wrapping
- UI cleanup - headers & such
- fix nsTraceMalloc to at least support long stacks, so that we don't barf if we have trouble reading the stacks


git-svn-id: svn://10.0.0.236/trunk@143293 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
alecf%flett.org 2003-06-04 20:15:10 +00:00
parent 02c0ec9772
commit 8c9811e251
5 changed files with 143 additions and 74 deletions

View File

@ -708,7 +708,9 @@ static callsite *calltree(int skip)
/*
* Time to increase the number of stack frames?
*/
PR_ASSERT(framenum < MAX_STACKFRAMES);
if (framenum >= MAX_STACKFRAMES)
break;
PR_ASSERT(framenum < MAX_STACKFRAMES);
}
depth = framenum;

View File

@ -380,9 +380,24 @@ gdImagePtr createGraph(int* aTransparencyColor)
** This function mainly exists to simplify putitng all the pretty lace
** around a home made graph.
*/
void drawGraph(gdImagePtr aImage, int aColor, const char* aGraphTitle, const char* aXAxisTitle, const char* aYAxisTitle, PRUint32 aXMarkCount, PRUint32* aXMarkPercents, const char** aXMarkTexts, PRUint32 aYMarkCount, PRUint32* aYMarkPercents, const char** aYMarkTexts, PRUint32 aLegendCount, int* aLegendColors, const char** aLegendTexts)
void drawGraph(gdImagePtr aImage, int aColor,
const char* aGraphTitle,
const char* aXAxisTitle,
const char* aYAxisTitle,
PRUint32 aXMarkCount,
PRUint32* aXMarkPercents,
const char** aXMarkTexts,
PRUint32 aYMarkCount,
PRUint32* aYMarkPercents,
const char** aYMarkTexts,
PRUint32 aLegendCount,
int* aLegendColors, const char** aLegendTexts)
{
if(NULL != aImage && NULL != aGraphTitle && NULL != aXAxisTitle && NULL != aYAxisTitle && (0 == aXMarkCount || (NULL != aXMarkPercents && NULL != aXMarkTexts)) && (0 == aYMarkCount || (NULL != aYMarkPercents && NULL != aYMarkTexts)) && (0 == aLegendCount || (NULL != aLegendColors && NULL != aLegendTexts)))
if(NULL != aImage && NULL != aGraphTitle &&
NULL != aXAxisTitle && NULL != aYAxisTitle &&
(0 == aXMarkCount || (NULL != aXMarkPercents && NULL != aXMarkTexts)) &&
(0 == aYMarkCount || (NULL != aYMarkPercents && NULL != aYMarkTexts)) &&
(0 == aLegendCount || (NULL != aLegendColors && NULL != aLegendTexts)))
{
int margin = 1;
PRUint32 traverse = 0;
@ -682,8 +697,10 @@ int recalculateAllocationCost(STOptions* inOptions, STContext* inContext, STRun*
aRun->mStats[inContext->mIndex].mCompositeCount++;
aRun->mStats[inContext->mIndex].mHeapRuntimeCost += heapCost;
aRun->mStats[inContext->mIndex].mSize += size;
LL_ADD(aRun->mStats[inContext->mIndex].mTimeval64, aRun->mStats[inContext->mIndex].mTimeval64, timeval64);
LL_ADD(aRun->mStats[inContext->mIndex].mWeight64, aRun->mStats[inContext->mIndex].mWeight64, weight64);
LL_ADD(aRun->mStats[inContext->mIndex].mTimeval64,
aRun->mStats[inContext->mIndex].mTimeval64, timeval64);
LL_ADD(aRun->mStats[inContext->mIndex].mWeight64,
aRun->mStats[inContext->mIndex].mWeight64, weight64);
/*
** Use the first event of the allocation to update the parent
@ -707,10 +724,13 @@ int recalculateAllocationCost(STOptions* inOptions, STContext* inContext, STRun*
/*
** Do we init it?
*/
if(callsiteRun->mStats[inContext->mIndex].mStamp != aRun->mStats[inContext->mIndex].mStamp)
if(callsiteRun->mStats[inContext->mIndex].mStamp !=
aRun->mStats[inContext->mIndex].mStamp)
{
memset(&callsiteRun->mStats[inContext->mIndex], 0, sizeof(STCallsiteStats));
callsiteRun->mStats[inContext->mIndex].mStamp = aRun->mStats[inContext->mIndex].mStamp;
memset(&callsiteRun->mStats[inContext->mIndex], 0,
sizeof(STCallsiteStats));
callsiteRun->mStats[inContext->mIndex].mStamp =
aRun->mStats[inContext->mIndex].mStamp;
}
/*
@ -730,10 +750,15 @@ int recalculateAllocationCost(STOptions* inOptions, STContext* inContext, STRun*
** is perhaps good enough for now.
*/
callsiteRun->mStats[inContext->mIndex].mCompositeCount++;
callsiteRun->mStats[inContext->mIndex].mHeapRuntimeCost += heapCost;
callsiteRun->mStats[inContext->mIndex].mHeapRuntimeCost +=
heapCost;
callsiteRun->mStats[inContext->mIndex].mSize += size;
LL_ADD(callsiteRun->mStats[inContext->mIndex].mTimeval64, callsiteRun->mStats[inContext->mIndex].mTimeval64, timeval64);
LL_ADD(callsiteRun->mStats[inContext->mIndex].mWeight64, callsiteRun->mStats[inContext->mIndex].mWeight64, weight64);
LL_ADD(callsiteRun->mStats[inContext->mIndex].mTimeval64,
callsiteRun->mStats[inContext->mIndex].mTimeval64,
timeval64);
LL_ADD(callsiteRun->mStats[inContext->mIndex].mWeight64,
callsiteRun->mStats[inContext->mIndex].mWeight64,
weight64);
}
callsite = callsite->parent;
@ -756,7 +781,9 @@ int recalculateAllocationCost(STOptions* inOptions, STContext* inContext, STRun*
** such information when it was created.
** Returns !0 on success.
*/
int appendAllocation(STOptions* inOptions, STContext* inContext, STRun* aRun, STAllocation* aAllocation)
int
appendAllocation(STOptions* inOptions, STContext* inContext,
STRun* aRun, STAllocation* aAllocation)
{
int retval = 0;
@ -767,7 +794,8 @@ int appendAllocation(STOptions* inOptions, STContext* inContext, STRun* aRun, ST
/*
** Expand the size of the array if needed.
*/
expand = (STAllocation**)realloc(aRun->mAllocations, sizeof(STAllocation*) * (aRun->mAllocationCount + 1));
expand = (STAllocation**)realloc(aRun->mAllocations,
sizeof(STAllocation*) * (aRun->mAllocationCount + 1));
if(NULL != expand)
{
/*
@ -828,7 +856,8 @@ int hasCallsiteMatch(tmcallsite* aCallsite, const char* aMatch, int aDirection)
{
int retval = 0;
if(NULL != aCallsite && NULL != aCallsite->method && NULL != aMatch && '\0' != *aMatch)
if(NULL != aCallsite && NULL != aCallsite->method &&
NULL != aMatch && '\0' != *aMatch)
{
const char* methodName = NULL;
@ -884,7 +913,9 @@ int hasCallsiteMatch(tmcallsite* aCallsite, const char* aMatch, int aDirection)
**
** Returns !0 on error, though aOutRun may contain a partial data set.
*/
int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STContext* inContext)
int
harvestRun(const STRun* aInRun, STRun* aOutRun,
STOptions* aOptions, STContext* inContext)
{
int retval = 0;
@ -898,7 +929,8 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
PRUint32 traverse = 0;
STAllocation* current = NULL;
for(traverse = 0; 0 == retval && traverse < aInRun->mAllocationCount; traverse++)
for(traverse = 0;
0 == retval && traverse < aInRun->mAllocationCount; traverse++)
{
current = aInRun->mAllocations[traverse];
if(NULL != current)
@ -927,11 +959,10 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
** We have to slide the recorded timevals to be zero
** based, so that the comparisons make sense.
*/
if(aOptions->mAllocationTimevalMin > (current->mMinTimeval - globals.mMinTimeval))
{
continue;
}
else if(aOptions->mAllocationTimevalMax < (current->mMinTimeval - globals.mMinTimeval))
if ((aOptions->mAllocationTimevalMin >
(current->mMinTimeval - globals.mMinTimeval)) ||
(aOptions->mAllocationTimevalMax <
(current->mMinTimeval - globals.mMinTimeval)))
{
continue;
}
@ -941,11 +972,10 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
** We have to slide the recorded timevals to be zero
** based, so that the comparisons make sense.
*/
if(aOptions->mTimevalMin > (current->mMaxTimeval - globals.mMinTimeval))
{
continue;
}
else if(aOptions->mTimevalMax < (current->mMinTimeval - globals.mMinTimeval))
if ((aOptions->mTimevalMin >
(current->mMinTimeval - globals.mMinTimeval)) ||
(aOptions->mTimevalMax <
(current->mMinTimeval - globals.mMinTimeval)))
{
continue;
}
@ -954,11 +984,8 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
** Check lifetime restrictions.
*/
lifetime = current->mMaxTimeval - current->mMinTimeval;
if(lifetime < aOptions->mLifetimeMin)
{
continue;
}
else if(lifetime > aOptions->mLifetimeMax)
if ((lifetime < aOptions->mLifetimeMin) ||
(lifetime > aOptions->mLifetimeMax))
{
continue;
}
@ -967,11 +994,8 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
** Check byte size restrictions.
*/
bytesize = byteSize(aOptions, current);
if(bytesize < aOptions->mSizeMin)
{
continue;
}
else if(bytesize > aOptions->mSizeMax)
if ((bytesize < aOptions->mSizeMin) ||
(bytesize > aOptions->mSizeMax))
{
continue;
}
@ -982,11 +1006,8 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
LL_UI2L(bytesize64, bytesize);
LL_UI2L(lifetime64, lifetime);
LL_MUL(weight64, bytesize64, lifetime64);
if(LL_UCMP(weight64, <, aOptions->mWeightMin64))
{
continue;
}
else if(LL_UCMP(weight64, >, aOptions->mWeightMax64))
if(LL_UCMP(weight64, <, aOptions->mWeightMin64) ||
LL_UCMP(weight64, >, aOptions->mWeightMax64))
{
continue;
}
@ -1002,7 +1023,9 @@ int harvestRun(const STRun* aInRun, STRun* aOutRun, STOptions* aOptions, STConte
{
if('\0' != aOptions->mRestrictText[looper][0])
{
if(0 == hasCallsiteMatch(current->mEvents[0].mCallsite, aOptions->mRestrictText[looper], ST_FOLLOW_PARENTS))
if(0 == hasCallsiteMatch(current->mEvents[0].mCallsite,
aOptions->mRestrictText[looper],
ST_FOLLOW_PARENTS))
{
break;
}
@ -2312,16 +2335,16 @@ void htmlCallsiteAnchor(STRequest* inRequest, tmcallsite* aCallsite, const char*
{
char lxrHREFBuf[512];
PR_snprintf(lxrHREFBuf, sizeof(lxrHREFBuf), "<a href=\"http://lxr.mozilla.org/mozilla/source/%s#%u\" class=\"lxr\" target=\"_st_lxr\">(%s:%u)</a>", namesite->method->sourcefile + 8, namesite->method->linenumber, sourceFile, namesite->method->linenumber);
PR_snprintf(lxrHREFBuf, sizeof(lxrHREFBuf), " [<a href=\"http://lxr.mozilla.org/mozilla/source/%s#%u\" class=\"lxr\" target=\"_st_lxr\">%s:%u</a>]", namesite->method->sourcefile + 8, namesite->method->linenumber, sourceFile, namesite->method->linenumber);
PR_snprintf(textBuf, sizeof(textBuf), "<span class=\"source mozilla-source\">%s</span>%s", methodName, lxrHREFBuf);
}
else if(NULL != sourceFile)
{
PR_snprintf(textBuf, sizeof(textBuf), "<span class=\"source external-source\">%s<span class=\"source-extra\">(%s:%u)</span></span>", methodName, sourceFile, namesite->method->linenumber);
PR_snprintf(textBuf, sizeof(textBuf), "<span class=\"source external-source\">%s [<span class=\"source-extra\">%s:%u</span>]</span>", methodName, sourceFile, namesite->method->linenumber);
}
else
{
PR_snprintf(textBuf, sizeof(textBuf), "<span class=\"source binary-source\">%s<span class=\"source-extra\">+%u(%u)</span></span>", methodName, namesite->offset, (PRUint32)namesite->entry.key);
PR_snprintf(textBuf, sizeof(textBuf), "<span class=\"source binary-source\">%s [<span class=\"source-extra\">+%u(%u)</span>]</span>", methodName, namesite->offset, (PRUint32)namesite->entry.key);
}
aText = textBuf;
@ -2352,7 +2375,8 @@ void htmlHeader(STRequest* inRequest, const char* aTitle)
"</head>\n"
"<body>\n"
"<div class=spacetrace-header>\n"
"<div class=navigate>\n"
"<span class=spacetrace-title>Spacetrace</span>"
"<span class=navigate>\n"
"<span class=\"category-title header-text\">Category:</span>\n"
"<span class=\"current-category\">%s</span>\n",
aTitle,
@ -2364,9 +2388,9 @@ void htmlHeader(STRequest* inRequest, const char* aTitle)
PR_fprintf(inRequest->mFD,"<span class=\"header-item\">");
htmlAnchor(inRequest, "options.html", "Options", NULL, "header-menuitem", &inRequest->mOptions);
PR_fprintf(inRequest->mFD,"</span>\n");
PR_fprintf(inRequest->mFD,"</span>\n");
PR_fprintf(inRequest->mFD,"</div>\n");
PR_fprintf(inRequest->mFD,"</span>\n"); /* class=navigate */
PR_fprintf(inRequest->mFD, "</div>\n<div class=\"header-separator\"></div>\n");
}
@ -5660,7 +5684,7 @@ void handleClient(void* inArg)
** mime type, otherwise, say it is text/html.
*/
PR_fprintf(aFD, "HTTP/1.1 200 OK%s", crlf);
PR_fprintf(aFD, "Server: %s%s", "$Id: spacetrace.c,v 1.42 2003-05-22 20:59:55 alecf%flett.org Exp $", crlf);
PR_fprintf(aFD, "Server: %s%s", "$Id: spacetrace.c,v 1.43 2003-06-04 20:15:07 alecf%flett.org Exp $", crlf);
PR_fprintf(aFD, "Content-type: ");
if(NULL != strstr(start, ".png"))
{

View File

@ -1,16 +1,25 @@
body {
margin: 0px;
padding: 0px;
font: Arial, sans-serif;
}
/* header stuff */
.spacetrace-header {
color: white;
background: green;
min-height: 2em;
/* min-height: 2em; */
}
.spacetrace-title {
font-size: x-large;
font-weight: bold;
padding: 0.5em;
}
.navigate {
background: lightgrey;
/* background: lightgrey; */
color: black;
position: absolute;
right: 0px;
margin: 0px;
@ -18,8 +27,11 @@ body {
}
.header-item {
border: 2px outset;
border: 1px outset;
color: ButtonText;
background: ButtonFace;
margin: 0px;
padding: 2px;
}
.header-item > a {

View File

@ -43,6 +43,10 @@
#endif
#include "prlog.h"
#include "plhash.h"
/* make sure this happens before tmreader.h */
#define PL_ARENA_CONST_ALIGN_MASK 2
#include "plarena.h"
#include "prnetdb.h"
#include "nsTraceMalloc.h"
#include "tmreader.h"
@ -274,31 +278,37 @@ static int get_tmevent(FILE *fp, tmevent *event)
return 1;
}
static void *arena_alloc(void* pool, PRSize size)
{
PLArenaPool* arena = (PLArenaPool*)pool;
void* result;
PL_ARENA_ALLOCATE(result, arena, size);
memset(result, 0, size);
return result;
}
static void *generic_alloctable(void *pool, PRSize size)
{
return malloc(size);
return arena_alloc(pool, size);
}
static void generic_freetable(void *pool, void *item)
{
free(item);
/* do nothing - arena-allocated */
}
static PLHashEntry *filename_allocentry(void *pool, const void *key)
{
return calloc(1, sizeof(PLHashEntry));
return (PLHashEntry*)arena_alloc(pool, sizeof(PLHashEntry));
}
static PLHashEntry *callsite_allocentry(void *pool, const void *key)
{
return calloc(1, sizeof(tmcallsite));
return (PLHashEntry*)arena_alloc(pool, sizeof(tmcallsite));
}
static PLHashEntry *graphnode_allocentry(void *pool, const void *key)
static init_graphnode(tmgraphnode* node)
{
tmgraphnode *node = (tmgraphnode*) malloc(sizeof(tmgraphnode));
if (!node)
return NULL;
node->in = node->out = NULL;
node->up = node->down = node->next = NULL;
node->low = 0;
@ -308,14 +318,19 @@ static PLHashEntry *graphnode_allocentry(void *pool, const void *key)
node->frees.calls.direct = node->frees.calls.total = 0;
node->sqsum = 0;
node->sort = -1;
}
static PLHashEntry *graphnode_allocentry(void *pool, const void *key)
{
tmgraphnode* node = (tmgraphnode*)arena_alloc(pool, sizeof(tmgraphnode));
if (!node)
return NULL;
init_graphnode(node);
return &node->entry;
}
static PLHashEntry *method_allocentry(void *pool, const void *key)
static void init_method(tmmethodnode *node)
{
tmmethodnode *node = (tmmethodnode*) malloc(sizeof(tmmethodnode));
if (!node)
return NULL;
node->graphnode.in = node->graphnode.out = NULL;
node->graphnode.up = node->graphnode.down = node->graphnode.next = NULL;
node->graphnode.low = 0;
@ -327,6 +342,15 @@ static PLHashEntry *method_allocentry(void *pool, const void *key)
node->graphnode.sort = -1;
node->sourcefile = NULL;
node->linenumber = 0;
}
static PLHashEntry *method_allocentry(void *pool, const void *key)
{
tmmethodnode *node =
(tmmethodnode*) arena_alloc(pool, sizeof(tmmethodnode));
if (!node)
return NULL;
init_method(node);
return &node->graphnode.entry;
}
@ -334,10 +358,11 @@ static void graphnode_freeentry(void *pool, PLHashEntry *he, PRUintn flag)
{
/* Always free the value, which points to a strdup'd string. */
free(he->value);
#if 0 /* using arenas now, no freeing! */
/* Free the whole thing if we're told to. */
if (flag == HT_FREE_ENTRY)
free((void*) he);
#endif
}
static void component_freeentry(void *pool, PLHashEntry *he, PRUintn flag)
@ -347,7 +372,9 @@ static void component_freeentry(void *pool, PLHashEntry *he, PRUintn flag)
/* Free the key, which was strdup'd (N.B. value also points to it). */
free((void*) tmcomponent_name(comp));
#if 0 /* using arenas now, no freeing! */
free((void*) comp);
#endif
}
}
@ -390,22 +417,23 @@ tmreader *tmreader_new(const char *program, void *data)
return NULL;
tmr->program = program;
tmr->data = data;
PL_INIT_ARENA_POOL(&tmr->arena, "TMReader", 256*1024);
tmr->libraries = PL_NewHashTable(100, hash_serial, PL_CompareValues,
PL_CompareStrings, &graphnode_hashallocops,
NULL);
&tmr->arena);
tmr->filenames = PL_NewHashTable(100, hash_serial, PL_CompareValues,
PL_CompareStrings, &filename_hashallocops,
NULL);
&tmr->arena);
tmr->components = PL_NewHashTable(10000, PL_HashString, PL_CompareStrings,
PL_CompareValues, &component_hashallocops,
NULL);
&tmr->arena);
tmr->methods = PL_NewHashTable(10000, hash_serial, PL_CompareValues,
PL_CompareStrings, &method_hashallocops,
NULL);
&tmr->arena);
tmr->callsites = PL_NewHashTable(200000, hash_serial, PL_CompareValues,
PL_CompareValues, &callsite_hashallocops,
NULL);
&tmr->arena);
tmr->calltree_root.entry.value = (void*) strdup("root");
if (!tmr->libraries || !tmr->components || !tmr->methods ||
@ -429,6 +457,7 @@ void tmreader_destroy(tmreader *tmr)
PL_HashTableDestroy(tmr->methods);
if (tmr->callsites)
PL_HashTableDestroy(tmr->callsites);
PL_FinishArenaPool(&tmr->arena);
free(tmr);
}
@ -669,12 +698,12 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
size = event.u.alloc.size;
oldsize = event.u.alloc.oldsize;
delta = (double)size - (double)oldsize;
site->allocs.bytes.direct += delta;
site->allocs.bytes.direct += (unsigned long)delta;
if (event.type != TM_EVENT_REALLOC)
site->allocs.calls.direct++;
meth = site->method;
if (meth) {
meth->graphnode.allocs.bytes.direct += delta;
meth->graphnode.allocs.bytes.direct += (unsigned long)delta;
sqdelta = delta * delta;
if (event.type == TM_EVENT_REALLOC) {
sqszdelta = ((double)size * size)
@ -686,7 +715,7 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
}
comp = meth->graphnode.up;
if (comp) {
comp->allocs.bytes.direct += delta;
comp->allocs.bytes.direct += (unsigned long)delta;
if (event.type == TM_EVENT_REALLOC) {
comp->sqsum += sqszdelta;
} else {
@ -695,7 +724,7 @@ int tmreader_eventloop(tmreader *tmr, const char *filename,
}
lib = comp->up;
if (lib) {
lib->allocs.bytes.direct += delta;
lib->allocs.bytes.direct += (unsigned long)delta;
if (event.type == TM_EVENT_REALLOC) {
lib->sqsum += sqszdelta;
} else {

View File

@ -38,6 +38,7 @@
#include "prtypes.h"
#include "plhash.h"
#include "nsTraceMalloc.h"
#include "plarena.h"
PR_BEGIN_EXTERN_C
@ -168,6 +169,7 @@ struct tmreader {
PLHashTable *components;
PLHashTable *methods;
PLHashTable *callsites;
PLArenaPool arena;
tmcallsite calltree_root;
uint32 ticksPerSec;
};