Bug 750989 - Pause Profiler during saving. r=mstange,jrmuizel
authorBenoit Girard <b56girard@gmail.com>
Fri, 18 May 2012 17:03:10 -0400
changeset 94524 fdea12fb00634da270f1cdbbd95437c2d4ce0d6b
parent 94523 4110f744518b93ffc0ccd11ca6bad9ae7009e978
child 94525 68e2fd6845edbcf7476e788b1cb5e9edcae2c933
push id22725
push useremorley@mozilla.com
push dateTue, 22 May 2012 09:50:27 +0000
treeherdermozilla-central@ce618ce8d84a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, jrmuizel
bugs750989
milestone15.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 750989 - Pause Profiler during saving. r=mstange,jrmuizel
tools/profiler/TableTicker.cpp
tools/profiler/platform-linux.cc
tools/profiler/platform-macos.cc
tools/profiler/platform-win32.cc
tools/profiler/platform.h
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -376,26 +376,33 @@ public:
     // Expand %TEMP% on Windows
     {
       char tmp[MAXPATHLEN];
       ExpandEnvironmentStringsA(buff, tmp, mozilla::ArrayLength(tmp));
       strcpy(buff, tmp);
     }
 #endif
 
+    // Pause the profiler during saving.
+    // This will prevent us from recording sampling
+    // regarding profile saving. This will also
+    // prevent bugs caused by the circular buffer not
+    // being thread safe. Bug 750989.
     std::ofstream stream;
     stream.open(buff);
+    t->SetPaused(true);
     if (stream.is_open()) {
       stream << *(t->GetPrimaryThreadProfile());
       stream << "h-" << GetSharedLibraryInfoString() << std::endl;
       stream.close();
       LOG("Saved to " FOLDER "profile_TYPE_PID.txt");
     } else {
       LOG("Fail to open profile log file.");
     }
