Bug 873914 - Allow selecting profiled thread. r=snorp
☠☠ backed out by ebc9b2b98ad7 ☠ ☠
authorBenoit Girard <b56girard@gmail.com>
Thu, 16 May 2013 16:31:50 -0400
changeset 146879 090ebbb90a7fe87fe4b0b8da1ad2942784c585b5
parent 146878 78ecf4488be028e91b82378c735c828277793056
child 146880 3f4d5bcba1fb731aadbe44e53ceb05bdcad0c1bb
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs873914
milestone24.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 873914 - Allow selecting profiled thread. r=snorp
tools/profiler/GeckoProfiler.h
tools/profiler/GeckoProfilerFunc.h
tools/profiler/GeckoProfilerImpl.h
tools/profiler/TableTicker.h
tools/profiler/nsIProfiler.idl
tools/profiler/nsProfiler.cpp
tools/profiler/platform-linux.cc
tools/profiler/platform-macos.cc
tools/profiler/platform-win32.cc
tools/profiler/platform.cpp
--- a/tools/profiler/GeckoProfiler.h
+++ b/tools/profiler/GeckoProfiler.h
@@ -90,17 +90,18 @@ static inline void profiler_shutdown() {
 // recorded in a circular buffer.
 //   "aProfileEntries" is an abstract size indication of how big
 //       the profile's circular buffer should be. Multiply by 4
 //       words to get the cost.
 //   "aInterval" the sampling interval. The profiler will do its
 //       best to sample at this interval. The profiler visualization
 //       should represent the actual sampling accuracy.
 static inline void profiler_start(int aProfileEntries, int aInterval,
-                              const char** aFeatures, uint32_t aFeatureCount) {}
+                              const char** aFeatures, uint32_t aFeatureCount,
+                              const char** aThreadNameFilters, uint32_t aFilterCount) {}
 
 // Stop the profiler and discard the profile. Call 'profiler_save' before this
 // to retrieve the profile.
 static inline void profiler_stop() {}
 
 static inline bool profiler_is_active() { return false; }
 
 // Internal-only. Used by the event tracer.
--- a/tools/profiler/GeckoProfilerFunc.h
+++ b/tools/profiler/GeckoProfilerFunc.h
@@ -16,18 +16,19 @@ using mozilla::TimeDuration;
 
 // Returns a handle to pass on exit. This can check that we are popping the
 // correct callstack.
 inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL,
                                         bool aCopy = false, uint32_t line = 0);
 inline void  mozilla_sampler_call_exit(void* handle);
 inline void  mozilla_sampler_add_marker(const char *aInfo);
 
-void mozilla_sampler_start(int aEntries, int aInterval, const char** aFeatures,
-                            uint32_t aFeatureCount);
+void mozilla_sampler_start(int aEntries, int aInterval,
+                           const char** aFeatures, uint32_t aFeatureCount,
+                           const char** aThreadNameFilters, uint32_t aFilterCount);
 
 void mozilla_sampler_stop();
 
 bool mozilla_sampler_is_active();
 
 void mozilla_sampler_responsiveness(const TimeStamp& time);
 
 void mozilla_sampler_frame_number(int frameNumber);
--- a/tools/profiler/GeckoProfilerImpl.h
+++ b/tools/profiler/GeckoProfilerImpl.h
@@ -60,19 +60,20 @@ void profiler_init(void* stackTop)
 static inline
 void profiler_shutdown()
 {
   mozilla_sampler_shutdown();
 }
 
 static inline
 void profiler_start(int aProfileEntries, int aInterval,
-                       const char** aFeatures, uint32_t aFeatureCount)
+                       const char** aFeatures, uint32_t aFeatureCount,
+                       const char** aThreadNameFilters, uint32_t aFilterCount)
 {
-  mozilla_sampler_start(aProfileEntries, aInterval, aFeatures, aFeatureCount);
+  mozilla_sampler_start(aProfileEntries, aInterval, aFeatures, aFeatureCount, aThreadNameFilters, aFilterCount);
 }
 
 static inline
 void profiler_stop()
 {
   mozilla_sampler_stop();
 }
 
