Bug 1707489 - Pass StackWalkControl to ExtractJsFrames and then forward it to stack walkers - r=canaltinova
☠☠ backed out by d56356d09ec0 ☠ ☠
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 03 Jun 2021 02:39:37 +0000
changeset 654279 5fb8ebb1a36524fe1e4631acf86a6a6175f85702
parent 654278 a5c85f93707c2790de3cceeda5155bb29d371909
child 654280 e582c06a7323b12032177411d9f024f4b049d518
push id2623
push userffxbld-merge
push dateMon, 02 Aug 2021 14:47:51 +0000
treeherdermozilla-release@8500ce65f7c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscanaltinova
bugs1707489
milestone91.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 1707489 - Pass StackWalkControl to ExtractJsFrames and then forward it to stack walkers - r=canaltinova This is almost code-free: A StackWalkControl (skeleton for now) is constructed when the platform supports it, and then passed to ExtractJsFrames and the stack walker; but is not actively used yet. Differential Revision: https://phabricator.services.mozilla.com/D113272
tools/profiler/core/platform.cpp
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -1704,25 +1704,29 @@ struct AutoWalkJSStack {
 
   ~AutoWalkJSStack() {
     if (walkAllowed) {
       WALKING_JS_STACK = false;
     }
   }
 };
 
+class StackWalkControl {
+ public:
+  static constexpr bool scIsSupported = false;
+};
+
 // Make a copy of the JS stack into a JSFrame array, and return the number of
 // copied frames.
 // This copy is necessary since, like the native stack, the JS stack is iterated
 // youngest-to-oldest and we need to iterate oldest-to-youngest in MergeStacks.
-static uint32_t ExtractJsFrames(bool aIsSynchronous,
-                                const RegisteredThread& aRegisteredThread,
-                                const Registers& aRegs,
-                                ProfilerStackCollector& aCollector,
-                                JsFrameBuffer aJsFrames) {
+static uint32_t ExtractJsFrames(
+    bool aIsSynchronous, const RegisteredThread& aRegisteredThread,
+    const Registers& aRegs, ProfilerStackCollector& aCollector,
+    JsFrameBuffer aJsFrames, StackWalkControl* aStackWalkControlIfSupported) {
   uint32_t jsFramesCount = 0;
 
   // Only walk jit stack if profiling frame iterator is turned on.
   JSContext* context = aRegisteredThread.GetJSContext();
   if (context && JS::IsProfilingEnabledForContext(context)) {
     AutoWalkJSStack autoWalkJSStack;
 
     if (autoWalkJSStack.walkAllowed) {
@@ -1757,16 +1761,18 @@ static uint32_t ExtractJsFrames(bool aIs
               jsIter.getPhysicalFrameWithoutLabel();
           if (frame.isSome()) {
             aJsFrames[jsFramesCount++] = std::move(frame).ref();
             if (jsFramesCount == MAX_JS_FRAMES) {
               break;
             }
           }
         }
+
+        // TODO: Store JIT data in aStackWalkControlIfSupported. See next patch.
       }
     }
   }
 
   return jsFramesCount;
 }
 
 // Merges the profiling stack, native stack, and JS stack, outputting the
@@ -1982,20 +1988,20 @@ static void StackWalkCallback(uint32_t a
   MOZ_ASSERT(nativeStack->mCount < MAX_NATIVE_FRAMES);
   nativeStack->mSPs[nativeStack->mCount] = aSP;
   nativeStack->mPCs[nativeStack->mCount] = aPC;
   nativeStack->mCount++;
 }
 #endif
 
 #if defined(USE_FRAME_POINTER_STACK_WALK)
