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

Side by Side Diff: src/profiler/sampler.cc

Issue 1858143003: Get rid of UnsafeCurrent in Sampler (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « src/profiler/sampler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/profiler/sampler.h" 5 #include "src/profiler/sampler.h"
6 6
7 #if V8_OS_POSIX && !V8_OS_CYGWIN 7 #if V8_OS_POSIX && !V8_OS_CYGWIN
8 8
9 #define USE_SIGNALS 9 #define USE_SIGNALS
10 10
11 #include <errno.h> 11 #include <errno.h>
12 #include <pthread.h> 12 #include <pthread.h>
13 #include <signal.h> 13 #include <signal.h>
14 #include <sys/time.h> 14 #include <sys/time.h>
15 #include <atomic>
15 16
16 #if !V8_OS_QNX && !V8_OS_NACL && !V8_OS_AIX 17 #if !V8_OS_QNX && !V8_OS_NACL && !V8_OS_AIX
17 #include <sys/syscall.h> // NOLINT 18 #include <sys/syscall.h> // NOLINT
18 #endif 19 #endif
19 20
20 #if V8_OS_MACOSX 21 #if V8_OS_MACOSX
21 #include <mach/mach.h> 22 #include <mach/mach.h>
22 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> 23 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h>
23 // and is a typedef for struct sigcontext. There is no uc_mcontext. 24 // and is a typedef for struct sigcontext. There is no uc_mcontext.
24 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \ 25 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && \
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 // pessimistically assume it could be the entire pattern match. 230 // pessimistically assume it could be the entire pattern match.
230 MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset); 231 MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset);
231 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) 232 if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset))
232 return true; 233 return true;
233 } 234 }
234 } 235 }
235 } 236 }
236 return false; 237 return false;
237 } 238 }
238 239
240 typedef List<Sampler*> SamplerList;
241 #if defined(USE_SIGNALS)
242 class ThreadSamplersPair {
243 public:
244 ThreadSamplersPair(pthread_t thread_id, SamplerList* samplers)
245 : thread_id_(thread_id), samplers_(samplers) {}
246 ~ThreadSamplersPair() {
247 delete samplers_;
248 }
249 pthread_t thread_id() const { return thread_id_; }
250 SamplerList* samplers() const { return samplers_; }
251 bool operator==(const ThreadSamplersPair& rhs) {
252 return thread_id_ == rhs.thread_id();
253 }
254 private:
255 pthread_t thread_id_;
256 SamplerList* samplers_;
257 ThreadSamplersPair() {}
258 };
259 typedef List<ThreadSamplersPair*> ThreadSamplersList;
260 #endif
261
262 template <typename T>
263 class AtomicGuard {
264 public:
265 explicit AtomicGuard(std::atomic<T>* atomic, T expected, T desired,
266 bool is_block)
fmeawad 2016/04/05 21:25:52 Try to the the v8 base version at https://code.goo
267 : is_success_(false) {
268 do {
269 is_success_ = std::atomic_compare_exchange_strong(atomic,
270 &expected, desired);
271 if (is_success_) break;
272 } while (is_block);
273 atomic_ = atomic;
274 expected_ = expected;
275 desired_ = desired;
276 }
277
278 bool is_success() { return is_success_; }
279
280 ~AtomicGuard() {
281 std::atomic_store(atomic_, expected_);
282 atomic_ = NULL;
283 }
284
285 private:
286 std::atomic<T>* atomic_;
287 T expected_;
288 T desired_;
289 bool is_success_;
290 };
291
239 } // namespace 292 } // namespace
240 293
241 #if defined(USE_SIGNALS) 294 #if defined(USE_SIGNALS)
242 295
243 class Sampler::PlatformData : public PlatformDataCommon { 296 class Sampler::PlatformData : public PlatformDataCommon {
244 public: 297 public:
245 PlatformData() : vm_tid_(pthread_self()) {} 298 PlatformData() : vm_tid_(pthread_self()) {}
246 pthread_t vm_tid() const { return vm_tid_; } 299 pthread_t vm_tid() const { return vm_tid_; }
247 300
248 private: 301 private:
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 420
368 static void DecreaseSamplerCount() { 421 static void DecreaseSamplerCount() {
369 base::LockGuard<base::Mutex> lock_guard(mutex_); 422 base::LockGuard<base::Mutex> lock_guard(mutex_);
370 if (--client_count_ == 0) Restore(); 423 if (--client_count_ == 0) Restore();
371 } 424 }
372 425
373 static bool Installed() { 426 static bool Installed() {
374 return signal_handler_installed_; 427 return signal_handler_installed_;
375 } 428 }
376 429
430 #if !V8_OS_NACL
431 static void CollectSample(void* context, Sampler* sampler);
432 #endif
433
377 private: 434 private:
378 static void Install() { 435 static void Install() {
379 #if !V8_OS_NACL 436 #if !V8_OS_NACL
380 struct sigaction sa; 437 struct sigaction sa;
381 sa.sa_sigaction = &HandleProfilerSignal; 438 sa.sa_sigaction = &HandleProfilerSignal;
382 sigemptyset(&sa.sa_mask); 439 sigemptyset(&sa.sa_mask);
383 #if V8_OS_QNX 440 #if V8_OS_QNX
384 sa.sa_flags = SA_SIGINFO; 441 sa.sa_flags = SA_SIGINFO;
385 #else 442 #else
386 sa.sa_flags = SA_RESTART | SA_SIGINFO; 443 sa.sa_flags = SA_RESTART | SA_SIGINFO;
(...skipping 24 matching lines...) Expand all
411 468
412 469
413 base::Mutex* SignalHandler::mutex_ = NULL; 470 base::Mutex* SignalHandler::mutex_ = NULL;
414 int SignalHandler::client_count_ = 0; 471 int SignalHandler::client_count_ = 0;
415 struct sigaction SignalHandler::old_signal_handler_; 472 struct sigaction SignalHandler::old_signal_handler_;
416 bool SignalHandler::signal_handler_installed_ = false; 473 bool SignalHandler::signal_handler_installed_ = false;
417 474
418 475
419 // As Native Client does not support signal handling, profiling is disabled. 476 // As Native Client does not support signal handling, profiling is disabled.
420 #if !V8_OS_NACL 477 #if !V8_OS_NACL
421 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 478 void SignalHandler::CollectSample(void* context, Sampler* sampler) {
422 void* context) { 479 if (sampler == NULL || (!sampler->IsProfiling() && !sampler->IsRegistered()))
423 USE(info);
424 if (signal != SIGPROF) return;
425 Isolate* isolate = Isolate::UnsafeCurrent();
426 if (isolate == NULL || !isolate->IsInUse()) {
427 // We require a fully initialized and entered isolate.
428 return; 480 return;
429 } 481 Isolate* isolate = sampler->isolate();
482
483 // We require a fully initialized and entered isolate.
484 if (isolate == NULL || !isolate->IsInUse()) return;
485
430 if (v8::Locker::IsActive() && 486 if (v8::Locker::IsActive() &&
431 !isolate->thread_manager()->IsLockedByCurrentThread()) { 487 !isolate->thread_manager()->IsLockedByCurrentThread()) {
432 return; 488 return;
433 } 489 }
434 490
435 Sampler* sampler = isolate->logger()->sampler();
436 if (sampler == NULL) return;
437
438 v8::RegisterState state; 491 v8::RegisterState state;
439 492
440 #if defined(USE_SIMULATOR) 493 #if defined(USE_SIMULATOR)
441 SimulatorHelper helper; 494 SimulatorHelper helper;
442 if (!helper.Init(isolate)) return; 495 if (!helper.Init(isolate)) return;
443 helper.FillRegisters(&state); 496 helper.FillRegisters(&state);
444 // It possible that the simulator is interrupted while it is updating 497 // It possible that the simulator is interrupted while it is updating
445 // the sp or fp register. ARM64 simulator does this in two steps: 498 // the sp or fp register. ARM64 simulator does this in two steps:
446 // first setting it to zero and then setting it to the new value. 499 // first setting it to zero and then setting it to the new value.
447 // Bailout if sp/fp doesn't contain the new value. 500 // Bailout if sp/fp doesn't contain the new value.
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 bool need_to_start = false; 653 bool need_to_start = false;
601 base::LockGuard<base::Mutex> lock_guard(mutex_); 654 base::LockGuard<base::Mutex> lock_guard(mutex_);
602 if (instance_ == NULL) { 655 if (instance_ == NULL) {
603 // Start a thread that will send SIGPROF signal to VM threads, 656 // Start a thread that will send SIGPROF signal to VM threads,
604 // when CPU profiling will be enabled. 657 // when CPU profiling will be enabled.
605 instance_ = new SamplerThread(sampler->interval()); 658 instance_ = new SamplerThread(sampler->interval());
606 need_to_start = true; 659 need_to_start = true;
607 } 660 }
608 661
609 DCHECK(sampler->IsActive()); 662 DCHECK(sampler->IsActive());
663 DCHECK(instance_->interval_ == sampler->interval());
664
665 #if defined(USE_SIGNALS)
666 AddSampler(sampler);
667 #else
610 DCHECK(!instance_->active_samplers_.Contains(sampler)); 668 DCHECK(!instance_->active_samplers_.Contains(sampler));
611 DCHECK(instance_->interval_ == sampler->interval());
612 instance_->active_samplers_.Add(sampler); 669 instance_->active_samplers_.Add(sampler);
670 #endif // USE_SIGNALS
613 671
614 if (need_to_start) instance_->StartSynchronously(); 672 if (need_to_start) instance_->StartSynchronously();
615 } 673 }
616 674
617 static void RemoveActiveSampler(Sampler* sampler) { 675 static void RemoveSampler(Sampler* sampler) {
618 SamplerThread* instance_to_remove = NULL; 676 SamplerThread* instance_to_remove = NULL;
619 { 677 {
620 base::LockGuard<base::Mutex> lock_guard(mutex_); 678 base::LockGuard<base::Mutex> lock_guard(mutex_);
621 679
622 DCHECK(sampler->IsActive()); 680 DCHECK(sampler->IsActive() || sampler->IsRegistered());
681 #if defined(USE_SIGNALS)
682 {
683 AtomicGuard<int> atomic_guard(&sampler_list_access_counter_,
684 0, 1, true);
685 // Remove sampler from map.
686 pthread_t thread_id = sampler->platform_data()->vm_tid();
687 SamplerList* samplers = NULL;
688 int i = 0;
689 for (; i < thread_id_to_samplers_.length(); ++i) {
690 ThreadSamplersPair* tsp = thread_id_to_samplers_.at(i);
691 if (pthread_equal(tsp->thread_id(), thread_id) != 0) {
692 samplers = tsp->samplers();
693 break;
694 }
695 }
696 if (samplers != NULL) {
697 samplers->RemoveElement(sampler);
698 if (samplers->is_empty()) {
699 ThreadSamplersPair* tsp = thread_id_to_samplers_.Remove(i);
700 delete tsp;
701 }
702 }
703 if (thread_id_to_samplers_.is_empty()) {
704 instance_to_remove = instance_;
705 instance_ = NULL;
706 }
707 }
708 #else
623 bool removed = instance_->active_samplers_.RemoveElement(sampler); 709 bool removed = instance_->active_samplers_.RemoveElement(sampler);
624 DCHECK(removed); 710 DCHECK(removed);
625 USE(removed); 711 USE(removed);
626 712
627 // We cannot delete the instance immediately as we need to Join() the 713 // We cannot delete the instance immediately as we need to Join() the
628 // thread but we are holding mutex_ and the thread may try to acquire it. 714 // thread but we are holding mutex_ and the thread may try to acquire it.
629 if (instance_->active_samplers_.is_empty()) { 715 if (instance_->active_samplers_.is_empty()) {
630 instance_to_remove = instance_; 716 instance_to_remove = instance_;
631 instance_ = NULL; 717 instance_ = NULL;
632 } 718 }
719 #endif // USE_SIGNALS
633 } 720 }
634 721
635 if (!instance_to_remove) return; 722 if (!instance_to_remove) return;
636 instance_to_remove->Join(); 723 instance_to_remove->Join();
637 delete instance_to_remove; 724 delete instance_to_remove;
638 } 725 }
639 726
727 // Unlike AddActiveSampler, this method only adds a sampler,
728 // but won't start the sampler thread.
729 static void RegisterSampler(Sampler* sampler) {
730 base::LockGuard<base::Mutex> lock_guard(mutex_);
731 #if defined(USE_SIGNALS)
732 AddSampler(sampler);
733 #endif // USE_SIGNALS
734 }
735
640 // Implement Thread::Run(). 736 // Implement Thread::Run().
641 virtual void Run() { 737 virtual void Run() {
642 while (true) { 738 while (true) {
643 { 739 {
644 base::LockGuard<base::Mutex> lock_guard(mutex_); 740 base::LockGuard<base::Mutex> lock_guard(mutex_);
741 #if defined(USE_SIGNALS)
742 if (thread_id_to_samplers_.is_empty()) break;
743 if (SignalHandler::Installed()) {
744 for (int i = 0; i < thread_id_to_samplers_.length(); ++i) {
745 pthread_t thread_id = thread_id_to_samplers_.at(i)->thread_id();
746 pthread_kill(thread_id, SIGPROF);
747 }
748 }
749 #else
645 if (active_samplers_.is_empty()) break; 750 if (active_samplers_.is_empty()) break;
646 // When CPU profiling is enabled both JavaScript and C++ code is 751 // When CPU profiling is enabled both JavaScript and C++ code is
647 // profiled. We must not suspend. 752 // profiled. We must not suspend.
648 for (int i = 0; i < active_samplers_.length(); ++i) { 753 for (int i = 0; i < active_samplers_.length(); ++i) {
649 Sampler* sampler = active_samplers_.at(i); 754 Sampler* sampler = active_samplers_.at(i);
650 if (!sampler->IsProfiling()) continue; 755 if (!sampler->IsProfiling()) continue;
651 sampler->DoSample(); 756 sampler->DoSample();
652 } 757 }
758 #endif // USE_SIGNALS
653 } 759 }
654 base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_)); 760 base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_));
655 } 761 }
656 } 762 }
657 763
658 private: 764 private:
659 // Protects the process wide state below. 765 // Protects the process wide state below.
660 static base::Mutex* mutex_; 766 static base::Mutex* mutex_;
661 static SamplerThread* instance_; 767 static SamplerThread* instance_;
662 768
663 const int interval_; 769 const int interval_;
664 List<Sampler*> active_samplers_; 770
771 #if defined(USE_SIGNALS)
772 friend class SignalHandler;
773 static ThreadSamplersList thread_id_to_samplers_;
774 static std::atomic<int> sampler_list_access_counter_;
775 static void AddSampler(Sampler* sampler) {
776 AtomicGuard<int> atomic_guard(&SamplerThread::sampler_list_access_counter_,
777 0, 1, true);
778 // Add sampler into map if needed.
779 pthread_t thread_id = sampler->platform_data()->vm_tid();
780 SamplerList* samplers = NULL;
781 for (int i = 0; i < thread_id_to_samplers_.length(); ++i) {
782 ThreadSamplersPair* tsp = thread_id_to_samplers_.at(i);
783 if (pthread_equal(tsp->thread_id(), thread_id) != 0) {
784 samplers = tsp->samplers();
785 break;
786 }
787 }
788 if (samplers != NULL) {
789 if (!samplers->Contains(sampler))
790 samplers->Add(sampler);
791 } else {
792 samplers = new SamplerList();
793 samplers->Add(sampler);
794 thread_id_to_samplers_.Add(new ThreadSamplersPair(thread_id, samplers));
795 }
796 }
797 #else
798 SamplerList active_samplers_;
799 #endif // USE_SIGNALS
665 800
666 DISALLOW_COPY_AND_ASSIGN(SamplerThread); 801 DISALLOW_COPY_AND_ASSIGN(SamplerThread);
667 }; 802 };
668 803
669 804
670 base::Mutex* SamplerThread::mutex_ = NULL; 805 base::Mutex* SamplerThread::mutex_ = NULL;
671 SamplerThread* SamplerThread::instance_ = NULL; 806 SamplerThread* SamplerThread::instance_ = NULL;
807 #if defined(USE_SIGNALS)
808 ThreadSamplersList SamplerThread::thread_id_to_samplers_;
809 std::atomic<int> SamplerThread::sampler_list_access_counter_(0);
810 #endif // USE_SIGNALS
811
812 // As Native Client does not support signal handling, profiling is disabled.
813 #if defined(USE_SIGNALS)
814 #if !V8_OS_NACL
815 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info,
816 void* context) {
817 USE(info);
818 if (signal != SIGPROF) return;
819 AtomicGuard<int> atomic_guard(&SamplerThread::sampler_list_access_counter_,
820 0, 1, false);
821 if (!atomic_guard.is_success()) return;
822 pthread_t thread_id = pthread_self();
823 SamplerList* samplers = NULL;
824 for (int i = 0; i < SamplerThread::thread_id_to_samplers_.length(); ++i) {
825 ThreadSamplersPair* tsp = SamplerThread::thread_id_to_samplers_.at(i);
826 if (pthread_equal(tsp->thread_id(), thread_id) != 0) {
827 samplers = tsp->samplers();
828 break;
829 }
830 }
831 DCHECK(samplers != NULL);
832 for (int i = 0; i < samplers->length(); ++i) {
833 Sampler* sampler = samplers->at(i);
834 SignalHandler::CollectSample(context, sampler);
835 }
836 }
837 #endif // !V8_OS_NACL
838 #endif // USE_SIGNALs
672 839
673 840
674 // 841 //
675 // StackTracer implementation 842 // StackTracer implementation
676 // 843 //
677 DISABLE_ASAN void TickSample::Init(Isolate* isolate, 844 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
678 const v8::RegisterState& regs, 845 const v8::RegisterState& regs,
679 RecordCEntryFrame record_c_entry_frame, 846 RecordCEntryFrame record_c_entry_frame,
680 bool update_stats) { 847 bool update_stats) {
681 timestamp = base::TimeTicks::HighResolutionNow(); 848 timestamp = base::TimeTicks::HighResolutionNow();
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
782 SignalHandler::TearDown(); 949 SignalHandler::TearDown();
783 #endif 950 #endif
784 } 951 }
785 952
786 Sampler::Sampler(Isolate* isolate, int interval) 953 Sampler::Sampler(Isolate* isolate, int interval)
787 : isolate_(isolate), 954 : isolate_(isolate),
788 interval_(interval), 955 interval_(interval),
789 profiling_(false), 956 profiling_(false),
790 has_processing_thread_(false), 957 has_processing_thread_(false),
791 active_(false), 958 active_(false),
959 registered_(false),
792 is_counting_samples_(false), 960 is_counting_samples_(false),
793 js_sample_count_(0), 961 js_sample_count_(0),
794 external_sample_count_(0) { 962 external_sample_count_(0) {
795 data_ = new PlatformData; 963 data_ = new PlatformData;
796 } 964 }
797 965
798 Sampler::~Sampler() { 966 Sampler::~Sampler() {
799 DCHECK(!IsActive()); 967 DCHECK(!IsActive());
968 if (IsRegistered())
969 SamplerThread::RemoveSampler(this);
800 delete data_; 970 delete data_;
801 } 971 }
802 972
803 void Sampler::Start() { 973 void Sampler::Start() {
804 DCHECK(!IsActive()); 974 DCHECK(!IsActive());
805 SetActive(true); 975 SetActive(true);
806 SamplerThread::AddActiveSampler(this); 976 SamplerThread::AddActiveSampler(this);
807 } 977 }
808 978
809 979
810 void Sampler::Stop() { 980 void Sampler::Stop() {
811 DCHECK(IsActive()); 981 DCHECK(IsActive());
812 SamplerThread::RemoveActiveSampler(this); 982 SamplerThread::RemoveSampler(this);
813 SetActive(false); 983 SetActive(false);
984 SetRegistered(false);
814 } 985 }
815 986
816 987
817 void Sampler::IncreaseProfilingDepth() { 988 void Sampler::IncreaseProfilingDepth() {
818 base::NoBarrier_AtomicIncrement(&profiling_, 1); 989 base::NoBarrier_AtomicIncrement(&profiling_, 1);
819 #if defined(USE_SIGNALS) 990 #if defined(USE_SIGNALS)
820 SignalHandler::IncreaseSamplerCount(); 991 SignalHandler::IncreaseSamplerCount();
821 #endif 992 #endif
822 } 993 }
823 994
(...skipping 19 matching lines...) Expand all
843 if (sample != &sample_obj) { 1014 if (sample != &sample_obj) {
844 isolate_->cpu_profiler()->FinishTickSample(); 1015 isolate_->cpu_profiler()->FinishTickSample();
845 } 1016 }
846 } 1017 }
847 1018
848 1019
849 #if defined(USE_SIGNALS) 1020 #if defined(USE_SIGNALS)
850 1021
851 void Sampler::DoSample() { 1022 void Sampler::DoSample() {
852 if (!SignalHandler::Installed()) return; 1023 if (!SignalHandler::Installed()) return;
1024 if (!IsActive() && !IsRegistered()) {
1025 SamplerThread::RegisterSampler(this);
1026 SetRegistered(true);
1027 }
853 pthread_kill(platform_data()->vm_tid(), SIGPROF); 1028 pthread_kill(platform_data()->vm_tid(), SIGPROF);
854 } 1029 }
855 1030
856 #elif V8_OS_WIN || V8_OS_CYGWIN 1031 #elif V8_OS_WIN || V8_OS_CYGWIN
857 1032
858 void Sampler::DoSample() { 1033 void Sampler::DoSample() {
859 HANDLE profiled_thread = platform_data()->profiled_thread(); 1034 HANDLE profiled_thread = platform_data()->profiled_thread();
860 if (profiled_thread == NULL) return; 1035 if (profiled_thread == NULL) return;
861 1036
862 #if defined(USE_SIMULATOR) 1037 #if defined(USE_SIMULATOR)
(...skipping 26 matching lines...) Expand all
889 SampleStack(state); 1064 SampleStack(state);
890 } 1065 }
891 ResumeThread(profiled_thread); 1066 ResumeThread(profiled_thread);
892 } 1067 }
893 1068
894 #endif // USE_SIGNALS 1069 #endif // USE_SIGNALS
895 1070
896 1071
897 } // namespace internal 1072 } // namespace internal
898 } // namespace v8 1073 } // namespace v8
OLDNEW
« no previous file with comments | « src/profiler/sampler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698