--- a/tools/profiler/TableTicker.h
+++ b/tools/profiler/TableTicker.h
@@ -11,66 +11,79 @@ static bool
 hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) {
   for(size_t i = 0; i < aFeatureCount; i++) {
     if (strcmp(aFeatures[i], aFeature) == 0)
       return true;
   }
   return false;
 }
 
+static bool
+threadSelected(ThreadInfo* aInfo, char** aThreadNameFilters, uint32_t aFeatureCount) {
+  if (aFeatureCount == 0) {
+    return true;
+  }
+
+  for (uint32_t i = 0; i < aFeatureCount; ++i) {
+    const char* filterPrefix = aThreadNameFilters[i];
+    if (strncmp(aInfo->Name(), filterPrefix, strlen(filterPrefix)) == 0) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 extern TimeStamp sLastTracerEvent;
 extern int sFrameNumber;
 extern int sLastFrameNumber;
 extern unsigned int sCurrentEventGeneration;
 extern unsigned int sLastSampledEventGeneration;
 
 class BreakpadSampler;
 
 class TableTicker: public Sampler {
  public:
   TableTicker(int aInterval, int aEntrySize,
-              const char** aFeatures, uint32_t aFeatureCount)
+              const char** aFeatures, uint32_t aFeatureCount,
+              const char** aThreadNameFilters, uint32_t aFilterCount)
     : Sampler(aInterval, true, aEntrySize)
     , mPrimaryThreadProfile(nullptr)
     , mSaveRequested(false)
     , mUnwinderThread(false)
+    , mFilterCount(aFilterCount)
   {
     mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
 
     //XXX: It's probably worth splitting the jank profiler out from the regular profiler at some point
     mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
     mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
     mProfileJava = hasFeature(aFeatures, aFeatureCount, "java");
     mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads");
     mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2();
     mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
     mPrivacyMode = hasFeature(aFeatures, aFeatureCount, "privacy");
     mAddMainThreadIO = hasFeature(aFeatures, aFeatureCount, "mainthreadio");
 
+    // Deep copy aThreadNameFilters
+    mThreadNameFilters = new char*[aFilterCount];
+    for (uint32_t i = 0; i < aFilterCount; ++i) {
+      mThreadNameFilters[i] = strdup(aThreadNameFilters[i]);
+    }
+
     sStartTime = TimeStamp::Now();
 
     {
       mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
 
       // Create ThreadProfile for each registered thread
       for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
         ThreadInfo* info = sRegisteredThreads->at(i);
 
-        if (!info->IsMainThread() && !mProfileThreads)
-          continue;
-
-        ThreadProfile* profile = new ThreadProfile(info->Name(),
-                                                   aEntrySize,
-                                                   info->Stack(),
-                                                   info->ThreadId(),
-                                                   info->GetPlatformData(),
-                                                   info->IsMainThread());
-        profile->addTag(ProfileEntry('m', "Start"));
-
-        info->SetProfile(profile);
+        RegisterThread(info);
       }
 
       SetActiveSampler(this);
     }
   }
 
   ~TableTicker() {
     if (IsActive())
@@ -88,16 +101,36 @@ class TableTicker: public Sampler {
         if (profile) {
           delete profile;
           info->SetProfile(nullptr);
         }
       }
     }
   }
 
+  void RegisterThread(ThreadInfo* aInfo) {
+    if (!aInfo->IsMainThread() && !mProfileThreads) {
+      return;
+    }
+
+    if (!threadSelected(aInfo, mThreadNameFilters, mFilterCount)) {
+      return;
+    }
+
+    ThreadProfile* profile = new ThreadProfile(aInfo->Name(),
+                                               EntrySize(),
+                                               aInfo->Stack(),
+                                               aInfo->ThreadId(),
+                                               aInfo->GetPlatformData(),
+                                               aInfo->IsMainThread());
+    profile->addTag(ProfileEntry('m', "Start"));
+
+    aInfo->SetProfile(profile);
+  }
+
   // Called within a signal. This function must be reentrant
   virtual void Tick(TickSample* sample);
 
   // Called within a signal. This function must be reentrant
   virtual void RequestSave()
   {
     mSaveRequested = true;
   }
