Bug 497999: collect context-specific TraceVis data in JS objects, r=jorendorff

This commit is contained in:
Mark Steele 2009-07-30 11:48:02 -07:00
Родитель af688b6d08
Коммит 571bfdff48
9 изменённых файлов: 505 добавлений и 18 удалений

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

@ -112,6 +112,7 @@ MOZ_JPROF = @MOZ_JPROF@
MOZ_SHARK = @MOZ_SHARK@
MOZ_CALLGRIND = @MOZ_CALLGRIND@
MOZ_VTUNE = @MOZ_VTUNE@
MOZ_TRACEVIS = @MOZ_TRACEVIS@
DEHYDRA_PATH = @DEHYDRA_PATH@
MOZ_XPCTOOLS = @MOZ_XPCTOOLS@

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

@ -6697,6 +6697,17 @@ MOZ_ARG_WITH_STRING(wrap-malloc,
[ --with-wrap-malloc=DIR Location of malloc wrapper library],
WRAP_MALLOC_LIB=$withval)
dnl ========================================================
dnl = Use TraceVis
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(tracevis,
[ --enable-tracevis Enable TraceVis tracing tool (default=no)],
MOZ_TRACEVIS=1,
MOZ_TRACEVIS= )
if test -n "$MOZ_TRACEVIS"; then
AC_DEFINE(MOZ_TRACEVIS)
fi
dnl ========================================================
dnl = Use Valgrind
dnl ========================================================

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