+    t->SetPaused(false);
 
     return NS_OK;
   }
 };
 
 void TableTicker::HandleSaveRequest()
 {
   if (!mSaveRequested)
@@ -417,18 +424,20 @@ JSObject* TableTicker::ToJSObject(JSCont
   // Put meta data
   // TODO: List things like feature, version number, profile time start/end
 
   // Lists the samples for each ThreadProfile
   JSObject *threads = b.CreateArray();
   b.DefineProperty(profile, "threads", threads);
 
   // For now we only have one thread
+  SetPaused(true);
   JSObject* threadSamples = GetPrimaryThreadProfile()->ToJSObject(aCx);
   b.ArrayPush(threads, threadSamples);
+  SetPaused(false);
 
   return profile;
 }
 
 
 #ifdef USE_BACKTRACE
 void TableTicker::doBacktrace(ThreadProfile &aProfile, TickSample* aSample)
 {
@@ -714,17 +723,19 @@ void mozilla_sampler_save()
 char* mozilla_sampler_get_profile()
 {
   TableTicker *t = tlsTicker.get();
   if (!t) {
     return NULL;
   }
 
   std::stringstream profile;
+  t->SetPaused(true);
   profile << *(t->GetPrimaryThreadProfile());
+  t->SetPaused(false);
 
   std::string profileString = profile.str();
   char *rtn = (char*)malloc( (profileString.length() + 1) * sizeof(char) );
   strcpy(rtn, profileString.c_str());
   return rtn;
 }
 
 JSObject *mozilla_sampler_get_profile_data(JSContext *aCx)
--- a/tools/profiler/platform-linux.cc
+++ b/tools/profiler/platform-linux.cc
@@ -134,38 +134,31 @@ class Sampler::PlatformData : public Mal
 #endif
   {
   }
 
   void SignalSender() {
     while (sampler_->IsActive()) {
       sampler_->HandleSaveRequest();
 
+      if (!sampler_->IsPaused()) {
 #ifdef XP_MACOSX
-      pthread_kill(signal_receiver_, SIGPROF);
+        pthread_kill(signal_receiver_, SIGPROF);
 #else
-      // Glibc doesn't provide a wrapper for tgkill(2).
-      tgkill(vm_tgid_, vm_tid_, SIGPROF);
+        // Glibc doesn't provide a wrapper for tgkill(2).
+        tgkill(vm_tgid_, vm_tid_, SIGPROF);
 #endif
+      }
+
       // Convert ms to us and subtract 100 us to compensate delays
       // occuring during signal delivery.
-
       // TODO measure and confirm this.
       const useconds_t interval = sampler_->interval_ * 1000 - 100;
       //int result = usleep(interval);
       usleep(interval);
-      // sometimes usleep is defined as returning void
-      int result = 0;
-#ifdef DEBUG
-      if (result != 0 && errno != EINTR) {
-        LOG("SignalSender usleep error");
-        ASSERT(result == 0 || errno == EINTR);
-      }
-#endif
-      mozilla::unused << result;
     }
   }
 
   Sampler* sampler_;
   bool signal_handler_installed_;
   struct sigaction old_sigprof_signal_handler_;
   struct sigaction old_sigsave_signal_handler_;
   pid_t vm_tgid_;
@@ -184,17 +177,18 @@ static void* SenderEntry(void* arg) {
   data->SignalSender();
   return 0;
 }
 
 
 Sampler::Sampler(int interval, bool profiling)
     : interval_(interval),
       profiling_(profiling),
-      active_(false) {
+      active_(false),
+      paused_(false) {
   data_ = new PlatformData(this);
 }
 
 Sampler::~Sampler() {
   ASSERT(!data_->signal_sender_launched_);
   delete data_;
 }
 
--- a/tools/profiler/platform-macos.cc
+++ b/tools/profiler/platform-macos.cc
@@ -218,17 +218,18 @@ class SamplerThread : public Thread {
       instance_ = NULL;
     }
     */
   }
 
   // Implement Thread::Run().
   virtual void Run() {
     while (SamplerRegistry::sampler->IsActive()) {
-      SampleContext(SamplerRegistry::sampler);
+      if (!SamplerRegistry::sampler->IsPaused())
+        SampleContext(SamplerRegistry::sampler);
       OS::Sleep(interval_);
     }
   }
 
   void SampleContext(Sampler* sampler) {
     thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
     TickSample sample_obj;
     TickSample* sample = &sample_obj;
@@ -290,17 +291,18 @@ class SamplerThread : public Thread {
 Mutex* SamplerThread::mutex_ = OS::CreateMutex();
 SamplerThread* SamplerThread::instance_ = NULL;
 
 
 Sampler::Sampler(int interval, bool profiling)
     : // isolate_(isolate),
       interval_(interval),
       profiling_(profiling),
-      active_(false) /*,
+      active_(false),
+      paused_(false) /*,
       samples_taken_(0)*/ {
   data_ = new PlatformData;
 }
 
 
 Sampler::~Sampler() {
   ASSERT(!IsActive());
   delete data_;
--- a/tools/profiler/platform-win32.cc
+++ b/tools/profiler/platform-win32.cc
@@ -59,17 +59,18 @@ class SamplerThread : public Thread {
     instance_->Join();
     delete instance_;
     instance_ = NULL;
   }
 
   // Implement Thread::Run().
   virtual void Run() {
     while (sampler_->IsActive()) {
-      SampleContext(sampler_);
+      if (!sampler_->IsPaused())
+        SampleContext(sampler_);
       OS::Sleep(interval_);
     }
   }
 
   void SampleContext(Sampler* sampler) {
     HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
     if (profiled_thread == NULL)
       return;
@@ -116,16 +117,17 @@ class SamplerThread : public Thread {
 
 SamplerThread* SamplerThread::instance_ = NULL;
 
 
 Sampler::Sampler(int interval, bool profiling)
     : interval_(interval),
       profiling_(profiling),
       active_(false),
+      paused_(false),
       data_(new PlatformData) {
 }
 
 Sampler::~Sampler() {
   ASSERT(!IsActive());
   delete data_;
 }
 
--- a/tools/profiler/platform.h
+++ b/tools/profiler/platform.h
@@ -206,16 +206,20 @@ class Sampler {
   void Stop();
 
   // Is the sampler used for profiling?
   bool IsProfiling() const { return profiling_; }
 
   // Whether the sampler is running (that is, consumes resources).
   bool IsActive() const { return active_; }
 
+  // Low overhead way to stop the sampler from ticking
+  bool IsPaused() const { return paused_; }
+  void SetPaused(bool value) { NoBarrier_Store(&paused_, value); }
+
   class PlatformData;
 
   PlatformData* platform_data() { return data_; }
 
   // If we move the backtracing code into the platform files we won't
   // need to have these hacks
 #ifdef XP_WIN
   // xxxehsan sucky hack :(
@@ -224,12 +228,13 @@ class Sampler {
 #ifdef XP_MACOSX
   static pthread_t GetProfiledThread(PlatformData*);
 #endif
  private:
   void SetActive(bool value) { NoBarrier_Store(&active_, value); }
 
   const int interval_;
   const bool profiling_;
+  Atomic32 paused_;
   Atomic32 active_;
   PlatformData* data_;  // Platform specific data.
 };