From 6c6a998e4eed2e6b0adaba4f39fa98b56d1ce5b9 Mon Sep 17 00:00:00 2001 From: "erik.corry@gmail.com" Date: Wed, 16 Mar 2011 11:15:43 +0000 Subject: [PATCH] * Fix build errors on FreeBSD 8.2 * Fix Crankshaft on FreeBSD. * Partially fix profiling on FreeBSD. * Remove bash-isms from tick processor script. Review URL: http://codereview.chromium.org/6673045 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7200 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- SConstruct | 1 + src/d8-posix.cc | 2 + src/platform-freebsd.cc | 172 ++++++++++++++++++++++++++--------- src/platform.h | 1 + tools/freebsd-tick-processor | 10 ++ tools/linux-tick-processor | 8 +- 6 files changed, 147 insertions(+), 47 deletions(-) create mode 100755 tools/freebsd-tick-processor diff --git a/SConstruct b/SConstruct index 84707e9847..8b09ca1607 100644 --- a/SConstruct +++ b/SConstruct @@ -174,6 +174,7 @@ LIBRARY_FLAGS = { 'CPPPATH' : ['/usr/local/include'], 'LIBPATH' : ['/usr/local/lib'], 'CCFLAGS': ['-ansi'], + 'LIBS': ['execinfo'] }, 'os:openbsd': { 'CPPPATH' : ['/usr/local/include'], diff --git a/src/d8-posix.cc b/src/d8-posix.cc index 335bd2b4bc..a7a4049361 100644 --- a/src/d8-posix.cc +++ b/src/d8-posix.cc @@ -375,8 +375,10 @@ static Handle GetStdout(int child_fd, // a parent process hangs on waiting while a child process is already a zombie. // See http://code.google.com/p/v8/issues/detail?id=401. #if defined(WNOWAIT) && !defined(ANDROID) && !defined(__APPLE__) +#if !defined(__FreeBSD__) #define HAS_WAITID 1 #endif +#endif // Get exit status of child. diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc index 21763b5de9..c2c81dc108 100644 --- a/src/platform-freebsd.cc +++ b/src/platform-freebsd.cc @@ -42,6 +42,7 @@ #include // open #include // open #include // getpagesize +// If you don't have execinfo.h then you need devel/libexecinfo from ports. #include // backtrace, backtrace_symbols #include // index #include @@ -526,6 +527,16 @@ class FreeBSDMutex : public Mutex { return result; } + virtual bool TryLock() { + int result = pthread_mutex_trylock(&mutex_); + // Return false if the lock is busy and locking failed. + if (result == EBUSY) { + return false; + } + ASSERT(result == 0); // Verify no other errors. + return true; + } + private: pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. }; @@ -595,60 +606,124 @@ Semaphore* OS::CreateSemaphore(int count) { #ifdef ENABLE_LOGGING_AND_PROFILING static Sampler* active_sampler_ = NULL; +static pthread_t vm_tid_ = NULL; -static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { - USE(info); - if (signal != SIGPROF) return; - if (active_sampler_ == NULL) return; - TickSample sample; - - // We always sample the VM state. - sample.state = VMState::current_state(); - - // 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(context); - mcontext_t& mcontext = ucontext->uc_mcontext; -#if V8_HOST_ARCH_IA32 - sample.pc = reinterpret_cast
(mcontext.mc_eip); - sample.sp = reinterpret_cast
(mcontext.mc_esp); - sample.fp = reinterpret_cast
(mcontext.mc_ebp); -#elif V8_HOST_ARCH_X64 - sample.pc = reinterpret_cast
(mcontext.mc_rip); - sample.sp = reinterpret_cast
(mcontext.mc_rsp); - sample.fp = reinterpret_cast
(mcontext.mc_rbp); -#elif V8_HOST_ARCH_ARM - sample.pc = reinterpret_cast
(mcontext.mc_r15); - sample.sp = reinterpret_cast
(mcontext.mc_r13); - sample.fp = reinterpret_cast
(mcontext.mc_r11); -#endif - active_sampler_->SampleStack(&sample); - } - - active_sampler_->Tick(&sample); +static pthread_t GetThreadID() { + pthread_t thread_id = pthread_self(); + return thread_id; } 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), + signal_sender_launched_(false) { } + void SignalSender() { + while (sampler_->IsActive()) { + if (rate_limiter_.SuspendIfNecessary()) continue; + if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { + Sleep(FULL_INTERVAL); + RuntimeProfiler::NotifyTick(); + } else { + if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); + Sleep(FULL_INTERVAL); + } + } + } + + 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_; + bool signal_sender_launched_; + pthread_t signal_sender_thread_; + RuntimeProfilerRateLimiter rate_limiter_; }; +static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { + USE(info); + if (signal != SIGPROF) return; + if (active_sampler_ == NULL) return; + if (!active_sampler_->IsActive()) { + // Restore old signal handler + Sampler::PlatformData* data = active_sampler_->data(); + if (data->signal_handler_installed_) { + sigaction(SIGPROF, &data->old_signal_handler_, 0); + data->signal_handler_installed_ = false; + } + return; + } + + if (vm_tid_ != GetThreadID()) return; + + TickSample sample_obj; + TickSample* sample = CpuProfiler::TickSampleEvent(); + if (sample == NULL) sample = &sample_obj; + + // Extracting the sample from the context is extremely machine dependent. + ucontext_t* ucontext = reinterpret_cast(context); + mcontext_t& mcontext = ucontext->uc_mcontext; +#if V8_HOST_ARCH_IA32 + sample->pc = reinterpret_cast
(mcontext.mc_eip); + sample->sp = reinterpret_cast
(mcontext.mc_esp); + sample->fp = reinterpret_cast
(mcontext.mc_ebp); +#elif V8_HOST_ARCH_X64 + sample->pc = reinterpret_cast
(mcontext.mc_rip); + sample->sp = reinterpret_cast
(mcontext.mc_rsp); + sample->fp = reinterpret_cast
(mcontext.mc_rbp); +#elif V8_HOST_ARCH_ARM + sample->pc = reinterpret_cast
(mcontext.mc_r15); + sample->sp = reinterpret_cast
(mcontext.mc_r13); + sample->fp = reinterpret_cast
(mcontext.mc_r11); +#endif + active_sampler_->SampleStack(sample); + active_sampler_->Tick(sample); +} + + +static void* SenderEntry(void* arg) { + Sampler::PlatformData* data = + reinterpret_cast(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); } @@ -660,7 +735,8 @@ 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; @@ -680,21 +756,29 @@ void Sampler::Start() { // Set this sampler as the active sampler. active_sampler_ = this; - active_ = true; + SetActive(true); + + // There's no way to send a signal to a thread on FreeBSD, but we can + // start a thread that uses the stack guard to interrupt the JS thread. + if (pthread_create( + &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { + data_->signal_sender_launched_ = true; + } } 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; - active_ = false; + 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; + } } #endif // ENABLE_LOGGING_AND_PROFILING diff --git a/src/platform.h b/src/platform.h index 88825e6457..e2f50a67fa 100644 --- a/src/platform.h +++ b/src/platform.h @@ -613,6 +613,7 @@ class Sampler { void ResetSamplesTaken() { samples_taken_ = 0; } class PlatformData; + PlatformData* data() { return data_; } protected: virtual void DoSampleStack(TickSample* sample) = 0; diff --git a/tools/freebsd-tick-processor b/tools/freebsd-tick-processor new file mode 100755 index 0000000000..2bb2618bfa --- /dev/null +++ b/tools/freebsd-tick-processor @@ -0,0 +1,10 @@ +#!/bin/sh + +# A wrapper script to call 'linux-tick-processor'. + +# Known issues on FreeBSD: +# No ticks from C++ code. +# You must have d8 built and in your path before calling this. + +tools_path=`cd $(dirname "$0");pwd` +$tools_path/linux-tick-processor "$@" diff --git a/tools/linux-tick-processor b/tools/linux-tick-processor index 17157050df..9789697547 100755 --- a/tools/linux-tick-processor +++ b/tools/linux-tick-processor @@ -3,12 +3,12 @@ tools_path=`cd $(dirname "$0");pwd` if [ ! "$D8_PATH" ]; then d8_public=`which d8` - if [ $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi + if [ -x $d8_public ]; then D8_PATH=$(dirname "$d8_public"); fi fi [ "$D8_PATH" ] || D8_PATH=$tools_path/.. d8_exec=$D8_PATH/d8 -if [ "$1" == "--no-build" ]; then +if [ "$1" = "--no-build" ]; then shift else # compile d8 if it doesn't exist, assuming this script @@ -16,15 +16,17 @@ else [ -x $d8_exec ] || scons -j4 -C $D8_PATH -Y $tools_path/.. d8 fi + # find the name of the log file to process, it must not start with a dash. log_file="v8.log" for arg in "$@" do - if [[ "${arg}" != -* ]]; then + if ! expr "X${arg}" : "^X-" > /dev/null; then log_file=${arg} fi done + # nm spits out 'no symbols found' messages to stderr. cat $log_file | $d8_exec $tools_path/splaytree.js $tools_path/codemap.js \ $tools_path/csvparser.js $tools_path/consarray.js \