@ -3269,6 +3269,14 @@ static JSFunctionSpec VtuneFunctions[] = {
};
#endif
#ifdef MOZ_TRACEVIS
static JSFunctionSpec EthogramFunctions[] = {
{"initEthogram", js_InitEthogram, 0, 0, 0},
{"shutdownEthogram", js_ShutdownEthogram, 0, 0, 0},
{nsnull, nsnull, 0, 0, 0}
};
#endif
nsresult
nsJSContext::InitClasses(void *aGlobalObj)
{
@ -3316,6 +3324,11 @@ nsJSContext::InitClasses(void *aGlobalObj)
::JS_DefineFunctions(mContext, globalObj, VtuneFunctions);
#endif
#ifdef MOZ_TRACEVIS
// Attempt to initialize Ethogram functions
::JS_DefineFunctions(mContext, globalObj, EthogramFunctions);
#endif
JSOptionChangedCallback(js_options_dot_str, this);
return rv;

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

@ -2012,3 +2012,435 @@ js_ResumeVtune(JSContext *cx, JSObject *obj,
}
#endif /* MOZ_VTUNE */
#ifdef MOZ_TRACEVIS
/*
* Ethogram - Javascript wrapper for TraceVis state
*
* ethology: The scientific study of animal behavior,
* especially as it occurs in a natural environment.
* ethogram: A pictorial catalog of the behavioral patterns of
* an organism or a species.
*
*/
#if defined(XP_WIN)
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include "jstracer.h"
#define ETHOGRAM_BUF_SIZE 65536
static JSBool
ethogram_construct(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval);
static void
ethogram_finalize(JSContext *cx, JSObject *obj);
static JSClass ethogram_class = {
"Ethogram",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ethogram_finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
struct EthogramEvent {
TraceVisState s;
TraceVisExitReason r;
int ts;
int tus;
JSString *filename;
int lineno;
};
static int
compare_strings(const void *k1, const void *k2)
{
return strcmp((const char *) k1, (const char *) k2) == 0;
}
class EthogramEventBuffer {
private:
EthogramEvent mBuf[ETHOGRAM_BUF_SIZE];
int mReadPos;
int mWritePos;
JSObject *mFilenames;
int mStartSecond;
struct EthogramScriptEntry {
char *filename;
JSString *jsfilename;
EthogramScriptEntry *next;
};
EthogramScriptEntry *mScripts;
public:
friend JSBool
ethogram_construct(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval);
inline void push(TraceVisState s, TraceVisExitReason r, char *filename, int lineno) {
mBuf[mWritePos].s = s;
mBuf[mWritePos].r = r;
#if defined(XP_WIN)
FILETIME now;
GetSystemTimeAsFileTime(&now);
unsigned long long raw_us = 0.1 *
(((unsigned long long) now.dwHighDateTime << 32ULL) |
(unsigned long long) now.dwLowDateTime);
unsigned int sec = raw_us / 1000000L;
unsigned int usec = raw_us % 1000000L;
mBuf[mWritePos].ts = sec - mStartSecond;
mBuf[mWritePos].tus = usec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
mBuf[mWritePos].ts = tv.tv_sec - mStartSecond;
mBuf[mWritePos].tus = tv.tv_usec;
#endif
JSString *jsfilename = findScript(filename);
mBuf[mWritePos].filename = jsfilename;
mBuf[mWritePos].lineno = lineno;
mWritePos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE;
if (mWritePos == mReadPos) {
mReadPos = (mWritePos + 1) % ETHOGRAM_BUF_SIZE;
}
}
inline EthogramEvent *pop() {
EthogramEvent *e = &mBuf[mReadPos];
mReadPos = (mReadPos + 1) % ETHOGRAM_BUF_SIZE;
return e;
}
bool isEmpty() {
return (mReadPos == mWritePos);
}
EthogramScriptEntry *addScript(JSContext *cx, JSObject *obj, char *filename, JSString *jsfilename) {
JSHashNumber hash = JS_HashString(filename);
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
if (*hep != NULL)
return JS_FALSE;
JS_HashTableRawAdd(traceVisScriptTable, hep, hash, filename, this);
EthogramScriptEntry * entry = (EthogramScriptEntry *) JS_malloc(cx, sizeof(EthogramScriptEntry));
if (entry == NULL)
return NULL;
entry->next = mScripts;
mScripts = entry;
entry->filename = filename;
entry->jsfilename = jsfilename;
return mScripts;
}
void removeScripts(JSContext *cx) {
EthogramScriptEntry *se = mScripts;
while (se != NULL) {
char *filename = se->filename;
JSHashNumber hash = JS_HashString(filename);
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, filename);
JSHashEntry *he = *hep;
if (he) {
/* we hardly knew he */
JS_HashTableRawRemove(traceVisScriptTable, hep, he);
}
EthogramScriptEntry *se_head = se;
se = se->next;
JS_free(cx, se_head);
}
}
JSString *findScript(char *filename) {
EthogramScriptEntry *se = mScripts;
while (se != NULL) {
if (compare_strings(se->filename, filename))
return (se->jsfilename);
se = se->next;
}
return NULL;
}
JSObject *filenames() {
return mFilenames;
}
int length() {
if (mWritePos < mReadPos)
return (mWritePos + ETHOGRAM_BUF_SIZE) - mReadPos;
else
return mWritePos - mReadPos;
}
};
static char jstv_empty[] = "<null>";
inline char *
jstv_Filename(JSStackFrame *fp)
{
while (fp && fp->script == NULL)
fp = fp->down;
return (fp && fp->script && fp->script->filename)
? (char *)fp->script->filename
: jstv_empty;
}
inline uintN
jstv_Lineno(JSContext *cx, JSStackFrame *fp)
{
while (fp && fp->regs == NULL)
fp = fp->down;
return (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
}
/* Collect states here and distribute to a matching buffer, if any */
JS_FRIEND_API(void)
js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
{
JSStackFrame *fp = cx->fp;
char *script_file = jstv_Filename(fp);
JSHashNumber hash = JS_HashString(script_file);
JSHashEntry **hep = JS_HashTableRawLookup(traceVisScriptTable, hash, script_file);
/* update event buffer, flag if overflowed */
JSHashEntry *he = *hep;
if (he) {
EthogramEventBuffer *p;
p = (EthogramEventBuffer *) he->value;
p->push(s, r, script_file, jstv_Lineno(cx, fp));
}
}
static JSBool
ethogram_construct(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
EthogramEventBuffer *p;
p = (EthogramEventBuffer *) JS_malloc(cx, sizeof(EthogramEventBuffer));
p->mReadPos = p->mWritePos = 0;
p->mScripts = NULL;
p->mFilenames = JS_NewArrayObject(cx, 0, NULL);
#if defined(XP_WIN)
FILETIME now;
GetSystemTimeAsFileTime(&now);
unsigned long long raw_us = 0.1 *
(((unsigned long long) now.dwHighDateTime << 32ULL) |
(unsigned long long) now.dwLowDateTime);
unsigned int s = raw_us / 1000000L;
p->mStartSecond = s;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
p->mStartSecond = tv.tv_sec;
#endif
jsval filenames = OBJECT_TO_JSVAL(p->filenames());
if (!JS_DefineProperty(cx, obj, "filenames", filenames,
NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT))
return JS_FALSE;
if (!JS_IsConstructing(cx)) {
obj = JS_NewObject(cx, &ethogram_class, NULL, NULL);
if (!obj)
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(obj);
}
JS_SetPrivate(cx, obj, p);
return JS_TRUE;
}
static void
ethogram_finalize(JSContext *cx, JSObject *obj)
{
EthogramEventBuffer *p;
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, NULL);
if (!p)
return;
p->removeScripts(cx);
JS_free(cx, p);
}
static JSBool
ethogram_addScript(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
JSString *str;
char *filename = NULL;
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]);
filename = js_DeflateString(cx,
str->chars(),
str->length());
}
/* silently ignore no args */
if (!filename)
return JS_TRUE;
EthogramEventBuffer *p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
p->addScript(cx, obj, filename, str);
JS_CallFunctionName(cx, p->filenames(), "push", 1, argv, rval);
return JS_TRUE;
}
static JSBool
ethogram_getAllEvents(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
EthogramEventBuffer *p;
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
if (!p)
return JS_FALSE;
if (p->isEmpty()) {
*rval = JSVAL_NULL;
return JS_TRUE;
}
JSObject *rarray = JS_NewArrayObject(cx, 0, NULL);
if (rarray == NULL) {
*rval = JSVAL_NULL;
return JS_TRUE;
}
*rval = OBJECT_TO_JSVAL(rarray);
for (int i = 0; !p->isEmpty(); i++) {
JSObject *x = JS_NewObject(cx, NULL, NULL, NULL);
if (x == NULL)
return JS_FALSE;
EthogramEvent *e = p->pop();
jsval state = INT_TO_JSVAL(e->s);
jsval reason = INT_TO_JSVAL(e->r);
jsval ts = INT_TO_JSVAL(e->ts);
jsval tus = INT_TO_JSVAL(e->tus);
jsval filename = STRING_TO_JSVAL(e->filename);
jsval lineno = INT_TO_JSVAL(e->lineno);
if (!JS_SetProperty(cx, x, "state", &state))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "reason", &reason))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "ts", &ts))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "tus", &tus))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "filename", &filename))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "lineno", &lineno))
return JS_FALSE;
jsval element = OBJECT_TO_JSVAL(x);
JS_SetElement(cx, rarray, i, &element);
}
return JS_TRUE;
}
static JSBool
ethogram_getNextEvent(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
EthogramEventBuffer *p;
p = (EthogramEventBuffer *) JS_GetInstancePrivate(cx, obj, &ethogram_class, argv);
if (!p)
return JS_FALSE;
JSObject *x = JS_NewObject(cx, NULL, NULL, NULL);
if (x == NULL)
return JS_FALSE;
if (p->isEmpty()) {
*rval = JSVAL_NULL;
return JS_TRUE;
}
EthogramEvent *e = p->pop();
jsval state = INT_TO_JSVAL(e->s);
jsval reason = INT_TO_JSVAL(e->r);
jsval ts = INT_TO_JSVAL(e->ts);
jsval tus = INT_TO_JSVAL(e->tus);
jsval filename = STRING_TO_JSVAL(e->filename);
jsval lineno = INT_TO_JSVAL(e->lineno);
if (!JS_SetProperty(cx, x, "state", &state))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "reason", &reason))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "ts", &ts))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "tus", &tus))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "filename", &filename))
return JS_FALSE;
if (!JS_SetProperty(cx, x, "lineno", &lineno))
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(x);
return JS_TRUE;
}
static JSFunctionSpec ethogram_methods[] = {
{"addScript", ethogram_addScript, 1},
{"getAllEvents", ethogram_getAllEvents, 0},
{"getNextEvent", ethogram_getNextEvent, 0},
{0}
};
/*
* An |Ethogram| organizes the output of a collection of files that should be
* monitored together. A single object gets events for the group.
*/
JS_FRIEND_API(JSBool)
js_InitEthogram(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
if (!traceVisScriptTable) {
traceVisScriptTable = JS_NewHashTable(8, JS_HashString, compare_strings,
NULL, NULL, NULL);
}
JS_InitClass(cx, JS_GetGlobalObject(cx), NULL, &ethogram_class,
ethogram_construct, 0, NULL, ethogram_methods,
NULL, NULL);
return JS_TRUE;
}
JS_FRIEND_API(JSBool)
js_ShutdownEthogram(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval)
{
if (traceVisScriptTable)
JS_HashTableDestroy(traceVisScriptTable);
return JS_TRUE;
}
#endif /* MOZ_TRACEVIS */

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

