Bug 444023, Add JS functions to stop/start callgrind, r=sayrer
authorGraydon Hoare <graydon@mozilla.com>
Tue, 08 Jul 2008 15:58:08 -0700
changeset 15763 e004755902369e2623c2565d7de5d9b45500b49b
parent 15762 98e43ce43c792869c7de48e278bd6d71ace5a136
child 15764 b863a74743937ece5646edcb761aad2bf4d4c53b
push idunknown
push userunknown
push dateunknown
reviewerssayrer
bugs444023
milestone1.9.1a1pre
Bug 444023, Add JS functions to stop/start callgrind, r=sayrer
config/autoconf.mk.in
configure.in
dom/src/base/nsJSEnvironment.cpp
js/src/Makefile.ref
js/src/js.cpp
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/shell/Makefile.in
js/src/xpconnect/shell/xpcshell.cpp
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -98,16 +98,17 @@ MOZ_EXTENSIONS  = @MOZ_EXTENSIONS@
 MOZ_IMG_DECODERS= @MOZ_IMG_DECODERS@
 MOZ_IMG_ENCODERS= @MOZ_IMG_ENCODERS@
 MOZ_JSDEBUGGER  = @MOZ_JSDEBUGGER@
 MOZ_PERF_METRICS = @MOZ_PERF_METRICS@
 MOZ_LEAKY	= @MOZ_LEAKY@
 MOZ_MEMORY      = @MOZ_MEMORY@
 MOZ_JPROF       = @MOZ_JPROF@
 MOZ_SHARK       = @MOZ_SHARK@
+MOZ_CALLGRIND   = @MOZ_CALLGRIND@
 DEHYDRA_PATH    = @DEHYDRA_PATH@
 
 MOZ_XPCTOOLS    = @MOZ_XPCTOOLS@
 ENABLE_EAZEL_PROFILER=@ENABLE_EAZEL_PROFILER@
 EAZEL_PROFILER_CFLAGS=@EAZEL_PROFILER_CFLAGS@
 EAZEL_PROFILER_LIBS=@EAZEL_PROFILER_LIBS@
 GC_LEAK_DETECTOR = @GC_LEAK_DETECTOR@
 NS_TRACE_MALLOC = @NS_TRACE_MALLOC@
--- a/configure.in
+++ b/configure.in
@@ -6405,16 +6405,27 @@ MOZ_ARG_ENABLE_BOOL(shark,
 [  --enable-shark          Enable shark remote profiling (needs CHUD framework)],
     MOZ_SHARK=1,
     MOZ_SHARK= )
 if test -n "$MOZ_SHARK"; then
     AC_DEFINE(MOZ_SHARK)
 fi
 
 dnl ========================================================
+dnl callgrind
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(callgrind,
+[  --enable-callgrind          Enable callgrind profiling],
+    MOZ_CALLGRIND=1,
+    MOZ_CALLGRIND= )
+if test -n "$MOZ_CALLGRIND"; then
+    AC_DEFINE(MOZ_CALLGRIND)
+fi
+
+dnl ========================================================
 dnl = Enable static checking using gcc-dehydra
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(static-checking,
 [  --with-static-checking=path/to/gcc_dehydra.so
                             Enable static checking of code using GCC-dehydra],
     DEHYDRA_PATH=$withval,
     DEHYDRA_PATH= )
@@ -7796,16 +7807,17 @@ AC_SUBST(ENABLE_EAZEL_PROFILER)
 AC_SUBST(EAZEL_PROFILER_CFLAGS)
 AC_SUBST(EAZEL_PROFILER_LIBS)
 AC_SUBST(MOZ_PERF_METRICS)
 AC_SUBST(GC_LEAK_DETECTOR)
 AC_SUBST(MOZ_LOG_REFCNT)
 AC_SUBST(MOZ_LEAKY)
 AC_SUBST(MOZ_JPROF)
 AC_SUBST(MOZ_SHARK)
