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

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

Issue 7348008: Merge up to 8597 to experimental/gc from the bleeding edge. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: '' Created 9 years, 5 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 | « src/platform-posix.cc ('k') | src/platform-win32.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-2009 the V8 project authors. All rights reserved. 1 // Copyright 2011 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
11 // with the distribution. 11 // with the distribution.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 // 0 is never a valid thread id on Solaris since the main thread is 1 and 81 // 0 is never a valid thread id on Solaris since the main thread is 1 and
82 // subsequent have their ids incremented from there 82 // subsequent have their ids incremented from there
83 static const pthread_t kNoThread = (pthread_t) 0; 83 static const pthread_t kNoThread = (pthread_t) 0;
84 84
85 85
86 double ceiling(double x) { 86 double ceiling(double x) {
87 return ceil(x); 87 return ceil(x);
88 } 88 }
89 89
90 90
91 static Mutex* limit_mutex = NULL;
91 void OS::Setup() { 92 void OS::Setup() {
92 // Seed the random number generator. 93 // Seed the random number generator.
93 // Convert the current time to a 64-bit integer first, before converting it 94 // Convert the current time to a 64-bit integer first, before converting it
94 // to an unsigned. Going directly will cause an overflow and the seed to be 95 // to an unsigned. Going directly will cause an overflow and the seed to be
95 // set to all ones. The seed will be identical for different instances that 96 // set to all ones. The seed will be identical for different instances that
96 // call this setup code within the same millisecond. 97 // call this setup code within the same millisecond.
97 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); 98 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
98 srandom(static_cast<unsigned int>(seed)); 99 srandom(static_cast<unsigned int>(seed));
100 limit_mutex = CreateMutex();
99 } 101 }
100 102
101 103
102 uint64_t OS::CpuFeaturesImpliedByPlatform() { 104 uint64_t OS::CpuFeaturesImpliedByPlatform() {
103 return 0; // Solaris runs on a lot of things. 105 return 0; // Solaris runs on a lot of things.
104 } 106 }
105 107
106 108
107 int OS::ActivationFrameAlignment() { 109 int OS::ActivationFrameAlignment() {
108 return STACK_ALIGN; 110 // GCC generates code that requires 16 byte alignment such as movdqa.
111 return Max(STACK_ALIGN, 16);
109 } 112 }
110 113
111 114
112 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) { 115 void OS::ReleaseStore(volatile AtomicWord* ptr, AtomicWord value) {
113 __asm__ __volatile__("" : : : "memory"); 116 __asm__ __volatile__("" : : : "memory");
114 *ptr = value; 117 *ptr = value;
115 } 118 }
116 119
117 120
118 const char* OS::LocalTimezone(double time) { 121 const char* OS::LocalTimezone(double time) {
(...skipping 18 matching lines...) Expand all
137 // We keep the lowest and highest addresses mapped as a quick way of 140 // We keep the lowest and highest addresses mapped as a quick way of
138 // determining that pointers are outside the heap (used mostly in assertions 141 // determining that pointers are outside the heap (used mostly in assertions
139 // and verification). The estimate is conservative, ie, not all addresses in 142 // and verification). The estimate is conservative, ie, not all addresses in
140 // 'allocated' space are actually allocated to our heap. The range is 143 // 'allocated' space are actually allocated to our heap. The range is
141 // [lowest, highest), inclusive on the low and and exclusive on the high end. 144 // [lowest, highest), inclusive on the low and and exclusive on the high end.
142 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); 145 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
143 static void* highest_ever_allocated = reinterpret_cast<void*>(0); 146 static void* highest_ever_allocated = reinterpret_cast<void*>(0);
144 147
145 148
146 static void UpdateAllocatedSpaceLimits(void* address, int size) { 149 static void UpdateAllocatedSpaceLimits(void* address, int size) {
150 ASSERT(limit_mutex != NULL);
151 ScopedLock lock(limit_mutex);
152
147 lowest_ever_allocated = Min(lowest_ever_allocated, address); 153 lowest_ever_allocated = Min(lowest_ever_allocated, address);
148 highest_ever_allocated = 154 highest_ever_allocated =
149 Max(highest_ever_allocated, 155 Max(highest_ever_allocated,
150 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); 156 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
151 } 157 }
152 158
153 159
154 bool OS::IsOutsideAllocatedSpace(void* address) { 160 bool OS::IsOutsideAllocatedSpace(void* address) {
155 return address < lowest_ever_allocated || address >= highest_ever_allocated; 161 return address < lowest_ever_allocated || address >= highest_ever_allocated;
156 } 162 }
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 } 379 }
374 380
375 381
376 class Thread::PlatformData : public Malloced { 382 class Thread::PlatformData : public Malloced {
377 public: 383 public:
378 PlatformData() : thread_(kNoThread) { } 384 PlatformData() : thread_(kNoThread) { }
379 385
380 pthread_t thread_; // Thread handle for pthread. 386 pthread_t thread_; // Thread handle for pthread.
381 }; 387 };
382 388
383 Thread::Thread(Isolate* isolate, const Options& options) 389 Thread::Thread(const Options& options)
384 : data_(new PlatformData()), 390 : data_(new PlatformData()),
385 isolate_(isolate),
386 stack_size_(options.stack_size) { 391 stack_size_(options.stack_size) {
387 set_name(options.name); 392 set_name(options.name);
388 } 393 }
389 394
390 395
391 Thread::Thread(Isolate* isolate, const char* name) 396 Thread::Thread(const char* name)
392 : data_(new PlatformData()), 397 : data_(new PlatformData()),
393 isolate_(isolate),
394 stack_size_(0) { 398 stack_size_(0) {
395 set_name(name); 399 set_name(name);
396 } 400 }
397 401
398 402
399 Thread::~Thread() { 403 Thread::~Thread() {
400 delete data_; 404 delete data_;
401 } 405 }
402 406
403 407
404 static void* ThreadEntry(void* arg) { 408 static void* ThreadEntry(void* arg) {
405 Thread* thread = reinterpret_cast<Thread*>(arg); 409 Thread* thread = reinterpret_cast<Thread*>(arg);
406 // This is also initialized by the first argument to pthread_create() but we 410 // This is also initialized by the first argument to pthread_create() but we
407 // don't know which thread will run first (the original thread or the new 411 // don't know which thread will run first (the original thread or the new
408 // one) so we initialize it here too. 412 // one) so we initialize it here too.
409 thread->data()->thread_ = pthread_self(); 413 thread->data()->thread_ = pthread_self();
410 ASSERT(thread->data()->thread_ != kNoThread); 414 ASSERT(thread->data()->thread_ != kNoThread);
411 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate());
412 thread->Run(); 415 thread->Run();
413 return NULL; 416 return NULL;
414 } 417 }
415 418
416 419
417 void Thread::set_name(const char* name) { 420 void Thread::set_name(const char* name) {
418 strncpy(name_, name, sizeof(name_)); 421 strncpy(name_, name, sizeof(name_));
419 name_[sizeof(name_) - 1] = '\0'; 422 name_[sizeof(name_) - 1] = '\0';
420 } 423 }
421 424
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 } 584 }
582 585
583 586
584 Semaphore* OS::CreateSemaphore(int count) { 587 Semaphore* OS::CreateSemaphore(int count) {
585 return new SolarisSemaphore(count); 588 return new SolarisSemaphore(count);
586 } 589 }
587 590
588 591
589 #ifdef ENABLE_LOGGING_AND_PROFILING 592 #ifdef ENABLE_LOGGING_AND_PROFILING
590 593
591 static Sampler* active_sampler_ = NULL;
592 static pthread_t vm_tid_ = 0;
593
594
595 static pthread_t GetThreadID() { 594 static pthread_t GetThreadID() {
596 return pthread_self(); 595 return pthread_self();
597 } 596 }
598 597
599
600 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { 598 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
601 USE(info); 599 USE(info);
602 if (signal != SIGPROF) return; 600 if (signal != SIGPROF) return;
603 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; 601 Isolate* isolate = Isolate::UncheckedCurrent();
604 if (vm_tid_ != GetThreadID()) return; 602 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) {
603 // We require a fully initialized and entered isolate.
604 return;
605 }
606 if (v8::Locker::IsActive() &&
607 !isolate->thread_manager()->IsLockedByCurrentThread()) {
608 return;
609 }
610
611 Sampler* sampler = isolate->logger()->sampler();
612 if (sampler == NULL || !sampler->IsActive()) return;
605 613
606 TickSample sample_obj; 614 TickSample sample_obj;
607 TickSample* sample = CpuProfiler::TickSampleEvent(); 615 TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
608 if (sample == NULL) sample = &sample_obj; 616 if (sample == NULL) sample = &sample_obj;
609 617
610 // Extracting the sample from the context is extremely machine dependent. 618 // Extracting the sample from the context is extremely machine dependent.
611 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 619 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
612 mcontext_t& mcontext = ucontext->uc_mcontext; 620 mcontext_t& mcontext = ucontext->uc_mcontext;
613 sample->state = Top::current_vm_state(); 621 sample->state = isolate->current_vm_state();
614 622
615 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]); 623 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_PC]);
616 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]); 624 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_SP]);
617 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]); 625 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_FP]);
618 626
619 active_sampler_->SampleStack(sample); 627 sampler->SampleStack(sample);
620 active_sampler_->Tick(sample); 628 sampler->Tick(sample);
621 } 629 }
622 630
623
624 class Sampler::PlatformData : public Malloced { 631 class Sampler::PlatformData : public Malloced {
625 public: 632 public:
633 PlatformData() : vm_tid_(GetThreadID()) {}
634
635 pthread_t vm_tid() const { return vm_tid_; }
636
637 private:
638 pthread_t vm_tid_;
639 };
640
641
642 class SignalSender : public Thread {
643 public:
626 enum SleepInterval { 644 enum SleepInterval {
627 FULL_INTERVAL, 645 HALF_INTERVAL,
628 HALF_INTERVAL 646 FULL_INTERVAL
629 }; 647 };
630 648
631 explicit PlatformData(Sampler* sampler) 649 explicit SignalSender(int interval)
632 : sampler_(sampler), 650 : Thread("SignalSender"),
633 signal_handler_installed_(false), 651 interval_(interval) {}
634 vm_tgid_(getpid()), 652
635 signal_sender_launched_(false) { 653 static void InstallSignalHandler() {
654 struct sigaction sa;
655 sa.sa_sigaction = ProfilerSignalHandler;
656 sigemptyset(&sa.sa_mask);
657 sa.sa_flags = SA_RESTART | SA_SIGINFO;
658 signal_handler_installed_ =
659 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0);
636 } 660 }
637 661
638 void SignalSender() { 662 static void RestoreSignalHandler() {
639 while (sampler_->IsActive()) { 663 if (signal_handler_installed_) {
640 if (rate_limiter_.SuspendIfNecessary()) continue; 664 sigaction(SIGPROF, &old_signal_handler_, 0);
641 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { 665 signal_handler_installed_ = false;
642 SendProfilingSignal(); 666 }
667 }
668
669 static void AddActiveSampler(Sampler* sampler) {
670 ScopedLock lock(mutex_);
671 SamplerRegistry::AddActiveSampler(sampler);
672 if (instance_ == NULL) {
673 // Start a thread that will send SIGPROF signal to VM threads,
674 // when CPU profiling will be enabled.
675 instance_ = new SignalSender(sampler->interval());
676 instance_->Start();
677 } else {
678 ASSERT(instance_->interval_ == sampler->interval());
679 }
680 }
681
682 static void RemoveActiveSampler(Sampler* sampler) {
683 ScopedLock lock(mutex_);
684 SamplerRegistry::RemoveActiveSampler(sampler);
685 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
686 RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
687 delete instance_;
688 instance_ = NULL;
689 RestoreSignalHandler();
690 }
691 }
692
693 // Implement Thread::Run().
694 virtual void Run() {
695 SamplerRegistry::State state;
696 while ((state = SamplerRegistry::GetState()) !=
697 SamplerRegistry::HAS_NO_SAMPLERS) {
698 bool cpu_profiling_enabled =
699 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS);
700 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled();
701 if (cpu_profiling_enabled && !signal_handler_installed_) {
702 InstallSignalHandler();
703 } else if (!cpu_profiling_enabled && signal_handler_installed_) {
704 RestoreSignalHandler();
705 }
706
707 // When CPU profiling is enabled both JavaScript and C++ code is
708 // profiled. We must not suspend.
709 if (!cpu_profiling_enabled) {
710 if (rate_limiter_.SuspendIfNecessary()) continue;
711 }
712 if (cpu_profiling_enabled && runtime_profiler_enabled) {
713 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) {
714 return;
715 }
643 Sleep(HALF_INTERVAL); 716 Sleep(HALF_INTERVAL);
644 RuntimeProfiler::NotifyTick(); 717 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) {
718 return;
719 }
645 Sleep(HALF_INTERVAL); 720 Sleep(HALF_INTERVAL);
646 } else { 721 } else {
647 if (sampler_->IsProfiling()) SendProfilingSignal(); 722 if (cpu_profiling_enabled) {
648 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); 723 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile,
724 this)) {
725 return;
726 }
727 }
728 if (runtime_profiler_enabled) {
729 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile,
730 NULL)) {
731 return;
732 }
733 }
649 Sleep(FULL_INTERVAL); 734 Sleep(FULL_INTERVAL);
650 } 735 }
651 } 736 }
652 } 737 }
653 738
654 void SendProfilingSignal() { 739 static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
740 if (!sampler->IsProfiling()) return;
741 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
742 sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
743 }
744
745 static void DoRuntimeProfile(Sampler* sampler, void* ignored) {
746 if (!sampler->isolate()->IsInitialized()) return;
747 sampler->isolate()->runtime_profiler()->NotifyTick();
748 }
749
750 void SendProfilingSignal(pthread_t tid) {
655 if (!signal_handler_installed_) return; 751 if (!signal_handler_installed_) return;
656 pthread_kill(vm_tid_, SIGPROF); 752 pthread_kill(tid, SIGPROF);
657 } 753 }
658 754
659 void Sleep(SleepInterval full_or_half) { 755 void Sleep(SleepInterval full_or_half) {
660 // Convert ms to us and subtract 100 us to compensate delays 756 // Convert ms to us and subtract 100 us to compensate delays
661 // occuring during signal delivery. 757 // occuring during signal delivery.
662 useconds_t interval = sampler_->interval_ * 1000 - 100; 758 useconds_t interval = interval_ * 1000 - 100;
663 if (full_or_half == HALF_INTERVAL) interval /= 2; 759 if (full_or_half == HALF_INTERVAL) interval /= 2;
664 int result = usleep(interval); 760 int result = usleep(interval);
665 #ifdef DEBUG 761 #ifdef DEBUG
666 if (result != 0 && errno != EINTR) { 762 if (result != 0 && errno != EINTR) {
667 fprintf(stderr, 763 fprintf(stderr,
668 "SignalSender usleep error; interval = %u, errno = %d\n", 764 "SignalSender usleep error; interval = %u, errno = %d\n",
669 interval, 765 interval,
670 errno); 766 errno);
671 ASSERT(result == 0 || errno == EINTR); 767 ASSERT(result == 0 || errno == EINTR);
672 } 768 }
673 #endif 769 #endif
674 USE(result); 770 USE(result);
675 } 771 }
676 772
677 Sampler* sampler_; 773 const int interval_;
678 bool signal_handler_installed_;
679 struct sigaction old_signal_handler_;
680 int vm_tgid_;
681 bool signal_sender_launched_;
682 pthread_t signal_sender_thread_;
683 RuntimeProfilerRateLimiter rate_limiter_; 774 RuntimeProfilerRateLimiter rate_limiter_;
775
776 // Protects the process wide state below.
777 static Mutex* mutex_;
778 static SignalSender* instance_;
779 static bool signal_handler_installed_;
780 static struct sigaction old_signal_handler_;
781
782 DISALLOW_COPY_AND_ASSIGN(SignalSender);
684 }; 783 };
685 784
686 785 Mutex* SignalSender::mutex_ = OS::CreateMutex();
687 static void* SenderEntry(void* arg) { 786 SignalSender* SignalSender::instance_ = NULL;
688 Sampler::PlatformData* data = 787 struct sigaction SignalSender::old_signal_handler_;
689 reinterpret_cast<Sampler::PlatformData*>(arg); 788 bool SignalSender::signal_handler_installed_ = false;
690 data->SignalSender();
691 return 0;
692 }
693 789
694 790
695 Sampler::Sampler(Isolate* isolate, int interval) 791 Sampler::Sampler(Isolate* isolate, int interval)
696 : isolate_(isolate), 792 : isolate_(isolate),
697 interval_(interval), 793 interval_(interval),
698 profiling_(false), 794 profiling_(false),
699 active_(false), 795 active_(false),
700 samples_taken_(0) { 796 samples_taken_(0) {
701 data_ = new PlatformData(this); 797 data_ = new PlatformData;
702 } 798 }
703 799
704 800
705 Sampler::~Sampler() { 801 Sampler::~Sampler() {
706 ASSERT(!data_->signal_sender_launched_); 802 ASSERT(!IsActive());
707 delete data_; 803 delete data_;
708 } 804 }
709 805
710 806
711 void Sampler::Start() { 807 void Sampler::Start() {
712 // There can only be one active sampler at the time on POSIX
713 // platforms.
714 ASSERT(!IsActive()); 808 ASSERT(!IsActive());
715 vm_tid_ = GetThreadID();
716
717 // Request profiling signals.
718 struct sigaction sa;
719 sa.sa_sigaction = ProfilerSignalHandler;
720 sigemptyset(&sa.sa_mask);
721 sa.sa_flags = SA_RESTART | SA_SIGINFO;
722 data_->signal_handler_installed_ =
723 sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0;
724
725 // Start a thread that sends SIGPROF signal to VM thread.
726 // Sending the signal ourselves instead of relying on itimer provides
727 // much better accuracy.
728 SetActive(true); 809 SetActive(true);
729 if (pthread_create( 810 SignalSender::AddActiveSampler(this);
730 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) {
731 data_->signal_sender_launched_ = true;
732 }
733
734 // Set this sampler as the active sampler.
735 active_sampler_ = this;
736 } 811 }
737 812
738 813
739 void Sampler::Stop() { 814 void Sampler::Stop() {
815 ASSERT(IsActive());
816 SignalSender::RemoveActiveSampler(this);
740 SetActive(false); 817 SetActive(false);
741
742 // Wait for signal sender termination (it will exit after setting
743 // active_ to false).
744 if (data_->signal_sender_launched_) {
745 Top::WakeUpRuntimeProfilerThreadBeforeShutdown();
746 pthread_join(data_->signal_sender_thread_, NULL);
747 data_->signal_sender_launched_ = false;
748 }
749
750 // Restore old signal handler
751 if (data_->signal_handler_installed_) {
752 sigaction(SIGPROF, &data_->old_signal_handler_, 0);
753 data_->signal_handler_installed_ = false;
754 }
755
756 // This sampler is no longer the active sampler.
757 active_sampler_ = NULL;
758 } 818 }
759 819
760 #endif // ENABLE_LOGGING_AND_PROFILING 820 #endif // ENABLE_LOGGING_AND_PROFILING
761 821
762 } } // namespace v8::internal 822 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/platform-posix.cc ('k') | src/platform-win32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698