Bug 1439014 - Add a profiler feature to enable JIT optimization tracking. r?sfink, r?njn draft
authorMarkus Stange <mstange@themasta.com>
Sat, 17 Feb 2018 19:38:14 -0500
changeset 773215 f43d3b9576066f389a6fd07fefbd4a6f570927ae
parent 773214 c62abf54c7cdad141aa669a490a51b33caeb85d6
child 773252 3a614432de0351c25817d23591186f89ab2d03f1
push id104180
push userbmo:mstange@themasta.com
push dateTue, 27 Mar 2018 17:19:32 +0000
reviewerssfink, njn
bugs1439014
milestone61.0a1
Bug 1439014 - Add a profiler feature to enable JIT optimization tracking. r?sfink, r?njn MozReview-Commit-ID: LDxiLVp7e9v
browser/components/extensions/schemas/geckoProfiler.json
js/src/jsapi.cpp
js/src/jsapi.h
tools/profiler/core/RegisteredThread.cpp
tools/profiler/core/RegisteredThread.h
tools/profiler/core/platform.cpp
tools/profiler/public/GeckoProfiler.h
--- a/browser/components/extensions/schemas/geckoProfiler.json
+++ b/browser/components/extensions/schemas/geckoProfiler.json
@@ -27,17 +27,18 @@
           "js",
           "leaf",
           "mainthreadio",
           "memory",
           "privacy",
           "restyle",
           "stackwalk",
           "tasktracer",
-          "threads"
+          "threads",
+          "trackopts"
         ]
       }
     ],
     "functions": [
       {
        "name": "start",
        "type": "function",
        "description": "Starts the profiler with the specified settings.",
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -7255,16 +7255,19 @@ JS_SetGlobalJitCompilerOption(JSContext*
         break;
       case JSJITCOMPILER_JUMP_THRESHOLD:
         if (value == uint32_t(-1)) {
             jit::DefaultJitOptions defaultValues;
             value = defaultValues.jumpThreshold;
         }
         jit::JitOptions.jumpThreshold = value;
         break;
+      case JSJITCOMPILER_TRACK_OPTIMIZATIONS:
+        jit::JitOptions.disableOptimizationTracking = !value;
+        break;
       case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
         jit::JitOptions.spectreIndexMasking = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
         jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
         jit::JitOptions.spectreObjectMitigationsMisc = !!value;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5862,16 +5862,17 @@ JS_SetOffthreadIonCompilationEnabled(JSC
     Register(ION_FORCE_IC, "ion.forceinlineCaches")                         \
     Register(ION_ENABLE, "ion.enable")                                      \
     Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
     Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis")          \
     Register(BASELINE_ENABLE, "baseline.enable")                            \
     Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable")  \
     Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks")                    \
     Register(JUMP_THRESHOLD, "jump-threshold")                              \
+    Register(TRACK_OPTIMIZATIONS, "jit.track-optimizations")                \
     Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt")      \
     Register(SPECTRE_INDEX_MASKING, "spectre.index-masking")                \
     Register(SPECTRE_OBJECT_MITIGATIONS_BARRIERS, "spectre.object-mitigations.barriers") \
     Register(SPECTRE_OBJECT_MITIGATIONS_MISC, "spectre.object-mitigations.misc") \
     Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations")      \
     Register(SPECTRE_VALUE_MASKING, "spectre.value-masking")                \
     Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls")          \
     Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable")                  \
--- a/tools/profiler/core/RegisteredThread.cpp
+++ b/tools/profiler/core/RegisteredThread.cpp
@@ -10,16 +10,17 @@ RegisteredThread::RegisteredThread(Threa
                                    void* aStackTop)
   : mRacyRegisteredThread(aInfo->ThreadId())
   , mPlatformData(AllocPlatformData(aInfo->ThreadId()))
   , mStackTop(aStackTop)
   , mThreadInfo(aInfo)
   , mThread(aThread)
   , mContext(nullptr)
   , mJSSampling(INACTIVE)
+  , mJSTrackOptimizations(false)
 {
   MOZ_COUNT_CTOR(RegisteredThread);
 
   // We don't have to guess on mac
 #if defined(GP_OS_darwin)
   pthread_t self = pthread_self();
   mStackTop = pthread_get_stackaddr_np(self);
 #endif
--- a/tools/profiler/core/RegisteredThread.h
+++ b/tools/profiler/core/RegisteredThread.h
@@ -192,23 +192,24 @@ public:
   JSContext* GetJSContext() const { return mContext; }
 
   const RefPtr<ThreadInfo> Info() const { return mThreadInfo; }
   const nsCOMPtr<nsIEventTarget> GetEventTarget() const { return mThread; }
 
   // Request that this thread start JS sampling. JS sampling won't actually
   // start until a subsequent PollJSSampling() call occurs *and* mContext has
   // been set.
-  void StartJSSampling()
+  void StartJSSampling(bool aTrackOptimizations)
   {
     // This function runs on-thread or off-thread.
 
     MOZ_RELEASE_ASSERT(mJSSampling == INACTIVE ||
                        mJSSampling == INACTIVE_REQUESTED);
     mJSSampling = ACTIVE_REQUESTED;
+    mJSTrackOptimizations = aTrackOptimizations;
   }
 
   // Request that this thread stop JS sampling. JS sampling won't actually stop
   // until a subsequent PollJSSampling() call occurs.
   void StopJSSampling()
   {
     // This function runs on-thread or off-thread.
 
@@ -231,16 +232,18 @@ public:
       // - ACTIVE, INACTIVE_REQUESTED, ACTIVE_REQUESTED, ACTIVE
       //
       // Therefore, the if and else branches here aren't always interleaved.
       // This is ok because the JS engine can handle that.
       //
       if (mJSSampling == ACTIVE_REQUESTED) {
         mJSSampling = ACTIVE;
         js::EnableContextProfilingStack(mContext, true);
+        JS_SetGlobalJitCompilerOption(mContext, JSJITCOMPILER_TRACK_OPTIMIZATIONS,
+                                      mJSTrackOptimizations);
         js::RegisterContextProfilingEventMarker(mContext, profiler_add_marker);
 
       } else if (mJSSampling == INACTIVE_REQUESTED) {
         mJSSampling = INACTIVE;
         js::EnableContextProfilingStack(mContext, false);
       }
     }
   }
@@ -299,11 +302,13 @@ private:
   // to actually happen.
   //
   enum {
     INACTIVE = 0,
     ACTIVE_REQUESTED = 1,
     ACTIVE = 2,
     INACTIVE_REQUESTED = 3,
   } mJSSampling;
+
+  bool mJSTrackOptimizations;
 };
 
 #endif  // RegisteredThread_h
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2248,17 +2248,18 @@ locked_register_thread(PSLockRef aLock, 
     nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
     ProfiledThreadData* profiledThreadData =
       ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
         MakeUnique<ProfiledThreadData>(info, eventTarget));
 
     if (ActivePS::FeatureJS(aLock)) {
       // This StartJSSampling() call is on-thread, so we can poll manually to
       // start JS sampling immediately.
-      registeredThread->StartJSSampling();
+      registeredThread->StartJSSampling(
+        ActivePS::FeatureTrackOptimizations(aLock));
       registeredThread->PollJSSampling();
       if (registeredThread->GetJSContext()) {
         profiledThreadData->NotifyReceivedJSContext(ActivePS::Buffer(aLock).mRangeEnd);
       }
     }
   }
 
   CorePS::AppendRegisteredThread(aLock, Move(registeredThread));