+AC_SUBST(MOZ_CALLGRIND)
 AC_SUBST(MOZ_XPCTOOLS)
 AC_SUBST(MOZ_JSLOADER)
 AC_SUBST(MOZ_USE_NATIVE_UCONV)
 AC_SUBST(MOZ_INSURE)
 AC_SUBST(MOZ_INSURE_DIRS)
 AC_SUBST(MOZ_INSURE_EXCLUDE_DIRS)
 AC_SUBST(MOZ_QUANTIFY)
 AC_SUBST(MOZ_INSURIFYING)
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -3102,16 +3102,25 @@ static JSFunctionSpec SharkFunctions[] =
     {"startShark",                 js_StartShark,              0, 0, 0},
     {"stopShark",                  js_StopShark,               0, 0, 0},
     {"connectShark",               js_ConnectShark,            0, 0, 0},
     {"disconnectShark",            js_DisconnectShark,         0, 0, 0},
     {nsnull,                       nsnull,                     0, 0, 0}
 };
 #endif
 
+#ifdef MOZ_CALLGRIND
+static JSFunctionSpec CallgrindFunctions[] = {
+    {"startCallgrind",             js_StartCallgrind,          0, 0, 0},
+    {"stopCallgrind",              js_StopCallgrind,           0, 0, 0},
+    {"dumpCallgrind",              js_DumpCallgrind,           1, 0, 0},
+    {nsnull,                       nsnull,                     0, 0, 0}
+};
+#endif
+
 nsresult
 nsJSContext::InitClasses(void *aGlobalObj)
 {
   nsresult rv = NS_OK;
 
   JSObject *globalObj = static_cast<JSObject *>(aGlobalObj);
 
   rv = InitializeExternalClasses();
@@ -3139,16 +3148,21 @@ nsJSContext::InitClasses(void *aGlobalOb
   ::JS_DefineFunctions(mContext, globalObj, JProfFunctions);
 #endif
 
 #ifdef MOZ_SHARK
   // Attempt to initialize Shark functions
   ::JS_DefineFunctions(mContext, globalObj, SharkFunctions);
 #endif
 
+#ifdef MOZ_CALLGRIND
+  // Attempt to initialize Callgrind functions
+  ::JS_DefineFunctions(mContext, globalObj, CallgrindFunctions);
+#endif
+
   JSOptionChangedCallback(js_options_dot_str, this);
     
   return rv;
 }
 
 void
 nsJSContext::ClearScope(void *aGlobalObj, PRBool aClearFromProtoChain)
 {
--- a/js/src/Makefile.ref
+++ b/js/src/Makefile.ref
@@ -89,16 +89,19 @@ INTERP_CFLAGS   += $(INTERP_OPTIMIZER) $
 LDFLAGS		= $(XLDFLAGS)
 LDFLAGS += $(OS_LDFLAGS)
 
 ifdef MOZ_SHARK
 DEFINES += -DMOZ_SHARK
 CFLAGS += -F/System/Library/PrivateFrameworks
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
 endif
+ifdef MOZ_CALLGRIND
+DEFINES += -DMOZ_CALLGRIND
+endif
 
 ifndef NO_LIBM
 LDFLAGS += -lm
 endif
 
 # Prevent floating point errors caused by VC++ optimizations
 ifeq ($(OS_ARCH),WINNT)
 _MSC_VER = $(shell $(CXX) 2>&1 | sed -n 's/.*Compiler Version \([0-9]*\)\.\([0-9]*\).*/\1\2/p')
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -2819,16 +2819,21 @@ static JSFunctionSpec shell_functions[] 
     JS_FN("toint32",        ToInt32,        1,1,0),
     JS_FS("evalcx",         EvalInContext,  1,0,0),
 #ifdef MOZ_SHARK
     JS_FS("startShark",      js_StartShark,      0,0,0),
     JS_FS("stopShark",       js_StopShark,       0,0,0),
     JS_FS("connectShark",    js_ConnectShark,    0,0,0),
     JS_FS("disconnectShark", js_DisconnectShark, 0,0,0),
 #endif
+#ifdef MOZ_CALLGRIND
+    JS_FS("startCallgrind",  js_StartCallgrind,  0,0,0),
+    JS_FS("stopCallgrind",   js_StopCallgrind,   0,0,0),
+    JS_FS("dumpCallgrind",   js_DumpCallgrind,   1,0,0),
+#endif
 #ifdef DEBUG_ARRAYS
     JS_FS("arrayInfo",       js_ArrayInfo,       1,0,0),
 #endif
 #ifdef JS_THREADSAFE
     JS_FN("sleep",          Sleep,          1,1,0),
     JS_FN("scatter",        Scatter,        1,1,0),
 #endif
     JS_FS_END
@@ -2896,16 +2901,21 @@ static const char *const shell_help_mess
 #ifdef MOZ_SHARK
 "startShark()             Start a Shark session.\n"
 "                         Shark must be running with programatic sampling.",
 "stopShark()              Stop a running Shark session.",
 "connectShark()           Connect to Shark.\n"
 "                         The -k switch does this automatically.",
 "disconnectShark()        Disconnect from Shark.",
 #endif
+#ifdef MOZ_CALLGRIND
+"startCallgrind()         Start callgrind instrumentation.\n",
+"stopCallgrind()          Stop callgrind instumentation.",
+"dumpCallgrind()          Dump callgrind counters.\n",
+#endif
 #ifdef DEBUG_ARRAYS
 "arrayInfo(a1, a2, ...)   Report statistics about arrays.",
 #endif
 #ifdef JS_THREADSAFE
 "sleep(dt)                Sleep for dt seconds",
 "scatter(fns)             Call functions concurrently (ignoring errors)",
 #endif
 };
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1794,8 +1794,52 @@ js_DisconnectShark(JSContext *cx, JSObje
     if (!JS_DisconnectShark()) {
         JS_ReportError(cx, "Error disconnecting from Shark.");
     }
 
     return JS_TRUE;
 }
 
 #endif /* MOZ_SHARK */
+
+#ifdef MOZ_CALLGRIND
+
+#include <valgrind/callgrind.h>
+
+JS_FRIEND_API(JSBool)
+js_StartCallgrind(JSContext *cx, JSObject *obj,
+                  uintN argc, jsval *argv, jsval *rval)
+{
+    CALLGRIND_START_INSTRUMENTATION;    
+    CALLGRIND_ZERO_STATS;
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_StopCallgrind(JSContext *cx, JSObject *obj,
+                 uintN argc, jsval *argv, jsval *rval)
+{
+    CALLGRIND_STOP_INSTRUMENTATION;
+    return JS_TRUE;
+}
+
+JS_FRIEND_API(JSBool)
+js_DumpCallgrind(JSContext *cx, JSObject *obj,
+                 uintN argc, jsval *argv, jsval *rval)
+{
+    JSString *str;
+    char *cstr;
+
+    if (argc > 0 && JSVAL_IS_STRING(argv[0])) {
+        str = JSVAL_TO_STRING(argv[0]);
+        cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
+        if (cstr) {
+            CALLGRIND_DUMP_STATS_AT(cstr);
+            JS_free(cx, cstr);
+            return JS_TRUE;
+        }
+    }
+    CALLGRIND_DUMP_STATS;
+
+    return JS_TRUE;
+}
+
+#endif /* MOZ_CALLGRIND */
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -454,11 +454,27 @@ js_ConnectShark(JSContext *cx, JSObject 
                 jsval *rval);
 
 extern JS_FRIEND_API(JSBool)
 js_DisconnectShark(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                    jsval *rval);
 
 #endif /* MOZ_SHARK */
 
+#ifdef MOZ_CALLGRIND
+
+extern JS_FRIEND_API(JSBool)
+js_StopCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval);
+
+extern JS_FRIEND_API(JSBool)
+js_StartCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                  jsval *rval);
+
+extern JS_FRIEND_API(JSBool)
+js_DumpCallgrind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+                 jsval *rval);
+
+#endif /* MOZ_CALLGRIND */
+
 JS_END_EXTERN_C
 
 #endif /* jsdbgapi_h___ */
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -78,17 +78,17 @@
 #include "jsprf.h"
 #include "nsIFastLoadFileControl.h"
 // For reporting errors with the console service
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "prmem.h"
 #include "plbase64.h"
 
