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 85852 2273e0264d4ab5b24c35b56fda8b825d1001cbbc
parent 85851 3077b729dfd5454ba95c4294987262d74e731c07
child 85853 e40e72d6264ddf069d78a4c99a9544e6d396092c
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs718025
milestone12.0a1
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.
 };