Bug 413744: JS_GCMETER requires to recompile just js/src, not the whole browser. r,a=brendan

This commit is contained in:
igor@mir2.org 2008-01-29 14:17:25 -08:00
Родитель 6c944d399a
Коммит dbb75e97c2
3 изменённых файлов: 100 добавлений и 95 удалений

Просмотреть файл

@ -210,10 +210,6 @@ struct JSRuntime {
*/
JSPtrTable gcIteratorTable;
#ifdef JS_GCMETER
JSGCStats gcStats;
#endif
/*
* The trace operation and its data argument to trace embedding-specific
* GC roots.
@ -383,6 +379,12 @@ struct JSRuntime {
/* Literal table maintained by jsatom.c functions. */
JSAtomState atomState;
/*
* Various metering fields are defined at the end of JSRuntime. In this
* way there is no need to recompile all the code that refers to other
* fields of JSRuntime after enabling the corresponding metering macro.
*/
#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
/* Function invocation metering. */
jsrefcount inlineCalls;
@ -434,6 +436,10 @@ struct JSRuntime {
JSBasicStats hostenvScopeDepthStats;
JSBasicStats lexicalScopeDepthStats;
#endif
#ifdef JS_GCMETER
JSGCStats gcStats;
#endif
};
#ifdef DEBUG

Просмотреть файл

@ -506,11 +506,16 @@ ShrinkPtrTable(JSPtrTable *table, const JSPtrTableInfo *info,
}
#ifdef JS_GCMETER
# define METER(x) x
# define METER(x) ((void) (x))
# define METER_IF(condition, x) ((void) ((condition) && (x)))
#else
# define METER(x) ((void) 0)
# define METER(x) ((void) 0)
# define METER_IF(condition, x) ((void) 0)
#endif
#define METER_UPDATE_MAX(maxLval, rval) \
METER_IF((maxLval) < (rval), (maxLval) = (rval))
/*
* For chunks allocated via over-sized malloc, get a pointer to store the gap
* between the malloc's result and the first arena in the chunk.
@ -738,7 +743,6 @@ InitGCArenaLists(JSRuntime *rt)
arenaList->lastCount = THINGS_PER_ARENA(thingSize);
arenaList->thingSize = (uint16)thingSize;
arenaList->freeList = NULL;
METER(memset(&arenaList->stats, 0, sizeof arenaList->stats));
}
}
@ -759,7 +763,7 @@ FinishGCArenaLists(JSRuntime *rt)
arenaList->last = NULL;
arenaList->lastCount = THINGS_PER_ARENA(arenaList->thingSize);
arenaList->freeList = NULL;
METER(arenaList->stats.narenas = 0);
METER(rt->gcStats.arenas[i].narenas = 0);
}
rt->gcBytes = 0;
JS_ASSERT(rt->gcChunkList == 0);
@ -899,6 +903,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
*/
rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
return JS_TRUE;
}
@ -911,12 +916,15 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
size_t totalThings, totalMaxThings, totalBytes;
size_t sumArenas, sumTotalArenas;
size_t sumFreeSize, sumTotalFreeSize;
JSGCArenaList *list;
JSGCArenaStats *stats;
fprintf(fp, "\nGC allocation statistics:\n");
#define UL(x) ((unsigned long)(x))
#define ULSTAT(x) UL(rt->gcStats.x)
totalThings = 0;
totalMaxThings = 0;
totalBytes = 0;
sumArenas = 0;
@ -924,8 +932,8 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
sumFreeSize = 0;
sumTotalFreeSize = 0;
for (i = 0; i < GC_NUM_FREELISTS; i++) {
JSGCArenaList *list = &rt->gcArenaList[i];
JSGCArenaStats *stats = &list->stats;
list = &rt->gcArenaList[i];
stats = &rt->gcStats.arenas[i];
if (stats->maxarenas == 0) {
fprintf(fp, "ARENA LIST %u (thing size %lu): NEVER USED\n",
i, UL(GC_FREELIST_NBYTES(i)));
@ -1289,6 +1297,9 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
JSGCThing *thing;
uint8 *flagp;
JSGCArenaList *arenaList;
#ifdef JS_GCMETER
JSGCArenaStats *listStats;
#endif
JSGCArenaInfo *a;
uintN thingsLimit;
JSLocalRootStack *lrs;
@ -1299,13 +1310,13 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
JSGCThing *tmpthing;
uint8 *tmpflagp;
uintN maxFreeThings; /* max to take from the global free list */
METER(size_t nfree);
#endif
rt = cx->runtime;
METER(rt->gcStats.alloc++); /* this is not thread-safe */
nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing));
flindex = GC_FREELIST_INDEX(nbytes);
METER(listStats = &rt->gcStats.arenas[flindex]);
#ifdef JS_THREADSAFE
gcLocked = JS_FALSE;
@ -1366,8 +1377,8 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
arenaList->freeList = thing->next;
flagp = thing->flagp;
JS_ASSERT(*flagp & GCF_FINAL);
METER(arenaList->stats.freelen--);
METER(arenaList->stats.recycle++);
METER(listStats->freelen--);
METER(listStats->recycle++);
#ifdef JS_THREADSAFE
/*
@ -1415,10 +1426,8 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
}
rt->gcBytes += GC_ARENA_SIZE;
METER(++arenaList->stats.narenas);
METER(arenaList->stats.maxarenas
= JS_MAX(arenaList->stats.maxarenas,
arenaList->stats.narenas));
METER(listStats->narenas++);
METER_UPDATE_MAX(listStats->maxarenas, listStats->narenas);
a->list = arenaList;
a->prev = arenaList->last;
@ -1440,12 +1449,11 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
*/
if (rt->gcMallocBytes >= rt->gcMaxMallocBytes || flbase[flindex])
break;
METER(nfree = 0);
lastptr = &flbase[flindex];
maxFreeThings = thingsLimit - arenaList->lastCount;
if (maxFreeThings > MAX_THREAD_LOCAL_THINGS)
maxFreeThings = MAX_THREAD_LOCAL_THINGS;
METER(arenaList->stats.freelen += maxFreeThings);
METER(listStats->freelen += maxFreeThings);
while (maxFreeThings != 0) {
--maxFreeThings;
@ -1503,19 +1511,13 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
if (++gchpos == NGCHIST)
gchpos = 0;
#endif
#ifdef JS_GCMETER
{
JSGCArenaStats *stats = &rt->gcArenaList[flindex].stats;
/* This is not thread-safe for thread-local allocations. */
if (flags & GCF_LOCK)
rt->gcStats.lockborn++;
stats->totalnew++;
stats->nthings++;
if (stats->nthings > stats->maxthings)
stats->maxthings = stats->nthings;
}
#endif
/* This is not thread-safe for thread-local allocations. */
METER_IF(flags & GCF_LOCK, rt->gcStats.lockborn++);
METER(listStats->totalnew++);
METER(listStats->nthings++);
METER_UPDATE_MAX(listStats->maxthings, listStats->nthings);
#ifdef JS_THREADSAFE
if (gcLocked)
JS_UNLOCK_GC(rt);
@ -1748,8 +1750,7 @@ DelayTracingChildren(JSRuntime *rt, uint8 *flagp)
METER(rt->gcStats.untraced++);
#ifdef DEBUG
++rt->gcTraceLaterCount;
METER(if (rt->gcTraceLaterCount > rt->gcStats.maxuntraced)
rt->gcStats.maxuntraced = rt->gcTraceLaterCount);
METER_UPDATE_MAX(rt->gcStats.maxuntraced, rt->gcTraceLaterCount);
#endif
a = FLAGP_TO_ARENA(flagp);
@ -2322,6 +2323,10 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
uint32 requestDebit;
JSContext *acx, *iter;
#endif
#ifdef JS_GCMETER
JSGCArenaStats *listStats;
size_t nfree;
#endif
rt = cx->runtime;
#ifdef JS_THREADSAFE
@ -2372,8 +2377,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
if (rt->gcThread == cx->thread) {
JS_ASSERT(rt->gcLevel > 0);
rt->gcLevel++;
METER(if (rt->gcLevel > rt->gcStats.maxlevel)
rt->gcStats.maxlevel = rt->gcLevel);
METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel);
if (gckind != GC_LAST_DITCH)
JS_UNLOCK_GC(rt);
return;
@ -2423,8 +2427,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
if (rt->gcLevel > 0) {
/* Bump gcLevel to restart the current GC, so it finds new garbage. */
rt->gcLevel++;
METER(if (rt->gcLevel > rt->gcStats.maxlevel)
rt->gcStats.maxlevel = rt->gcLevel);
METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel);
/* Wait for the other thread to finish, then resume our request. */
while (rt->gcLevel > 0)
@ -2448,8 +2451,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
/* Bump gcLevel and return rather than nest; the outer gc will restart. */
rt->gcLevel++;
METER(if (rt->gcLevel > rt->gcStats.maxlevel)
rt->gcStats.maxlevel = rt->gcLevel);
METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel);
if (rt->gcLevel > 1)
return;
@ -2580,23 +2582,25 @@ restart:
JS_ASSERT(arenaList->lastCount > 0);
arenaList->freeList = NULL;
freeList = NULL;
METER(arenaList->stats.nthings = 0);
METER(arenaList->stats.freelen = 0);
/* Here i is not the list index due to the above swap. */
METER(listStats = &rt->gcStats.arenas[arenaList - &rt->gcArenaList[0]]);
METER(listStats->nthings = 0);
METER(listStats->freelen = 0);
thingSize = arenaList->thingSize;
indexLimit = THINGS_PER_ARENA(thingSize);
flagp = THING_FLAGP(a, arenaList->lastCount - 1);
for (;;) {
METER(size_t nfree = 0);
JS_ASSERT(a->prevUntracedPage == 0);
JS_ASSERT(a->untracedThings == 0);
allClear = JS_TRUE;
METER(nfree = 0);
do {
flags = *flagp;
if (flags & (GCF_MARK | GCF_LOCK)) {
*flagp &= ~GCF_MARK;
allClear = JS_FALSE;
METER(++arenaList->stats.nthings);
METER(listStats->nthings++);
} else {
thing = FLAGP_TO_THING(flagp, thingSize);
if (!(flags & GCF_FINAL)) {
@ -2661,9 +2665,9 @@ restart:
} else {
arenaList->freeList = freeList;
ap = &a->prev;
METER(arenaList->stats.freelen += nfree);
METER(arenaList->stats.totalfreelen += nfree);
METER(++arenaList->stats.totalarenas);
METER(listStats->freelen += nfree);
METER(listStats->totalfreelen += nfree);
METER(listStats->totalarenas++);
}
if (!(a = *ap))
break;

Просмотреть файл

@ -256,12 +256,53 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind);
extern void
js_UpdateMallocCounter(JSContext *cx, size_t nbytes);
typedef struct JSGCArenaInfo JSGCArenaInfo;
typedef struct JSGCArenaList JSGCArenaList;
typedef struct JSGCChunkInfo JSGCChunkInfo;
struct JSGCArenaList {
JSGCArenaInfo *last; /* last allocated GC arena */
uint16 lastCount; /* number of allocated things in the last
arena */
uint16 thingSize; /* size of things to allocate on this list
*/
JSGCThing *freeList; /* list of free GC things */
};
struct JSWeakRoots {
/* Most recently created things by type, members of the GC's root set. */
void *newborn[GCX_NTYPES];
/* Atom root for the last-looked-up atom on this context. */
jsval lastAtom;
/* Root for the result of the most recent js_InternalInvoke call. */
jsval lastInternalResult;
};
JS_STATIC_ASSERT(JSVAL_NULL == 0);
#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
#ifdef DEBUG_notme
#define JS_GCMETER 1
#endif
#ifdef JS_GCMETER
typedef struct JSGCArenaStats {
uint32 narenas; /* number of arena in list */
uint32 maxarenas; /* maximun number of allocated arenas */
uint32 nthings; /* number of allocates JSGCThing */
uint32 maxthings; /* maximum number number of allocates JSGCThing */
uint32 totalnew; /* number of succeeded calls to js_NewGCThing */
uint32 freelen; /* freeList lengths */
uint32 recycle; /* number of things recycled through freeList */
uint32 totalarenas; /* total number of arenas with live things that
GC scanned so far */
uint32 totalfreelen; /* total number of things that GC put to free
list so far */
} JSGCArenaStats;
typedef struct JSGCStats {
#ifdef JS_THREADSAFE
uint32 localalloc; /* number of succeeded allocations from local lists */
@ -294,6 +335,8 @@ typedef struct JSGCStats {
uint32 maxnclose; /* max number of objects with close hooks */
uint32 closelater; /* number of close hooks scheduled to run */
uint32 maxcloselater; /* max number of close hooks scheduled to run */
JSGCArenaStats arenas[GC_NUM_FREELISTS];
} JSGCStats;
extern JS_FRIEND_API(void)
@ -301,54 +344,6 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp);
#endif /* JS_GCMETER */
typedef struct JSGCArenaInfo JSGCArenaInfo;
typedef struct JSGCArenaList JSGCArenaList;
typedef struct JSGCChunkInfo JSGCChunkInfo;
#ifdef JS_GCMETER
typedef struct JSGCArenaStats JSGCArenaStats;
struct JSGCArenaStats {
uint32 narenas; /* number of arena in list */
uint32 maxarenas; /* maximun number of allocated arenas */
uint32 nthings; /* number of allocates JSGCThing */
uint32 maxthings; /* maximum number number of allocates JSGCThing */
uint32 totalnew; /* number of succeeded calls to js_NewGCThing */
uint32 freelen; /* freeList lengths */
uint32 recycle; /* number of things recycled through freeList */
uint32 totalarenas; /* total number of arenas with live things that
GC scanned so far */
uint32 totalfreelen; /* total number of things that GC put to free
list so far */
};
#endif
struct JSGCArenaList {
JSGCArenaInfo *last; /* last allocated GC arena */
uint16 lastCount; /* number of allocated things in the last
arena */
uint16 thingSize; /* size of things to allocate on this list
*/
JSGCThing *freeList; /* list of free GC things */
#ifdef JS_GCMETER
JSGCArenaStats stats;
#endif
};
struct JSWeakRoots {
/* Most recently created things by type, members of the GC's root set. */
void *newborn[GCX_NTYPES];
/* Atom root for the last-looked-up atom on this context. */
jsval lastAtom;
/* Root for the result of the most recent js_InternalInvoke call. */
jsval lastInternalResult;
};
JS_STATIC_ASSERT(JSVAL_NULL == 0);
#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots)))
JS_END_EXTERN_C
#endif /* jsgc_h___ */