@ -495,6 +495,15 @@ js_ResumeVtune(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
#endif /* MOZ_VTUNE */
#ifdef MOZ_TRACEVIS
extern JS_FRIEND_API(JSBool)
js_InitEthogram(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval);
extern JS_FRIEND_API(JSBool)
js_ShutdownEthogram(JSContext *cx, JSObject *obj,
uintN argc, jsval *argv, jsval *rval);
#endif /* MOZ_TRACEVIS */
JS_END_EXTERN_C
#endif /* jsdbgapi_h___ */

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

@ -2664,7 +2664,7 @@ JS_REQUIRES_STACK JSBool
js_Interpret(JSContext *cx)
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso(S_INTERP);
TraceVisStateObj tvso(cx, S_INTERP);
#endif
JSRuntime *rt;
@ -2880,11 +2880,18 @@ js_Interpret(JSContext *cx)
#ifdef JS_TRACER
#ifdef MOZ_TRACEVIS
#if JS_THREADED_INTERP
#define MONITOR_BRANCH_TRACEVIS \
JS_BEGIN_MACRO \
if (jumpTable != interruptJumpTable) \
js_EnterTraceVisState(S_RECORD, R_NONE); \
js_EnterTraceVisState(cx, S_RECORD, R_NONE); \
JS_END_MACRO
#else /* !JS_THREADED_INTERP */
#define MONITOR_BRANCH_TRACEVIS \
JS_BEGIN_MACRO \
js_EnterTraceVisState(cx, S_RECORD, R_NONE); \
JS_END_MACRO
#endif
#else
#define MONITOR_BRANCH_TRACEVIS
#endif
@ -3115,7 +3122,7 @@ js_Interpret(JSContext *cx)
#if JS_THREADED_INTERP
#ifdef MOZ_TRACEVIS
if (!moreInterrupts)
js_ExitTraceVisState(R_ABORT);
js_ExitTraceVisState(cx, R_ABORT);
#endif
jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable;
JS_EXTENSION_(goto *normalJumpTable[op]);

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

@ -3729,7 +3729,7 @@ JS_REQUIRES_STACK void
TraceRecorder::compile(JSTraceMonitor* tm)
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso(S_COMPILE);
TraceVisStateObj tvso(cx, S_COMPILE);
#endif
if (tm->needFlush) {
@ -5427,7 +5427,7 @@ ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
VMSideExit** innermostNestedGuardp)
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso(S_EXECUTE);
TraceVisStateObj tvso(cx, S_EXECUTE);
#endif
JS_ASSERT(f->root == f && f->code() && f->vmprivate);
@ -5525,7 +5525,7 @@ ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
// TraceVisStateObj constructors and destructors must run at the right times.
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso_n(S_NATIVE);
TraceVisStateObj tvso_n(cx, S_NATIVE);
#endif
#if defined(JS_NO_FASTCALL) && defined(NANOJIT_IA32)
SIMULATE_FASTCALL(rec, state, NULL, u.func);
@ -5837,7 +5837,7 @@ JS_REQUIRES_STACK bool
js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso(S_MONITOR);
TraceVisStateObj tvso(cx, S_MONITOR);
#endif
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
@ -12732,6 +12732,7 @@ DumpPeerStability(JSTraceMonitor* tm, const void* ip, JSObject* globalObj, uint3
#ifdef MOZ_TRACEVIS
FILE* traceVisLogFile = NULL;
JSHashTable *traceVisScriptTable = NULL;
JS_FRIEND_API(bool)
JS_StartTraceVis(const char* filename = "tracevis.dat")

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

@ -1005,14 +1005,18 @@ enum TraceVisExitReason {
R_OTHER_EXIT
};
const unsigned long long MS64_MASK = 0xfllu << 60;
const unsigned long long MR64_MASK = 0x1fllu << 55;
const unsigned long long MS64_MASK = 0xfull << 60;
const unsigned long long MR64_MASK = 0x1full << 55;
const unsigned long long MT64_MASK = ~(MS64_MASK | MR64_MASK);
extern FILE* traceVisLogFile;
extern JSHashTable *traceVisScriptTable;
extern JS_FRIEND_API(void)
js_StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r);
static inline void
js_LogTraceVisState(TraceVisState s, TraceVisExitReason r)
js_LogTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
{
if (traceVisLogFile) {
unsigned long long sllu = s;
@ -1020,30 +1024,35 @@ js_LogTraceVisState(TraceVisState s, TraceVisExitReason r)
unsigned long long d = (sllu << 60) | (rllu << 55) | (rdtsc() & MT64_MASK);
fwrite(&d, sizeof(d), 1, traceVisLogFile);
}
if (traceVisScriptTable) {
js_StoreTraceVisState(cx, s, r);
}
}
static inline void
js_EnterTraceVisState(TraceVisState s, TraceVisExitReason r)
js_EnterTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
{
js_LogTraceVisState(s, r);
js_LogTraceVisState(cx, s, r);
}
static inline void
js_ExitTraceVisState(TraceVisExitReason r)
js_ExitTraceVisState(JSContext *cx, TraceVisExitReason r)
{
js_LogTraceVisState(S_EXITLAST, r);
js_LogTraceVisState(cx, S_EXITLAST, r);
}
struct TraceVisStateObj {
TraceVisExitReason r;
JSContext *mCx;
inline TraceVisStateObj(TraceVisState s) : r(R_NONE)
inline TraceVisStateObj(JSContext *cx, TraceVisState s) : r(R_NONE)
{
js_EnterTraceVisState(s, R_NONE);
js_EnterTraceVisState(cx, s, R_NONE);
mCx = cx;
}
inline ~TraceVisStateObj()
{
js_ExitTraceVisState(r);
js_ExitTraceVisState(mCx, r);
}
};

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

@ -83,7 +83,7 @@
#include "prmem.h"
#include "plbase64.h"
#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE)
#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE) || defined(MOZ_TRACEVIS)
#include "jsdbgapi.h"
#endif
@ -291,6 +291,10 @@ static JSFunctionSpec gGlobalFun[] = {
{"stopVtune", js_StopVtune, 0,0,0},
{"pauseVtune", js_PauseVtune, 0,0,0},
{"resumeVtune", js_ResumeVtune, 0,0,0},
#endif
#ifdef MOZ_TRACEVIS
{"initEthogram", js_InitEthogram, 0,0,0},
{"shutdownEthogram", js_ShutdownEthogram, 0,0,0},
#endif
{nsnull,nsnull,0,0,0}
};