Index: src/platform-solaris.cc |
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc |
index ebe0475f4d3f123afca187d792338104196bcc33..833bea7e44cfcc9331d4eb4a7e90c4b8f8ecb673 100644 |
--- a/src/platform-solaris.cc |
+++ b/src/platform-solaris.cc |
@@ -612,11 +612,16 @@ static Sampler* active_sampler_ = NULL; |
static pthread_t vm_tid_ = 0; |
+static pthread_t GetThreadID() { |
+ return pthread_self(); |
+} |
+ |
+ |
static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
USE(info); |
if (signal != SIGPROF) return; |
if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; |
- if (vm_tid_ != pthread_self()) return; |
+ if (vm_tid_ != GetThreadID()) return; |
TickSample sample_obj; |
TickSample* sample = CpuProfiler::TickSampleEvent(); |
@@ -645,26 +650,86 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
class Sampler::PlatformData : public Malloced { |
public: |
- PlatformData() { |
- signal_handler_installed_ = false; |
+ enum SleepInterval { |
+ FULL_INTERVAL, |
+ HALF_INTERVAL |
+ }; |
+ |
+ explicit PlatformData(Sampler* sampler) |
+ : sampler_(sampler), |
+ signal_handler_installed_(false), |
+ vm_tgid_(getpid()), |
+ signal_sender_launched_(false) { |
+ } |
+ |
+ void SignalSender() { |
+ while (sampler_->IsActive()) { |
+ if (rate_limiter_.SuspendIfNecessary()) continue; |
+ if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
+ SendProfilingSignal(); |
+ Sleep(HALF_INTERVAL); |
+ RuntimeProfiler::NotifyTick(); |
+ Sleep(HALF_INTERVAL); |
+ } else { |
+ if (sampler_->IsProfiling()) SendProfilingSignal(); |
+ if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
+ Sleep(FULL_INTERVAL); |
+ } |
+ } |
+ } |
+ |
+ void SendProfilingSignal() { |
+ if (!signal_handler_installed_) return; |
+ pthread_kill(vm_tgid_, SIGPROF); |
Vitaly Repeshko
2011/03/11 00:08:27
Does work with vm_tid_ here?
Vyacheslav Egorov (Chromium)
2011/03/11 00:30:47
This looks really suspicious. vm_tgid_ is not a pt
ry
2011/03/11 01:02:00
Oops. With that I get crashes
Vitaly Repeshko
2011/03/11 01:08:46
So if it crashes because of a stale thread handle,
|
+ } |
+ |
+ void Sleep(SleepInterval full_or_half) { |
+ // Convert ms to us and subtract 100 us to compensate delays |
+ // occuring during signal delivery. |
+ useconds_t interval = sampler_->interval_ * 1000 - 100; |
+ if (full_or_half == HALF_INTERVAL) interval /= 2; |
+ int result = usleep(interval); |
+#ifdef DEBUG |
+ if (result != 0 && errno != EINTR) { |
+ fprintf(stderr, |
+ "SignalSender usleep error; interval = %u, errno = %d\n", |
+ interval, |
+ errno); |
+ ASSERT(result == 0 || errno == EINTR); |
+ } |
+#endif |
+ USE(result); |
} |
+ Sampler* sampler_; |
bool signal_handler_installed_; |
struct sigaction old_signal_handler_; |
- struct itimerval old_timer_value_; |
+ int vm_tgid_; |
+ bool signal_sender_launched_; |
+ pthread_t signal_sender_thread_; |
+ RuntimeProfilerRateLimiter rate_limiter_; |
}; |
+static void* SenderEntry(void* arg) { |
+ Sampler::PlatformData* data = |
+ reinterpret_cast<Sampler::PlatformData*>(arg); |
+ data->SignalSender(); |
+ return 0; |
+} |
+ |
+ |
Sampler::Sampler(int interval) |
: interval_(interval), |
profiling_(false), |
active_(false), |
samples_taken_(0) { |
- data_ = new PlatformData(); |
+ data_ = new PlatformData(this); |
} |
Sampler::~Sampler() { |
+ ASSERT(!data_->signal_sender_launched_); |
delete data_; |
} |
@@ -672,43 +737,53 @@ Sampler::~Sampler() { |
void Sampler::Start() { |
// There can only be one active sampler at the time on POSIX |
// platforms. |
- if (active_sampler_ != NULL) return; |
+ ASSERT(!IsActive()); |
+ vm_tid_ = GetThreadID(); |
// 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_); |
+ sa.sa_flags = SA_RESTART | SA_SIGINFO; |
+ data_->signal_handler_installed_ = |
+ sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0; |
+ |
+ // Start a thread that sends SIGPROF signal to VM thread. |
+ // Sending the signal ourselves instead of relying on itimer provides |
+ // much better accuracy. |
+ SetActive(true); |
+ if (pthread_create( |
+ &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
+ data_->signal_sender_launched_ = true; |
+ } |
// Set this sampler as the active sampler. |
active_sampler_ = this; |
- active_ = true; |
} |
void Sampler::Stop() { |
+ SetActive(false); |
+ |
+ // Wait for signal sender termination (it will exit after setting |
+ // active_ to false). |
+ if (data_->signal_sender_launched_) { |
+ Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
+ pthread_join(data_->signal_sender_thread_, NULL); |
+ data_->signal_sender_launched_ = false; |
+ } |
+ |
// 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; |
- active_ = false; |
} |
+ |
#endif // ENABLE_LOGGING_AND_PROFILING |
} } // namespace v8::internal |