@@ -149,12 +182,17 @@ protected:
   bool mSaveRequested;
   bool mAddLeafAddresses;
   bool mUseStackWalk;
   bool mJankOnly;
   bool mProfileJS;
   bool mProfileThreads;
   bool mUnwinderThread;
   bool mProfileJava;
+
+  // Keep the thread filter to check against new thread that
+  // are started while profiling
+  char** mThreadNameFilters;
+  uint32_t mFilterCount;
   bool mPrivacyMode;
   bool mAddMainThreadIO;
 };
 
--- a/tools/profiler/nsIProfiler.idl
+++ b/tools/profiler/nsIProfiler.idl
@@ -1,21 +1,23 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
 #include "nsISupports.idl"
 
-[scriptable, uuid(c94651cf-082f-45e2-9481-33a1a700b46a)]
+[scriptable, uuid(eb77a9b0-285f-472c-93b0-04db5e9e3e7e)]
 interface nsIProfiler : nsISupports
 {
   void StartProfiler(in uint32_t aEntries, in uint32_t aInterval,
                       [array, size_is(aFeatureCount)] in string aFeatures,
-                      in uint32_t aFeatureCount);
+                      in uint32_t aFeatureCount,
+                      [array, size_is(aFilterCount), optional] in string aThreadNameFilters,
+                      [optional] in uint32_t aFilterCount);
   void StopProfiler();
   void AddMarker(in string aMarker);
   string GetProfile();
   [implicit_jscontext]
   jsval getProfileData();
   boolean IsActive();
   void GetResponsivenessTimes(out uint32_t aCount, [retval, array, size_is(aCount)] out double aResult);
   void GetFeatures(out uint32_t aCount, [retval, array, size_is(aCount)] out string aFeatures);
--- a/tools/profiler/nsProfiler.cpp
+++ b/tools/profiler/nsProfiler.cpp
@@ -66,23 +66,26 @@ nsProfiler::Observe(nsISupports *aSubjec
     mLockedForPrivateBrowsing = false;
     profiler_unlock();
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsProfiler::StartProfiler(uint32_t aEntries, uint32_t aInterval,
-                          const char** aFeatures, uint32_t aFeatureCount)
+                          const char** aFeatures, uint32_t aFeatureCount,
+                          const char** aThreadNameFilters, uint32_t aFilterCount)
 {
   if (mLockedForPrivateBrowsing) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  profiler_start(aEntries, aInterval, aFeatures, aFeatureCount);
+  profiler_start(aEntries, aInterval,
+                 aFeatures, aFeatureCount,
+                 aThreadNameFilters, aFilterCount);
 #ifdef MOZ_INSTRUMENT_EVENT_LOOP
   bool printToConsole = false;
   mozilla::InitEventTracing(printToConsole);
 #endif
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/tools/profiler/platform-linux.cc
+++ b/tools/profiler/platform-linux.cc
@@ -366,30 +366,18 @@ bool Sampler::RegisterCurrentThread(cons
   if (!Sampler::sRegisteredThreadsMutex)
     return false;
 
   mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
 
   ThreadInfo* info = new ThreadInfo(aName, gettid(),
     aIsMainThread, aPseudoStack);
 
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       info->ThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
+  if (sActiveSampler) {
+    sActiveSampler->RegisterThread(info);
   }
 
   sRegisteredThreads->push_back(info);
 
   uwt__register_thread_for_profiling(stackTop);
   return true;
 }
 
@@ -415,17 +403,18 @@ void Sampler::UnregisterCurrentThread()
 }
 
 #ifdef ANDROID
 static struct sigaction old_sigstart_signal_handler;
 const int SIGSTART = SIGUSR1;
 
 static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
   profiler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL,