@@ -2847,17 +2848,18 @@ locked_profiler_start(PSLockRef aLock, u
     RefPtr<ThreadInfo> info = registeredThread->Info();
 
     if (ActivePS::ShouldProfileThread(aLock, info)) {
       nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
       ProfiledThreadData* profiledThreadData =
         ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
           MakeUnique<ProfiledThreadData>(info, eventTarget));
       if (ActivePS::FeatureJS(aLock)) {
-        registeredThread->StartJSSampling();
+        registeredThread->StartJSSampling(
+          ActivePS::FeatureTrackOptimizations(aLock));
         if (info->ThreadId() == tid) {
           // We can manually poll the current thread so it starts sampling
           // immediately.
           registeredThread->PollJSSampling();
         } else if (info->IsMainThread()) {
           // Dispatch a runnable to the main thread to call PollJSSampling(),
           // so that we don't have wait for the next JS interrupt callback in
           // order to start profiling JS.
@@ -3475,17 +3477,18 @@ profiler_clear_js_context()
       // nulling out the JSContext.
       registeredThread->StopJSSampling();
       registeredThread->PollJSSampling();
 
       registeredThread->ClearJSContext();
 
       // Tell the thread that we'd like to have JS sampling on this
       // thread again, once it gets a new JSContext (if ever).
-      registeredThread->StartJSSampling();
+      registeredThread->StartJSSampling(
+        ActivePS::FeatureTrackOptimizations(lock));
       return;
     }
   }
 
   registeredThread->ClearJSContext();
 }
 
 int
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -123,17 +123,20 @@ class TimeStamp;
   \
   /* Walk the C++ stack. Not available on all platforms. */ \
   macro(7, "stackwalk", StackWalk) \
   \
   /* Start profiling with feature TaskTracer. */ \
   macro(8, "tasktracer", TaskTracer) \
   \
   /* Profile the registered secondary threads. */ \
-  macro(9, "threads", Threads)
+  macro(9, "threads", Threads) \
+  \
+  /* Have the JavaScript engine track JIT optimizations. */ \
+  macro(10, "trackopts", TrackOptimizations)
 
 struct ProfilerFeature
 {
   #define DECLARE(n_, str_, Name_) \
     static const uint32_t Name_ = (1u << n_); \
     static bool Has##Name_(uint32_t aFeatures) { return aFeatures & Name_; } \
     static void Set##Name_(uint32_t& aFeatures) { aFeatures |= Name_; } \
     static void Clear##Name_(uint32_t& aFeatures) { aFeatures &= ~Name_; }