Bug 790117: Move external profiler control functions to their own source file in js/src/builtin; drop VTune. r=sfink
authorJim Blandy <jimb@mozilla.com>
Fri, 21 Sep 2012 16:36:13 -0700
changeset 107782 6fd36867bac751417fce03468cbe2c771810f24c
parent 107781 87bcca77b8579875a593fddaa71b8ef91aee8be5
child 107783 c914225fc39adfa6e9865fea3002a67eca84e211
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-esr52@2704e441363f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs790117, 675098
milestone18.0a1
Bug 790117: Move external profiler control functions to their own source file in js/src/builtin; drop VTune. r=sfink The VTune support needed to be updated for changes to the VTune control API; that work is bug 675098.
js/src/Makefile.in
js/src/builtin/Profilers.cpp
js/src/builtin/Profilers.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -126,16 +126,17 @@ CPPSRCS		= \
 		NameFunctions.cpp \
 		ParallelArray.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SPSProfiler.cpp \
 		TokenStream.cpp \
 		TestingFunctions.cpp \
+		Profilers.cpp \
 		LifoAlloc.cpp \
 		Eval.cpp \
 		MapObject.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
 		Marking.cpp \
 		Memory.cpp \
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Profilers.cpp
@@ -0,0 +1,502 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Profiling-related API */
+
+#include <stdarg.h>
+
+#include "Profilers.h"
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsprobes.h"
+
+#include "jscntxtinlines.h"
+#include "vm/Stack-inl.h"
+
+#ifdef MOZ_CALLGRIND
+#include <valgrind/callgrind.h>
+#endif
+
+#ifdef __APPLE__
+#include "devtools/sharkctl.h"
+#endif
+
+using namespace js;
+
+/* Thread-unsafe error management */
+
+static char gLastError[2000];
+
+static void
+#ifdef __GNUC__
+__attribute__((unused,format(printf,1,2)))
+#endif
+UnsafeError(const char *format, ...)
+{
+    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(const char *)
+JS_UnsafeGetLastProfilingError()
+{
+    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 __linux__
+    if (!js_StartPerf())
+        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 __linux__
+    if (!js_StopPerf())
+        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
+    } 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
+    }
+
+    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, unsigned 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)
+            js_free(mBytes);
+    }
+};
+
+static JSBool
+StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
+{
+    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, unsigned argc, jsval *vp)
+{
+    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, unsigned 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, unsigned 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, unsigned 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;
+}
+
+#ifdef MOZ_SHARK
+
+static JSBool
+IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, JSVAL_TRUE);
+    return true;
+}
+
+#endif
+
+#ifdef MOZ_CALLGRIND
+static JSBool
+StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
+    return JS_TRUE;
+}
+
+static JSBool
+StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
+{
+    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
+    return JS_TRUE;
+}
+
+static JSBool
+DumpCallgrind(JSContext *cx, unsigned 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
+
+static JSFunctionSpec profiling_functions[] = {
+    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
+    JS_FS_END
+};
+
+#endif
+
+JS_PUBLIC_API(JSBool)
+JS_DefineProfilingFunctions(JSContext *cx, JSObject *objArg)
+{
+    RootedObject obj(cx, objArg);
+
+    assertSameCompartment(cx, obj);
+#ifdef MOZ_PROFILING
+    return JS_DefineFunctions(cx, obj, profiling_functions);
+#else
+    return true;
+#endif
+}
+
+#ifdef MOZ_CALLGRIND
+
+JS_FRIEND_API(JSBool)
+js_StartCallgrind()
+{
+    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
+    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
+    return true;
+}
+
+JS_FRIEND_API(JSBool)
+js_StopCallgrind()
+{
+    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
+    return true;
+}
+
+JS_FRIEND_API(JSBool)
+js_DumpCallgrind(const char *outfile)
+{
+    if (outfile) {
+        JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
+    } else {
+        JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
+    }
+
+    return true;
+}
+
+#endif /* MOZ_CALLGRIND */
+
+#ifdef __linux__
+
+/*
+ * Code for starting and stopping |perf|, the Linux profiler.
+ *
+ * Output from profiling is written to mozperf.data in your cwd.
+ *
+ * To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
+ *
+ * To pass additional parameters to |perf record|, provide them in the
+ * MOZ_PROFILE_PERF_FLAGS environment variable.  If this variable does not
+ * exist, we default it to "--call-graph".  (If you don't want --call-graph but
+ * don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
+ * string.)
+ *
+ * If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
+ * asking for trouble.
+ *
+ * Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
+ * work if you pass an argument which includes a space (e.g.
+ * MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+
+static bool perfInitialized = false;
+static pid_t perfPid = 0;
+
+JSBool js_StartPerf()
+{
+    const char *outfile = "mozperf.data";
+
+    if (perfPid != 0) {
+        UnsafeError("js_StartPerf: called while perf was already running!\n");
+        return false;
+    }
+
+    // Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
+    if (!getenv("MOZ_PROFILE_WITH_PERF") ||
+        !strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
+        return true;
+    }
+
+    /*
+     * Delete mozperf.data the first time through -- we're going to append to it
+     * later on, so we want it to be clean when we start out.
+     */
+    if (!perfInitialized) {
+        perfInitialized = true;
+        unlink(outfile);
+        char cwd[4096];
+        printf("Writing perf profiling data to %s/%s\n",
+               getcwd(cwd, sizeof(cwd)), outfile);
+    }
+
+    pid_t mainPid = getpid();
+
+    pid_t childPid = fork();
+    if (childPid == 0) {
+        /* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
+
+        char mainPidStr[16];
+        snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
+        const char *defaultArgs[] = {"perf", "record", "--append",
+                                     "--pid", mainPidStr, "--output", outfile};
+
+        Vector<const char*, 0, SystemAllocPolicy> args;
+        args.append(defaultArgs, ArrayLength(defaultArgs));
+
+        const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
+        if (!flags) {
+            flags = "--call-graph";
+        }
+
+        // Split |flags| on spaces.  (Don't bother to free it -- we're going to
+        // exec anyway.)
+        char *toksave;
+        char *tok = strtok_r(strdup(flags), " ", &toksave);
+        while (tok) {
+            args.append(tok);
+            tok = strtok_r(NULL, " ", &toksave);
+        }
+
+        args.append((char*) NULL);
+
+        execvp("perf", const_cast<char**>(args.begin()));
+
+        /* Reached only if execlp fails. */
+        fprintf(stderr, "Unable to start perf.\n");
+        exit(1);
+    }
+    else if (childPid > 0) {
+        perfPid = childPid;
+
+        /* Give perf a chance to warm up. */
+        usleep(500 * 1000);
+        return true;
+    }
+    else {
+        UnsafeError("js_StartPerf: fork() failed\n");
+        return false;
+    }
+}
+
+JSBool js_StopPerf()
+{
+    if (perfPid == 0) {
+        UnsafeError("js_StopPerf: perf is not running.\n");
+        return true;
+    }
+
+    if (kill(perfPid, SIGINT)) {
+        UnsafeError("js_StopPerf: kill failed\n");
+
+        // Try to reap the process anyway.
+        waitpid(perfPid, NULL, WNOHANG);
+    }
+    else {
+        waitpid(perfPid, NULL, 0);
+    }
+
+    perfPid = 0;
+    return true;
+}
+
+#endif /* __linux__ */
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Profilers.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Functions for controlling profilers from within JS: Valgrind, Perf,
+ * Shark, etc.
+ */
+#ifndef Profilers_h___
+#define Profilers_h___
+
+#include "jsapi.h"
+
+/**
+ * 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(const char *profileName);
+
+/**
+ * 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);
+
+/**
+ * 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();
+
+extern JS_FRIEND_API(JSBool)
+js_StartCallgrind();
+
+extern JS_FRIEND_API(JSBool)
+js_DumpCallgrind(const char *outfile);
+
+#endif /* MOZ_CALLGRIND */
+
+#ifdef __linux__
+
+extern JS_FRIEND_API(JSBool)
+js_StartPerf();
+
+extern JS_FRIEND_API(JSBool)
+js_StopPerf();
+
+#endif /* __linux__ */
+
+#endif /* Profilers_h___ */
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -4,17 +4,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * JS debugging API.
  */
 #include <string.h>
