Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(302)

Side by Side Diff: src/platform-linux.cc

Issue 4000007: Improve sampler resolution on Linux. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: comments addressed Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | test/cctest/test-log.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 15 matching lines...) Expand all
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 // Platform specific code for Linux goes here. For the POSIX comaptible parts 28 // Platform specific code for Linux goes here. For the POSIX comaptible parts
29 // the implementation is in platform-posix.cc. 29 // the implementation is in platform-posix.cc.
30 30
31 #include <pthread.h> 31 #include <pthread.h>
32 #include <semaphore.h> 32 #include <semaphore.h>
33 #include <signal.h> 33 #include <signal.h>
34 #include <sys/time.h> 34 #include <sys/time.h>
35 #include <sys/resource.h> 35 #include <sys/resource.h>
36 #include <sys/syscall.h>
36 #include <sys/types.h> 37 #include <sys/types.h>
37 #include <stdlib.h> 38 #include <stdlib.h>
38 39
39 // Ubuntu Dapper requires memory pages to be marked as 40 // Ubuntu Dapper requires memory pages to be marked as
40 // executable. Otherwise, OS raises an exception when executing code 41 // executable. Otherwise, OS raises an exception when executing code
41 // in that page. 42 // in that page.
42 #include <sys/types.h> // mmap & munmap 43 #include <sys/types.h> // mmap & munmap
43 #include <sys/mman.h> // mmap & munmap 44 #include <sys/mman.h> // mmap & munmap
44 #include <sys/stat.h> // open 45 #include <sys/stat.h> // open
45 #include <fcntl.h> // open 46 #include <fcntl.h> // open
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 708
708 709
709 Semaphore* OS::CreateSemaphore(int count) { 710 Semaphore* OS::CreateSemaphore(int count) {
710 return new LinuxSemaphore(count); 711 return new LinuxSemaphore(count);
711 } 712 }
712 713
713 714
714 #ifdef ENABLE_LOGGING_AND_PROFILING 715 #ifdef ENABLE_LOGGING_AND_PROFILING
715 716
716 static Sampler* active_sampler_ = NULL; 717 static Sampler* active_sampler_ = NULL;
717 static pthread_t vm_thread_ = 0;
718 718
719 719
720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) 720 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__))
721 // Android runs a fairly new Linux kernel, so signal info is there, 721 // Android runs a fairly new Linux kernel, so signal info is there,
722 // but the C library doesn't have the structs defined. 722 // but the C library doesn't have the structs defined.
723 723
724 struct sigcontext { 724 struct sigcontext {
725 uint32_t trap_no; 725 uint32_t trap_no;
726 uint32_t error_code; 726 uint32_t error_code;
727 uint32_t oldmask; 727 uint32_t oldmask;
728 uint32_t gregs[16]; 728 uint32_t gregs[16];
729 uint32_t arm_cpsr; 729 uint32_t arm_cpsr;
730 uint32_t fault_address; 730 uint32_t fault_address;
731 }; 731 };
732 typedef uint32_t __sigset_t; 732 typedef uint32_t __sigset_t;
733 typedef struct sigcontext mcontext_t; 733 typedef struct sigcontext mcontext_t;
734 typedef struct ucontext { 734 typedef struct ucontext {
735 uint32_t uc_flags; 735 uint32_t uc_flags;
736 struct ucontext* uc_link; 736 struct ucontext* uc_link;
737 stack_t uc_stack; 737 stack_t uc_stack;
738 mcontext_t uc_mcontext; 738 mcontext_t uc_mcontext;
739 __sigset_t uc_sigmask; 739 __sigset_t uc_sigmask;
740 } ucontext_t; 740 } ucontext_t;
741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11}; 741 enum ArmRegisters {R15 = 15, R13 = 13, R11 = 11};
742 742
743 #endif 743 #endif
744 744
745 745
746 // A function that determines if a signal handler is called in the context
747 // of a VM thread.
748 //
749 // The problem is that SIGPROF signal can be delivered to an arbitrary thread
750 // (see http://code.google.com/p/google-perftools/issues/detail?id=106#c2)
751 // So, if the signal is being handled in the context of a non-VM thread,
752 // it means that the VM thread is running, and trying to sample its stack can
753 // cause a crash.
754 static inline bool IsVmThread() {
755 // In the case of a single VM thread, this check is enough.
756 if (pthread_equal(pthread_self(), vm_thread_)) return true;
757 // If there are multiple threads that use VM, they must have a thread id
758 // stored in TLS. To verify that the thread is really executing VM,
759 // we check Top's data. Having that ThreadManager::RestoreThread first
760 // restores ThreadLocalTop from TLS, and only then erases the TLS value,
761 // reading Top::thread_id() should not be affected by races.
762 if (ThreadManager::HasId() && !ThreadManager::IsArchived() &&
763 ThreadManager::CurrentId() == Top::thread_id()) {
764 return true;
765 }
766 return false;
767 }
768
769
770 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { 746 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
771 #ifndef V8_HOST_ARCH_MIPS 747 #ifndef V8_HOST_ARCH_MIPS
772 USE(info); 748 USE(info);
773 if (signal != SIGPROF) return; 749 if (signal != SIGPROF) return;
774 if (active_sampler_ == NULL) return; 750 if (active_sampler_ == NULL) return;
775 if (!IsVmThread()) return;
776 751
777 TickSample sample_obj; 752 TickSample sample_obj;
778 TickSample* sample = CpuProfiler::TickSampleEvent(); 753 TickSample* sample = CpuProfiler::TickSampleEvent();
779 if (sample == NULL) sample = &sample_obj; 754 if (sample == NULL) sample = &sample_obj;
780 755
781 // We always sample the VM state. 756 // We always sample the VM state.
782 sample->state = VMState::current_state(); 757 sample->state = VMState::current_state();
783 758
784 // If profiling, we extract the current pc and sp. 759 // If profiling, we extract the current pc and sp.
785 if (active_sampler_->IsProfiling()) { 760 if (active_sampler_->IsProfiling()) {
(...skipping 26 matching lines...) Expand all
812 active_sampler_->SampleStack(sample); 787 active_sampler_->SampleStack(sample);
813 } 788 }
814 789
815 active_sampler_->Tick(sample); 790 active_sampler_->Tick(sample);
816 #endif 791 #endif
817 } 792 }
818 793
819 794
820 class Sampler::PlatformData : public Malloced { 795 class Sampler::PlatformData : public Malloced {
821 public: 796 public:
822 PlatformData() { 797 explicit PlatformData(Sampler* sampler)
823 signal_handler_installed_ = false; 798 : sampler_(sampler),
799 signal_handler_installed_(false),
800 vm_tgid_(getpid()),
801 // Glibc doesn't provide a wrapper for gettid(2).
802 vm_tid_(syscall(SYS_gettid)),
803 signal_sender_launched_(false) {
824 } 804 }
825 805
806 void SignalSender() {
807 while (sampler_->IsActive()) {
808 // Glibc doesn't provide a wrapper for tgkill(2).
809 syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF);
810 // Convert ms to us and subtract 100 us to compensate delays
811 // occuring during signal delivery.
812 usleep(sampler_->interval_ * 1000 - 100);
813 }
814 }
815
816 Sampler* sampler_;
826 bool signal_handler_installed_; 817 bool signal_handler_installed_;
827 struct sigaction old_signal_handler_; 818 struct sigaction old_signal_handler_;
828 struct itimerval old_timer_value_; 819 int vm_tgid_;
820 int vm_tid_;
821 bool signal_sender_launched_;
822 pthread_t signal_sender_thread_;
829 }; 823 };
830 824
831 825
826 static void* SenderEntry(void* arg) {
827 Sampler::PlatformData* data =
828 reinterpret_cast<Sampler::PlatformData*>(arg);
829 data->SignalSender();
830 return 0;
831 }
832
833
832 Sampler::Sampler(int interval, bool profiling) 834 Sampler::Sampler(int interval, bool profiling)
833 : interval_(interval), 835 : interval_(interval),
834 profiling_(profiling), 836 profiling_(profiling),
835 synchronous_(profiling), 837 synchronous_(profiling),
836 active_(false) { 838 active_(false) {
837 data_ = new PlatformData(); 839 data_ = new PlatformData(this);
838 } 840 }
839 841
840 842
841 Sampler::~Sampler() { 843 Sampler::~Sampler() {
842 delete data_; 844 delete data_;
843 } 845 }
844 846
845 847
846 void Sampler::Start() { 848 void Sampler::Start() {
847 // There can only be one active sampler at the time on POSIX 849 // There can only be one active sampler at the time on POSIX
848 // platforms. 850 // platforms.
849 if (active_sampler_ != NULL) return; 851 if (active_sampler_ != NULL) return;
850 852
851 vm_thread_ = pthread_self();
852
853 // Request profiling signals. 853 // Request profiling signals.
854 struct sigaction sa; 854 struct sigaction sa;
855 sa.sa_sigaction = ProfilerSignalHandler; 855 sa.sa_sigaction = ProfilerSignalHandler;
856 sigemptyset(&sa.sa_mask); 856 sigemptyset(&sa.sa_mask);
857 sa.sa_flags = SA_SIGINFO; 857 sa.sa_flags = SA_SIGINFO;
858 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; 858 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
859 data_->signal_handler_installed_ = true; 859 data_->signal_handler_installed_ = true;
860 860
861 // Set the itimer to generate a tick for each interval. 861 // Start a thread that sends SIGPROF signal to VM thread.
862 itimerval itimer; 862 // Sending the signal ourselves instead of relying on itimer provides
863 itimer.it_interval.tv_sec = interval_ / 1000; 863 // much better accuracy.
864 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; 864 active_ = true;
865 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; 865 if (pthread_create(
866 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; 866 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
867 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); 867 data_->signal_sender_launched_ = true;
868 }
868 869
869 // Set this sampler as the active sampler. 870 // Set this sampler as the active sampler.
870 active_sampler_ = this; 871 active_sampler_ = this;
871 active_ = true;
872 } 872 }
873 873
874 874
875 void Sampler::Stop() { 875 void Sampler::Stop() {
876 active_ = false;
877
878 // Wait for signal sender termination (it will exit after setting
879 // active_ to false).
880 if (data_->signal_sender_launched_) {
881 pthread_join(data_->signal_sender_thread_, NULL);
882 data_->signal_sender_launched_ = false;
883 }
884
876 // Restore old signal handler 885 // Restore old signal handler
877 if (data_->signal_handler_installed_) { 886 if (data_->signal_handler_installed_) {
878 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
879 sigaction(SIGPROF, &data_->old_signal_handler_, 0); 887 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
880 data_->signal_handler_installed_ = false; 888 data_->signal_handler_installed_ = false;
881 } 889 }
882 890
883 // This sampler is no longer the active sampler. 891 // This sampler is no longer the active sampler.
884 active_sampler_ = NULL; 892 active_sampler_ = NULL;
885 active_ = false;
886 } 893 }
887 894
888 895
889 #endif // ENABLE_LOGGING_AND_PROFILING 896 #endif // ENABLE_LOGGING_AND_PROFILING
890 897
891 } } // namespace v8::internal 898 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | test/cctest/test-log.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698