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 idunknown
push userunknown
push dateunknown
reviewersmstange, jrmuizel
bugs750989
milestone15.0a1
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.
 };