Bug 718025 - Add support for stacktraces on Windows to the built-in profiler; r=jrmuizel
☠☠ backed out by e40e72d6264d ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 16 Jan 2012 19:59:15 -0500
changeset 84627 2273e0264d4ab5b24c35b56fda8b825d1001cbbc
parent 84626 3077b729dfd5454ba95c4294987262d74e731c07
child 84628 e40e72d6264ddf069d78a4c99a9544e6d396092c
push id21868
push usermak77@bonardo.net
push dateTue, 17 Jan 2012 15:23:07 +0000
treeherdermozilla-central@ff1bedd7d463 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs718025
milestone12.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 718025 - Add support for stacktraces on Windows to the built-in profiler; r=jrmuizel
tools/profiler/sps/TableTicker.cpp
tools/profiler/sps/platform-win32.cc
tools/profiler/sps/platform.h
--- a/tools/profiler/sps/TableTicker.cpp
+++ b/tools/profiler/sps/TableTicker.cpp
@@ -51,16 +51,23 @@
  #ifndef ANDROID
   #define USE_BACKTRACE
  #endif
 #endif
 #ifdef USE_BACKTRACE
  #include <execinfo.h>
 #endif
 
+#ifdef XP_WIN
+ #define USE_NS_STACKWALK
+#endif
+#ifdef USE_NS_STACKWALK
+ #include "nsStackWalk.h"
+#endif
+
 using std::string;
 using namespace mozilla;
 
 #ifdef XP_WIN
 #include <windows.h>
 #define getpid GetCurrentProcessId
 #else
 #include <unistd.h>
@@ -267,17 +274,22 @@ class TableTicker: public Sampler {
   {
     return mStack;
   }
 
   Profile* GetProfile()
   {
     return &mProfile;
   }
- private:
+
+private:
+  // Not implemented on platforms which do not support backtracing
+  void doBacktrace(Profile &aProfile);
+
+private:
   Profile mProfile;
   Stack *mStack;
   bool mSaveRequested;
   bool mUseStackWalk;
   bool mJankOnly;
 };
 
 /**
@@ -332,31 +344,69 @@ void TableTicker::HandleSaveRequest()
 
   // TODO: Use use the ipc/chromium Tasks here to support processes
   // without XPCOM.
   nsCOMPtr<nsIRunnable> runnable = new SaveProfileTask();
   NS_DispatchToMainThread(runnable);
 }
 
 #ifdef USE_BACKTRACE
-static
-void doBacktrace(Profile &aProfile)
+void TableTicker::doBacktrace(Profile &aProfile)
 {
   void *array[100];
   int count = backtrace (array, 100);
 
   aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
 
   for (int i = 0; i < count; i++) {
     if( (intptr_t)array[i] == -1 ) break;
     aProfile.addTag(ProfileEntry('l', (const char*)array[i]));
   }
 }
 #endif
 
+#ifdef USE_NS_STACKWALK
+typedef struct {
+  void* array[];
+  size_t size;
+  size_t count;
+} PCArray;
+
+static
+void StackWalkCallback(void* aPC, void* aClosure)
+{
+  PCArray* array = static_cast<PCArray*>(aClosure);
+  if (array->count >= array->size) {
+    // too many frames, ignore
+    return;
+  }
+  array->array[array->count++] = aPC;
+}
+
+void TableTicker::doBacktrace(Profile &aProfile)
+{
+  uintptr_t thread = GetThreadHandle(platform_data());
+  MOZ_ASSERT(thread);
+  void* pc_array[1000];
+  PCArray array = {
+    pc_array,
+    mozilla::ArrayLength(array),
+    0
+  };
+  nsresult rv = NS_StackWalk(StackWalkCallback, 0, &array, thread);
+  if (NS_SUCCEEDED(rv)) {
+    aProfile.addTag(ProfileEntry('s', "XRE_Main", 0));
+
+    for (size_t i = array.count; i > 0; --i) {
+      aProfile.addTag(ProfileEntry('l', (const char*)array.array[i - 1]));
+    }
+  }
+}
+#endif
+
 static
 void doSampleStackTrace(Stack *aStack, Profile &aProfile, TickSample *sample)
 {
   // Sample
   // 's' tag denotes the start of a sample block
   // followed by 0 or more 'c' tags.
   for (int i = 0; i < aStack->mStackPointer; i++) {
     if (i == 0) {
@@ -390,17 +440,17 @@ void TableTicker::Tick(TickSample* sampl
       TimeDuration delta = sample->timestamp - sLastTracerEvent;
       if (delta.ToMilliseconds() > 100.0) {
           recordSample = true;
       }
     }
   }
 
   if (recordSample) {
-#ifdef USE_BACKTRACE
+#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
     if (mUseStackWalk) {
       doBacktrace(mProfile);
     } else {
       doSampleStackTrace(mStack, mProfile, sample);
     }
 #else
     doSampleStackTrace(mStack, mProfile, sample);
 #endif
--- a/tools/profiler/sps/platform-win32.cc
+++ b/tools/profiler/sps/platform-win32.cc
@@ -28,16 +28,21 @@ class Sampler::PlatformData : public Mal
   }
 
   HANDLE profiled_thread() { return profiled_thread_; }
 
  private:
   HANDLE profiled_thread_;
 };
 
+uintptr_t
+Sampler::GetThreadHandle(Sampler::PlatformData* aData)
+{
+  return (uintptr_t) aData->profiled_thread();
+}
 
 class SamplerThread : public Thread {
  public:
   SamplerThread(int interval, Sampler* sampler)
       : Thread("SamplerThread"),
         interval_(interval),
         sampler_(sampler) {}
 
--- a/tools/profiler/sps/platform.h
+++ b/tools/profiler/sps/platform.h
@@ -198,16 +198,21 @@ class Sampler {
 
   // Whether the sampler is running (that is, consumes resources).
   bool IsActive() const { return active_; }
 
   class PlatformData;
 
   PlatformData* platform_data() { return data_; }
 
+#ifdef XP_WIN
+  // xxxehsan sucky hack :(
+  static uintptr_t GetThreadHandle(PlatformData*);
+#endif
+
  private:
   void SetActive(bool value) { NoBarrier_Store(&active_, value); }
 
   const int interval_;
   const bool profiling_;
   Atomic32 active_;
   PlatformData* data_;  // Platform specific data.
 };