Fixes and improvements for property instrumentation (411630, r=igor).

* Menu of -D flags for enabling instrumentation, as a commented-out CFLAGS +=
  setting for convenient testing.
* js_FindProperty and js_LookupPropertyWithFlags return indexes into the scope
  and prototype chains, respectively, to support internal instrumentation, and
  to pave the way for the return of the property cache (bug 365851)..
* jsutil.[ch] JSBasicStats struct and functions for computing mean/sigma/max
  and auto-scaling histogram.
* JS_SCOPE_DEPTH_METER instrumentation for compile- and run-time scope chain
  length instrumentation:
+ At compile time, rt->hostenvScopeDepthStats and rt->lexicalScopeDepthStats
  meter scope chains passed into the compile and evaluate APIs.
+ At runtime, rt->protoLookupDepthStats and rt->scopeSearchDepthStats track
  steps along the prototype and scope chains until the sought-after property
  is found.
* JS_ARENAMETER uses JSBasicStats now.
* Added rt->liveScopePropsPreSweep to fix the property tree stats code that
  rotted when property tree sweeping moved to after the finalization phase.
* Un-bitrotted some DEBUG_brendan code, turned some off for myself via XXX.
* Mac OS X toolchain requires initialized data shared across dynamic library
  member files, outlaws common data, so initialize extern metering vars.
* Old HASHMETER code in jshash.[ch] is now JS_HASHMETER-controlled and based
  on JSBasicStats.
* DEBUG_scopemeters macro renamed JS_DUMP_SCOPE_METERS; uses JSBasicStats now.
* Disentangle DEBUG and DUMP_SCOPE_STATS (now JS_DUMP_PROPTREE_STATS) and fix
  inconsistent thread safety for liveScopeProps (sometimes atomic-incremented,
  sometimes runtime-locked).
* Compiler-modeled maxScopeDepth will propagate via JSScript to runtime for
  capability-based, interpreter-inlined cache hit qualifier bits, to bypass
  scope and prototype chain lookup by optimizing for common monomorphic get,
  set, and call site referencing a prototype property in a well-named object
  (no shadowing or mutation in 99.9% of the cases).


git-svn-id: svn://10.0.0.236/trunk@242973 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
brendan%mozilla.org 2008-01-13 00:31:32 +00:00
parent 71ef3532f5
commit efa68f7304
21 changed files with 448 additions and 245 deletions

View File

@ -82,6 +82,7 @@ endif
#
# XCFLAGS may be set in the environment or on the gmake command line
#
#CFLAGS += -DDEBUG -DDEBUG_brendan -DJS_ARENAMETER -DJS_HASHMETER -DJS_DUMP_PROPTREE_STATS -DJS_DUMP_SCOPE_METERS -DJS_SCOPE_DEPTH_METER -DJS_BASIC_STATS
CFLAGS += $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS)
LDFLAGS = $(XLDFLAGS)

View File

@ -1567,7 +1567,7 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
atom = js_Atomize(cx, bytes, JS_GetStringLength(str), 0);
if (!atom)
return JS_FALSE;
if (!js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop))
if (js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &obj2, &prop) < 0)
return JS_FALSE;
if (prop) {
OBJ_DROP_PROPERTY(cx, obj2, prop);

View File

@ -3388,7 +3388,7 @@ JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
return JS_FALSE;
ok = OBJ_IS_NATIVE(obj)
? js_LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(atom), flags,
&obj2, &prop)
&obj2, &prop) >= 0
: OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop);
if (ok)
*vp = LookupResult(cx, obj, obj2, prop);
@ -4693,6 +4693,17 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj,
fun = NULL;
}
#ifdef JS_SCOPE_DEPTH_METER
if (fun && obj) {
JSObject *pobj = obj;
uintN depth = 1;
while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
++depth;
JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
}
#endif
out:
LAST_FRAME_CHECKS(cx, fun);
return fun;

View File

