OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. | 616 CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup. |
617 } | 617 } |
618 } | 618 } |
619 | 619 |
620 | 620 |
621 Semaphore* OS::CreateSemaphore(int count) { | 621 Semaphore* OS::CreateSemaphore(int count) { |
622 return new CygwinSemaphore(count); | 622 return new CygwinSemaphore(count); |
623 } | 623 } |
624 | 624 |
625 | 625 |
626 // ---------------------------------------------------------------------------- | |
627 // Cygwin profiler support. | |
628 // | |
629 // On Cygwin we use the same sampler implementation as on win32. | |
630 | |
631 class Sampler::PlatformData : public Malloced { | |
632 public: | |
633 // Get a handle to the calling thread. This is the thread that we are | |
634 // going to profile. We need to make a copy of the handle because we are | |
635 // going to use it in the sampler thread. Using GetThreadHandle() will | |
636 // not work in this case. We're using OpenThread because DuplicateHandle | |
637 // for some reason doesn't work in Chrome's sandbox. | |
638 PlatformData() | |
639 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | | |
640 THREAD_SUSPEND_RESUME | | |
641 THREAD_QUERY_INFORMATION, | |
642 false, | |
643 GetCurrentThreadId())), | |
644 profiled_thread_id_(ThreadId::Current()) {} | |
645 | |
646 ~PlatformData() { | |
647 if (profiled_thread_ != NULL) { | |
648 CloseHandle(profiled_thread_); | |
649 profiled_thread_ = NULL; | |
650 } | |
651 } | |
652 | |
653 HANDLE profiled_thread() { return profiled_thread_; } | |
654 ThreadId profiled_thread_id() { return profiled_thread_id_; } | |
655 | |
656 private: | |
657 HANDLE profiled_thread_; | |
658 ThreadId profiled_thread_id_; | |
659 }; | |
660 | |
661 | |
662 class SamplerThread : public Thread { | |
663 public: | |
664 static const int kSamplerThreadStackSize = 64 * KB; | |
665 | |
666 explicit SamplerThread(int interval) | |
667 : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)), | |
668 interval_(interval) {} | |
669 | |
670 static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); } | |
671 static void TearDown() { delete mutex_; } | |
672 | |
673 static void AddActiveSampler(Sampler* sampler) { | |
674 ScopedLock lock(mutex_); | |
675 SamplerRegistry::AddActiveSampler(sampler); | |
676 if (instance_ == NULL) { | |
677 instance_ = new SamplerThread(sampler->interval()); | |
678 instance_->StartSynchronously(); | |
679 } else { | |
680 ASSERT(instance_->interval_ == sampler->interval()); | |
681 } | |
682 } | |
683 | |
684 static void RemoveActiveSampler(Sampler* sampler) { | |
685 ScopedLock lock(mutex_); | |
686 SamplerRegistry::RemoveActiveSampler(sampler); | |
687 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { | |
688 instance_->Join(); | |
689 delete instance_; | |
690 instance_ = NULL; | |
691 } | |
692 } | |
693 | |
694 // Implement Thread::Run(). | |
695 virtual void Run() { | |
696 SamplerRegistry::State state; | |
697 while ((state = SamplerRegistry::GetState()) != | |
698 SamplerRegistry::HAS_NO_SAMPLERS) { | |
699 // When CPU profiling is enabled both JavaScript and C++ code is | |
700 // profiled. We must not suspend. | |
701 if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) { | |
702 SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this); | |
703 } | |
704 OS::Sleep(interval_); | |
705 } | |
706 } | |
707 | |
708 static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { | |
709 if (!sampler->isolate()->IsInitialized()) return; | |
710 if (!sampler->IsProfiling()) return; | |
711 SamplerThread* sampler_thread = | |
712 reinterpret_cast<SamplerThread*>(raw_sampler_thread); | |
713 sampler_thread->SampleContext(sampler); | |
714 } | |
715 | |
716 void SampleContext(Sampler* sampler) { | |
717 HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); | |
718 if (profiled_thread == NULL) return; | |
719 | |
720 // Context used for sampling the register state of the profiled thread. | |
721 CONTEXT context; | |
722 memset(&context, 0, sizeof(context)); | |
723 | |
724 Isolate* isolate = sampler->isolate(); | |
725 #if defined(USE_SIMULATOR) | |
726 #if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | |
727 ThreadId thread_id = sampler->platform_data()->profiled_thread_id(); | |
728 Isolate::PerIsolateThreadData* per_thread_data = isolate-> | |
729 FindPerThreadDataForThread(thread_id); | |
730 if (!per_thread_data) return; | |
731 Simulator* sim = per_thread_data->simulator(); | |
732 // Check if there is active simulator before allocating TickSample. | |
733 if (!sim) return; | |
734 #endif | |
735 #endif // USE_SIMULATOR | |
736 TickSample sample_obj; | |
737 TickSample* sample = isolate->cpu_profiler()->TickSampleEvent(); | |
738 if (sample == NULL) sample = &sample_obj; | |
739 | |
740 static const DWORD kSuspendFailed = static_cast<DWORD>(-1); | |
741 if (SuspendThread(profiled_thread) == kSuspendFailed) return; | |
742 sample->state = isolate->current_vm_state(); | |
743 | |
744 context.ContextFlags = CONTEXT_FULL; | |
745 if (GetThreadContext(profiled_thread, &context) != 0) { | |
746 #if defined(USE_SIMULATOR) | |
747 #if V8_TARGET_ARCH_ARM | |
748 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
749 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
750 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11)); | |
751 #elif V8_TARGET_ARCH_MIPS | |
752 sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc)); | |
753 sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp)); | |
754 sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp)); | |
755 #endif | |
756 #else | |
757 #if V8_HOST_ARCH_X64 | |
758 sample->pc = reinterpret_cast<Address>(context.Rip); | |
759 sample->sp = reinterpret_cast<Address>(context.Rsp); | |
760 sample->fp = reinterpret_cast<Address>(context.Rbp); | |
761 #else | |
762 sample->pc = reinterpret_cast<Address>(context.Eip); | |
763 sample->sp = reinterpret_cast<Address>(context.Esp); | |
764 sample->fp = reinterpret_cast<Address>(context.Ebp); | |
765 #endif | |
766 #endif // USE_SIMULATOR | |
767 sampler->SampleStack(sample); | |
768 sampler->Tick(sample); | |
769 } | |
770 ResumeThread(profiled_thread); | |
771 } | |
772 | |
773 const int interval_; | |
774 | |
775 // Protects the process wide state below. | |
776 static Mutex* mutex_; | |
777 static SamplerThread* instance_; | |
778 | |
779 private: | |
780 DISALLOW_COPY_AND_ASSIGN(SamplerThread); | |
781 }; | |
782 | |
783 | |
784 Mutex* SamplerThread::mutex_ = NULL; | |
785 SamplerThread* SamplerThread::instance_ = NULL; | |
786 | |
787 | |
788 void OS::SetUp() { | 626 void OS::SetUp() { |
789 // Seed the random number generator. | 627 // Seed the random number generator. |
790 // Convert the current time to a 64-bit integer first, before converting it | 628 // Convert the current time to a 64-bit integer first, before converting it |
791 // to an unsigned. Going directly can cause an overflow and the seed to be | 629 // to an unsigned. Going directly can cause an overflow and the seed to be |
792 // set to all ones. The seed will be identical for different instances that | 630 // set to all ones. The seed will be identical for different instances that |
793 // call this setup code within the same millisecond. | 631 // call this setup code within the same millisecond. |
794 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 632 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
795 srandom(static_cast<unsigned int>(seed)); | 633 srandom(static_cast<unsigned int>(seed)); |
796 limit_mutex = CreateMutex(); | 634 limit_mutex = CreateMutex(); |
797 SamplerThread::SetUp(); | |
798 } | 635 } |
799 | 636 |
800 | 637 |
801 void OS::TearDown() { | 638 void OS::TearDown() { |
802 SamplerThread::TearDown(); | |
803 delete limit_mutex; | 639 delete limit_mutex; |
804 } | 640 } |
805 | 641 |
806 | 642 |
807 Sampler::Sampler(Isolate* isolate, int interval) | |
808 : isolate_(isolate), | |
809 interval_(interval), | |
810 profiling_(false), | |
811 active_(false), | |
812 samples_taken_(0) { | |
813 data_ = new PlatformData; | |
814 } | |
815 | |
816 | |
817 Sampler::~Sampler() { | |
818 ASSERT(!IsActive()); | |
819 delete data_; | |
820 } | |
821 | |
822 | |
823 void Sampler::Start() { | |
824 ASSERT(!IsActive()); | |
825 SetActive(true); | |
826 SamplerThread::AddActiveSampler(this); | |
827 } | |
828 | |
829 | |
830 void Sampler::Stop() { | |
831 ASSERT(IsActive()); | |
832 SamplerThread::RemoveActiveSampler(this); | |
833 SetActive(false); | |
834 } | |
835 | |
836 | |
837 } } // namespace v8::internal | 643 } } // namespace v8::internal |
OLD | NEW |