Bug 969456 - Add pause/resume API to profiler. r=bgirard
authorViktor Stanchev <vstanche@mozilla.com>
Fri, 28 Feb 2014 15:16:38 -0500
changeset 171611 d59f2795cc4087bbe070982119c1841efc855e66
parent 171610 e5619772fa6338398343ea196077a0dd2bb0f8d6
child 171612 7266f46b4dfc4bb812b392a2b44893b739e23f38
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersbgirard
bugs969456
milestone30.0a1
Bug 969456 - Add pause/resume API to profiler. r=bgirard
tools/profiler/GeckoProfiler.h
tools/profiler/GeckoProfilerFunc.h
tools/profiler/GeckoProfilerImpl.h
tools/profiler/nsIProfiler.idl
tools/profiler/nsProfiler.cpp
tools/profiler/platform-macos.cc
tools/profiler/platform-win32.cc
tools/profiler/platform.cpp
tools/profiler/tests/test_pause.js
tools/profiler/tests/xpcshell.ini
--- a/tools/profiler/GeckoProfiler.h
+++ b/tools/profiler/GeckoProfiler.h
@@ -112,16 +112,25 @@ static inline void profiler_shutdown() {
 static inline void profiler_start(int aProfileEntries, double aInterval,
                               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() {}
 
+// These functions pause and resume the profiler. While paused the profile will not
+// take any samples and will not record any data into its buffers. The profiler
+// remains fully initialized in this state. Timeline markers will still be stored.
+// This feature will keep javascript profiling enabled, thus allowing toggling the
+// profiler without invalidating the JIT.
+static inline bool profiler_is_paused() { return false; }
+static inline void profiler_pause() {}
+static inline void profiler_resume() {}
+
 class ProfilerBacktrace;
 
 // Immediately capture the current thread's call stack and return it
 static inline ProfilerBacktrace* profiler_get_backtrace() { return nullptr; }
 
 // Free a ProfilerBacktrace returned by profiler_get_backtrace()
 static inline void profiler_free_backtrace(ProfilerBacktrace* aBacktrace) {}
 
--- a/tools/profiler/GeckoProfilerFunc.h
+++ b/tools/profiler/GeckoProfilerFunc.h
@@ -30,16 +30,20 @@ void  mozilla_sampler_add_marker(const c
                                  ProfilerMarkerPayload *aPayload = nullptr);
 
 void mozilla_sampler_start(int aEntries, double aInterval,
                            const char** aFeatures, uint32_t aFeatureCount,
                            const char** aThreadNameFilters, uint32_t aFilterCount);
 
 void mozilla_sampler_stop();
 
+bool mozilla_sampler_is_paused();
+void mozilla_sampler_pause();
+void mozilla_sampler_resume();
+
 ProfilerBacktrace* mozilla_sampler_get_backtrace();
 void mozilla_sampler_free_backtrace(ProfilerBacktrace* aBacktrace);
 
 bool mozilla_sampler_is_active();
 
 void mozilla_sampler_responsiveness(const mozilla::TimeStamp& time);
 
 void mozilla_sampler_frame_number(int frameNumber);
--- a/tools/profiler/GeckoProfilerImpl.h
+++ b/tools/profiler/GeckoProfilerImpl.h
@@ -75,16 +75,34 @@ void profiler_start(int aProfileEntries,
 
 static inline
 void profiler_stop()
 {
   mozilla_sampler_stop();
 }
 
 static inline
+bool profiler_is_paused()
+{
+  return mozilla_sampler_is_paused();
+}
+
+static inline
+void profiler_pause()
+{
+  mozilla_sampler_pause();
+}
+
+static inline
+void profiler_resume()
+{
+  mozilla_sampler_resume();
+}
+
+static inline
 ProfilerBacktrace* profiler_get_backtrace()
 {
   return mozilla_sampler_get_backtrace();
 }
 
 static inline
 void profiler_free_backtrace(ProfilerBacktrace* aBacktrace)
 {
--- a/tools/profiler/nsIProfiler.idl
+++ b/tools/profiler/nsIProfiler.idl
@@ -1,24 +1,27 @@
 /* -*- 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(ea89f3b3-804f-40e0-8f40-a1b13cde2b9b)]
+[scriptable, uuid(d64e01e1-603f-4478-bb9e-47d502f23f7b)]
 interface nsIProfiler : nsISupports
 {
   void StartProfiler(in uint32_t aEntries, in double aInterval,
                       [array, size_is(aFeatureCount)] in string aFeatures,
                       in uint32_t aFeatureCount,
                       [array, size_is(aFilterCount), optional] in string aThreadNameFilters,
                       [optional] in uint32_t aFilterCount);
   void StopProfiler();
+  boolean IsPaused();
+  void PauseSampling();
+  void ResumeSampling();
   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
@@ -91,16 +91,37 @@ nsProfiler::StartProfiler(uint32_t aEntr
 NS_IMETHODIMP
 nsProfiler::StopProfiler()
 {
   profiler_stop();
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsProfiler::IsPaused(bool *aIsPaused)
+{
+  *aIsPaused = profiler_is_paused();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsProfiler::PauseSampling()
+{
+  profiler_pause();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsProfiler::ResumeSampling()
+{
+  profiler_resume();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsProfiler::AddMarker(const char *aMarker)
 {
   PROFILER_MARKER(aMarker);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsProfiler::GetProfile(char **aProfile)
--- a/tools/profiler/platform-macos.cc
+++ b/tools/profiler/platform-macos.cc
@@ -190,31 +190,30 @@ class SamplerThread : public Thread {
     SamplerRegistry::RemoveActiveSampler(sampler);
     delete instance_;
     instance_ = NULL;
   }
 
   // Implement Thread::Run().
   virtual void Run() {
     while (SamplerRegistry::sampler->IsActive()) {
-      {
+      if (!SamplerRegistry::sampler->IsPaused()) {
         mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
         std::vector<ThreadInfo*> threads =
           SamplerRegistry::sampler->GetRegisteredThreads();
         for (uint32_t i = 0; i < threads.size(); i++) {
           ThreadInfo* info = threads[i];
 
           // This will be null if we're not interested in profiling this thread.
           if (!info->Profile())
             continue;
 
           ThreadProfile* thread_profile = info->Profile();
 
-          if (!SamplerRegistry::sampler->IsPaused())
-            SampleContext(SamplerRegistry::sampler, thread_profile);
+          SampleContext(SamplerRegistry::sampler, thread_profile);
         }
       }
       OS::SleepMicro(intervalMicro_);
     }
   }
 
   void SampleContext(Sampler* sampler, ThreadProfile* thread_profile) {
     thread_act_t profiled_thread =
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -111,32 +111,30 @@ class SamplerThread : public Thread {
 
     // By default we'll not adjust the timer resolution which tends to be around
     // 16ms. However, if the requested interval is sufficiently low we'll try to
     // adjust the resolution to match.
     if (interval_ < 10)
         ::timeBeginPeriod(interval_);
 
     while (sampler_->IsActive()) {
-      {
+      if (!sampler_->IsPaused()) {
         mozilla::MutexAutoLock lock(*Sampler::sRegisteredThreadsMutex);
         std::vector<ThreadInfo*> threads =
           sampler_->GetRegisteredThreads();
         for (uint32_t i = 0; i < threads.size(); i++) {
           ThreadInfo* info = threads[i];
 
           // This will be null if we're not interested in profiling this thread.
           if (!info->Profile())
             continue;
 
           ThreadProfile* thread_profile = info->Profile();
 
-          if (!sampler_->IsPaused()) {
-            SampleContext(sampler_, thread_profile);
-          }
+          SampleContext(sampler_, thread_profile);
         }
       }
       OS::Sleep(interval_);
     }
 
     // disable any timer resolution changes we've made
     if (interval_ < 10)
         ::timeEndPeriod(interval_);
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -744,16 +744,36 @@ void mozilla_sampler_stop()
 
   sIsProfiling = false;
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-stopped", nullptr);
 }
 
+bool mozilla_sampler_is_paused() {
+  if (Sampler::GetActiveSampler()) {
+    return Sampler::GetActiveSampler()->IsPaused();
+  } else {
+    return false;
+  }
+}
+
+void mozilla_sampler_pause() {
+  if (Sampler::GetActiveSampler()) {
+    Sampler::GetActiveSampler()->SetPaused(true);
+  }
+}
+
+void mozilla_sampler_resume() {
+  if (Sampler::GetActiveSampler()) {
+    Sampler::GetActiveSampler()->SetPaused(false);
+  }
+}
+
 bool mozilla_sampler_is_active()
 {
   return sIsProfiling;
 }
 
 static double sResponsivenessTimes[100];
 static unsigned int sResponsivenessLoc = 0;
 void mozilla_sampler_responsiveness(const TimeStamp& aTime)
new file mode 100644
--- /dev/null
+++ b/tools/profiler/tests/test_pause.js
@@ -0,0 +1,35 @@
+/* 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/. */
+
+function run_test() {
+  // If we can't get the profiler component then assume gecko was
+  // built without it and pass all the tests
+  var profilerCc = Cc["@mozilla.org/tools/profiler;1"];
+  if (!profilerCc)
+    return;
+
+  var profiler = profilerCc.getService(Ci.nsIProfiler);
+  if (!profiler)
+    return;
+
+  do_check_true(!profiler.IsActive());
+  do_check_true(!profiler.IsPaused());
+
+  profiler.StartProfiler(1000, 10, [], 0);
+
+  do_check_true(profiler.IsActive());
+
+  profiler.PauseSampling();
+
+  do_check_true(profiler.IsPaused());
+
+  profiler.ResumeSampling();
+
+  do_check_true(!profiler.IsPaused());
+
+  profiler.StopProfiler();
+  do_check_true(!profiler.IsActive());
+  do_check_true(!profiler.IsPaused());
+  do_test_finished();
+}
--- a/tools/profiler/tests/xpcshell.ini
+++ b/tools/profiler/tests/xpcshell.ini
@@ -3,8 +3,9 @@ head = head_profiler.js
 tail =
 
 [test_start.js]
 skip-if = true
 [test_get_features.js]
 [test_shared_library.js]
 [test_run.js]
 skip-if = true
+[test_pause.js]