@ -419,8 +419,10 @@ JS_FinishArenaPool(JSArenaPool *pool)
{
JSArenaStats *stats, **statsp;
if (pool->stats.name)
if (pool->stats.name) {
free(pool->stats.name);
pool->stats.name = NULL;
}
for (statsp = &arena_stats_list; (stats = *statsp) != 0;
statsp = &stats->next) {
if (stats == &pool->stats) {
@ -483,30 +485,17 @@ JS_ArenaCountRetract(JSArenaPool *pool, char *mark)
pool->stats.nfastrels++;
}
#include <math.h>
#include <stdio.h>
JS_PUBLIC_API(void)
JS_DumpArenaStats(FILE *fp)
{
JSArenaStats *stats;
uint32 nallocs, nbytes;
double mean, variance, sigma;
double mean, sigma;
for (stats = arena_stats_list; stats; stats = stats->next) {
nallocs = stats->nallocs;
if (nallocs != 0) {
nbytes = stats->nbytes;
mean = (double)nbytes / nallocs;
variance = stats->variance * nallocs - nbytes * nbytes;
if (variance < 0 || nallocs == 1)
variance = 0;
else
variance /= nallocs * (nallocs - 1);
sigma = sqrt(variance);
} else {
mean = variance = sigma = 0;
}
mean = JS_MeanAndStdDev(stats->nallocs, stats->nbytes, stats->variance,
&sigma);
fprintf(fp, "\n%s allocation statistics:\n", stats->name);
fprintf(fp, " number of arenas: %u\n", stats->narenas);

View File

@ -383,7 +383,7 @@ struct JSRuntime {
/* Literal table maintained by jsatom.c functions. */
JSAtomState atomState;
#ifdef DEBUG
#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
/* Function invocation metering. */
jsrefcount inlineCalls;
jsrefcount nativeCalls;
@ -398,8 +398,8 @@ struct JSRuntime {
jsrefcount liveScopes;
jsrefcount sharedScopes;
jsrefcount totalScopes;
jsrefcount badUndependStrings;
jsrefcount liveScopeProps;
jsrefcount liveScopePropsPreSweep;
jsrefcount totalScopeProps;
jsrefcount livePropTreeNodes;
jsrefcount duplicatePropTreeNodes;
@ -412,10 +412,27 @@ struct JSRuntime {
jsrefcount totalStrings;
jsrefcount liveDependentStrings;
jsrefcount totalDependentStrings;
jsrefcount badUndependStrings;
double lengthSum;
double lengthSquaredSum;
double strdepLengthSum;
double strdepLengthSquaredSum;
#endif /* DEBUG || JS_DUMP_PROPTREE_STATS */
#ifdef JS_SCOPE_DEPTH_METER
/*
* Stats on runtime prototype chain lookups and scope chain depths, i.e.,
* counts of objects traversed on a chain until the wanted id is found.
*/
JSBasicStats protoLookupDepthStats;
JSBasicStats scopeSearchDepthStats;
/*
* Stats on compile-time host environment and lexical scope chain lengths
* (maximum depths).
*/
JSBasicStats hostenvScopeDepthStats;
JSBasicStats lexicalScopeDepthStats;
#endif
};

View File

@ -871,8 +871,10 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
if (growth) {
#ifdef DEBUG_brendan
JSTokenStream *ts = &cg->treeContext.parseContext->tokenStream;
printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",
cg->filename ? cg->filename : "stdin", cg->firstLine,
ts->filename ? ts->filename : "stdin", cg->firstLine,
growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps,
passes, offset + growth, offset, growth);
#endif
@ -1499,8 +1501,10 @@ js_PopStatement(JSTreeContext *tc)
tc->topStmt = stmt->down;
if (STMT_LINKS_SCOPE(stmt)) {
tc->topScopeStmt = stmt->downScope;
if (stmt->flags & SIF_SCOPE)
if (stmt->flags & SIF_SCOPE) {
tc->blockChain = STOBJ_GET_PARENT(stmt->u.blockObj);
--tc->scopeDepth;
}
}
}
@ -3905,7 +3909,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
return !(pn->pn_extra & PNX_POPVAR) || js_Emit1(cx, cg, JSOP_POP) >= 0;
}
#if defined DEBUG_brendan || defined DEBUG_mrbkap
#if defined DEBUG_brendanXXX || defined DEBUG_mrbkap
static JSBool
GettableNoteForNextOp(JSCodeGenerator *cg)
{
@ -3982,6 +3986,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
cg->codePool, cg->notePool,
pn->pn_pos.begin.lineno);
cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION);
cg2->treeContext.maxScopeDepth = pn->pn_sclen;
fun = GET_FUNCTION_PRIVATE(cx, pn->pn_funpob->object);
cg2->treeContext.fun = fun;
cg2->parent = cg;
@ -5952,7 +5957,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
(!(stmt = stmtInfo.down)
? !(cg->treeContext.flags & TCF_IN_FUNCTION)
: stmt->type == STMT_BLOCK)) {
#if defined DEBUG_brendan || defined DEBUG_mrbkap
#if defined DEBUG_brendanXXX || defined DEBUG_mrbkap
/* There must be no source note already output for the next op. */
JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||

View File

@ -163,6 +163,8 @@ struct JSTreeContext { /* tree context for semantic checks */
uint16 ngvars; /* max. no. of global variables/regexps */
uint32 globalUses; /* optimizable global var uses in total */
uint32 loopyGlobalUses;/* optimizable global var uses in loops */
uint16 scopeDepth; /* current lexical scope chain depth */
uint16 maxScopeDepth; /* maximum lexical scope chain depth */
JSStmtInfo *topStmt; /* top of statement info stack */
JSStmtInfo *topScopeStmt; /* top lexical scope statement */
JSObject *blockChain; /* compile time block scope chain (NB: one
@ -207,6 +209,7 @@ struct JSTreeContext { /* tree context for semantic checks */
#define TREE_CONTEXT_INIT(tc, pc) \
((tc)->flags = (tc)->ngvars = 0, \
(tc)->globalUses = (tc)->loopyGlobalUses = 0, \
(tc)->scopeDepth = (tc)->maxScopeDepth = 0, \
(tc)->topStmt = (tc)->topScopeStmt = NULL, \
(tc)->blockChain = NULL, \
ATOM_LIST_INIT(&(tc)->decls), \

View File

@ -1277,7 +1277,7 @@ static struct GCHist {
JSGCThing *freeList;
} gchist[NGCHIST];
unsigned gchpos;
unsigned gchpos = 0;
#endif
void *
@ -2469,7 +2469,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
/* Reset malloc counter. */
rt->gcMallocBytes = 0;
#ifdef DEBUG_scopemeters
#ifdef JS_DUMP_SCOPE_METERS
{ extern void js_DumpScopeMeters(JSRuntime *rt);
js_DumpScopeMeters(rt);
}
@ -2553,6 +2553,11 @@ restart:
/* Finalize watch points associated with unreachable objects. */
js_SweepWatchPoints(cx);
#ifdef DEBUG
/* Save the pre-sweep count of scope-mapped properties. */
rt->liveScopePropsPreSweep = rt->liveScopeProps;
#endif
/*
* Here we need to ensure that JSObject instances are finalized before GC-
* allocated JSString and jsdouble instances so object's finalizer can
@ -2693,6 +2698,23 @@ restart:
}
#endif
#ifdef JS_SCOPE_DEPTH_METER
{ static FILE *fp;
if (!fp)
fp = fopen("/tmp/scopedepth.stats", "w");
if (fp) {
JS_DumpBasicStats(&rt->protoLookupDepthStats, "proto-lookup depth", fp);
JS_DumpBasicStats(&rt->scopeSearchDepthStats, "scope-search depth", fp);
JS_DumpBasicStats(&rt->hostenvScopeDepthStats, "hostenv scope depth", fp);
JS_DumpBasicStats(&rt->lexicalScopeDepthStats, "lexical scope depth", fp);
putc('\n', fp);
fflush(fp);
}
}
#endif /* JS_SCOPE_DEPTH_METER */
JS_LOCK_GC(rt);
/*

View File

@ -171,7 +171,7 @@ JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
{
JSHashEntry *he, **hep, **hep0;
#ifdef HASHMETER
#ifdef JS_HASHMETER
ht->nlookups++;
#endif
hep = hep0 = BUCKET_HEAD(ht, keyHash);
@ -186,7 +186,7 @@ JS_HashTableRawLookup(JSHashTable *ht, JSHashNumber keyHash, const void *key)
return hep0;
}
hep = &he->next;
#ifdef HASHMETER
#ifdef JS_HASHMETER
ht->nsteps++;
#endif
}
@ -256,7 +256,7 @@ JS_HashTableRawAdd(JSHashTable *ht, JSHashEntry **hep,
if (ht->nentries >= OVERLOADED(n)) {
if (!Resize(ht, ht->shift - 1))
return NULL;
#ifdef HASHMETER
#ifdef JS_HASHMETER
ht->ngrows++;
#endif
hep = JS_HashTableRawLookup(ht, keyHash, key);
@ -309,7 +309,7 @@ JS_HashTableRawRemove(JSHashTable *ht, JSHashEntry **hep, JSHashEntry *he)
n = NBUCKETS(ht);
if (--ht->nentries < UNDERLOADED(n)) {
Resize(ht, ht->shift + 1);
#ifdef HASHMETER
#ifdef JS_HASHMETER
ht->nshrinks++;
#endif
}
@ -396,21 +396,20 @@ out:
return (int)n;
}
#ifdef HASHMETER
#include <math.h>
#ifdef JS_HASHMETER
#include <stdio.h>
JS_PUBLIC_API(void)
JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
{
double sqsum, mean, variance, sigma;
uint32 nchains, nbuckets, nentries;
double sqsum, mean, sigma;
uint32 nchains, nbuckets;
uint32 i, n, maxChain, maxChainLen;
JSHashEntry *he;
sqsum = 0;
nchains = 0;
maxChainLen = 0;
maxChain = maxChainLen = 0;
nbuckets = NBUCKETS(ht);
for (i = 0; i < nbuckets; i++) {
he = ht->buckets[i];
@ -425,14 +424,8 @@ JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
maxChain = i;
}
}
nentries = ht->nentries;
mean = (double)nentries / nchains;
variance = nchains * sqsum - nentries * nentries;
if (variance < 0 || nchains == 1)
variance = 0;
else
variance /= nchains * (nchains - 1);
sigma = sqrt(variance);
mean = JS_MeanAndStdDev(nchains, ht->nentries, sqsum, &sigma);
fprintf(fp, "\nHash table statistics:\n");
fprintf(fp, " number of lookups: %u\n", ht->nlookups);
@ -450,7 +443,7 @@ JS_HashTableDumpMeter(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
if (dump(he, i, fp) != HT_ENUMERATE_NEXT)
break;
}
#endif /* HASHMETER */
#endif /* JS_HASHMETER */
JS_PUBLIC_API(int)
JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
@ -458,7 +451,7 @@ JS_HashTableDump(JSHashTable *ht, JSHashEnumerator dump, FILE *fp)
int count;
count = JS_HashTableEnumerateEntries(ht, dump, fp);
#ifdef HASHMETER
#ifdef JS_HASHMETER
JS_HashTableDumpMeter(ht, dump, fp);
#endif
return count;

View File

@ -91,7 +91,7 @@ struct JSHashTable {
JSHashComparator valueCompare; /* value comparison function */
JSHashAllocOps *allocOps; /* allocation operations */
void *allocPriv; /* allocation private data */
#ifdef HASHMETER
#ifdef JS_HASHMETER
uint32 nlookups; /* total number of lookups */
uint32 nsteps; /* number of hash chains traversed */
uint32 ngrows; /* number of table expansions */

View File

@ -2593,7 +2593,7 @@ interrupt:
* call. See bug 372331.
*/
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop) >= 0;
if (!ok)
goto out;
if (prop)
@ -3184,7 +3184,7 @@ interrupt:
id = ATOM_TO_JSID(atom);
SAVE_SP_AND_PC(fp);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop) >= 0;
if (!ok)
goto out;
@ -3262,7 +3262,7 @@ interrupt:
id = ATOM_TO_JSID(atom);
SAVE_SP_AND_PC(fp);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop) >= 0;
if (!ok)
goto out;
if (!prop)
@ -3927,7 +3927,7 @@ interrupt:
id = ATOM_TO_JSID(atom);
SAVE_SP_AND_PC(fp);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
ok = js_FindProperty(cx, id, &obj, &obj2, &prop) >= 0;
if (!ok)
goto out;
if (!prop) {

View File

@ -2752,8 +2752,8 @@ js_FindClassObject(JSContext *cx, JSObject *start, jsid id, jsval *vp)
}
JS_ASSERT(OBJ_IS_NATIVE(obj));
if (!js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME,
&pobj, &prop)) {
if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME,
&pobj, &prop) < 0) {
return JS_FALSE;
}
v = JSVAL_VOID;
@ -3225,14 +3225,21 @@ JS_FRIEND_API(JSBool)
js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp)
{
return js_LookupPropertyWithFlags(cx, obj, id, 0, objp, propp);
return js_LookupPropertyWithFlags(cx, obj, id, 0, objp, propp) >= 0;
}
JSBool
#ifdef JS_SCOPE_DEPTH_METER
# define SCOPE_DEPTH_ACCUM(bs,val) JS_BASIC_STATS_ACCUM(bs,val)
#else
# define SCOPE_DEPTH_ACCUM(bs,val) /* nothing */
#endif
int
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp)
{
JSObject *start, *obj2, *proto;
int protoIndex;
JSScope *scope;
JSScopeProperty *sprop;
JSClass *clasp;
@ -3255,7 +3262,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JS_COUNT_OPERATION(cx, JSOW_LOOKUP_PROPERTY);
/* Search scopes starting with obj and following the prototype link. */
start = obj;
for (;;) {
for (protoIndex = 0; ; protoIndex++) {
JS_LOCK_OBJ(cx, obj);
scope = OBJ_SCOPE(obj);
if (scope->object == obj) {
@ -3282,7 +3289,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
*/
if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
JS_UNLOCK_OBJ(cx, obj);
return JS_FALSE;
return -1;
}
if (!entry) {
/* Already resolving id in obj -- suppress recursion. */
@ -3380,60 +3387,70 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
cleanup:
js_StopResolving(cx, &key, JSRESFLAG_LOOKUP, entry, generation);
if (!ok || *propp)
return ok;
if (!ok)
return -1;
if (*propp)
return protoIndex;
}
}
if (sprop) {
SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex);
JS_ASSERT(OBJ_SCOPE(obj) == scope);
*objp = scope->object; /* XXXbe hide in jsscope.[ch] */
*propp = (JSProperty *) sprop;
return JS_TRUE;
return protoIndex;
}
proto = LOCKED_OBJ_GET_PROTO(obj);
JS_UNLOCK_OBJ(cx, obj);
if (!proto)
break;
if (!OBJ_IS_NATIVE(proto))
return OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp);
if (!OBJ_IS_NATIVE(proto)) {
if (!OBJ_LOOKUP_PROPERTY(cx, proto, id, objp, propp))
return -1;
return protoIndex;
}
obj = proto;
}
out:
*objp = NULL;
*propp = NULL;
return JS_TRUE;
return protoIndex;
}
JS_FRIEND_API(JSBool)
JS_FRIEND_API(int)
js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
JSProperty **propp)
{
JSRuntime *rt;
JSObject *obj, *pobj, *lastobj;
int scopeIndex;
JSProperty *prop;
rt = cx->runtime;
obj = cx->fp->scopeChain;
scopeIndex = 0;
do {
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
return JS_FALSE;
return -1;
if (prop) {
SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex);
*objp = obj;
*pobjp = pobj;
*propp = prop;
return JS_TRUE;
return scopeIndex;
}
lastobj = obj;
scopeIndex++;
} while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL);
*objp = lastobj;
*pobjp = NULL;
*propp = NULL;
return JS_TRUE;
return scopeIndex;
}
JSObject *
@ -3446,7 +3463,7 @@ js_FindIdentifierBase(JSContext *cx, jsid id)
* Look for id's property along the "with" statement chain and the
* statically-linked scope chain.
*/
if (!js_FindProperty(cx, id, &obj, &pobj, &prop))
if (js_FindProperty(cx, id, &obj, &pobj, &prop) < 0)
return NULL;
if (prop) {
OBJ_DROP_PROPERTY(cx, pobj, prop);
@ -4747,32 +4764,18 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp)
#endif /* JS_HAS_XDR */
#ifdef DEBUG_brendan
#ifdef JS_DUMP_SCOPE_METERS
#include <stdio.h>
#include <math.h>
uint32 js_entry_count_max;
uint32 js_entry_count_sum;
double js_entry_count_sqsum;
uint32 js_entry_count_hist[11];
JSBasicStats js_entry_count_bs = JS_INIT_STATIC_BASIC_STATS;
static void
MeterEntryCount(uintN count)
{
if (count) {
js_entry_count_sum += count;
js_entry_count_sqsum += (double)count * count;
if (count > js_entry_count_max)
js_entry_count_max = count;
}
js_entry_count_hist[JS_MIN(count, 10)]++;
JS_BASIC_STATS_ACCUM(&js_entry_count_bs, count);
}
#define DEBUG_scopemeters
#endif /* DEBUG_brendan */
#ifdef DEBUG_scopemeters
void
js_DumpScopeMeters(JSRuntime *rt)
{
@ -4781,36 +4784,17 @@ js_DumpScopeMeters(JSRuntime *rt)
logfp = fopen("/tmp/scope.stats", "a");
{
double mean = 0., var = 0., sigma = 0.;
double nscopes = rt->liveScopes;
double nentrys = js_entry_count_sum;
if (nscopes > 0 && nentrys >= 0) {
mean = nentrys / nscopes;
var = nscopes * js_entry_count_sqsum - nentrys * nentrys;
if (var < 0.0 || nscopes <= 1)
var = 0.0;
else
var /= nscopes * (nscopes - 1);
double mean, sigma;
/* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
sigma = (var != 0.) ? sqrt(var) : 0.;
}
mean = JS_MeanAndStdDevBS(&js_entry_count_bs, &sigma);
fprintf(logfp,
"scopes %g entries %g mean %g sigma %g max %u",
nscopes, nentrys, mean, sigma, js_entry_count_max);
fprintf(logfp, "scopes %u entries %g mean %g sigma %g max %u",
js_entry_count_bs.num, js_entry_count_bs.sum, mean, sigma,
js_entry_count_bs.max);
}
fprintf(logfp, " histogram %u %u %u %u %u %u %u %u %u %u %u\n",
js_entry_count_hist[0], js_entry_count_hist[1],
js_entry_count_hist[2], js_entry_count_hist[3],
js_entry_count_hist[4], js_entry_count_hist[5],
js_entry_count_hist[6], js_entry_count_hist[7],
js_entry_count_hist[8], js_entry_count_hist[9],
js_entry_count_hist[10]);
js_entry_count_sum = js_entry_count_max = 0;
js_entry_count_sqsum = 0;
memset(js_entry_count_hist, 0, sizeof js_entry_count_hist);
JS_DumpHistogram(&js_entry_count_bs, logfp);
JS_BASIC_STATS_INIT(&js_entry_count_bs);
fflush(logfp);
}
#endif
@ -4887,7 +4871,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
JS_ASSERT(OBJ_IS_NATIVE(obj));
scope = OBJ_SCOPE(obj);
#ifdef DEBUG_brendan
#ifdef JS_DUMP_SCOPE_METERS
if (scope->object == obj)
MeterEntryCount(scope->entryCount);
#endif

View File

@ -1,5 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=80:
* vim: set ts=8 sw=4 et tw=78:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -480,10 +480,10 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
uintN flags, intN shortid, JSProperty **propp);
/*
* Unlike js_DefineProperty, propp must be non-null. On success, and if id was
* Unlike js_DefineProperty, propp must be non-null. On success, and if id was
* found, return true with *objp non-null and locked, and with a held property
* stored in *propp. If successful but id was not found, return true with both
* *objp and *propp null. Therefore all callers who receive a non-null *propp
* stored in *propp. If successful but id was not found, return true with both
* *objp and *propp null. Therefore all callers who receive a non-null *propp
* must later call OBJ_DROP_PROPERTY(cx, *objp, *propp).
*/
extern JS_FRIEND_API(JSBool)
@ -491,13 +491,19 @@ js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp);
/*
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
* Specialized subroutine that allows caller to preset JSRESOLVE_* flags and
* returns the index along the prototype chain in which *propp was found, or
* the last index if not found, or -1 on error.
*/
extern JSBool
extern int
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp);
extern JS_FRIEND_API(JSBool)
/*
* Return the index along the scope chain in which id was found, or the last
* index if not found, or -1 on error.
*/
extern JS_FRIEND_API(int)
js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
JSProperty **propp);

