Bug 1393046 - Enable JS sampling on the main thread as soon as possible after the profiler has started. r=njn
☠☠ backed out by 0a3ef9979709 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Tue, 29 Aug 2017 19:13:57 +0200
changeset 377797 ce0752c07ff698c8dd7c94928e5160812318edfd
parent 377796 d00a28769dbe0bcb2b0f9e1948ebe97cdd7a973f
child 377798 2a76f87b6c1737ca624dd746da8f84aa96027fa9
push id94338
push userkwierso@gmail.com
push dateThu, 31 Aug 2017 02:58:58 +0000
treeherdermozilla-inbound@9ca18987dabb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1393046
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1393046 - Enable JS sampling on the main thread as soon as possible after the profiler has started. r=njn MozReview-Commit-ID: CIj3GGI3TQo
tools/profiler/core/platform.cpp
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2635,16 +2635,56 @@ profiler_get_buffer_info_helper(uint32_t
   }
 
   *aCurrentPosition = ActivePS::Buffer(lock).mWritePos;
   *aEntries = ActivePS::Entries(lock);
   *aGeneration = ActivePS::Buffer(lock).mGeneration;
 }
 
 static void
+PollJSSamplingForCurrentThread()
+{
+  MOZ_RELEASE_ASSERT(CorePS::Exists());
+
+  PSAutoLock lock(gPSMutex);
+
+  ThreadInfo* info = TLSInfo::Info(lock);
+  if (!info) {
+    return;
+  }
+
+  info->PollJSSampling();
+}
+
+// When the profiler is started on a background thread, we can't synchronously
+// call PollJSSampling on the main thread's ThreadInfo. And the next regular
+// call to PollJSSampling on the main thread would only happen once the main
+// thread triggers a JS interrupt callback.
+// This means that all the JS execution between profiler_start() and the first
+// JS interrupt would happen with JS sampling disabled, and we wouldn't get any
+// JS function information for that period of time.
+// So in order to start JS sampling as soon as possible, we dispatch a runnable
+// to the main thread which manually calls PollJSSamplingForCurrentThread().
+// In some cases this runnable will lose the race with the next JS interrupt.
+// That's fine; PollJSSamplingForCurrentThread() is immune to redundant calls.
+static void
+TriggerPollJSSamplingOnMainThread()
+{
+  nsCOMPtr<nsIThread> mainThread;
+  nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
+  if (NS_SUCCEEDED(rv) && mainThread) {
+    nsCOMPtr<nsIRunnable> task =
+      NS_NewRunnableFunction("TriggerPollJSSamplingOnMainThread", []() {
+        PollJSSamplingForCurrentThread();
+      });
+    SystemGroup::Dispatch(TaskCategory::Other, task.forget());
+  }
+}
+
+static void
 locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
                       uint32_t aFeatures,
                       const char** aFilters, uint32_t aFilterCount)
 {
   if (LOG_TEST) {
     LOG("locked_profiler_start");
     LOG("- entries  = %d", aEntries);
     LOG("- interval = %.2f", aInterval);
@@ -2684,16 +2724,21 @@ locked_profiler_start(PSLockRef aLock, i
     if (ActivePS::ShouldProfileThread(aLock, info)) {
       info->StartProfiling();
       if (ActivePS::FeatureJS(aLock)) {
         info->StartJSSampling();
         if (info->ThreadId() == tid) {
           // We can manually poll the current thread so it starts sampling
           // immediately.
           info->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.
+          TriggerPollJSSamplingOnMainThread();
         }
       }
     }
   }
 
   // Dead ThreadInfos are deleted in profiler_stop(), and dead ThreadInfos
   // aren't saved when the profiler is inactive. Therefore the dead threads
   // vector should be empty here.
@@ -3071,27 +3116,17 @@ profiler_thread_is_sleeping()
   }
   return racyInfo->IsSleeping();
 }
 
 void
 profiler_js_interrupt_callback()
 {
   // This function runs on JS threads being sampled.
-
-  MOZ_RELEASE_ASSERT(CorePS::Exists());
-
-  PSAutoLock lock(gPSMutex);
-
-  ThreadInfo* info = TLSInfo::Info(lock);
-  if (!info) {
-    return;
-  }
-
-  info->PollJSSampling();
+  PollJSSamplingForCurrentThread();
 }
 
 double
 profiler_time()
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   TimeDuration delta = TimeStamp::Now() - CorePS::ProcessStartTime();