-static void DoFramePointerBacktrace(PSLockRef aLock,
-                                    const RegisteredThread& aRegisteredThread,
-                                    const Registers& aRegs,
-                                    NativeStack& aNativeStack) {
+static void DoFramePointerBacktrace(
+    PSLockRef aLock, const RegisteredThread& aRegisteredThread,
+    const Registers& aRegs, NativeStack& aNativeStack,
+    StackWalkControl* aStackWalkControlIfSupported) {
   // WARNING: this function runs within the profiler's "critical section".
   // WARNING: this function might be called while the profiler is inactive, and
   //          cannot rely on ActivePS.
 
   // Start with the current function. We use 0 as the frame number here because
   // the FramePointerStackWalk() call below will use 1..N. This is a bit weird
   // but it doesn't matter because StackWalkCallback() doesn't use the frame
   // number argument.
@@ -2008,20 +2014,20 @@ static void DoFramePointerBacktrace(PSLo
     FramePointerStackWalk(StackWalkCallback, maxFrames, &aNativeStack,
                           reinterpret_cast<void**>(aRegs.mFP),
                           const_cast<void*>(stackEnd));
   }
 }
 #endif
 
 #if defined(USE_MOZ_STACK_WALK)
-static void DoMozStackWalkBacktrace(PSLockRef aLock,
-                                    const RegisteredThread& aRegisteredThread,
-                                    const Registers& aRegs,
-                                    NativeStack& aNativeStack) {
+static void DoMozStackWalkBacktrace(
+    PSLockRef aLock, const RegisteredThread& aRegisteredThread,
+    const Registers& aRegs, NativeStack& aNativeStack,
+    StackWalkControl* aStackWalkControlIfSupported) {
   // WARNING: this function runs within the profiler's "critical section".
   // WARNING: this function might be called while the profiler is inactive, and
   //          cannot rely on ActivePS.
 
   // Start with the current function. We use 0 as the frame number here because
   // the MozStackWalkThread() call below will use 1..N. This is a bit weird but
   // it doesn't matter because StackWalkCallback() doesn't use the frame number
   // argument.
@@ -2034,26 +2040,27 @@ static void DoMozStackWalkBacktrace(PSLo
   MozStackWalkThread(StackWalkCallback, maxFrames, &aNativeStack, thread,
                      /* context */ nullptr);
 }
 #endif
 
 #ifdef USE_EHABI_STACKWALK
 static void DoEHABIBacktrace(PSLockRef aLock,
                              const RegisteredThread& aRegisteredThread,
-                             const Registers& aRegs,
-                             NativeStack& aNativeStack) {
+                             const Registers& aRegs, NativeStack& aNativeStack,
+                             StackWalkControl* aStackWalkControlIfSupported) {
   // WARNING: this function runs within the profiler's "critical section".
   // WARNING: this function might be called while the profiler is inactive, and
   //          cannot rely on ActivePS.
 
   aNativeStack.mCount =
       EHABIStackWalk(aRegs.mContext->uc_mcontext,
                      const_cast<void*>(aRegisteredThread.StackTop()),
                      aNativeStack.mSPs, aNativeStack.mPCs, MAX_NATIVE_FRAMES);
+  (void)aStackWalkControlIfSupported;  // TODO: Implement.
 }
 #endif
 
 #ifdef USE_LUL_STACKWALK
 
 // See the comment at the callsite for why this function is necessary.
 #  if defined(MOZ_HAVE_ASAN_BLACKLIST)
 MOZ_ASAN_BLACKLIST static void ASAN_memcpy(void* aDst, const void* aSrc,
@@ -2068,21 +2075,24 @@ MOZ_ASAN_BLACKLIST static void ASAN_memc
   for (size_t i = 0; i < aLen; i++) {
     dst[i] = src[i];
   }
 }
 #  endif
 
 static void DoLULBacktrace(PSLockRef aLock,
                            const RegisteredThread& aRegisteredThread,
-                           const Registers& aRegs, NativeStack& aNativeStack) {
+                           const Registers& aRegs, NativeStack& aNativeStack,
+                           StackWalkControl* aStackWalkControlIfSupported) {
   // WARNING: this function runs within the profiler's "critical section".
   // WARNING: this function might be called while the profiler is inactive, and
   //          cannot rely on ActivePS.
 
+  (void)aStackWalkControlIfSupported;  // TODO: Implement.
+
   const mcontext_t* mc = &aRegs.mContext->uc_mcontext;
 
   lul::UnwindRegs startRegs;
   memset(&startRegs, 0, sizeof(startRegs));
 
 #  if defined(GP_PLAT_amd64_linux) || defined(GP_PLAT_amd64_android)
   startRegs.xip = lul::TaggedUWord(mc->gregs[REG_RIP]);
   startRegs.xsp = lul::TaggedUWord(mc->gregs[REG_RSP]);
@@ -2219,31 +2229,35 @@ static void DoLULBacktrace(PSLockRef aLo
   lul->mStats.mFP += framePointerFramesAcquired;
 }
 
 #endif
 
 #ifdef HAVE_NATIVE_UNWIND
 static void DoNativeBacktrace(PSLockRef aLock,
                               const RegisteredThread& aRegisteredThread,
-                              const Registers& aRegs,
-                              NativeStack& aNativeStack) {
+                              const Registers& aRegs, NativeStack& aNativeStack,
+                              StackWalkControl* aStackWalkControlIfSupported) {
   // This method determines which stackwalker is used for periodic and
   // synchronous samples. (Backtrace samples are treated differently, see
   // profiler_suspend_and_sample_thread() for details). The only part of the
   // ordering that matters is that LUL must precede FRAME_POINTER, because on
   // Linux they can both be present.
 #  if defined(USE_LUL_STACKWALK)
-  DoLULBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack);
+  DoLULBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack,
+                 aStackWalkControlIfSupported);
 #  elif defined(USE_EHABI_STACKWALK)
-  DoEHABIBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack);
+  DoEHABIBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack,
+                   aStackWalkControlIfSupported);
 #  elif defined(USE_FRAME_POINTER_STACK_WALK)
-  DoFramePointerBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack);
+  DoFramePointerBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack,
+                          aStackWalkControlIfSupported);
 #  elif defined(USE_MOZ_STACK_WALK)
