| OLD | NEW |
| 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 24 matching lines...) Expand all Loading... |
| 35 #include <sys/resource.h> | 35 #include <sys/resource.h> |
| 36 #include <sys/types.h> | 36 #include <sys/types.h> |
| 37 #include <sys/ucontext.h> | 37 #include <sys/ucontext.h> |
| 38 #include <stdlib.h> | 38 #include <stdlib.h> |
| 39 | 39 |
| 40 #include <sys/types.h> // mmap & munmap | 40 #include <sys/types.h> // mmap & munmap |
| 41 #include <sys/mman.h> // mmap & munmap | 41 #include <sys/mman.h> // mmap & munmap |
| 42 #include <sys/stat.h> // open | 42 #include <sys/stat.h> // open |
| 43 #include <sys/fcntl.h> // open | 43 #include <sys/fcntl.h> // open |
| 44 #include <unistd.h> // getpagesize | 44 #include <unistd.h> // getpagesize |
| 45 // If you don't have execinfo.h then you need devel/libexecinfo from ports. |
| 45 #include <execinfo.h> // backtrace, backtrace_symbols | 46 #include <execinfo.h> // backtrace, backtrace_symbols |
| 46 #include <strings.h> // index | 47 #include <strings.h> // index |
| 47 #include <errno.h> | 48 #include <errno.h> |
| 48 #include <stdarg.h> | 49 #include <stdarg.h> |
| 49 #include <limits.h> | 50 #include <limits.h> |
| 50 | 51 |
| 51 #undef MAP_TYPE | 52 #undef MAP_TYPE |
| 52 | 53 |
| 53 #include "v8.h" | 54 #include "v8.h" |
| 54 | 55 |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 virtual int Lock() { | 524 virtual int Lock() { |
| 524 int result = pthread_mutex_lock(&mutex_); | 525 int result = pthread_mutex_lock(&mutex_); |
| 525 return result; | 526 return result; |
| 526 } | 527 } |
| 527 | 528 |
| 528 virtual int Unlock() { | 529 virtual int Unlock() { |
| 529 int result = pthread_mutex_unlock(&mutex_); | 530 int result = pthread_mutex_unlock(&mutex_); |
| 530 return result; | 531 return result; |
| 531 } | 532 } |
| 532 | 533 |
| 534 virtual bool TryLock() { |
| 535 int result = pthread_mutex_trylock(&mutex_); |
| 536 // Return false if the lock is busy and locking failed. |
| 537 if (result == EBUSY) { |
| 538 return false; |
| 539 } |
| 540 ASSERT(result == 0); // Verify no other errors. |
| 541 return true; |
| 542 } |
| 543 |
| 533 private: | 544 private: |
| 534 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. | 545 pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms. |
| 535 }; | 546 }; |
| 536 | 547 |
| 537 | 548 |
| 538 Mutex* OS::CreateMutex() { | 549 Mutex* OS::CreateMutex() { |
| 539 return new FreeBSDMutex(); | 550 return new FreeBSDMutex(); |
| 540 } | 551 } |
| 541 | 552 |
| 542 | 553 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 | 603 |
| 593 | 604 |
| 594 Semaphore* OS::CreateSemaphore(int count) { | 605 Semaphore* OS::CreateSemaphore(int count) { |
| 595 return new FreeBSDSemaphore(count); | 606 return new FreeBSDSemaphore(count); |
| 596 } | 607 } |
| 597 | 608 |
| 598 | 609 |
| 599 #ifdef ENABLE_LOGGING_AND_PROFILING | 610 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 600 | 611 |
| 601 static Sampler* active_sampler_ = NULL; | 612 static Sampler* active_sampler_ = NULL; |
| 613 static pthread_t vm_tid_ = NULL; |
| 614 |
| 615 |
| 616 static pthread_t GetThreadID() { |
| 617 pthread_t thread_id = pthread_self(); |
| 618 return thread_id; |
| 619 } |
| 620 |
| 621 |
| 622 class Sampler::PlatformData : public Malloced { |
| 623 public: |
| 624 enum SleepInterval { |
| 625 FULL_INTERVAL, |
| 626 HALF_INTERVAL |
| 627 }; |
| 628 |
| 629 explicit PlatformData(Sampler* sampler) |
| 630 : sampler_(sampler), |
| 631 signal_handler_installed_(false), |
| 632 signal_sender_launched_(false) { |
| 633 } |
| 634 |
| 635 void SignalSender() { |
| 636 while (sampler_->IsActive()) { |
| 637 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 638 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
| 639 Sleep(FULL_INTERVAL); |
| 640 RuntimeProfiler::NotifyTick(); |
| 641 } else { |
| 642 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
| 643 Sleep(FULL_INTERVAL); |
| 644 } |
| 645 } |
| 646 } |
| 647 |
| 648 void Sleep(SleepInterval full_or_half) { |
| 649 // Convert ms to us and subtract 100 us to compensate delays |
| 650 // occuring during signal delivery. |
| 651 useconds_t interval = sampler_->interval_ * 1000 - 100; |
| 652 if (full_or_half == HALF_INTERVAL) interval /= 2; |
| 653 int result = usleep(interval); |
| 654 #ifdef DEBUG |
| 655 if (result != 0 && errno != EINTR) { |
| 656 fprintf(stderr, |
| 657 "SignalSender usleep error; interval = %u, errno = %d\n", |
| 658 interval, |
| 659 errno); |
| 660 ASSERT(result == 0 || errno == EINTR); |
| 661 } |
| 662 #endif |
| 663 USE(result); |
| 664 } |
| 665 |
| 666 Sampler* sampler_; |
| 667 bool signal_handler_installed_; |
| 668 struct sigaction old_signal_handler_; |
| 669 struct itimerval old_timer_value_; |
| 670 bool signal_sender_launched_; |
| 671 pthread_t signal_sender_thread_; |
| 672 RuntimeProfilerRateLimiter rate_limiter_; |
| 673 }; |
| 674 |
| 602 | 675 |
| 603 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 676 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 604 USE(info); | 677 USE(info); |
| 605 if (signal != SIGPROF) return; | 678 if (signal != SIGPROF) return; |
| 606 if (active_sampler_ == NULL) return; | 679 if (active_sampler_ == NULL) return; |
| 607 | 680 if (!active_sampler_->IsActive()) { |
| 608 TickSample sample; | 681 // Restore old signal handler |
| 609 | 682 Sampler::PlatformData* data = active_sampler_->data(); |
| 610 // We always sample the VM state. | 683 if (data->signal_handler_installed_) { |
| 611 sample.state = VMState::current_state(); | 684 sigaction(SIGPROF, &data->old_signal_handler_, 0); |
| 612 | 685 data->signal_handler_installed_ = false; |
| 613 // If profiling, we extract the current pc and sp. | 686 } |
| 614 if (active_sampler_->IsProfiling()) { | 687 return; |
| 615 // Extracting the sample from the context is extremely machine dependent. | |
| 616 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | |
| 617 mcontext_t& mcontext = ucontext->uc_mcontext; | |
| 618 #if V8_HOST_ARCH_IA32 | |
| 619 sample.pc = reinterpret_cast<Address>(mcontext.mc_eip); | |
| 620 sample.sp = reinterpret_cast<Address>(mcontext.mc_esp); | |
| 621 sample.fp = reinterpret_cast<Address>(mcontext.mc_ebp); | |
| 622 #elif V8_HOST_ARCH_X64 | |
| 623 sample.pc = reinterpret_cast<Address>(mcontext.mc_rip); | |
| 624 sample.sp = reinterpret_cast<Address>(mcontext.mc_rsp); | |
| 625 sample.fp = reinterpret_cast<Address>(mcontext.mc_rbp); | |
| 626 #elif V8_HOST_ARCH_ARM | |
| 627 sample.pc = reinterpret_cast<Address>(mcontext.mc_r15); | |
| 628 sample.sp = reinterpret_cast<Address>(mcontext.mc_r13); | |
| 629 sample.fp = reinterpret_cast<Address>(mcontext.mc_r11); | |
| 630 #endif | |
| 631 active_sampler_->SampleStack(&sample); | |
| 632 } | 688 } |
| 633 | 689 |
| 634 active_sampler_->Tick(&sample); | 690 if (vm_tid_ != GetThreadID()) return; |
| 691 |
| 692 TickSample sample_obj; |
| 693 TickSample* sample = CpuProfiler::TickSampleEvent(); |
| 694 if (sample == NULL) sample = &sample_obj; |
| 695 |
| 696 // Extracting the sample from the context is extremely machine dependent. |
| 697 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 698 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 699 #if V8_HOST_ARCH_IA32 |
| 700 sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); |
| 701 sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); |
| 702 sample->fp = reinterpret_cast<Address>(mcontext.mc_ebp); |
| 703 #elif V8_HOST_ARCH_X64 |
| 704 sample->pc = reinterpret_cast<Address>(mcontext.mc_rip); |
| 705 sample->sp = reinterpret_cast<Address>(mcontext.mc_rsp); |
| 706 sample->fp = reinterpret_cast<Address>(mcontext.mc_rbp); |
| 707 #elif V8_HOST_ARCH_ARM |
| 708 sample->pc = reinterpret_cast<Address>(mcontext.mc_r15); |
| 709 sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); |
| 710 sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); |
| 711 #endif |
| 712 active_sampler_->SampleStack(sample); |
| 713 active_sampler_->Tick(sample); |
| 635 } | 714 } |
| 636 | 715 |
| 637 | 716 |
| 638 class Sampler::PlatformData : public Malloced { | 717 static void* SenderEntry(void* arg) { |
| 639 public: | 718 Sampler::PlatformData* data = |
| 640 PlatformData() { | 719 reinterpret_cast<Sampler::PlatformData*>(arg); |
| 641 signal_handler_installed_ = false; | 720 data->SignalSender(); |
| 642 } | 721 return 0; |
| 643 | 722 } |
| 644 bool signal_handler_installed_; | |
| 645 struct sigaction old_signal_handler_; | |
| 646 struct itimerval old_timer_value_; | |
| 647 }; | |
| 648 | 723 |
| 649 | 724 |
| 650 Sampler::Sampler(Isolate* isolate, int interval) | 725 Sampler::Sampler(Isolate* isolate, int interval) |
| 651 : isolate_(isolate), | 726 : isolate_(isolate), |
| 652 interval_(interval), | 727 interval_(interval), |
| 653 profiling_(false), | 728 profiling_(false), |
| 654 active_(false), | 729 active_(false), |
| 655 samples_taken_(0) { | 730 samples_taken_(0) { |
| 656 data_ = new PlatformData(); | 731 data_ = new PlatformData(this); |
| 657 } | 732 } |
| 658 | 733 |
| 659 | 734 |
| 660 Sampler::~Sampler() { | 735 Sampler::~Sampler() { |
| 661 delete data_; | 736 delete data_; |
| 662 } | 737 } |
| 663 | 738 |
| 664 | 739 |
| 665 void Sampler::Start() { | 740 void Sampler::Start() { |
| 666 // There can only be one active sampler at the time on POSIX | 741 // There can only be one active sampler at the time on POSIX |
| 667 // platforms. | 742 // platforms. |
| 668 if (active_sampler_ != NULL) return; | 743 ASSERT(!IsActive()); |
| 744 vm_tid_ = GetThreadID(); |
| 669 | 745 |
| 670 // Request profiling signals. | 746 // Request profiling signals. |
| 671 struct sigaction sa; | 747 struct sigaction sa; |
| 672 sa.sa_sigaction = ProfilerSignalHandler; | 748 sa.sa_sigaction = ProfilerSignalHandler; |
| 673 sigemptyset(&sa.sa_mask); | 749 sigemptyset(&sa.sa_mask); |
| 674 sa.sa_flags = SA_SIGINFO; | 750 sa.sa_flags = SA_SIGINFO; |
| 675 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; | 751 if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; |
| 676 data_->signal_handler_installed_ = true; | 752 data_->signal_handler_installed_ = true; |
| 677 | 753 |
| 678 // Set the itimer to generate a tick for each interval. | 754 // Set the itimer to generate a tick for each interval. |
| 679 itimerval itimer; | 755 itimerval itimer; |
| 680 itimer.it_interval.tv_sec = interval_ / 1000; | 756 itimer.it_interval.tv_sec = interval_ / 1000; |
| 681 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; | 757 itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; |
| 682 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; | 758 itimer.it_value.tv_sec = itimer.it_interval.tv_sec; |
| 683 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; | 759 itimer.it_value.tv_usec = itimer.it_interval.tv_usec; |
| 684 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); | 760 setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); |
| 685 | 761 |
| 686 // Set this sampler as the active sampler. | 762 // Set this sampler as the active sampler. |
| 687 active_sampler_ = this; | 763 active_sampler_ = this; |
| 688 active_ = true; | 764 SetActive(true); |
| 765 |
| 766 // There's no way to send a signal to a thread on FreeBSD, but we can |
| 767 // start a thread that uses the stack guard to interrupt the JS thread. |
| 768 if (pthread_create( |
| 769 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
| 770 data_->signal_sender_launched_ = true; |
| 771 } |
| 689 } | 772 } |
| 690 | 773 |
| 691 | 774 |
| 692 void Sampler::Stop() { | 775 void Sampler::Stop() { |
| 693 // Restore old signal handler | |
| 694 if (data_->signal_handler_installed_) { | |
| 695 setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL); | |
| 696 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | |
| 697 data_->signal_handler_installed_ = false; | |
| 698 } | |
| 699 | |
| 700 // This sampler is no longer the active sampler. | 776 // This sampler is no longer the active sampler. |
| 701 active_sampler_ = NULL; | 777 active_sampler_ = NULL; |
| 702 active_ = false; | 778 SetActive(false); |
| 779 |
| 780 // Wait for signal sender termination (it will exit after setting |
| 781 // active_ to false). |
| 782 if (data_->signal_sender_launched_) { |
| 783 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 784 pthread_join(data_->signal_sender_thread_, NULL); |
| 785 data_->signal_sender_launched_ = false; |
| 786 } |
| 703 } | 787 } |
| 704 | 788 |
| 705 #endif // ENABLE_LOGGING_AND_PROFILING | 789 #endif // ENABLE_LOGGING_AND_PROFILING |
| 706 | 790 |
| 707 } } // namespace v8::internal | 791 } } // namespace v8::internal |
| OLD | NEW |