-#ifdef MOZ_SHARK
+#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND)
 #include "jsdbgapi.h"
 #endif
 
 static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1";
 static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
 static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
 
 /* Some platforms don't have an implementation of PR_MemMap(). */
@@ -277,16 +277,21 @@ static JSFunctionSpec gGlobalFun[] = {
     {"atob",    Atob,   1,0,0},
     {"btoa",    Btoa,   1,0,0},
 #ifdef MOZ_SHARK
     {"startShark",      js_StartShark,     0,0,0},
     {"stopShark",       js_StopShark,      0,0,0},
     {"connectShark",    js_ConnectShark,   0,0,0},
     {"disconnectShark", js_DisconnectShark,0,0,0},
 #endif
+#ifdef MOZ_CALLGRIND
+    {"startCallgrind",  js_StartCallgrind, 0,0,0},
+    {"stopCallgrind",   js_StopCallgrind,  0,0,0},
+    {"dumpCallgrind",   js_DumpCallgrind,  1,0,0},
+#endif
     {nsnull,nsnull,0,0,0}
 };
 
 class JSCLContextHelper
 {
 public:
     JSCLContextHelper(JSContext* cx);
     ~JSCLContextHelper();
--- a/js/src/xpconnect/shell/Makefile.in
+++ b/js/src/xpconnect/shell/Makefile.in
@@ -69,17 +69,19 @@ include $(topsrcdir)/config/rules.mk
 
 DEFINES		+= -DJS_THREADSAFE
 
 ifdef MOZ_SHARK
 DEFINES += -DMOZ_SHARK
 CFLAGS += -F/System/Library/PrivateFrameworks
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework CHUD
 endif
-
+ifdef MOZ_CALLGRIND
+DEFINES += -DMOZ_CALLGRIND
+endif
 #
 # Line editing support.  If your OS supplies the readline library, define
 # JS_READLINE to get line editing in the xpcshell.
 #
 # If you can't link against readline because of GPL licensing issues
 # (which may not apply, as xpcshell.c has the dual license) you might
 # look at mozilla/js/src/editline, which is license-free (but not part
 # of the mozilla build.)
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -79,17 +79,17 @@
 #if defined(XP_WIN) || defined(XP_OS2)
 #include <io.h>     /* for isatty() */
 #elif defined(XP_UNIX) || defined(XP_BEOS)
 #include <unistd.h>     /* for isatty() */
 #endif
 
 #include "nsIJSContextStack.h"
 
-#ifdef MOZ_SHARK
+#if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND)
 #include "jsdbgapi.h"
 #endif
 
 /***************************************************************************/
 
 #ifdef JS_THREADSAFE
 #define DoBeginRequest(cx) JS_BeginRequest((cx))
 #define DoEndRequest(cx)   JS_EndRequest((cx))
@@ -434,16 +434,21 @@ static JSFunctionSpec glob_functions[] =
     {"dumpHeap",        DumpHeap,       5,0,0},
 #endif
 #ifdef MOZ_SHARK
     {"startShark",      js_StartShark,      0,0,0},
     {"stopShark",       js_StopShark,       0,0,0},
     {"connectShark",    js_ConnectShark,    0,0,0},
     {"disconnectShark", js_DisconnectShark, 0,0,0},
 #endif
+#ifdef MOZ_CALLGRIND
+    {"startCallgrind",  js_StartCallgrind,  0,0,0},
+    {"stopCallgrind",   js_StopCallgrind,   0,0,0},
+    {"dumpCallgrind",   js_DumpCallgrind,   1,0,0},
+#endif
     {nsnull,nsnull,0,0,0}
 };
 
 JSClass global_class = {
     "global", 0,
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,
     JS_EnumerateStub, JS_ResolveStub,   JS_ConvertStub,   JS_FinalizeStub
 };