Author: [email protected]
Date: Wed Jul  1 01:46:59 2009
New Revision: 2315

Modified:
    branches/bleeding_edge/src/log.cc
    branches/bleeding_edge/src/platform-freebsd.cc
    branches/bleeding_edge/src/platform-linux.cc
    branches/bleeding_edge/src/platform-macos.cc
    branches/bleeding_edge/src/platform-win32.cc
    branches/bleeding_edge/src/platform.h

Log:
Reimplement profiler sampler on Mac OS X to get it working under Chromium.

Previous implementation of sampler for OS X was copied from the Linux one.  
But BSD (OS X) and Linux has a very important difference in signal  
handling. LinuxThreads doesn't support the notion of process-directed  
signals. So, the SIGPROF signal was directed to the thread that installed  
the handler---the V8 thread. But on BSD, signal handling is implemented  
according to POSIX spec, where process-directed signal is to be handled by  
an arbitrary selected thread. By a coincidence, in V8's sample shell and in  
Chromium's test shell, V8's thread was picked almost every time, so  
sampling seemed working. But not in case of Chromium.

So, I've changed the implementation of profiler sampler to use the same  
scheme as on Windows---a dedicated thread with high priority is used to  
periodically pause and sample V8's thread.

Review URL: http://codereview.chromium.org/147150

Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc   (original)
+++ branches/bleeding_edge/src/log.cc   Wed Jul  1 01:46:59 2009
@@ -176,8 +176,11 @@

    ~Ticker() { if (IsActive()) Stop(); }

+  void SampleStack(TickSample* sample) {
+    StackTracer::Trace(sample);
+  }
+
    void Tick(TickSample* sample) {
-    if (IsProfiling()) StackTracer::Trace(sample);
      if (profiler_) profiler_->Insert(sample);
      if (window_) window_->AddState(sample->state);
    }

Modified: branches/bleeding_edge/src/platform-freebsd.cc
==============================================================================
--- branches/bleeding_edge/src/platform-freebsd.cc      (original)
+++ branches/bleeding_edge/src/platform-freebsd.cc      Wed Jul  1 01:46:59 2009
@@ -561,6 +561,7 @@
      sample.sp = mcontext.mc_esp;
      sample.fp = mcontext.mc_ebp;
  #endif
+    active_sampler_->SampleStack(&sample);
    }

    // We always sample the VM state.

Modified: branches/bleeding_edge/src/platform-linux.cc
==============================================================================
--- branches/bleeding_edge/src/platform-linux.cc        (original)
+++ branches/bleeding_edge/src/platform-linux.cc        Wed Jul  1 01:46:59 2009
@@ -639,6 +639,7 @@
      sample.fp = mcontext.arm_fp;
  #endif
  #endif
+    active_sampler_->SampleStack(&sample);
    }

    // We always sample the VM state.

Modified: branches/bleeding_edge/src/platform-macos.cc
==============================================================================
--- branches/bleeding_edge/src/platform-macos.cc        (original)
+++ branches/bleeding_edge/src/platform-macos.cc        Wed Jul  1 01:46:59 2009
@@ -38,6 +38,7 @@
  #include <pthread.h>
  #include <semaphore.h>
  #include <signal.h>
+#include <mach/mach.h>
  #include <mach/semaphore.h>
  #include <mach/task.h>
  #include <sys/time.h>
@@ -475,63 +476,94 @@

  #ifdef ENABLE_LOGGING_AND_PROFILING