-                 PROFILE_DEFAULT_FEATURES, PROFILE_DEFAULT_FEATURE_COUNT);
+                 PROFILE_DEFAULT_FEATURES, PROFILE_DEFAULT_FEATURE_COUNT,
+                 NULL, 0);
 }
 
 void OS::RegisterStartHandler()
 {
   LOG("Registering start signal");
   struct sigaction sa;
   sa.sa_sigaction = StartSignalHandler;
   sigemptyset(&sa.sa_mask);
--- a/tools/profiler/platform-macos.cc
+++ b/tools/profiler/platform-macos.cc
@@ -348,30 +348,18 @@ bool Sampler::RegisterCurrentThread(cons
   if (!Sampler::sRegisteredThreadsMutex)
     return false;
 
   mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
 
   ThreadInfo* info = new ThreadInfo(aName, gettid(),
     aIsMainThread, aPseudoStack);
 
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       info->ThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
+  if (sActiveSampler) {
+    sActiveSampler->RegisterThread(info);
   }
 
   sRegisteredThreads->push_back(info);
 
   uwt__register_thread_for_profiling(stackTop);
   return true;
 }
 
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -269,30 +269,18 @@ bool Sampler::RegisterCurrentThread(cons
   if (!Sampler::sRegisteredThreadsMutex)
     return false;
 
   mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
 
   ThreadInfo* info = new ThreadInfo(aName, GetCurrentThreadId(),
     aIsMainThread, aPseudoStack);
 
-  bool profileThread = sActiveSampler &&
-    (aIsMainThread || sActiveSampler->ProfileThreads());
-
-  if (profileThread) {
-    // We need to create the ThreadProfile now
-    info->SetProfile(new ThreadProfile(info->Name(),
-                                       sActiveSampler->EntrySize(),
-                                       info->Stack(),
-                                       GetCurrentThreadId(),
-                                       info->GetPlatformData(),
-                                       aIsMainThread));
-    if (sActiveSampler->ProfileJS()) {
-      info->Profile()->GetPseudoStack()->enableJSSampling();
-    }
+  if (sActiveSampler) {
+    sActiveSampler->RegisterThread(info);
   }
 
   sRegisteredThreads->push_back(info);
 
   uwt__register_thread_for_profiling(stackTop);
   return true;
 }
 
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -298,17 +298,19 @@ void mozilla_sampler_init(void* stackTop
 
   const char* features[] = {"js"
                          , "leaf"
 #if defined(XP_WIN) || defined(XP_MACOSX)
                          , "stackwalk"
 #endif
                          };
   profiler_start(PROFILE_DEFAULT_ENTRY, PROFILE_DEFAULT_INTERVAL,
-                         features, sizeof(features)/sizeof(const char*));
+                         features, sizeof(features)/sizeof(const char*),
+                         // TODO Add env variable to select threads
+                         NULL, 0);
   LOG("END   mozilla_sampler_init");
 }
 
 void mozilla_sampler_shutdown()
 {
   sInitCount--;
 
   if (sInitCount > 0)
@@ -409,33 +411,36 @@ const char** mozilla_sampler_get_feature
     NULL
   };
 
   return features;
 }
 
 // Values are only honored on the first start
 void mozilla_sampler_start(int aProfileEntries, int aInterval,
-                           const char** aFeatures, uint32_t aFeatureCount)
+                           const char** aFeatures, uint32_t aFeatureCount,
+                           const char** aThreadNameFilters, uint32_t aFilterCount)
+
 {
   if (!stack_key_initialized)
     profiler_init(NULL);
 
   /* If the sampling interval was set using env vars, use that
      in preference to anything else. */
   if (sUnwindInterval > 0)
     aInterval = sUnwindInterval;
 
   // Reset the current state if the profiler is running
   profiler_stop();
 
   TableTicker* t;
   t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
                       aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
-                      aFeatures, aFeatureCount);
+                      aFeatures, aFeatureCount,
+                      aThreadNameFilters, aFilterCount);
   if (t->HasUnwinderThread()) {
     // Create the unwinder thread.  ATM there is only one.
     uwt__init();
   }
 
   tlsTicker.set(t);
   t->Start();
   if (t->ProfileJS() || t->InPrivacyMode()) {