-  DoMozStackWalkBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack);
+  DoMozStackWalkBacktrace(aLock, aRegisteredThread, aRegs, aNativeStack,
+                          aStackWalkControlIfSupported);
 #  else
 #    error "Invalid configuration"
 #  endif
 }
 #endif
 
 // Writes some components shared by periodic and synchronous profiles to
 // ActivePS's ProfileBuffer. (This should only be called from DoSyncSample()
@@ -2260,23 +2274,35 @@ static inline void DoSharedSample(
 
   MOZ_ASSERT(!aBuffer.IsThreadSafe(),
              "Mutexes cannot be used inside this critical section");
 
   MOZ_RELEASE_ASSERT(ActivePS::Exists(aLock));
 
   ProfileBufferCollector collector(aBuffer, aSamplePos, aBufferRangeStart);
   JsFrameBuffer& jsFrames = CorePS::JsFrames(aLock);
-  const uint32_t jsFramesCount = ExtractJsFrames(
-      aIsSynchronous, aRegisteredThread, aRegs, collector, jsFrames);
+  StackWalkControl* stackWalkControlIfSupported = nullptr;
+#if defined(HAVE_NATIVE_UNWIND)
+  const bool captureNative = ActivePS::FeatureStackWalk(aLock) &&
+                             aCaptureOptions == StackCaptureOptions::Full;
+  StackWalkControl stackWalkControl;
+  if constexpr (StackWalkControl::scIsSupported) {
+    if (captureNative) {
+      stackWalkControlIfSupported = &stackWalkControl;
+    }
+  }
+#endif  // defined(HAVE_NATIVE_UNWIND)
+  const uint32_t jsFramesCount =
+      ExtractJsFrames(aIsSynchronous, aRegisteredThread, aRegs, collector,
+                      jsFrames, stackWalkControlIfSupported);
   NativeStack nativeStack;
 #if defined(HAVE_NATIVE_UNWIND)
-  if (ActivePS::FeatureStackWalk(aLock) &&
-      aCaptureOptions == StackCaptureOptions::Full) {
-    DoNativeBacktrace(aLock, aRegisteredThread, aRegs, nativeStack);
+  if (captureNative) {
+    DoNativeBacktrace(aLock, aRegisteredThread, aRegs, nativeStack,
+                      stackWalkControlIfSupported);
 
     MergeStacks(ActivePS::Features(aLock), aIsSynchronous, aRegisteredThread,
                 aRegs, nativeStack, collector, jsFrames, jsFramesCount);
   } else
 #endif
   {
     MergeStacks(ActivePS::Features(aLock), aIsSynchronous, aRegisteredThread,
                 aRegs, nativeStack, collector, jsFrames, jsFramesCount);
@@ -5969,28 +5995,40 @@ void profiler_suspend_and_sample_thread(
 
       // Allocate the space for the native stack
       NativeStack nativeStack;
 
       auto collectStack = [&](const Registers& aRegs, const TimeStamp& aNow) {
         // The target thread is now suspended. Collect a native backtrace,
         // and call the callback.
         JsFrameBuffer& jsFrames = CorePS::JsFrames(lock);
-        const uint32_t jsFramesCount = ExtractJsFrames(
-            isSynchronous, registeredThread, aRegs, aCollector, jsFrames);
+        StackWalkControl* stackWalkControlIfSupported = nullptr;
+#if defined(HAVE_FASTINIT_NATIVE_UNWIND)
+        StackWalkControl stackWalkControl;
+        if constexpr (StackWalkControl::scIsSupported) {
+          if (aSampleNative) {
+            stackWalkControlIfSupported = &stackWalkControl;
+          }
+        }
+#endif
+        const uint32_t jsFramesCount =
+            ExtractJsFrames(isSynchronous, registeredThread, aRegs, aCollector,
+                            jsFrames, stackWalkControlIfSupported);
 
 #if defined(HAVE_FASTINIT_NATIVE_UNWIND)
         if (aSampleNative) {
           // We can only use FramePointerStackWalk or MozStackWalk from
           // suspend_and_sample_thread as other stackwalking methods may not be
           // initialized.
 #  if defined(USE_FRAME_POINTER_STACK_WALK)
-          DoFramePointerBacktrace(lock, registeredThread, aRegs, nativeStack);
+          DoFramePointerBacktrace(lock, registeredThread, aRegs, nativeStack,
+                                  stackWalkControlIfSupported);
 #  elif defined(USE_MOZ_STACK_WALK)
-          DoMozStackWalkBacktrace(lock, registeredThread, aRegs, nativeStack);
+          DoMozStackWalkBacktrace(lock, registeredThread, aRegs, nativeStack,
+                                  stackWalkControlIfSupported);
 #  else
 #    error "Invalid configuration"
 #  endif
 
           MergeStacks(aFeatures, isSynchronous, registeredThread, aRegs,
                       nativeStack, aCollector, jsFrames, jsFramesCount);
         } else
 #endif