-static Sampler* active_sampler_ = NULL;
-
-static void ProfilerSignalHandler(int signal, siginfo_t* info, void*  
context) {
-  USE(info);
-  if (signal != SIGPROF) return;
-  if (active_sampler_ == NULL) return;
-
-  TickSample sample;
-
-  // If profiling, we extract the current pc and sp.
-  if (active_sampler_->IsProfiling()) {
-    // Extracting the sample from the context is extremely machine  
dependent.
-    ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
-    mcontext_t& mcontext = ucontext->uc_mcontext;
+class Sampler::PlatformData : public Malloced {
+ public:
+  explicit PlatformData(Sampler* sampler)
+      : sampler_(sampler),
+        task_self_(mach_task_self()),
+        profiled_thread_(0),
+        sampler_thread_(0) {
+  }
+
+  Sampler* sampler_;
+  // Note: for profiled_thread_ Mach primitives are used instead of  
PThread's
+  // because the latter doesn't provide thread manipulation primitives  
required.
+  // For details, consult "Mac OS X Internals" book, Section 7.3.
+  mach_port_t task_self_;
+  thread_act_t profiled_thread_;
+  pthread_t sampler_thread_;
+
+  // Sampler thread handler.
+  void Runner() {
+    // Loop until the sampler is disengaged.
+    while (sampler_->IsActive()) {
+      TickSample sample;
+
+      // If profiling, we record the pc and sp of the profiled thread.
+      if (sampler_->IsProfiling()
+          && KERN_SUCCESS == thread_suspend(profiled_thread_)) {
  #if V8_HOST_ARCH_X64
-    UNIMPLEMENTED();
-    USE(mcontext);
-    sample.pc = 0;
-    sample.sp = 0;
-    sample.fp = 0;
+        thread_state_flavor_t flavor = x86_THREAD_STATE64;
+        x86_thread_state64_t state;
+        mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+#elif V8_HOST_ARCH_IA32
+        thread_state_flavor_t flavor = i386_THREAD_STATE;
+        i386_thread_state_t state;
+        mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#else
+#error Unsupported Mac OS X host architecture.
+#endif  // V8_TARGET_ARCH_IA32
+        if (KERN_SUCCESS == thread_get_state(profiled_thread_,
+                                             flavor,
+                                             (natural_t*)&state,
+                                             &count)) {
+#if V8_HOST_ARCH_X64
+          UNIMPLEMENTED();
+          sample.pc = 0;
+          sample.sp = 0;
+          sample.fp = 0;
  #elif V8_HOST_ARCH_IA32
  #if __DARWIN_UNIX03
-    sample.pc = mcontext->__ss.__eip;
-    sample.sp = mcontext->__ss.__esp;
-    sample.fp = mcontext->__ss.__ebp;
+          sample.pc = state.__eip;
+          sample.sp = state.__esp;
+          sample.fp = state.__ebp;
  #else  // !__DARWIN_UNIX03
-    sample.pc = mcontext->ss.eip;
-    sample.sp = mcontext->ss.esp;
-    sample.fp = mcontext->ss.ebp;
+          sample.pc = state.eip;
+          sample.sp = state.esp;
+          sample.fp = state.ebp;
  #endif  // __DARWIN_UNIX03
  #else
  #error Unsupported Mac OS X host architecture.
  #endif  // V8_HOST_ARCH_IA32
+          sampler_->SampleStack(&sample);
+        }
+        thread_resume(profiled_thread_);
+      }
+
+      // We always sample the VM state.
+      sample.state = Logger::state();
+      // Invoke tick handler with program counter and stack pointer.
+      sampler_->Tick(&sample);
+
+      // Wait until next sampling.
+      usleep(sampler_->interval_ * 1000);
+    }
    }
+};

-  // We always sample the VM state.
-  sample.state = Logger::state();

-  active_sampler_->Tick(&sample);
+// Entry point for sampler thread.
+static void* SamplerEntry(void* arg) {
+  Sampler::PlatformData* data =
+      reinterpret_cast<Sampler::PlatformData*>(arg);
+  data->Runner();
+  return 0;
  }


-class Sampler::PlatformData : public Malloced {
- public:
-  PlatformData() {
-    signal_handler_installed_ = false;
-  }
-
-  bool signal_handler_installed_;
-  struct sigaction old_signal_handler_;
-  struct itimerval old_timer_value_;
-};
-
-
  Sampler::Sampler(int interval, bool profiling)
      : interval_(interval), profiling_(profiling), active_(false) {
-  data_ = new PlatformData();
+  data_ = new PlatformData(this);
  }


@@ -541,43 +573,40 @@


  void Sampler::Start() {
-  // There can only be one active sampler at the time on POSIX
-  // platforms.
-  if (active_sampler_ != NULL) return;
-
-  // Request profiling signals.
-  struct sigaction sa;
-  sa.sa_sigaction = ProfilerSignalHandler;
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = SA_SIGINFO;
-  if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
-  data_->signal_handler_installed_ = true;
-
-  // Set the itimer to generate a tick for each interval.
-  itimerval itimer;
-  itimer.it_interval.tv_sec = interval_ / 1000;
-  itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
-  itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
-  itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
-  setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+  // If we are profiling, we need to be able to access the calling
+  // thread.
+  if (IsProfiling()) {
+    data_->profiled_thread_ = mach_thread_self();
+  }
+
+  // Create sampler thread with high priority.
+  // According to POSIX spec, when SCHED_FIFO policy is used, a thread
+  // runs until it exits or blocks.
+  pthread_attr_t sched_attr;
+  sched_param fifo_param;
+  pthread_attr_init(&sched_attr);
+  pthread_attr_setinheritsched(&sched_attr, PTHREAD_EXPLICIT_SCHED);
+  pthread_attr_setschedpolicy(&sched_attr, SCHED_FIFO);
+  fifo_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+  pthread_attr_setschedparam(&sched_attr, &fifo_param);

-  // Set this sampler as the active sampler.
-  active_sampler_ = this;
    active_ = true;
+  pthread_create(&data_->sampler_thread_, &sched_attr, SamplerEntry,  
data_);
  }


  void Sampler::Stop() {
-  // Restore old signal handler
-  if (data_->signal_handler_installed_) {
-    setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
-    sigaction(SIGPROF, &data_->old_signal_handler_, 0);
-    data_->signal_handler_installed_ = false;
-  }
-
-  // This sampler is no longer the active sampler.
-  active_sampler_ = NULL;
+  // Seting active to false triggers termination of the sampler
+  // thread.
    active_ = false;
+
+  // Wait for sampler thread to terminate.
+  pthread_join(data_->sampler_thread_, NULL);
+
+  // Deallocate Mach port for thread.
+  if (IsProfiling()) {
+    mach_port_deallocate(data_->task_self_, data_->profiled_thread_);
+  }
  }

  #endif  // ENABLE_LOGGING_AND_PROFILING

Modified: branches/bleeding_edge/src/platform-win32.cc
==============================================================================
--- branches/bleeding_edge/src/platform-win32.cc        (original)
+++ branches/bleeding_edge/src/platform-win32.cc        Wed Jul  1 01:46:59 2009
@@ -1776,31 +1776,29 @@
        TickSample sample;

        // If profiling, we record the pc and sp of the profiled thread.
-      if (sampler_->IsProfiling()) {
-        // Pause the profiled thread and get its context.
-        SuspendThread(profiled_thread_);
+      if (sampler_->IsProfiling()
+          && SuspendThread(profiled_thread_) != (DWORD)-1) {
          context.ContextFlags = CONTEXT_FULL;
-        GetThreadContext(profiled_thread_, &context);
-        // Invoke tick handler with program counter and stack pointer.
+        if (GetThreadContext(profiled_thread_, &context) != 0) {
  #if V8_HOST_ARCH_X64
-        UNIMPLEMENTED();
-        sample.pc = context.Rip;
-        sample.sp = context.Rsp;
-        sample.fp = context.Rbp;
+          UNIMPLEMENTED();
+          sample.pc = context.Rip;
+          sample.sp = context.Rsp;
+          sample.fp = context.Rbp;
  #else
-        sample.pc = context.Eip;
-        sample.sp = context.Esp;
-        sample.fp = context.Ebp;
+          sample.pc = context.Eip;
+          sample.sp = context.Esp;
+          sample.fp = context.Ebp;
  #endif
+          sampler_->SampleStack(&sample);
+        }
+        ResumeThread(profiled_thread_);
        }

        // We always sample the VM state.
        sample.state = Logger::state();
+      // Invoke tick handler with program counter and stack pointer.
        sampler_->Tick(&sample);
-
-      if (sampler_->IsProfiling()) {
-        ResumeThread(profiled_thread_);
-      }

        // Wait until next sampling.
        Sleep(sampler_->interval_);

Modified: branches/bleeding_edge/src/platform.h
==============================================================================
--- branches/bleeding_edge/src/platform.h       (original)
+++ branches/bleeding_edge/src/platform.h       Wed Jul  1 01:46:59 2009
@@ -510,6 +510,9 @@
    explicit Sampler(int interval, bool profiling);
    virtual ~Sampler();

+  // Performs stack sampling.
+  virtual void SampleStack(TickSample* sample) = 0;
+
    // This method is called for each sampling period with the current
    // program counter.
    virtual void Tick(TickSample* sample) = 0;
@@ -527,8 +530,8 @@
    class PlatformData;

   private:
-  int interval_;
-  bool profiling_;
+  const int interval_;
+  const bool profiling_;
    bool active_;
    PlatformData* data_;  // Platform specific data.
    DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to