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