42
42
#include < sys/stat.h> // open
43
43
#include < sys/fcntl.h> // open
44
44
#include < unistd.h> // getpagesize
45
+ // If you don't have execinfo.h then you need devel/libexecinfo from ports.
45
46
#include < execinfo.h> // backtrace, backtrace_symbols
46
47
#include < strings.h> // index
47
48
#include < errno.h>
@@ -526,6 +527,16 @@ class FreeBSDMutex : public Mutex {
526
527
return result;
527
528
}
528
529
530
+ virtual bool TryLock () {
531
+ int result = pthread_mutex_trylock (&mutex_);
532
+ // Return false if the lock is busy and locking failed.
533
+ if (result == EBUSY) {
534
+ return false ;
535
+ }
536
+ ASSERT (result == 0 ); // Verify no other errors.
537
+ return true ;
538
+ }
539
+
529
540
private:
530
541
pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
531
542
};
@@ -595,60 +606,124 @@ Semaphore* OS::CreateSemaphore(int count) {
595
606
#ifdef ENABLE_LOGGING_AND_PROFILING
596
607
597
608
static Sampler* active_sampler_ = NULL ;
609
+ static pthread_t vm_tid_ = NULL ;
610
+
611
+
612
+ static pthread_t GetThreadID () {
613
+ pthread_t thread_id = pthread_self ();
614
+ return thread_id;
615
+ }
616
+
617
+
618
+ class Sampler ::PlatformData : public Malloced {
619
+ public:
620
+ enum SleepInterval {
621
+ FULL_INTERVAL,
622
+ HALF_INTERVAL
623
+ };
624
+
625
+ explicit PlatformData (Sampler* sampler)
626
+ : sampler_(sampler),
627
+ signal_handler_installed_(false ),
628
+ signal_sender_launched_(false ) {
629
+ }
630
+
631
+ void SignalSender () {
632
+ while (sampler_->IsActive ()) {
633
+ if (rate_limiter_.SuspendIfNecessary ()) continue ;
634
+ if (sampler_->IsProfiling () && RuntimeProfiler::IsEnabled ()) {
635
+ Sleep (FULL_INTERVAL);
636
+ RuntimeProfiler::NotifyTick ();
637
+ } else {
638
+ if (RuntimeProfiler::IsEnabled ()) RuntimeProfiler::NotifyTick ();
639
+ Sleep (FULL_INTERVAL);
640
+ }
641
+ }
642
+ }
643
+
644
+ void Sleep (SleepInterval full_or_half) {
645
+ // Convert ms to us and subtract 100 us to compensate delays
646
+ // occuring during signal delivery.
647
+ useconds_t interval = sampler_->interval_ * 1000 - 100 ;
648
+ if (full_or_half == HALF_INTERVAL) interval /= 2 ;
649
+ int result = usleep (interval);
650
+ #ifdef DEBUG
651
+ if (result != 0 && errno != EINTR) {
652
+ fprintf (stderr,
653
+ " SignalSender usleep error; interval = %u, errno = %d\n " ,
654
+ interval,
655
+ errno);
656
+ ASSERT (result == 0 || errno == EINTR);
657
+ }
658
+ #endif
659
+ USE (result);
660
+ }
661
+
662
+ Sampler* sampler_;
663
+ bool signal_handler_installed_;
664
+ struct sigaction old_signal_handler_;
665
+ struct itimerval old_timer_value_;
666
+ bool signal_sender_launched_;
667
+ pthread_t signal_sender_thread_;
668
+ RuntimeProfilerRateLimiter rate_limiter_;
669
+ };
670
+
598
671
599
672
static void ProfilerSignalHandler (int signal, siginfo_t * info, void * context) {
600
673
USE (info);
601
674
if (signal != SIGPROF) return ;
602
675
if (active_sampler_ == NULL ) return ;
676
+ if (!active_sampler_->IsActive ()) {
677
+ // Restore old signal handler
678
+ Sampler::PlatformData* data = active_sampler_->data ();
679
+ if (data->signal_handler_installed_ ) {
680
+ sigaction (SIGPROF, &data->old_signal_handler_ , 0 );
681
+ data->signal_handler_installed_ = false ;
682
+ }
683
+ return ;
684
+ }
603
685
604
- TickSample sample ;
686
+ if (vm_tid_ != GetThreadID ()) return ;
605
687
606
- // We always sample the VM state.
607
- sample.state = VMState::current_state ();
688
+ TickSample sample_obj;
689
+ TickSample* sample = CpuProfiler::TickSampleEvent ();
690
+ if (sample == NULL ) sample = &sample_obj;
608
691
609
- // If profiling, we extract the current pc and sp.
610
- if (active_sampler_->IsProfiling ()) {
611
- // Extracting the sample from the context is extremely machine dependent.
612
- ucontext_t * ucontext = reinterpret_cast <ucontext_t *>(context);
613
- mcontext_t & mcontext = ucontext->uc_mcontext ;
692
+ // Extracting the sample from the context is extremely machine dependent.
693
+ ucontext_t * ucontext = reinterpret_cast <ucontext_t *>(context);
694
+ mcontext_t & mcontext = ucontext->uc_mcontext ;
614
695
#if V8_HOST_ARCH_IA32
615
- sample. pc = reinterpret_cast <Address>(mcontext.mc_eip );
616
- sample. sp = reinterpret_cast <Address>(mcontext.mc_esp );
617
- sample. fp = reinterpret_cast <Address>(mcontext.mc_ebp );
696
+ sample-> pc = reinterpret_cast <Address>(mcontext.mc_eip );
697
+ sample-> sp = reinterpret_cast <Address>(mcontext.mc_esp );
698
+ sample-> fp = reinterpret_cast <Address>(mcontext.mc_ebp );
618
699
#elif V8_HOST_ARCH_X64
619
- sample. pc = reinterpret_cast <Address>(mcontext.mc_rip );
620
- sample. sp = reinterpret_cast <Address>(mcontext.mc_rsp );
621
- sample. fp = reinterpret_cast <Address>(mcontext.mc_rbp );
700
+ sample-> pc = reinterpret_cast <Address>(mcontext.mc_rip );
701
+ sample-> sp = reinterpret_cast <Address>(mcontext.mc_rsp );
702
+ sample-> fp = reinterpret_cast <Address>(mcontext.mc_rbp );
622
703
#elif V8_HOST_ARCH_ARM
623
- sample. pc = reinterpret_cast <Address>(mcontext.mc_r15 );
624
- sample. sp = reinterpret_cast <Address>(mcontext.mc_r13 );
625
- sample. fp = reinterpret_cast <Address>(mcontext.mc_r11 );
704
+ sample-> pc = reinterpret_cast <Address>(mcontext.mc_r15 );
705
+ sample-> sp = reinterpret_cast <Address>(mcontext.mc_r13 );
706
+ sample-> fp = reinterpret_cast <Address>(mcontext.mc_r11 );
626
707
#endif
627
- active_sampler_->SampleStack (&sample);
628
- }
629
-
630
- active_sampler_->Tick (&sample);
708
+ active_sampler_->SampleStack (sample);
709
+ active_sampler_->Tick (sample);
631
710
}
632
711
633
712
634
- class Sampler ::PlatformData : public Malloced {
635
- public:
636
- PlatformData () {
637
- signal_handler_installed_ = false ;
638
- }
639
-
640
- bool signal_handler_installed_;
641
- struct sigaction old_signal_handler_;
642
- struct itimerval old_timer_value_;
643
- };
713
+ static void * SenderEntry (void * arg) {
714
+ Sampler::PlatformData* data =
715
+ reinterpret_cast <Sampler::PlatformData*>(arg);
716
+ data->SignalSender ();
717
+ return 0 ;
718
+ }
644
719
645
720
646
721
Sampler::Sampler (int interval)
647
722
: interval_(interval),
648
723
profiling_(false ),
649
724
active_(false ),
650
725
samples_taken_(0 ) {
651
- data_ = new PlatformData ();
726
+ data_ = new PlatformData (this );
652
727
}
653
728
654
729
@@ -660,7 +735,8 @@ Sampler::~Sampler() {
660
735
void Sampler::Start () {
661
736
// There can only be one active sampler at the time on POSIX
662
737
// platforms.
663
- if (active_sampler_ != NULL ) return ;
738
+ ASSERT (!IsActive ());
739
+ vm_tid_ = GetThreadID ();
664
740
665
741
// Request profiling signals.
666
742
struct sigaction sa;
@@ -680,21 +756,29 @@ void Sampler::Start() {
680
756
681
757
// Set this sampler as the active sampler.
682
758
active_sampler_ = this ;
683
- active_ = true ;
759
+ SetActive (true );
760
+
761
+ // There's no way to send a signal to a thread on FreeBSD, but we can
762
+ // start a thread that uses the stack guard to interrupt the JS thread.
763
+ if (pthread_create (
764
+ &data_->signal_sender_thread_ , NULL , SenderEntry, data_) == 0 ) {
765
+ data_->signal_sender_launched_ = true ;
766
+ }
684
767
}
685
768
686
769
687
770
void Sampler::Stop () {
688
- // Restore old signal handler
689
- if (data_->signal_handler_installed_ ) {
690
- setitimer (ITIMER_PROF, &data_->old_timer_value_ , NULL );
691
- sigaction (SIGPROF, &data_->old_signal_handler_ , 0 );
692
- data_->signal_handler_installed_ = false ;
693
- }
694
-
695
771
// This sampler is no longer the active sampler.
696
772
active_sampler_ = NULL ;
697
- active_ = false ;
773
+ SetActive (false );
774
+
775
+ // Wait for signal sender termination (it will exit after setting
776
+ // active_ to false).
777
+ if (data_->signal_sender_launched_ ) {
778
+ Top::WakeUpRuntimeProfilerThreadBeforeShutdown ();
779
+ pthread_join (data_->signal_sender_thread_ , NULL );
780
+ data_->signal_sender_launched_ = false ;
781
+ }
698
782
}
699
783
700
784
#endif // ENABLE_LOGGING_AND_PROFILING
0 commit comments