| 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 |