Bug 673631 - Clean up probes and register (almost) all profiler control entry points in JS_DefineProfilingFunctions (r=luke,waldo,jst)

Previously, JS_DefineProfilingFunctions only defined a very basic set of
functions (startProfiling and stopProfiling), and various scattered places
added more specific ones (start/stop vtune, dumpProfile, etc.) This patch makes
jsdbgapi do all of it, so that all users get the same set.

Also rename JS_DumpProfile -> JS_DumpBytecode to avoid name conflict. The
bytecode dumps are how the counters ("profiles") are displayed, so the
DumpProfile name was bogus anyway.

--HG--
extra : rebase_source : 2d3e626ef43ac41c6da401a779775a63fc96a427
This commit is contained in:
Steve Fink 2011-07-26 15:56:09 -07:00
parent 21539bdc2a
commit 93cd3119ac
11 changed files with 712 additions and 525 deletions

View File

@ -2963,25 +2963,6 @@ static JSFunctionSpec JProfFunctions[] = {
#endif /* defined(MOZ_JPROF) */
#ifdef MOZ_CALLGRIND
static JSFunctionSpec CallgrindFunctions[] = {
{"startCallgrind", js_StartCallgrind, 0, 0},
{"stopCallgrind", js_StopCallgrind, 0, 0},
{"dumpCallgrind", js_DumpCallgrind, 1, 0},
{nsnull, nsnull, 0, 0}
};
#endif
#ifdef MOZ_VTUNE
static JSFunctionSpec VtuneFunctions[] = {
{"startVtune", js_StartVtune, 1, 0},
{"stopVtune", js_StopVtune, 0, 0},
{"pauseVtune", js_PauseVtune, 0, 0},
{"resumeVtune", js_ResumeVtune, 0, 0},
{nsnull, nsnull, 0, 0}
};
#endif
#ifdef MOZ_TRACEVIS
static JSFunctionSpec EthogramFunctions[] = {
{"initEthogram", js_InitEthogram, 0, 0},
@ -3017,16 +2998,6 @@ nsJSContext::InitClasses(void *aGlobalObj)
::JS_DefineFunctions(mContext, globalObj, JProfFunctions);
#endif
#ifdef MOZ_CALLGRIND
// Attempt to initialize Callgrind functions
::JS_DefineFunctions(mContext, globalObj, CallgrindFunctions);
#endif
#ifdef MOZ_VTUNE
// Attempt to initialize Vtune functions
::JS_DefineFunctions(mContext, globalObj, VtuneFunctions);
#endif
#ifdef MOZ_TRACEVIS
// Attempt to initialize Ethogram functions
::JS_DefineFunctions(mContext, globalObj, EthogramFunctions);

View File

@ -558,11 +558,6 @@ JSFunctionSpec gGlobalFunctions[] =
{"clear", Clear, 1,0},
#ifdef DEBUG
{"dumpHeap", DumpHeap, 5,0},
#endif
#ifdef MOZ_CALLGRIND
{"startCallgrind", js_StartCallgrind, 0,0},
{"stopCallgrind", js_StopCallgrind, 0,0},
{"dumpCallgrind", js_DumpCallgrind, 1,0},
#endif
{nsnull,nsnull,0,0}
};

View File

@ -43,6 +43,7 @@
* JS debugging API.
*/
#include <string.h>
#include <stdarg.h>
#include "jsprvtd.h"
#include "jstypes.h"
#include "jsstdint.h"
@ -83,6 +84,10 @@
#include "methodjit/MethodJIT.h"
#include "methodjit/Retcon.h"
#ifdef __APPLE__
#include "sharkctl.h"
#endif
using namespace js;
using namespace js::gc;
@ -1213,32 +1218,251 @@ JS_ClearContextDebugHooks(JSContext *cx)
return JS_SetContextDebugHooks(cx, &js_NullDebugHooks);
}
JS_PUBLIC_API(JSBool)
JS_StartProfiling()
/************************************************************************/
/* Profiling-related API */
/* Thread-unsafe error management */
static char gLastError[2000];
static void
#ifdef _GNU_SOURCE
__attribute__((unused,format(printf,1,2)))
#endif
UnsafeError(const char *format, ...)
{
return Probes::startProfiling();
va_list args;
va_start(args, format);
(void) vsnprintf(gLastError, sizeof(gLastError), format, args);
va_end(args);
gLastError[sizeof(gLastError) - 1] = '\0';
}
JS_PUBLIC_API(void)
JS_StopProfiling()
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError()
{
Probes::stopProfiling();
return gLastError;
}
JS_PUBLIC_API(JSBool)
JS_StartProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark for %s", profileName);
ok = JS_FALSE;
}
#endif
#ifdef MOZ_VTUNE
if (!js_StartVtune(profileName))
ok = JS_FALSE;
#endif
return ok;
}
JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef MOZ_VTUNE
if (!js_StopVtune())
ok = JS_FALSE;
#endif
return ok;
}
/*
* Start or stop whatever platform- and configuration-specific profiling
* backends are available.
*/
static JSBool
ControlProfilers(bool toState)
{
JSBool ok = JS_TRUE;
if (! Probes::ProfilingActive && toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start()) {
UnsafeError("Failed to start Shark");
ok = JS_FALSE;
}
#endif
#ifdef MOZ_CALLGRIND
if (! js_StartCallgrind()) {
UnsafeError("Failed to start Callgrind");
ok = JS_FALSE;
}
#endif
#ifdef MOZ_VTUNE
if (! js_ResumeVtune())
ok = JS_FALSE;
#endif
} else if (Probes::ProfilingActive && ! toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef MOZ_CALLGRIND
if (! js_StopCallgrind()) {
UnsafeError("failed to stop Callgrind");
ok = JS_FALSE;
}
#endif
#ifdef MOZ_VTUNE
if (! js_PauseVtune())
ok = JS_FALSE;
#endif
}
Probes::ProfilingActive = toState;
return ok;
}
/*
* Pause/resume whatever profiling mechanism is currently compiled
* in, if applicable. This will not affect things like dtrace.
*
* Do not mix calls to these APIs with calls to the individual
* profilers' pause/resume functions, because only overall state is
* tracked, not the state of each profiler.
*/
JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName)
{
return ControlProfilers(false);
}
JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName)
{
return ControlProfilers(true);
}
JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName)
{
JSBool ok = JS_TRUE;
#ifdef MOZ_CALLGRIND
js_DumpCallgrind(outfile);
#endif
return ok;
}
#ifdef MOZ_PROFILING
struct RequiredStringArg {
JSContext *mCx;
char *mBytes;
RequiredStringArg(JSContext *cx, uintN argc, jsval *vp, size_t argi, const char *caller)
: mCx(cx), mBytes(NULL)
{
if (argc <= argi) {
JS_ReportError(cx, "%s: not enough arguments", caller);
} else if (!JSVAL_IS_STRING(JS_ARGV(cx, vp)[argi])) {
JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
} else {
mBytes = JS_EncodeString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[argi]));
}
}
operator void*() {
return (void*) mBytes;
}
~RequiredStringArg() {
if (mBytes)
mCx->free_(mBytes);
}
};
static JSBool
StartProfiling(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling()));
return true;
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "startProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StartProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
StopProfiling(JSContext *cx, uintN argc, jsval *vp)
{
JS_StopProfiling();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "stopProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_StopProfiling(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
PauseProfilers(JSContext *cx, uintN argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "pauseProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_PauseProfilers(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
ResumeProfilers(JSContext *cx, uintN argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(NULL)));
return JS_TRUE;
}
RequiredStringArg profileName(cx, argc, vp, 0, "resumeProfiling");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(JS_ResumeProfilers(profileName.mBytes)));
return JS_TRUE;
}
/* Usage: DumpProfile([filename[, profileName]]) */
static JSBool
DumpProfile(JSContext *cx, uintN argc, jsval *vp)
{
bool ret;
if (argc == 0) {
ret = JS_DumpProfile(NULL, NULL);
} else {
RequiredStringArg filename(cx, argc, vp, 0, "dumpProfile");
if (!filename)
return JS_FALSE;
if (argc == 1) {
ret = JS_DumpProfile(filename.mBytes, NULL);
} else {
RequiredStringArg profileName(cx, argc, vp, 1, "dumpProfile");
if (!profileName)
return JS_FALSE;
ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
}
}
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
return true;
}
@ -1253,15 +1477,94 @@ IgnoreAndReturnTrue(JSContext *cx, uintN argc, jsval *vp)
#endif
#ifdef MOZ_CALLGRIND
static JSBool
StartCallgrind(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
return JS_TRUE;
}
static JSBool
StopCallgrind(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
return JS_TRUE;
}
static JSBool
DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
{
if (argc == 0) {
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(NULL)));
return JS_TRUE;
}
RequiredStringArg outFile(cx, argc, vp, 0, "dumpCallgrind");
if (!outFile)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_DumpCallgrind(outFile.mBytes)));
return JS_TRUE;
}
#endif
#ifdef MOZ_VTUNE
static JSBool
StartVtune(JSContext *cx, uintN argc, jsval *vp)
{
RequiredStringArg profileName(cx, argc, vp, 0, "startVtune");
if (!profileName)
return JS_FALSE;
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartVtune(profileName.mBytes)));
return JS_TRUE;
}
static JSBool
StopVtune(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopVtune()));
return JS_TRUE;
}
static JSBool
PauseVtune(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_PauseVtune()));
return JS_TRUE;
}
static JSBool
ResumeVtune(JSContext *cx, uintN argc, jsval *vp)
{
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_ResumeVtune()));
return JS_TRUE;
}
#endif
static JSFunctionSpec profiling_functions[] = {
JS_FN("startProfiling", StartProfiling, 0,0),
JS_FN("stopProfiling", StopProfiling, 0,0),
JS_FN("startProfiling", StartProfiling, 1,0),
JS_FN("stopProfiling", StopProfiling, 1,0),
JS_FN("pauseProfilers", PauseProfilers, 1,0),
JS_FN("resumeProfilers", ResumeProfilers, 1,0),
JS_FN("dumpProfile", DumpProfile, 2,0),
#ifdef MOZ_SHARK
/* Keep users of the old shark API happy. */
JS_FN("connectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
JS_FN("startShark", StartProfiling, 0,0),
JS_FN("stopShark", StopProfiling, 0,0),
#endif
#ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", StartCallgrind, 0,0),
JS_FN("stopCallgrind", StopCallgrind, 0,0),
JS_FN("dumpCallgrind", DumpCallgrind, 1,0),
#endif
#ifdef MOZ_VTUNE
JS_FN("startVtune", js_StartVtune, 1,0),
JS_FN("stopVtune", js_StopVtune, 0,0),
JS_FN("pauseVtune", js_PauseVtune, 0,0),
JS_FN("resumeVtune", js_ResumeVtune, 0,0),
#endif
JS_FS_END
};
@ -1284,40 +1587,30 @@ JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj)
#include <valgrind/callgrind.h>
JS_FRIEND_API(JSBool)
js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp)
js_StartCallgrind()
{
CALLGRIND_START_INSTRUMENTATION;
CALLGRIND_ZERO_STATS;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
return true;
}
JS_FRIEND_API(JSBool)
js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp)
js_StopCallgrind()
{
CALLGRIND_STOP_INSTRUMENTATION;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
return true;
}
JS_FRIEND_API(JSBool)
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp)
js_DumpCallgrind(const char *outfile)
{
JSString *str;
jsval *argv = JS_ARGV(cx, vp);
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]);
JSAutoByteString bytes(cx, str);
if (!!bytes) {
CALLGRIND_DUMP_STATS_AT(bytes.ptr());
return JS_TRUE;
}
}
if (outfile) {
CALLGRIND_DUMP_STATS_AT(outfile);
} else {
CALLGRIND_DUMP_STATS;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return JS_TRUE;
return true;
}
#endif /* MOZ_CALLGRIND */
@ -1352,8 +1645,8 @@ static const char *vtuneErrorMessages[] = {
};
JS_FRIEND_API(JSBool)
js_StartVtune(JSContext *cx, uintN argc, jsval *vp)
bool
js_StartVtune(const char *profileName)
{
VTUNE_EVENT events[] = {
{ 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
@ -1380,62 +1673,54 @@ js_StartVtune(JSContext *cx, uintN argc, jsval *vp)
default_filename,
};
jsval *argv = JS_ARGV(cx, vp);
if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
str = JSVAL_TO_STRING(argv[0]);
params.tb5Filename = DeflateString(cx, str->chars(), str->length());
if (profileName) {
char filename[strlen(profileName) + strlen("-vtune.tb5") + 1];
snprintf(filename, sizeof(filename), "%s-vtune.tb5", profileName);
params.tb5Filename = filename;
}
status = VTStartSampling(&params);
if (params.tb5Filename != default_filename)
cx->free_(params.tb5Filename);
Foreground::free_(params.tb5Filename);
if (status != 0) {
if (status == VTAPI_MULTIPLE_RUNS)
VTStopSampling(0);
if (status < sizeof(vtuneErrorMessages))
JS_ReportError(cx, "Vtune setup error: %s",
vtuneErrorMessages[status]);
UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
else
JS_ReportError(cx, "Vtune setup error: %d",
status);
UnsafeError("Vtune setup error: %d", status);
return false;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
JS_FRIEND_API(JSBool)
js_StopVtune(JSContext *cx, uintN argc, jsval *vp)
bool
js_StopVtune()
{
U32 status = VTStopSampling(1);
if (status) {
if (status < sizeof(vtuneErrorMessages))
JS_ReportError(cx, "Vtune shutdown error: %s",
vtuneErrorMessages[status]);
UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
else
JS_ReportError(cx, "Vtune shutdown error: %d",
status);
UnsafeError("Vtune shutdown error: %d", status);
return false;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
JS_FRIEND_API(JSBool)
js_PauseVtune(JSContext *cx, uintN argc, jsval *vp)
bool
js_PauseVtune()
{
VTPause();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
JS_FRIEND_API(JSBool)
js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp)
bool
js_ResumeVtune()
{
VTResume();
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return true;
}
@ -1906,32 +2191,29 @@ JS_GetFunctionCallback(JSContext *cx)
#endif /* MOZ_TRACE_JSCALLS */
JS_PUBLIC_API(void)
JS_DumpProfile(JSContext *cx, JSScript *script)
JS_DumpBytecode(JSContext *cx, JSScript *script)
{
JS_ASSERT(!cx->runtime->gcRunning);
#if defined(DEBUG)
if (script->pcCounters) {
// Display hit counts for every JS code line
AutoArenaAllocator mark(&cx->tempPool);
Sprinter sprinter;
INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0);
fprintf(stdout, "--- PC COUNTS %s:%d ---\n", script->filename, script->lineno);
fprintf(stdout, "--- SCRIPT %s:%d ---\n", script->filename, script->lineno);
js_Disassemble(cx, script, true, &sprinter);
fprintf(stdout, "%s\n", sprinter.base);
fprintf(stdout, "--- END PC COUNTS %s:%d ---\n", script->filename, script->lineno);
}
fprintf(stdout, "--- END SCRIPT %s:%d ---\n", script->filename, script->lineno);
#endif
}
JS_PUBLIC_API(void)
JS_DumpAllProfiles(JSContext *cx)
JS_DumpCompartmentBytecode(JSContext *cx)
{
for (JSScript *script = (JSScript *) JS_LIST_HEAD(&cx->compartment->scripts);
script != (JSScript *) &cx->compartment->scripts;
script = (JSScript *) JS_NEXT_LINK((JSCList *)script))
{
JS_DumpProfile(cx, script);
JS_DumpBytecode(cx, script);
}
}

View File

@ -497,12 +497,51 @@ JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks);
extern JS_PUBLIC_API(JSDebugHooks *)
JS_ClearContextDebugHooks(JSContext *cx);
/**
* Start any profilers that are available and have been configured on for this
* platform. This is NOT thread safe.
*
* The profileName is used by some profilers to describe the current profiling
* run. It may be used for part of the filename of the output, but the
* specifics depend on the profiler. Many profilers will ignore it. Passing in
* NULL is legal; some profilers may use it to output to stdout or similar.
*
* Returns true if no profilers fail to start.
*/
extern JS_PUBLIC_API(JSBool)
JS_StartProfiling();
JS_StartProfiling(const char *profileName);
extern JS_PUBLIC_API(void)
JS_StopProfiling();
/**
* Stop any profilers that were previously started with JS_StartProfiling.
* Returns true if no profilers fail to stop.
*/
extern JS_PUBLIC_API(JSBool)
JS_StopProfiling(const char *profileName);
/**
* Write the current profile data to the given file, if applicable to whatever
* profiler is being used.
*/
extern JS_PUBLIC_API(JSBool)
JS_DumpProfile(const char *outfile, const char *profileName);
/**
* Pause currently active profilers (only supported by some profilers). Returns
* whether any profilers failed to pause. (Profilers that do not support
* pause/resume do not count.)
*/
extern JS_PUBLIC_API(JSBool)
JS_PauseProfilers(const char *profileName);
/**
* Resume suspended profilers
*/
extern JS_PUBLIC_API(JSBool)
JS_ResumeProfilers(const char *profileName);
/**
* Add various profiling-related functions as properties of the given object.
*/
extern JS_PUBLIC_API(JSBool)
JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
@ -510,32 +549,40 @@ JS_DefineProfilingFunctions(JSContext *cx, JSObject *obj);
extern JS_PUBLIC_API(JSBool)
JS_DefineDebuggerObject(JSContext *cx, JSObject *obj);
/**
* The profiling API calls are not able to report errors, so they use a
* thread-unsafe global memory buffer to hold the last error encountered. This
* should only be called after something returns false.
*/
JS_PUBLIC_API(const char *)
JS_UnsafeGetLastProfilingError();
#ifdef MOZ_CALLGRIND
extern JS_FRIEND_API(JSBool)
js_StopCallgrind(JSContext *cx, uintN argc, jsval *vp);
js_StopCallgrind();
extern JS_FRIEND_API(JSBool)
js_StartCallgrind(JSContext *cx, uintN argc, jsval *vp);
js_StartCallgrind();
extern JS_FRIEND_API(JSBool)
js_DumpCallgrind(JSContext *cx, uintN argc, jsval *vp);
js_DumpCallgrind(const char *outfile);
#endif /* MOZ_CALLGRIND */
#ifdef MOZ_VTUNE
extern JS_FRIEND_API(JSBool)
js_StartVtune(JSContext *cx, uintN argc, jsval *vp);
extern JS_FRIEND_API(bool)
js_StartVtune(const char *profileName);
extern JS_FRIEND_API(JSBool)
js_StopVtune(JSContext *cx, uintN argc, jsval *vp);
extern JS_FRIEND_API(bool)
js_StopVtune();
extern JS_FRIEND_API(JSBool)
js_PauseVtune(JSContext *cx, uintN argc, jsval *vp);
extern JS_FRIEND_API(bool)
js_PauseVtune();
extern JS_FRIEND_API(JSBool)
js_ResumeVtune(JSContext *cx, uintN argc, jsval *vp);
extern JS_FRIEND_API(bool)
js_ResumeVtune();
#endif /* MOZ_VTUNE */
@ -569,10 +616,10 @@ JS_GetFunctionCallback(JSContext *cx);
#endif /* MOZ_TRACE_JSCALLS */
extern JS_PUBLIC_API(void)
JS_DumpProfile(JSContext *cx, JSScript *script);
JS_DumpBytecode(JSContext *cx, JSScript *script);
extern JS_PUBLIC_API(void)
JS_DumpAllProfiles(JSContext *cx);
JS_DumpCompartmentBytecode(JSContext *cx);
JS_END_EXTERN_C

View File

@ -2202,7 +2202,6 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
(compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT))
{
compartment->freeLists.checkEmpty();
Probes::GCEndSweepPhase(compartment);
if (callback)
JS_ALWAYS_TRUE(callback(cx, compartment, JSCOMPARTMENT_DESTROY));
if (compartment->principals)
@ -2338,6 +2337,7 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
* unreachable compartments.
*/
if (comp) {
Probes::GCStartSweepPhase(comp);
comp->sweep(cx, 0);
comp->finalizeObjectArenaLists(cx);
GCTIMESTAMP(sweepObjectEnd);
@ -2345,6 +2345,7 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM
GCTIMESTAMP(sweepStringEnd);
comp->finalizeShapeArenaLists(cx);
GCTIMESTAMP(sweepShapeEnd);
Probes::GCEndSweepPhase(comp);
} else {
/*
* Some sweeping is not compartment-specific. Start a NULL-compartment

View File

@ -53,10 +53,6 @@
#include "jsstaticcheck.h"
#include "jsstr.h"
#ifdef __APPLE__
#include "sharkctl.h"
#endif
#include "jsprobes.h"
#include <sys/types.h>
@ -69,48 +65,65 @@ const char Probes::anonymousName[] = "(anonymous)";
bool Probes::ProfilingActive = true;
bool
Probes::controlProfilers(JSContext *cx, bool toState)
#ifdef INCLUDE_MOZILLA_DTRACE
static const char *
ScriptFilename(const JSScript *script)
{
JSBool ok = JS_TRUE;
#if defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE)
jsval dummy;
#endif
if (! ProfilingActive && toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (!Shark::Start())
ok = JS_FALSE;
#endif
#ifdef MOZ_CALLGRIND
if (! js_StartCallgrind(cx, 0, &dummy))
ok = JS_FALSE;
#endif
#ifdef MOZ_VTUNE
if (! js_ResumeVtune(cx, 0, &dummy))
ok = JS_FALSE;
#endif
} else if (ProfilingActive && ! toState) {
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
#ifdef MOZ_CALLGRIND
if (! js_StopCallgrind(cx, 0, &dummy))
ok = JS_FALSE;
#endif
#ifdef MOZ_VTUNE
if (! js_PauseVtune(cx, 0, &dummy))
ok = JS_FALSE;
#endif
if (!script)
return Probes::nullName;
if (!script->filename)
return Probes::anonymousName;
return script->filename;
}
ProfilingActive = toState;
static const char *
FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
{
if (!fun)
return Probes::nullName;
JSAtom *atom = const_cast<JSAtom*>(fun->atom);
if (!atom)
return Probes::anonymousName;
return bytes->encode(cx, atom) ? bytes->ptr() : Probes::nullName;
}
return ok;
static const char *
FunctionClassname(const JSFunction *fun)
{
if (!fun || FUN_INTERPRETED(fun))
return Probes::nullName;
if (!(fun->flags & JSFUN_TRCINFO) && FUN_CLASP(fun))
return (char *)FUN_CLASP(fun)->name;
return Probes::nullName;
}
/*
* These functions call the DTrace macros for the JavaScript USDT probes.
* Originally this code was inlined in the JavaScript code; however since
* a number of operations are called, these have been placed into functions
* to reduce any negative compiler optimization effect that the addition of
* a number of usually unused lines of code would cause.
*/
void
Probes::DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
{
JSAutoByteString funNameBytes;
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun, &funNameBytes));
}
void
Probes::current_location(JSContext *cx, int* lineno, char const **filename)
Probes::DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script)
{
JSAutoByteString funNameBytes;
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun, &funNameBytes));
}
#endif
#ifdef MOZ_ETW
static void
current_location(JSContext *cx, int* lineno, char const **filename)
{
JSScript *script = js_GetCurrentScript(cx);
if (! script) {
@ -122,75 +135,6 @@ Probes::current_location(JSContext *cx, int* lineno, char const **filename)
*filename = ScriptFilename(script);
}
const char *
Probes::FunctionClassname(const JSFunction *fun)
{
return (fun && !FUN_INTERPRETED(fun) && !(fun->flags & JSFUN_TRCINFO) && FUN_CLASP(fun))
? (char *)FUN_CLASP(fun)->name
: nullName;
}
const char *
Probes::ScriptFilename(JSScript *script)
{
return (script && script->filename) ? (char *)script->filename : nullName;
}
int
Probes::FunctionLineNumber(JSContext *cx, const JSFunction *fun)
{
if (fun && FUN_INTERPRETED(fun))
return (int) JS_GetScriptBaseLineNumber(cx, FUN_SCRIPT(fun));
return 0;
}
#ifdef INCLUDE_MOZILLA_DTRACE
/*
* These functions call the DTrace macros for the JavaScript USDT probes.
* Originally this code was inlined in the JavaScript code; however since
* a number of operations are called, these have been placed into functions
* to reduce any negative compiler optimization effect that the addition of
* a number of usually unused lines of code would cause.
*/
void
Probes::enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script)
{
JSAutoByteString funNameBytes;
JAVASCRIPT_FUNCTION_ENTRY(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun, &funNameBytes));
}
void
Probes::handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script)
{
JSAutoByteString funNameBytes;
JAVASCRIPT_FUNCTION_RETURN(ScriptFilename(script), FunctionClassname(fun),
FunctionName(cx, fun, &funNameBytes));
}
#endif
bool
Probes::startProfiling()
{
#if defined(MOZ_SHARK) && defined(__APPLE__)
if (Shark::Start())
return true;
#endif
return false;
}
void
Probes::stopProfiling()
{
#if defined(MOZ_SHARK) && defined(__APPLE__)
Shark::Stop();
#endif
}
#ifdef MOZ_ETW
/*
* ETW (Event Tracing for Windows)
*

View File

@ -14,10 +14,14 @@
* for the specific language governing rights and limitations under the
* License.
*
* Copyright (C) 2007 Sun Microsystems, Inc. All Rights Reserved.
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
* June 12, 2009.
*
* The Initial Developer of the Original Code is
* the Mozilla Corporation.
*
* Contributor(s):
* Brendan Eich <brendan@mozilla.org>
* Steve Fink <sfink@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -44,168 +48,204 @@
namespace js {
class Probes {
static bool ProfilingActive;
static bool controlProfilers(JSContext *cx, bool toState);
static const char nullName[];
static const char anonymousName[];
static const char *FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
{
if (!fun)
return nullName;
JSAtom *atom = const_cast<JSAtom*>(fun->atom);
if (!atom)
return anonymousName;
return bytes->encode(cx, atom) ? bytes->ptr() : nullName;
}
static const char *ScriptFilename(const JSScript *script) {
if (! script)
return "(null)";
if (! script->filename)
return "(anonymous)";
return script->filename;
}
static const char *ObjectClassname(JSObject *obj) {
if (! obj)
return "(null object)";
Class *clasp = obj->getClass();
if (! clasp)
return "(null)";
const char *class_name = clasp->name;
if (! class_name)
return "(null class name)";
return class_name;
}
static void current_location(JSContext *cx, int* lineno, char const **filename);
static const char *FunctionClassname(const JSFunction *fun);
static const char *ScriptFilename(JSScript *script);
static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
static void enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script);
static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
static void finalizeObjectImpl(JSObject *obj);
public:
static bool createRuntime(JSRuntime *rt);
static bool destroyRuntime(JSRuntime *rt);
static bool shutdown();
namespace Probes {
/*
* Pause/resume whatever profiling mechanism is currently compiled
* in, if applicable. This will not affect things like dtrace.
* Static probes
*
* Do not mix calls to these APIs with calls to the individual
* profilers' pase/resume functions, because only overall state is
* tracked, not the state of each profiler.
* The probe points defined in this file are scattered around the SpiderMonkey
* source tree. The presence of Probes::someEvent() means that someEvent is
* about to happen or has happened. To the extent possible, probes should be
* inserted in all paths associated with a given event, regardless of the
* active runmode (interpreter/traceJIT/methodJIT/ionJIT).
*
* Return the previous state.
* When a probe fires, it is handled by any probe handling backends that have
* been compiled in. By default, most probes do nothing or at least do nothing
* expensive, so the presence of the probe should have negligible effect on
* running time. (Probes in slow paths may do something by default, as long as
* there is no noticeable slowdown.)
*
* For some probes, the mere existence of the probe is too expensive even if it
* does nothing when called. For example, just having consistent information
* available for a function call entry/exit probe causes the JITs to
* de-optimize function calls. In those cases, the JITs may query at compile
* time whether a probe is desired, and omit the probe invocation if not. If a
* probe is runtime-disabled at compilation time, it is not guaranteed to fire
* within a compiled function if it is later enabled.
*
* Not all backends handle all of the probes listed here.
*/
static bool pauseProfilers(JSContext *cx) {
bool prevState = ProfilingActive;
controlProfilers(cx, false);
return prevState;
}
static bool resumeProfilers(JSContext *cx) {
bool prevState = ProfilingActive;
controlProfilers(cx, true);
return prevState;
}
static bool callTrackingActive(JSContext *);
static bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
static bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
static bool startExecution(JSContext *cx, JSScript *script);
static bool stopExecution(JSContext *cx, JSScript *script);
static bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
/* |obj| must exist (its class and size are computed) */
static bool createObject(JSContext *cx, JSObject *obj);
static bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
/* |obj| must still exist (its class is accessed) */
static bool finalizeObject(JSObject *obj);
/*
* |string| does not need to contain any content yet; only its
* pointer value is used. |length| is the length of the string and
* does not imply anything about the amount of storage consumed to
* store the string. (It may be a short string, an external
* string, or a rope, and the encoding is not taken into
* consideration.)
* Internal use only: remember whether "profiling", whatever that means, is
* currently active. Used for state management.
*/
static bool createString(JSContext *cx, JSString *string, size_t length);
extern bool ProfilingActive;
extern const char nullName[];
extern const char anonymousName[];
/* JSRuntime created, with currently valid fields */
bool createRuntime(JSRuntime *rt);
/* JSRuntime about to be destroyed */
bool destroyRuntime(JSRuntime *rt);
/* Total JS engine shutdown */
bool shutdown();
/*
* Test whether we are tracking JS function call enter/exit. The JITs use this
* to decide whether they can optimize in a way that would prevent probes from
* firing.
*/
bool callTrackingActive(JSContext *);
/* Entering a JS function */
bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1);
/* About to leave a JS function */
bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0);
/* Executing a script */
bool startExecution(JSContext *cx, JSScript *script);
/* Script has completed execution */
bool stopExecution(JSContext *cx, JSScript *script);
/* Heap has been resized */
bool resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
/*
* Object has been created. |obj| must exist (its class and size are read)
*/
bool createObject(JSContext *cx, JSObject *obj);
/* Object has been resized */
bool resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
/*
* Object is about to be finalized. |obj| must still exist (its class is
* read)
*/
bool finalizeObject(JSObject *obj);
/*
* String has been created.
*
* |string|'s content is not (yet) valid. |length| is the length of the string
* and does not imply anything about the amount of storage consumed to store
* the string. (It may be a short string, an external string, or a rope, and
* the encoding is not taken into consideration.)
*/
bool createString(JSContext *cx, JSString *string, size_t length);
/*
* String is about to be finalized
*
* |string| must still have a valid length.
*/
static bool finalizeString(JSString *string);
bool finalizeString(JSString *string);
static bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
static bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
/* Script is about to be compiled */
bool compileScriptBegin(JSContext *cx, const char *filename, int lineno);
static bool calloutBegin(JSContext *cx, JSFunction *fun);
static bool calloutEnd(JSContext *cx, JSFunction *fun);
/* Script has just finished compilation */
bool compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno);
static bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
static bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
/* About to make a call from JS into native code */
bool calloutBegin(JSContext *cx, JSFunction *fun);
static bool GCStart(JSCompartment *compartment);
static bool GCEnd(JSCompartment *compartment);
static bool GCStartMarkPhase(JSCompartment *compartment);
/* Native code called by JS has terminated */
bool calloutEnd(JSContext *cx, JSFunction *fun);
static bool GCEndMarkPhase(JSCompartment *compartment);
static bool GCStartSweepPhase(JSCompartment *compartment);
static bool GCEndSweepPhase(JSCompartment *compartment);
/* Unimplemented */
bool acquireMemory(JSContext *cx, void *address, size_t nbytes);
bool releaseMemory(JSContext *cx, void *address, size_t nbytes);
static bool CustomMark(JSString *string);
static bool CustomMark(const char *string);
static bool CustomMark(int marker);
/*
* Garbage collection probes
*
* GC timing is tricky and at the time of this writing is changing frequently.
* GCStart(NULL)/GCEnd(NULL) are intended to bracket the entire garbage
* collection (either global or single-compartment), but a separate thread may
* continue doing work after GCEnd.
*
* Multiple compartments' GC will be interleaved during a global collection
* (eg, compartment 1 starts, compartment 2 starts, compartment 1 ends, ...)
*/
bool GCStart(JSCompartment *compartment);
bool GCEnd(JSCompartment *compartment);
static bool startProfiling();
static void stopProfiling();
bool GCStartMarkPhase(JSCompartment *compartment);
bool GCEndMarkPhase(JSCompartment *compartment);
bool GCStartSweepPhase(JSCompartment *compartment);
bool GCEndSweepPhase(JSCompartment *compartment);
/*
* Various APIs for inserting custom probe points. These might be used to mark
* when something starts and stops, or for various other purposes the user has
* in mind. These are useful to export to JS so that JS code can mark
* application-meaningful events and phases of execution.
*
* Not all backends support these.
*/
bool CustomMark(JSString *string);
bool CustomMark(const char *string);
bool CustomMark(int marker);
/*
* Internal: DTrace-specific functions to be called during Probes::enterJSFun
* and Probes::exitJSFun. These will not be inlined, but the argument
* marshalling required for these probe points is expensive enough that it
* shouldn't really matter.
*/
void DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script);
void DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script);
/*
* Internal: ETW-specific probe functions
*/
#ifdef MOZ_ETW
// ETW Handlers
static bool ETWCreateRuntime(JSRuntime *rt);
static bool ETWDestroyRuntime(JSRuntime *rt);
static bool ETWShutdown();
static bool ETWCallTrackingActive(JSContext *cx);
static bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
static bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
static bool ETWCreateObject(JSContext *cx, JSObject *obj);
static bool ETWFinalizeObject(JSObject *obj);
static bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
static bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
static bool ETWFinalizeString(JSString *string);
static bool ETWCompileScriptBegin(const char *filename, int lineno);
static bool ETWCompileScriptEnd(const char *filename, int lineno);
static bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
static bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
static bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
static bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
static bool ETWGCStart(JSCompartment *compartment);
static bool ETWGCEnd(JSCompartment *compartment);
static bool ETWGCStartMarkPhase(JSCompartment *compartment);
static bool ETWGCEndMarkPhase(JSCompartment *compartment);
static bool ETWGCStartSweepPhase(JSCompartment *compartment);
static bool ETWGCEndSweepPhase(JSCompartment *compartment);
static bool ETWCustomMark(JSString *string);
static bool ETWCustomMark(const char *string);
static bool ETWCustomMark(int marker);
static bool ETWStartExecution(JSContext *cx, JSScript *script);
static bool ETWStopExecution(JSContext *cx, JSScript *script);
static bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
bool ETWCreateRuntime(JSRuntime *rt);
bool ETWDestroyRuntime(JSRuntime *rt);
bool ETWShutdown();
bool ETWCallTrackingActive(JSContext *cx);
bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
bool ETWCreateObject(JSContext *cx, JSObject *obj);
bool ETWFinalizeObject(JSObject *obj);
bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
bool ETWFinalizeString(JSString *string);
bool ETWCompileScriptBegin(const char *filename, int lineno);
bool ETWCompileScriptEnd(const char *filename, int lineno);
bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
bool ETWGCStart(JSCompartment *compartment);
bool ETWGCEnd(JSCompartment *compartment);
bool ETWGCStartMarkPhase(JSCompartment *compartment);
bool ETWGCEndMarkPhase(JSCompartment *compartment);
bool ETWGCStartSweepPhase(JSCompartment *compartment);
bool ETWGCEndSweepPhase(JSCompartment *compartment);
bool ETWCustomMark(JSString *string);
bool ETWCustomMark(const char *string);
bool ETWCustomMark(int marker);
bool ETWStartExecution(JSContext *cx, JSScript *script);
bool ETWStopExecution(JSContext *cx, JSScript *script);
bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
#endif
};
} /* namespace Probes */
/*
* Probe handlers are implemented inline for minimal performance impact,
* especially important when no backends are enabled.
*/
inline bool
Probes::createRuntime(JSRuntime *rt)
@ -258,30 +298,13 @@ Probes::callTrackingActive(JSContext *cx)
return false;
}
extern inline JS_FRIEND_API(JSBool)
js_PauseProfilers(JSContext *cx, uintN argc, jsval *vp)
{
Probes::pauseProfilers(cx);
return JS_TRUE;
}
extern inline JS_FRIEND_API(JSBool)
js_ResumeProfilers(JSContext *cx, uintN argc, jsval *vp)
{
Probes::resumeProfilers(cx);
return JS_TRUE;
}
extern JS_FRIEND_API(JSBool)
js_ResumeProfilers(JSContext *cx, uintN argc, jsval *vp);
inline bool
Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
{
bool ok = true;
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
enterJSFunImpl(cx, fun, script);
DTraceEnterJSFun(cx, fun, script);
#endif
#ifdef MOZ_TRACE_JSCALLS
cx->doFunctionCallback(fun, script, counter);
@ -301,7 +324,7 @@ Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
handleFunctionReturn(cx, fun, script);
DTraceExitJSFun(cx, fun, script);
#endif
#ifdef MOZ_TRACE_JSCALLS
if (counter > 0)
@ -329,6 +352,20 @@ Probes::resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
return ok;
}
#ifdef INCLUDE_MOZILLA_DTRACE
static const char *ObjectClassname(JSObject *obj) {
if (! obj)
return "(null object)";
Class *clasp = obj->getClass();
if (! clasp)
return "(null)";
const char *class_name = clasp->name;
if (! class_name)
return "(null class name)";
return class_name;
}
#endif
inline bool
Probes::createObject(JSContext *cx, JSObject *obj)
{
@ -658,4 +695,9 @@ struct AutoFunctionCallProbe {
} /* namespace js */
/*
* Internal functions for controlling various profilers. The profiler-specific
* implementations of these are mostly in jsdbgapi.cpp.
*/
#endif /* _JSPROBES_H */

View File

@ -3960,19 +3960,6 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("evalInFrame", EvalInFrame, 2,0),
JS_FN("shapeOf", ShapeOf, 1,0),
JS_FN("resolver", Resolver, 1,0),
JS_FN("pauseProfilers", js_PauseProfilers, 0,0),
JS_FN("resumeProfilers", js_ResumeProfilers, 0,0),
#ifdef MOZ_CALLGRIND
JS_FN("startCallgrind", js_StartCallgrind, 0,0),
JS_FN("stopCallgrind", js_StopCallgrind, 0,0),
JS_FN("dumpCallgrind", js_DumpCallgrind, 1,0),
#endif
#ifdef MOZ_VTUNE
JS_FN("startVtune", js_StartVtune, 1,0),
JS_FN("stopVtune", js_StopVtune, 0,0),
JS_FN("pauseVtune", js_PauseVtune, 0,0),
JS_FN("resumeVtune", js_ResumeVtune, 0,0),
#endif
#ifdef MOZ_TRACEVIS
JS_FN("startTraceVis", StartTraceVisNative, 1,0),
JS_FN("stopTraceVis", StopTraceVisNative, 0,0),
@ -4099,19 +4086,6 @@ static const char *const shell_help_messages[] = {
"shapeOf(obj) Get the shape of obj (an implementation detail)",
"resolver(src[, proto]) Create object with resolve hook that copies properties\n"
" from src. If proto is omitted, use Object.prototype.",
"pauseProfilers() Pause all profilers that can be paused",
"resumeProfilers() Resume profilers if they are paused",
#ifdef MOZ_CALLGRIND
"startCallgrind() Start callgrind instrumentation",
"stopCallgrind() Stop callgrind instrumentation",
"dumpCallgrind([name]) Dump callgrind counters",
#endif
#ifdef MOZ_VTUNE
"startVtune([filename]) Start vtune instrumentation",
"stopVtune() Stop vtune instrumentation",
"pauseVtune() Pause vtune collection",
"resumeVtune() Resume vtune collection",
#endif
#ifdef MOZ_TRACEVIS
"startTraceVis(filename) Start TraceVis recording (stops any current recording)",
"stopTraceVis() Stop TraceVis recording",
@ -4153,20 +4127,50 @@ static const char *const shell_help_messages[] = {
/* Keep these last: see the static assertion below. */
#ifdef MOZ_PROFILING
"startProfiling() Start a profiling session.\n"
"startProfiling([profileName])\n"
" Start a profiling session\n"
" Profiler must be running with programatic sampling",
"stopProfiling() Stop a running profiling session\n"
"stopProfiling([profileName])\n"
" Stop a running profiling session",
"pauseProfilers([profileName])\n"
" Pause a running profiling session",
"resumeProfilers([profileName])\n"
" Resume a paused profiling session",
"dumpProfile([outfile[, profileName]])\n"
" Dump out current profile info (only valid for callgrind)",
# ifdef MOZ_CALLGRIND
"startCallgrind() Start Callgrind instrumentation",
"stopCallgrind() Stop Callgrind instrumentation",
"dumpCallgrind([outfile]) Dump current Callgrind counters to file or stdout",
# endif
# ifdef MOZ_VTUNE
"startVtune() Start Vtune instrumentation",
"stopVtune() Stop Vtune instrumentation",
"pauseVtune() Pause Vtune collection",
"resumeVtune() Resume Vtune collection",
# endif
#endif
};
#ifdef MOZ_PROFILING
#define PROFILING_FUNCTION_COUNT 2
# define PROFILING_FUNCTION_COUNT 5
# ifdef MOZ_CALLGRIND
# define CALLGRIND_FUNCTION_COUNT 3
# else
#define PROFILING_FUNCTION_COUNT 0
# define CALLGRIND_FUNCTION_COUNT 0
# endif
# ifdef MOZ_VTUNE
# define VTUNE_FUNCTION_COUNT 4
# else
# define VTUNE_FUNCTION_COUNT 0
# endif
# define EXTERNAL_FUNCTION_COUNT (PROFILING_FUNCTION_COUNT + CALLGRIND_FUNCTION_COUNT + VTUNE_FUNCTION_COUNT)
#else
# define EXTERNAL_FUNCTION_COUNT 0
#endif
/* Help messages must match shell functions. */
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - PROFILING_FUNCTION_COUNT ==
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) - EXTERNAL_FUNCTION_COUNT ==
JS_ARRAY_LENGTH(shell_functions) - 1 /* JS_FS_END */);
#ifdef DEBUG
@ -4177,7 +4181,7 @@ CheckHelpMessages()
const char *lp;
/* Messages begin with "function_name(" prefix and don't end with \n. */
for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages) - PROFILING_FUNCTION_COUNT; ++m) {
for (m = shell_help_messages; m != JS_ARRAY_END(shell_help_messages) - EXTERNAL_FUNCTION_COUNT; ++m) {
lp = strchr(*m, '(');
JS_ASSERT(lp);
JS_ASSERT(memcmp(shell_functions[m - shell_help_messages].name,
@ -4190,6 +4194,9 @@ CheckHelpMessages()
#endif
#undef PROFILING_FUNCTION_COUNT
#undef CALLGRIND_FUNCTION_COUNT
#undef VTUNE_FUNCTION_COUNT
#undef EXTERNAL_FUNCTION_COUNT
static JSBool
Help(JSContext *cx, uintN argc, jsval *vp)
@ -5221,7 +5228,7 @@ Shell(JSContext *cx, OptionParser *op, char **envp)
#endif /* JSDEBUGGER */
if (enableDisassemblyDumps)
JS_DumpAllProfiles(cx);
JS_DumpCompartmentBytecode(cx);
return result;
}

View File

@ -291,17 +291,6 @@ static JSFunctionSpec gGlobalFun[] = {
{"atob", Atob, 1,0},
{"btoa", Btoa, 1,0},
{"File", File, 1,JSFUN_CONSTRUCTOR},
#ifdef MOZ_CALLGRIND
{"startCallgrind", js_StartCallgrind, 0,0},
{"stopCallgrind", js_StopCallgrind, 0,0},
{"dumpCallgrind", js_DumpCallgrind, 1,0},
#endif
#ifdef MOZ_VTUNE
{"startVtune", js_StartVtune, 1,0},
{"stopVtune", js_StopVtune, 0,0},
{"pauseVtune", js_PauseVtune, 0,0},
{"resumeVtune", js_ResumeVtune, 0,0},
#endif
#ifdef MOZ_TRACEVIS
{"initEthogram", js_InitEthogram, 0,0},
{"shutdownEthogram", js_ShutdownEthogram, 0,0},

View File

@ -847,11 +847,6 @@ static JSFunctionSpec glob_functions[] = {
#endif
{"sendCommand", SendCommand, 1,0},
{"getChildGlobalObject", GetChildGlobalObject, 0,0},
#ifdef MOZ_CALLGRIND
{"startCallgrind", js_StartCallgrind, 0,0},
{"stopCallgrind", js_StopCallgrind, 0,0},
{"dumpCallgrind", js_DumpCallgrind, 1,0},
#endif
{nsnull,nsnull,0,0}
};

View File

@ -56,6 +56,7 @@
#include "nsIFile.h"
#include "nsIProperties.h"
#include "nsXULAppAPI.h"
#include "jsdbgapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@ -95,17 +96,6 @@ void passed(const char* test)
// Code profiling
//
static const char* gCurrentProfile;
static PRBool gProfilerTriedInit = PR_FALSE;
static PRBool gProfilerInited = PR_FALSE;
// Platform profilers must implement these functions.
// Init and deinit are guaranteed to only be called once, and
// StartProfile/StopProfile may assume that they are only called
// when the profiler has successfully been initialized.
static PRBool _PlatformInitProfiler();
static PRBool _PlatformStartProfile(const char* profileName);
static PRBool _PlatformStopProfile(const char* profileName);
static PRBool _PlatformDeinitProfiler();
/**
* If the build has been configured properly, start the best code profiler
@ -124,19 +114,12 @@ static PRBool _PlatformDeinitProfiler();
inline PRBool
StartProfiling(const char* profileName)
{
if (!gProfilerTriedInit) {
gProfilerTriedInit = PR_TRUE;
gProfilerInited = _PlatformInitProfiler();
}
if (!gProfilerInited)
return PR_FALSE;
NS_ASSERTION(profileName, "need a name for this profile");
NS_PRECONDITION(!gCurrentProfile, "started a new profile before stopping another");
PRBool rv = _PlatformStartProfile(profileName);
JSBool ok = JS_StartProfiling(profileName);
gCurrentProfile = profileName;
return rv;
return ok ? PR_TRUE : PR_FALSE;
}
/**
@ -153,78 +136,13 @@ StartProfiling(const char* profileName)
inline PRBool
StopProfiling()
{
NS_ASSERTION(gProfilerTriedInit, "tried to stop profile before starting one");
if (!gProfilerInited)
return PR_FALSE;
NS_PRECONDITION(gCurrentProfile, "tried to stop profile before starting one");
const char* profileName = gCurrentProfile;
gCurrentProfile = 0;
return _PlatformStopProfile(profileName);
return JS_StopProfiling(profileName) ? PR_TRUE : PR_FALSE;
}
//--------------------------------------------------
// Shark impl
#if defined(MOZ_SHARK)
#include "jsdbgapi.h"
static PRBool
_PlatformInitProfiler()
{
return PR_TRUE;
}
static PRBool
_PlatformStartProfile(const char* profileName)
{
return JS_StartProfiling() ? PR_TRUE : PR_FALSE;
}
static PRBool
_PlatformStopProfile(const char* profileName)
{
JS_StopProfiling();
return PR_TRUE;
}
static PRBool
_PlatformDeinitProfiler()
{
return PR_TRUE;
}
//--------------------------------------------------
// Default, no-profiler impl
#else
static PRBool
_PlatformInitProfiler()
{
NS_WARNING("Profiling is not available/configured for your platform.");
return PR_FALSE;
}
static PRBool
_PlatformStartProfile(const char* profileName)
{
NS_WARNING("Profiling is not available/configured for your platform.");
return PR_FALSE;
}
static PRBool
_PlatformStopProfile(const char* profileName)
{
NS_WARNING("Profiling is not available/configured for your platform.");
return PR_FALSE;
}
static PRBool
_PlatformDeinitProfiler()
{
NS_WARNING("Profiling is not available/configured for your platform.");
return PR_FALSE;
}
#endif
//-----------------------------------------------------------------------------
class ScopedLogging
@ -264,10 +182,6 @@ class ScopedXPCOM : public nsIDirectoryServiceProvider2
~ScopedXPCOM()
{
if (gProfilerInited)
if (!_PlatformDeinitProfiler())
NS_WARNING("Problem shutting down profiler");
// If we created a profile directory, we need to remove it.
if (mProfD) {
if (NS_FAILED(mProfD->Remove(PR_TRUE)))