-#include <stdarg.h>
 #include "jsprvtd.h"
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
@@ -43,20 +42,16 @@
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/Stack-inl.h"
 
 #include "jsautooplen.h"
 #include "mozilla/Util.h"
 
-#ifdef __APPLE__
-#include "devtools/sharkctl.h"
-#endif
-
 using namespace js;
 using namespace js::gc;
 using namespace mozilla;
 
 JS_PUBLIC_API(JSBool)
 JS_GetDebugMode(JSContext *cx)
 {
     return cx->compartment->debugMode();
@@ -1059,662 +1054,16 @@ js_RevertVersion(JSContext *cx)
 JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt)
 {
     return &rt->debugHooks;
 }
 
 /************************************************************************/
 
-/* Profiling-related API */
-
-/* Thread-unsafe error management */
-
-static char gLastError[2000];
-
-static void
-#ifdef __GNUC__
-__attribute__((unused,format(printf,1,2)))
-#endif
-UnsafeError(const char *format, ...)
-{
-    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(const char *)
-JS_UnsafeGetLastProfilingError()
-{
-    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
-#if 0 //def MOZ_VTUNE
-    if (!js_StartVtune(profileName))
-        ok = JS_FALSE;
-#endif
-#ifdef __linux__
-    if (!js_StartPerf())
-        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
-#if 0 //def MOZ_VTUNE
-    if (!js_StopVtune())
-        ok = JS_FALSE;
-#endif
-#ifdef __linux__
-    if (!js_StopPerf())
-        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
-#if 0 //def 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
-#if 0 //def 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, unsigned 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)
-            js_free(mBytes);
-    }
-};
-
-static JSBool
-StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
-{
-    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, unsigned argc, jsval *vp)
-{
-    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, unsigned 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, unsigned 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, unsigned 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;
-}
-
-#ifdef MOZ_SHARK
-
-static JSBool
-IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
-{
-    JS_SET_RVAL(cx, vp, JSVAL_TRUE);
-    return true;
-}
-
-#endif
-
-#ifdef MOZ_CALLGRIND
-static JSBool
-StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
-{
-    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StartCallgrind()));
-    return JS_TRUE;
-}
-
-static JSBool
-StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
-{
-    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopCallgrind()));
-    return JS_TRUE;
-}
-
-static JSBool
-DumpCallgrind(JSContext *cx, unsigned 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, unsigned 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, unsigned argc, jsval *vp)
-{
-    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_StopVtune()));
-    return JS_TRUE;
-}
-
-static JSBool
-PauseVtune(JSContext *cx, unsigned argc, jsval *vp)
-{
-    JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(js_PauseVtune()));
-    return JS_TRUE;
-}
-
-static JSBool
-ResumeVtune(JSContext *cx, unsigned 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,      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
-#if 0 //ef 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
-};
-
-#endif
-
-JS_PUBLIC_API(JSBool)
-JS_DefineProfilingFunctions(JSContext *cx, JSObject *objArg)
-{
-    RootedObject obj(cx, objArg);
-
-    assertSameCompartment(cx, obj);
-#ifdef MOZ_PROFILING
-    return JS_DefineFunctions(cx, obj, profiling_functions);
-#else
-    return true;
-#endif
-}
-
-#ifdef MOZ_CALLGRIND
-
-#include <valgrind/callgrind.h>
-
-JS_FRIEND_API(JSBool)
-js_StartCallgrind()
-{
-    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
-    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
-    return true;
-}
-
-JS_FRIEND_API(JSBool)
-js_StopCallgrind()
-{
-    JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
-    return true;
-}
-
-JS_FRIEND_API(JSBool)
-js_DumpCallgrind(const char *outfile)
-{
-    if (outfile) {
-        JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
-    } else {
-        JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
-    }
-
-    return true;
-}
-
-#endif /* MOZ_CALLGRIND */
-
-#if 0 //def MOZ_VTUNE
-#include <VTuneApi.h>
-
-static const char *vtuneErrorMessages[] = {
-  "unknown, error #0",
-  "invalid 'max samples' field",
-  "invalid 'samples per buffer' field",
-  "invalid 'sample interval' field",
-  "invalid path",
-  "sample file in use",
-  "invalid 'number of events' field",
-  "unknown, error #7",
-  "internal error",
-  "bad event name",
-  "VTStopSampling called without calling VTStartSampling",
-  "no events selected for event-based sampling",
-  "events selected cannot be run together",
-  "no sampling parameters",
-  "sample database already exists",
-  "sampling already started",
-  "time-based sampling not supported",
-  "invalid 'sampling parameters size' field",
-  "invalid 'event size' field",
-  "sampling file already bound",
-  "invalid event path",
-  "invalid license",
-  "invalid 'global options' field",
-
-};
-
-bool
-js_StartVtune(const char *profileName)
-{
-    VTUNE_EVENT events[] = {
-        { 1000000, 0, 0, 0, "CPU_CLK_UNHALTED.CORE" },
-        { 1000000, 0, 0, 0, "INST_RETIRED.ANY" },
-    };
-
-    U32 n_events = sizeof(events) / sizeof(VTUNE_EVENT);
-    char *default_filename = "mozilla-vtune.tb5";
-    JSString *str;
-    U32 status;
-
-    VTUNE_SAMPLING_PARAMS params = {
-        sizeof(VTUNE_SAMPLING_PARAMS),
-        sizeof(VTUNE_EVENT),
-        0, 0, /* Reserved fields */
-        1,    /* Initialize in "paused" state */
-        0,    /* Max samples, or 0 for "continuous" */
-        4096, /* Samples per buffer */
-        0.1,  /* Sampling interval in ms */
-        1,    /* 1 for event-based sampling, 0 for time-based */
-
-        n_events,
-        events,
-        default_filename,
-    };
-
-    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)
-        js_free(params.tb5Filename);
-
-    if (status != 0) {
-        if (status == VTAPI_MULTIPLE_RUNS)
-            VTStopSampling(0);
-        if (status < sizeof(vtuneErrorMessages))
-            UnsafeError("Vtune setup error: %s", vtuneErrorMessages[status]);
-        else
-            UnsafeError("Vtune setup error: %d", status);
-        return false;
-    }
-    return true;
-}
-
-bool
-js_StopVtune()
-{
-    U32 status = VTStopSampling(1);
-    if (status) {
-        if (status < sizeof(vtuneErrorMessages))
-            UnsafeError("Vtune shutdown error: %s", vtuneErrorMessages[status]);
-        else
-            UnsafeError("Vtune shutdown error: %d", status);
-        return false;
-    }
-    return true;
-}
-
-bool
-js_PauseVtune()
-{
-    VTPause();
-    return true;
-}
-
-bool
-js_ResumeVtune()
-{
-    VTResume();
-    return true;
-}
-
-#endif /* MOZ_VTUNE */
-
-#ifdef __linux__
-
-/*
- * Code for starting and stopping |perf|, the Linux profiler.
- *
- * Output from profiling is written to mozperf.data in your cwd.
- *
- * To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
- *
- * To pass additional parameters to |perf record|, provide them in the
- * MOZ_PROFILE_PERF_FLAGS environment variable.  If this variable does not
- * exist, we default it to "--call-graph".  (If you don't want --call-graph but
- * don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
- * string.)
- *
- * If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
- * asking for trouble.
- *
- * Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
- * work if you pass an argument which includes a space (e.g.
- * MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
- */
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <signal.h>
-
-static bool perfInitialized = false;
-static pid_t perfPid = 0;
-
-JSBool js_StartPerf()
-{
-    const char *outfile = "mozperf.data";
-
-    if (perfPid != 0) {
-        UnsafeError("js_StartPerf: called while perf was already running!\n");
-        return false;
-    }
-
-    // Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
-    if (!getenv("MOZ_PROFILE_WITH_PERF") ||
-        !strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
-        return true;
-    }
-
-    /*
-     * Delete mozperf.data the first time through -- we're going to append to it
-     * later on, so we want it to be clean when we start out.
-     */
-    if (!perfInitialized) {
-        perfInitialized = true;
-        unlink(outfile);
-        char cwd[4096];
-        printf("Writing perf profiling data to %s/%s\n",
-               getcwd(cwd, sizeof(cwd)), outfile);
-    }
-
-    pid_t mainPid = getpid();
-
-    pid_t childPid = fork();
-    if (childPid == 0) {
-        /* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
-
-        char mainPidStr[16];
-        snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
-        const char *defaultArgs[] = {"perf", "record", "--append",
-                                     "--pid", mainPidStr, "--output", outfile};
-
-        Vector<const char*, 0, SystemAllocPolicy> args;
-        args.append(defaultArgs, ArrayLength(defaultArgs));
-
-        const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
-        if (!flags) {
-            flags = "--call-graph";
-        }
-
-        // Split |flags| on spaces.  (Don't bother to free it -- we're going to
-        // exec anyway.)
-        char *toksave;
-        char *tok = strtok_r(strdup(flags), " ", &toksave);
-        while (tok) {
-            args.append(tok);
-            tok = strtok_r(NULL, " ", &toksave);
-        }
-
-        args.append((char*) NULL);
-
-        execvp("perf", const_cast<char**>(args.begin()));
-
-        /* Reached only if execlp fails. */
-        fprintf(stderr, "Unable to start perf.\n");
-        exit(1);
-    }
-    else if (childPid > 0) {
-        perfPid = childPid;
-
-        /* Give perf a chance to warm up. */
-        usleep(500 * 1000);
-        return true;
-    }
-    else {
-        UnsafeError("js_StartPerf: fork() failed\n");
-        return false;
-    }
-}
-
-JSBool js_StopPerf()
-{
-    if (perfPid == 0) {
-        UnsafeError("js_StopPerf: perf is not running.\n");
-        return true;
-    }
-
-    if (kill(perfPid, SIGINT)) {
-        UnsafeError("js_StopPerf: kill failed\n");
-
-        // Try to reap the process anyway.
-        waitpid(perfPid, NULL, WNOHANG);
-    }
-    else {
-        waitpid(perfPid, NULL, 0);
-    }
-
-    perfPid = 0;
-    return true;
-}
-
-#endif /* __linux__ */
-
 JS_PUBLIC_API(void)
 JS_DumpBytecode(JSContext *cx, JSScript *scriptArg)
 {
 #if defined(DEBUG)
     Rooted<JSScript*> script(cx, scriptArg);
 
     Sprinter sprinter(cx);
     if (!sprinter.init())
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -390,114 +390,25 @@ JS_GetScriptTotalSize(JSContext *cx, JSS
 
 extern JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx);
 
 extern JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt);
 
 /**
- * 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(const char *profileName);
-
-/**
- * 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);
 
 /* Defined in vm/Debugger.cpp. */
 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();
-
-extern JS_FRIEND_API(JSBool)
-js_StartCallgrind();
-
-extern JS_FRIEND_API(JSBool)
-js_DumpCallgrind(const char *outfile);
-
-#endif /* MOZ_CALLGRIND */
-
-#ifdef MOZ_VTUNE
-
-extern JS_FRIEND_API(bool)
-js_StartVtune(const char *profileName);
-
-extern JS_FRIEND_API(bool)
-js_StopVtune();
-
-extern JS_FRIEND_API(bool)
-js_PauseVtune();
-
-extern JS_FRIEND_API(bool)
-js_ResumeVtune();
-
-#endif /* MOZ_VTUNE */
-
-#ifdef __linux__
-
-extern JS_FRIEND_API(JSBool)
-js_StartPerf();
-
-extern JS_FRIEND_API(JSBool)
-js_StopPerf();
-
-#endif /* __linux__ */
-
 extern JS_PUBLIC_API(void)
 JS_DumpBytecode(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(void)
 JS_DumpCompartmentBytecode(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_DumpPCCounts(JSContext *cx, JSScript *script);