View File

@ -662,6 +662,16 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
#endif
script = js_NewScriptFromCG(cx, &cg);
#ifdef JS_SCOPE_DEPTH_METER
if (script) {
JSObject *pobj = obj;
uintN depth = 1;
while ((pobj = OBJ_GET_PARENT(cx, pobj)) != NULL)
++depth;
JS_BASIC_STATS_ACCUM(&cx->runtime->hostenvScopeDepthStats, depth);
}
#endif
out:
js_FinishCodeGenerator(cx, &cg);
JS_FinishArenaPool(&codePool);
@ -1402,6 +1412,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
pn->pn_op = op;
pn->pn_body = body;
pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS);
pn->pn_sclen = funtc.maxScopeDepth;
TREE_CONTEXT_FINISH(&funtc);
return result;
}
@ -3258,6 +3269,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
stmt->type == STMT_FINALLY);
stmt->downScope = tc->topScopeStmt;
tc->topScopeStmt = stmt;
if (++tc->scopeDepth > tc->maxScopeDepth)
tc->maxScopeDepth = tc->scopeDepth;
} else {
JS_ASSERT(stmt->type == STMT_CATCH);
JS_ASSERT(stmt->downScope);

View File

@ -68,6 +68,7 @@ JS_BEGIN_EXTERN_C
* pn_body: TOK_LC node for function body statements
* pn_flags: TCF_FUN_* flags (see jsemit.h) collected
* while parsing the function's body
* pn_sclen: maximum lexical scope chain length
*
* <Statements>
* TOK_LC list pn_head: list of pn_count statements
@ -279,7 +280,8 @@ struct JSParseNode {
struct { /* TOK_FUNCTION node */
JSParsedObjectBox *funpob; /* function object */
JSParseNode *body; /* TOK_LC list of statements */
uint32 flags; /* accumulated tree context flags */
uint16 flags; /* accumulated tree context flags */
uint16 sclen; /* maximum scope chain length */
} func;
struct { /* list of next-linked nodes */
JSParseNode *head; /* first node in list */
@ -328,6 +330,7 @@ struct JSParseNode {
#define pn_funpob pn_u.func.funpob
#define pn_body pn_u.func.body
#define pn_flags pn_u.func.flags
#define pn_sclen pn_u.func.sclen
#define pn_head pn_u.list.head
#define pn_tail pn_u.list.tail
#define pn_count pn_u.list.count

View File

@ -177,6 +177,13 @@ extern void
js_unlog_scope(JSScope *scope);
#endif
#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
# include "jsprf.h"
# define LIVE_SCOPE_METER(cx,expr) JS_LOCK_RUNTIME_VOID(cx->runtime,expr)
#else
# define LIVE_SCOPE_METER(cx,expr) /* nothing */
#endif
void
js_DestroyScope(JSContext *cx, JSScope *scope)
{
@ -193,15 +200,12 @@ js_DestroyScope(JSContext *cx, JSScope *scope)
if (scope->table)
JS_free(cx, scope->table);
#ifdef DEBUG
JS_LOCK_RUNTIME_VOID(cx->runtime,
cx->runtime->liveScopeProps -= scope->entryCount);
#endif
LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount);
JS_RUNTIME_UNMETER(cx->runtime, liveScopes);
JS_free(cx, scope);
}
#ifdef DUMP_SCOPE_STATS
#ifdef JS_DUMP_PROPTREE_STATS
typedef struct JSScopeStats {
jsrefcount searches;
jsrefcount hits;
@ -222,7 +226,7 @@ typedef struct JSScopeStats {
jsrefcount shrinks;
} JSScopeStats;
JS_FRIEND_DATA(JSScopeStats) js_scope_stats;
JS_FRIEND_DATA(JSScopeStats) js_scope_stats = {0};
# define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x)
#else
@ -1271,10 +1275,12 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
scope->entryCount++;
scope->lastProp = sprop;
CHECK_ANCESTOR_LINE(scope, JS_FALSE);
#ifdef DEBUG
if (!overwriting) {
JS_RUNTIME_METER(cx->runtime, liveScopeProps);
LIVE_SCOPE_METER(cx, ++cx->runtime->liveScopeProps);
JS_RUNTIME_METER(cx->runtime, totalScopeProps);
}
#endif
/*
* If we reach the hashing threshold, try to allocate scope->table.
@ -1396,7 +1402,7 @@ js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
child.attrs, child.flags, child.shortid);
}
#ifdef DUMP_SCOPE_STATS
#ifdef JS_DUMP_PROPTREE_STATS
if (!newsprop)
METER(changeFailures);
#endif
@ -1451,7 +1457,7 @@ js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
*spp = NULL;
}
scope->entryCount--;
JS_RUNTIME_UNMETER(cx->runtime, liveScopeProps);
LIVE_SCOPE_METER(cx, --cx->runtime->liveScopeProps);
/* Update scope->lastProp directly, or set its deferred update flag. */
if (sprop == SCOPE_LAST_PROP(scope)) {
@ -1480,10 +1486,7 @@ void
js_ClearScope(JSContext *cx, JSScope *scope)
{
CHECK_ANCESTOR_LINE(scope, JS_TRUE);
#ifdef DEBUG
JS_LOCK_RUNTIME_VOID(cx->runtime,
cx->runtime->liveScopeProps -= scope->entryCount);
#endif
LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount);
if (scope->table)
free(scope->table);
@ -1501,10 +1504,6 @@ js_TraceId(JSTracer *trc, jsid id)
JS_CALL_VALUE_TRACER(trc, v, "id");
}
#if defined DEBUG || defined DUMP_SCOPE_STATS
# include "jsprf.h"
#endif
#ifdef DEBUG
static void
PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
@ -1558,30 +1557,19 @@ js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop)
#endif /* JS_HAS_GETTER_SETTER */
}
#ifdef DUMP_SCOPE_STATS
#ifdef JS_DUMP_PROPTREE_STATS
#include <stdio.h>
#include <math.h>
uint32 js_nkids_max;
uint32 js_nkids_sum;
double js_nkids_sqsum;
uint32 js_nkids_hist[11];
static void
MeterKidCount(uintN nkids)
MeterKidCount(JSBasicStats *bs, uintN nkids)
{
if (nkids) {
js_nkids_sum += nkids;
js_nkids_sqsum += (double)nkids * nkids;
if (nkids > js_nkids_max)
js_nkids_max = nkids;
}
js_nkids_hist[JS_MIN(nkids, 10)]++;
JS_BASIC_STATS_ACCUM(bs, nkids);
bs->hist[JS_MIN(nkids, 10)]++;
}
static void
MeterPropertyTree(JSScopeProperty *node)
MeterPropertyTree(JSBasicStats *bs, JSScopeProperty *node)
{
uintN i, nkids;
JSScopeProperty *kids, *kid;
@ -1596,17 +1584,17 @@ MeterPropertyTree(JSScopeProperty *node)
kid = chunk->kids[i];
if (!kid)
break;
MeterPropertyTree(kid);
MeterPropertyTree(bs, kid);
nkids++;
}
}
} else {
MeterPropertyTree(kids);
MeterPropertyTree(bs, kids);
nkids = 1;
}
}
MeterKidCount(nkids);
MeterKidCount(bs, nkids);
}
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
@ -1614,8 +1602,9 @@ js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
void *arg)
{
JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr;
JSBasicStats *bs = (JSBasicStats *)arg;
MeterPropertyTree(entry->child);
MeterPropertyTree(bs, entry->child);
return JS_DHASH_NEXT;
}
@ -1636,7 +1625,7 @@ DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
if (JSID_IS_ATOM(sprop->id)) {
str = JSVAL_TO_STRING(v);
} else {
JSASSERT(JSID_IS_OBJECT(sprop->id));
JS_ASSERT(JSID_IS_OBJECT(sprop->id));
str = js_ValueToString(cx, v);
fputs("object ", fp);
}
@ -1646,10 +1635,9 @@ DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
js_FileEscapedString(fp, str, '"');
}
fprintf(fp, " g/s %p/%p slot %lu attrs %x flags %x shortid %d\n",
(void *) sprop->getter, (void *) sprop->setter,
(unsigned long) sprop->slot, sprop->attrs, sprop->flags,
sprop->shortid);
fprintf(fp, " g/s %p/%p slot %u attrs %x flags %x shortid %d\n",
(void *) sprop->getter, (void *) sprop->setter, sprop->slot,
sprop->attrs, sprop->flags, sprop->shortid);
kids = sprop->kids;
if (kids) {
++level;
@ -1671,60 +1659,43 @@ DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
}
}
#endif /* DUMP_SCOPE_STATS */
#endif /* JS_DUMP_PROPTREE_STATS */
void
js_SweepScopeProperties(JSContext *cx)
{
JSRuntime *rt;
JSRuntime *rt = cx->runtime;
JSArena **ap, *a;
JSScopeProperty *limit, *sprop, *parent, *kids, *kid;
uintN liveCount;
PropTreeKidsChunk *chunk, *nextChunk, *freeChunk;
uintN i;
rt = cx->runtime;
#ifdef DUMP_SCOPE_STATS
#ifdef JS_DUMP_PROPTREE_STATS
JSBasicStats bs;
uint32 livePropCapacity = 0, totalLiveCount = 0;
static FILE *logfp;
if (!logfp)
logfp = fopen("/tmp/proptree.stats", "a");
logfp = fopen("/tmp/proptree.stats", "w");
MeterKidCount(rt->propertyTreeHash.entryCount);
JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, NULL);
JS_BASIC_STATS_INIT(&bs);
MeterKidCount(&bs, rt->propertyTreeHash.entryCount);
JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, &bs);
{
double mean = 0.0, var = 0.0, sigma = 0.0;
double nodesum = rt->livePropTreeNodes;
double kidsum = js_nkids_sum;
if (nodesum > 0 && kidsum >= 0) {
mean = kidsum / nodesum;
var = nodesum * js_nkids_sqsum - kidsum * kidsum;
if (var < 0.0 || nodesum <= 1)
var = 0.0;
else
var /= nodesum * (nodesum - 1);
double props, nodes, mean, sigma;
/* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
sigma = (var != 0.0) ? sqrt(var) : 0.0;
}
props = rt->liveScopePropsPreSweep;
nodes = rt->livePropTreeNodes;
JS_ASSERT(nodes == bs.sum);
mean = JS_MeanAndStdDevBS(&bs, &sigma);
fprintf(logfp,
"props %u nodes %g beta %g meankids %g sigma %g max %u",
rt->liveScopeProps, nodesum, nodesum / rt->liveScopeProps,
mean, sigma, js_nkids_max);
"props %g nodes %g beta %g meankids %g sigma %g max %u\n",
props, nodes, nodes / props, mean, sigma, bs.max);
}
fprintf(logfp, " histogram %u %u %u %u %u %u %u %u %u %u %u",
js_nkids_hist[0], js_nkids_hist[1],
js_nkids_hist[2], js_nkids_hist[3],
js_nkids_hist[4], js_nkids_hist[5],
js_nkids_hist[6], js_nkids_hist[7],
js_nkids_hist[8], js_nkids_hist[9],
js_nkids_hist[10]);
js_nkids_sum = js_nkids_max = 0;
js_nkids_sqsum = 0;
memset(js_nkids_hist, 0, sizeof js_nkids_hist);
JS_DumpHistogram(&bs, logfp);
#endif
ap = &rt->propertyArenaPool.first.next;
@ -1842,7 +1813,7 @@ js_SweepScopeProperties(JSContext *cx)
FREENODE_REMOVE(sprop);
JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap);
} else {
#ifdef DUMP_SCOPE_STATS
#ifdef JS_DUMP_PROPTREE_STATS
livePropCapacity += limit - (JSScopeProperty *) a->base;
totalLiveCount += liveCount;
#endif
@ -1850,9 +1821,11 @@ js_SweepScopeProperties(JSContext *cx)
}
}
#ifdef DUMP_SCOPE_STATS
fprintf(logfp, " arenautil %g%%\n",
(totalLiveCount * 100.0) / livePropCapacity);
#ifdef JS_DUMP_PROPTREE_STATS
fprintf(logfp, "arenautil %g%%\n",
(totalLiveCount && livePropCapacity)
? (totalLiveCount * 100.0) / livePropCapacity
: 0.0);
#define RATE(f1, f2) (((double)js_scope_stats.f1 / js_scope_stats.f2) * 100.0)

View File

@ -1451,8 +1451,15 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
fun->u.i.script = script;
if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
fun->flags |= JSFUN_HEAVYWEIGHT;
if (fun->flags & JSFUN_HEAVYWEIGHT)
++cg->treeContext.maxScopeDepth;
}
#ifdef JS_SCOPE_DEPTH_METER
JS_BASIC_STATS_ACCUM(&cx->runtime->lexicalScopeDepthStats,
cg->treeContext.maxScopeDepth);
#endif
/* Tell the debugger about this compiled script. */
js_CallNewScriptHook(cx, script, fun);
return script;

View File

@ -2545,39 +2545,21 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
#ifdef DEBUG
#include <math.h>
void printJSStringStats(JSRuntime *rt) {
double mean = 0., var = 0., sigma = 0.;
jsrefcount count = rt->totalStrings;
if (count > 0 && rt->lengthSum >= 0) {
mean = rt->lengthSum / count;
var = count * rt->lengthSquaredSum - rt->lengthSum * rt->lengthSum;
if (var < 0.0 || count <= 1)
var = 0.0;
else
var /= count * (count - 1);
void printJSStringStats(JSRuntime *rt)
{
double mean, sigma;
mean = JS_MeanAndStdDev(rt->totalStrings, rt->lengthSum,
rt->lengthSquaredSum, &sigma);
/* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
sigma = (var != 0.) ? sqrt(var) : 0.;
}
fprintf(stderr, "%lu total strings, mean length %g (sigma %g)\n",
(unsigned long)count, mean, sigma);
(unsigned long)rt->totalStrings, mean, sigma);
mean = var = sigma = 0.;
count = rt->totalDependentStrings;
if (count > 0 && rt->strdepLengthSum >= 0) {
mean = rt->strdepLengthSum / count;
var = count * rt->strdepLengthSquaredSum
- rt->strdepLengthSum * rt->strdepLengthSum;
if (var < 0.0 || count <= 1)
var = 0.0;
else
var /= count * (count - 1);
mean = JS_MeanAndStdDev(rt->totalDependentStrings, rt->strdepLengthSum,
rt->strdepLengthSquaredSum, &sigma);
/* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
sigma = (var != 0.) ? sqrt(var) : 0.;
}
fprintf(stderr, "%lu total dependent strings, mean length %g (sigma %g)\n",
(unsigned long)count, mean, sigma);
(unsigned long)rt->totalDependentStrings, mean, sigma);
}
#endif
@ -4924,7 +4906,7 @@ Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length)
return ucs4Char;
}
#if defined(DEBUG) || defined(DUMP_SCOPE_STATS)
#if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
JS_FRIEND_API(size_t)
js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp,

View File

@ -63,6 +63,153 @@ JS_PUBLIC_API(void) JS_Assert(const char *s, const char *file, JSIntn ln)
abort();
}
#ifdef JS_BASIC_STATS
#include <math.h>
#include <string.h>
#include "jscompat.h"
#include "jsbit.h"
/*
* Histogram bins count occurrences of values <= the bin label, as follows:
*
* linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more
* 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more
* 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more
*
* We wish to count occurrences of 0 and 1 values separately, always.
*/
static uint32
BinToVal(uintN logscale, uintN bin)
{
JS_ASSERT(bin <= 10);
if (bin <= 1 || logscale == 0)
return bin;
--bin;
if (logscale == 2)
return JS_BIT(bin);
JS_ASSERT(logscale == 10);
return (uint32) pow(10, bin);
}
static uintN
ValToBin(uintN logscale, uint32 val)
{
uintN bin;
if (val <= 1)
return val;
bin = (logscale == 10)
? (uintN) ceil(log10(val))
: (logscale == 2)
? (uintN) JS_CeilingLog2(val)
: val;
return JS_MIN(bin, 10);
}
void
JS_BasicStatsAccum(JSBasicStats *bs, uint32 val)
{
uintN oldscale, newscale, bin;
double mean;
++bs->num;
if (bs->max < val)
bs->max = val;
bs->sum += val;
bs->sqsum += (double)val * val;
oldscale = bs->logscale;
if (oldscale != 10) {
mean = bs->sum / bs->num;
if (bs->max > 16 && mean > 8) {
newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2;
if (newscale != oldscale) {
uint32 newhist[11], newbin;
memset(newhist, 0, sizeof newhist);
for (bin = 0; bin <= 10; bin++) {
newbin = ValToBin(newscale, BinToVal(oldscale, bin));
newhist[newbin] += bs->hist[bin];
}
memcpy(bs->hist, newhist, sizeof bs->hist);
bs->logscale = newscale;
}
}
}
bin = ValToBin(bs->logscale, val);
++bs->hist[bin];
}
double
JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma)
{
double var;
if (num == 0 || sum == 0) {
*sigma = 0;
return 0;
}
var = num * sqsum - sum * sum;
if (var < 0 || num == 1)
var = 0;
else
var /= (double)num * (num - 1);
/* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
*sigma = (var != 0) ? sqrt(var) : 0;
return sum / num;
}
void
JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp)
{
double mean, sigma;
mean = JS_MeanAndStdDevBS(bs, &sigma);
fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n",
title, mean, sigma, (unsigned long) bs->max);
JS_DumpHistogram(bs, fp);
}
void
JS_DumpHistogram(JSBasicStats *bs, FILE *fp)
{
uintN bin;
uint32 cnt, max, prev, val, i;
double sum, mean;
for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) {
cnt = bs->hist[bin];
if (max < cnt)
max = cnt;
sum += cnt;
}
mean = sum / cnt;
for (bin = 0, prev = 0; bin <= 10; bin++, prev = val) {
val = BinToVal(bs->logscale, bin);
cnt = bs->hist[bin];
if (prev + 1 >= val)
fprintf(fp, " [%6u]", val);
else
fprintf(fp, "[%6u, %6u]", prev + 1, val);
fprintf(fp, "%s %8u ", (bin == 10) ? "+" : ":", cnt);
if (cnt != 0) {
if (max > 1e6 && mean > 1e3)
cnt = ceil(log10(cnt));
else if (max > 16 && mean > 8)
cnt = JS_CeilingLog2(cnt);
for (i = 0; i < cnt; i++)
putc('*', fp);
}
putc('\n', fp);
}
}
#endif /* JS_BASIC_STATS */
#if defined DEBUG_notme && defined XP_UNIX
#define __USE_GNU 1

View File

@ -50,20 +50,21 @@ JS_BEGIN_EXTERN_C
extern JS_PUBLIC_API(void)
JS_Assert(const char *s, const char *file, JSIntn ln);
#define JS_ASSERT(_expr) \
((_expr)?((void)0):JS_Assert(# _expr,__FILE__,__LINE__))
#define JS_ASSERT_IF(_cond, _expr) \
(!(_cond) || (_expr)?((void)0):JS_Assert(# _expr,__FILE__,__LINE__))
#define JS_ASSERT(expr) \
((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
#define JS_NOT_REACHED(_reasonStr) \
JS_Assert(_reasonStr,__FILE__,__LINE__)
#define JS_ASSERT_IF(cond, expr) \
((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
#define JS_NOT_REACHED(reason) \
JS_Assert(reason, __FILE__, __LINE__)
#else
#define JS_ASSERT(expr) ((void) 0)
#define JS_ASSERT(expr) ((void) 0)
#define JS_ASSERT_IF(cond,expr) ((void) 0)
#define JS_NOT_REACHED(reasonStr)
#define JS_NOT_REACHED(reason)
#endif /* defined(DEBUG) */
@ -76,12 +77,62 @@ JS_Assert(const char *s, const char *file, JSIntn ln);
extern void js_static_assert(int arg[(condition) ? 1 : -1])
/*
** Abort the process in a non-graceful manner. This will cause a core file,
** call to the debugger or other moral equivalent as well as causing the
** entire process to stop.
*/
* Abort the process in a non-graceful manner. This will cause a core file,
* call to the debugger or other moral equivalent as well as causing the
* entire process to stop.
*/
extern JS_PUBLIC_API(void) JS_Abort(void);
#if 0
# define JS_BASIC_STATS 1
# define JS_SCOPE_DEPTH_METER 1
#endif
#if defined DEBUG && !defined JS_BASIC_STATS
# define JS_BASIC_STATS 1
#endif
#ifdef JS_BASIC_STATS
#include <stdio.h>
typedef struct JSBasicStats {
uint32 num;
uint32 max;
double sum;
double sqsum;
uint32 logscale; /* logarithmic scale: 0 (linear), 2, 10 */
uint32 hist[11];
} JSBasicStats;
#define JS_INIT_STATIC_BASIC_STATS {0,0,0,0,0,{0,0,0,0,0,0,0,0,0,0,0}}
#define JS_BASIC_STATS_INIT(bs) memset((bs), 0, sizeof(JSBasicStats))
#define JS_BASIC_STATS_ACCUM(bs,val) \
JS_BasicStatsAccum(bs, val)
#define JS_MeanAndStdDevBS(bs,sigma) \
JS_MeanAndStdDev((bs)->num, (bs)->sum, (bs)->sqsum, sigma)
extern void
JS_BasicStatsAccum(JSBasicStats *bs, uint32 val);
extern double
JS_MeanAndStdDev(uint32 num, double sum, double sqsum, double *sigma);
extern void
JS_DumpBasicStats(JSBasicStats *bs, const char *title, FILE *fp);
extern void
JS_DumpHistogram(JSBasicStats *bs, FILE *fp);
#else
#define JS_BASIC_STATS_ACCUM(bs,val) /* nothing */
#endif /* JS_BASIC_STATS */
#ifdef XP_UNIX
typedef struct JSCallsite JSCallsite;

View File

@ -86,11 +86,7 @@
* - JS_TypeOfValue sure could use a cleaner interface to "types"
*/
#ifdef DEBUG_brendan
#define METERING 1
#endif
#ifdef METERING
#ifdef XML_METERING
static struct {
jsrefcount qname;
jsrefcount qnameobj;