| 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 #endif // def __GLIBC__ | 51 #endif // def __GLIBC__ |
| 52 #include <strings.h> // index | 52 #include <strings.h> // index |
| 53 #include <errno.h> | 53 #include <errno.h> |
| 54 #include <stdarg.h> | 54 #include <stdarg.h> |
| 55 | 55 |
| 56 #undef MAP_TYPE | 56 #undef MAP_TYPE |
| 57 | 57 |
| 58 #include "v8.h" | 58 #include "v8.h" |
| 59 | 59 |
| 60 #include "platform.h" | 60 #include "platform.h" |
| 61 #include "top.h" | |
| 62 #include "v8threads.h" | 61 #include "v8threads.h" |
| 63 #include "vm-state-inl.h" | 62 #include "vm-state-inl.h" |
| 64 | 63 |
| 65 | 64 |
| 66 namespace v8 { | 65 namespace v8 { |
| 67 namespace internal { | 66 namespace internal { |
| 68 | 67 |
| 69 // 0 is never a valid thread id on Linux since tids and pids share a | 68 // 0 is never a valid thread id on Linux since tids and pids share a |
| 70 // name space and pid 0 is reserved (see man 2 kill). | 69 // name space and pid 0 is reserved (see man 2 kill). |
| 71 static const pthread_t kNoThread = (pthread_t) 0; | 70 static const pthread_t kNoThread = (pthread_t) 0; |
| 72 | 71 |
| 73 | 72 |
| 74 double ceiling(double x) { | 73 double ceiling(double x) { |
| 75 return ceil(x); | 74 return ceil(x); |
| 76 } | 75 } |
| 77 | 76 |
| 78 | 77 |
| 78 static Mutex* limit_mutex = NULL; |
| 79 |
| 80 |
| 79 void OS::Setup() { | 81 void OS::Setup() { |
| 80 // Seed the random number generator. | 82 // Seed the random number generator. |
| 81 // Convert the current time to a 64-bit integer first, before converting it | 83 // Convert the current time to a 64-bit integer first, before converting it |
| 82 // to an unsigned. Going directly can cause an overflow and the seed to be | 84 // to an unsigned. Going directly can cause an overflow and the seed to be |
| 83 // set to all ones. The seed will be identical for different instances that | 85 // set to all ones. The seed will be identical for different instances that |
| 84 // call this setup code within the same millisecond. | 86 // call this setup code within the same millisecond. |
| 85 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 87 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
| 86 srandom(static_cast<unsigned int>(seed)); | 88 srandom(static_cast<unsigned int>(seed)); |
| 89 limit_mutex = CreateMutex(); |
| 87 } | 90 } |
| 88 | 91 |
| 89 | 92 |
| 90 uint64_t OS::CpuFeaturesImpliedByPlatform() { | 93 uint64_t OS::CpuFeaturesImpliedByPlatform() { |
| 91 #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) | 94 #if (defined(__VFP_FP__) && !defined(__SOFTFP__)) |
| 92 // Here gcc is telling us that we are on an ARM and gcc is assuming that we | 95 // Here gcc is telling us that we are on an ARM and gcc is assuming that we |
| 93 // have VFP3 instructions. If gcc can assume it then so can we. | 96 // have VFP3 instructions. If gcc can assume it then so can we. |
| 94 return 1u << VFP3; | 97 return 1u << VFP3; |
| 95 #elif CAN_USE_ARMV7_INSTRUCTIONS | 98 #elif CAN_USE_ARMV7_INSTRUCTIONS |
| 96 return 1u << ARMv7; | 99 return 1u << ARMv7; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 // We keep the lowest and highest addresses mapped as a quick way of | 222 // We keep the lowest and highest addresses mapped as a quick way of |
| 220 // determining that pointers are outside the heap (used mostly in assertions | 223 // determining that pointers are outside the heap (used mostly in assertions |
| 221 // and verification). The estimate is conservative, ie, not all addresses in | 224 // and verification). The estimate is conservative, ie, not all addresses in |
| 222 // 'allocated' space are actually allocated to our heap. The range is | 225 // 'allocated' space are actually allocated to our heap. The range is |
| 223 // [lowest, highest), inclusive on the low and and exclusive on the high end. | 226 // [lowest, highest), inclusive on the low and and exclusive on the high end. |
| 224 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); | 227 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); |
| 225 static void* highest_ever_allocated = reinterpret_cast<void*>(0); | 228 static void* highest_ever_allocated = reinterpret_cast<void*>(0); |
| 226 | 229 |
| 227 | 230 |
| 228 static void UpdateAllocatedSpaceLimits(void* address, int size) { | 231 static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| 232 ASSERT(limit_mutex != NULL); |
| 233 ScopedLock lock(limit_mutex); |
| 234 |
| 229 lowest_ever_allocated = Min(lowest_ever_allocated, address); | 235 lowest_ever_allocated = Min(lowest_ever_allocated, address); |
| 230 highest_ever_allocated = | 236 highest_ever_allocated = |
| 231 Max(highest_ever_allocated, | 237 Max(highest_ever_allocated, |
| 232 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); | 238 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); |
| 233 } | 239 } |
| 234 | 240 |
| 235 | 241 |
| 236 bool OS::IsOutsideAllocatedSpace(void* address) { | 242 bool OS::IsOutsideAllocatedSpace(void* address) { |
| 237 return address < lowest_ever_allocated || address >= highest_ever_allocated; | 243 return address < lowest_ever_allocated || address >= highest_ever_allocated; |
| 238 } | 244 } |
| 239 | 245 |
| 240 | 246 |
| 241 size_t OS::AllocateAlignment() { | 247 size_t OS::AllocateAlignment() { |
| 242 return sysconf(_SC_PAGESIZE); | 248 return sysconf(_SC_PAGESIZE); |
| 243 } | 249 } |
| 244 | 250 |
| 245 | 251 |
| 246 void* OS::Allocate(const size_t requested, | 252 void* OS::Allocate(const size_t requested, |
| 247 size_t* allocated, | 253 size_t* allocated, |
| 248 bool is_executable) { | 254 bool is_executable) { |
| 249 // TODO(805): Port randomization of allocated executable memory to Linux. | 255 // TODO(805): Port randomization of allocated executable memory to Linux. |
| 250 const size_t msize = RoundUp(requested, AllocateAlignment()); | 256 const size_t msize = RoundUp(requested, AllocateAlignment()); |
| 251 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); | 257 int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); |
| 252 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 258 void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 253 if (mbase == MAP_FAILED) { | 259 if (mbase == MAP_FAILED) { |
| 254 LOG(StringEvent("OS::Allocate", "mmap failed")); | 260 LOG(i::Isolate::Current(), |
| 261 StringEvent("OS::Allocate", "mmap failed")); |
| 255 return NULL; | 262 return NULL; |
| 256 } | 263 } |
| 257 *allocated = msize; | 264 *allocated = msize; |
| 258 UpdateAllocatedSpaceLimits(mbase, msize); | 265 UpdateAllocatedSpaceLimits(mbase, msize); |
| 259 return mbase; | 266 return mbase; |
| 260 } | 267 } |
| 261 | 268 |
| 262 | 269 |
| 263 void OS::Free(void* address, const size_t size) { | 270 void OS::Free(void* address, const size_t size) { |
| 264 // TODO(1240712): munmap has a return value which is ignored here. | 271 // TODO(1240712): munmap has a return value which is ignored here. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 // This function assumes that the layout of the file is as follows: | 372 // This function assumes that the layout of the file is as follows: |
| 366 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] | 373 // hex_start_addr-hex_end_addr rwxp <unused data> [binary_file_name] |
| 367 // If we encounter an unexpected situation we abort scanning further entries. | 374 // If we encounter an unexpected situation we abort scanning further entries. |
| 368 FILE* fp = fopen("/proc/self/maps", "r"); | 375 FILE* fp = fopen("/proc/self/maps", "r"); |
| 369 if (fp == NULL) return; | 376 if (fp == NULL) return; |
| 370 | 377 |
| 371 // Allocate enough room to be able to store a full file name. | 378 // Allocate enough room to be able to store a full file name. |
| 372 const int kLibNameLen = FILENAME_MAX + 1; | 379 const int kLibNameLen = FILENAME_MAX + 1; |
| 373 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); | 380 char* lib_name = reinterpret_cast<char*>(malloc(kLibNameLen)); |
| 374 | 381 |
| 382 i::Isolate* isolate = ISOLATE; |
| 375 // This loop will terminate once the scanning hits an EOF. | 383 // This loop will terminate once the scanning hits an EOF. |
| 376 while (true) { | 384 while (true) { |
| 377 uintptr_t start, end; | 385 uintptr_t start, end; |
| 378 char attr_r, attr_w, attr_x, attr_p; | 386 char attr_r, attr_w, attr_x, attr_p; |
| 379 // Parse the addresses and permission bits at the beginning of the line. | 387 // Parse the addresses and permission bits at the beginning of the line. |
| 380 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; | 388 if (fscanf(fp, "%" V8PRIxPTR "-%" V8PRIxPTR, &start, &end) != 2) break; |
| 381 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; | 389 if (fscanf(fp, " %c%c%c%c", &attr_r, &attr_w, &attr_x, &attr_p) != 4) break; |
| 382 | 390 |
| 383 int c; | 391 int c; |
| 384 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { | 392 if (attr_r == 'r' && attr_w != 'w' && attr_x == 'x') { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 398 | 406 |
| 399 // Drop the newline character read by fgets. We do not need to check | 407 // Drop the newline character read by fgets. We do not need to check |
| 400 // for a zero-length string because we know that we at least read the | 408 // for a zero-length string because we know that we at least read the |
| 401 // '/' character. | 409 // '/' character. |
| 402 lib_name[strlen(lib_name) - 1] = '\0'; | 410 lib_name[strlen(lib_name) - 1] = '\0'; |
| 403 } else { | 411 } else { |
| 404 // No library name found, just record the raw address range. | 412 // No library name found, just record the raw address range. |
| 405 snprintf(lib_name, kLibNameLen, | 413 snprintf(lib_name, kLibNameLen, |
| 406 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); | 414 "%08" V8PRIxPTR "-%08" V8PRIxPTR, start, end); |
| 407 } | 415 } |
| 408 LOG(SharedLibraryEvent(lib_name, start, end)); | 416 LOG(isolate, SharedLibraryEvent(lib_name, start, end)); |
| 409 } else { | 417 } else { |
| 410 // Entry not describing executable data. Skip to end of line to setup | 418 // Entry not describing executable data. Skip to end of line to setup |
| 411 // reading the next entry. | 419 // reading the next entry. |
| 412 do { | 420 do { |
| 413 c = getc(fp); | 421 c = getc(fp); |
| 414 } while ((c != EOF) && (c != '\n')); | 422 } while ((c != EOF) && (c != '\n')); |
| 415 if (c == EOF) break; | 423 if (c == EOF) break; |
| 416 } | 424 } |
| 417 } | 425 } |
| 418 free(lib_name); | 426 free(lib_name); |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 bool ThreadHandle::IsSelf() const { | 599 bool ThreadHandle::IsSelf() const { |
| 592 return pthread_equal(data_->thread_, pthread_self()); | 600 return pthread_equal(data_->thread_, pthread_self()); |
| 593 } | 601 } |
| 594 | 602 |
| 595 | 603 |
| 596 bool ThreadHandle::IsValid() const { | 604 bool ThreadHandle::IsValid() const { |
| 597 return data_->thread_ != kNoThread; | 605 return data_->thread_ != kNoThread; |
| 598 } | 606 } |
| 599 | 607 |
| 600 | 608 |
| 601 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { | 609 Thread::Thread(Isolate* isolate) |
| 610 : ThreadHandle(ThreadHandle::INVALID), |
| 611 isolate_(isolate) { |
| 602 set_name("v8:<unknown>"); | 612 set_name("v8:<unknown>"); |
| 603 } | 613 } |
| 604 | 614 |
| 605 | 615 |
| 606 Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { | 616 Thread::Thread(Isolate* isolate, const char* name) |
| 617 : ThreadHandle(ThreadHandle::INVALID), |
| 618 isolate_(isolate) { |
| 607 set_name(name); | 619 set_name(name); |
| 608 } | 620 } |
| 609 | 621 |
| 610 | 622 |
| 611 Thread::~Thread() { | 623 Thread::~Thread() { |
| 612 } | 624 } |
| 613 | 625 |
| 614 | 626 |
| 615 static void* ThreadEntry(void* arg) { | 627 static void* ThreadEntry(void* arg) { |
| 616 Thread* thread = reinterpret_cast<Thread*>(arg); | 628 Thread* thread = reinterpret_cast<Thread*>(arg); |
| 617 // This is also initialized by the first argument to pthread_create() but we | 629 // This is also initialized by the first argument to pthread_create() but we |
| 618 // don't know which thread will run first (the original thread or the new | 630 // don't know which thread will run first (the original thread or the new |
| 619 // one) so we initialize it here too. | 631 // one) so we initialize it here too. |
| 620 prctl(PR_SET_NAME, | 632 prctl(PR_SET_NAME, |
| 621 reinterpret_cast<unsigned long>(thread->name()), // NOLINT | 633 reinterpret_cast<unsigned long>(thread->name()), // NOLINT |
| 622 0, 0, 0); | 634 0, 0, 0); |
| 623 thread->thread_handle_data()->thread_ = pthread_self(); | 635 thread->thread_handle_data()->thread_ = pthread_self(); |
| 624 ASSERT(thread->IsValid()); | 636 ASSERT(thread->IsValid()); |
| 637 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); |
| 625 thread->Run(); | 638 thread->Run(); |
| 626 return NULL; | 639 return NULL; |
| 627 } | 640 } |
| 628 | 641 |
| 629 | 642 |
| 630 void Thread::set_name(const char* name) { | 643 void Thread::set_name(const char* name) { |
| 631 strncpy(name_, name, sizeof(name_)); | 644 strncpy(name_, name, sizeof(name_)); |
| 632 name_[sizeof(name_) - 1] = '\0'; | 645 name_[sizeof(name_) - 1] = '\0'; |
| 633 } | 646 } |
| 634 | 647 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 } | 801 } |
| 789 | 802 |
| 790 | 803 |
| 791 Semaphore* OS::CreateSemaphore(int count) { | 804 Semaphore* OS::CreateSemaphore(int count) { |
| 792 return new LinuxSemaphore(count); | 805 return new LinuxSemaphore(count); |
| 793 } | 806 } |
| 794 | 807 |
| 795 | 808 |
| 796 #ifdef ENABLE_LOGGING_AND_PROFILING | 809 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 797 | 810 |
| 798 static Sampler* active_sampler_ = NULL; | |
| 799 static int vm_tid_ = 0; | |
| 800 | |
| 801 | |
| 802 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) | 811 #if !defined(__GLIBC__) && (defined(__arm__) || defined(__thumb__)) |
| 803 // Android runs a fairly new Linux kernel, so signal info is there, | 812 // Android runs a fairly new Linux kernel, so signal info is there, |
| 804 // but the C library doesn't have the structs defined. | 813 // but the C library doesn't have the structs defined. |
| 805 | 814 |
| 806 struct sigcontext { | 815 struct sigcontext { |
| 807 uint32_t trap_no; | 816 uint32_t trap_no; |
| 808 uint32_t error_code; | 817 uint32_t error_code; |
| 809 uint32_t oldmask; | 818 uint32_t oldmask; |
| 810 uint32_t gregs[16]; | 819 uint32_t gregs[16]; |
| 811 uint32_t arm_cpsr; | 820 uint32_t arm_cpsr; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 828 static int GetThreadID() { | 837 static int GetThreadID() { |
| 829 // Glibc doesn't provide a wrapper for gettid(2). | 838 // Glibc doesn't provide a wrapper for gettid(2). |
| 830 return syscall(SYS_gettid); | 839 return syscall(SYS_gettid); |
| 831 } | 840 } |
| 832 | 841 |
| 833 | 842 |
| 834 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { | 843 static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| 835 #ifndef V8_HOST_ARCH_MIPS | 844 #ifndef V8_HOST_ARCH_MIPS |
| 836 USE(info); | 845 USE(info); |
| 837 if (signal != SIGPROF) return; | 846 if (signal != SIGPROF) return; |
| 838 if (active_sampler_ == NULL || !active_sampler_->IsActive()) return; | 847 Isolate* isolate = Isolate::UncheckedCurrent(); |
| 839 if (vm_tid_ != GetThreadID()) return; | 848 if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| 849 // We require a fully initialized and entered isolate. |
| 850 return; |
| 851 } |
| 852 Sampler* sampler = isolate->logger()->sampler(); |
| 853 if (sampler == NULL || !sampler->IsActive()) return; |
| 840 | 854 |
| 841 TickSample sample_obj; | 855 TickSample sample_obj; |
| 842 TickSample* sample = CpuProfiler::TickSampleEvent(); | 856 TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| 843 if (sample == NULL) sample = &sample_obj; | 857 if (sample == NULL) sample = &sample_obj; |
| 844 | 858 |
| 845 // Extracting the sample from the context is extremely machine dependent. | 859 // Extracting the sample from the context is extremely machine dependent. |
| 846 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 860 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 847 mcontext_t& mcontext = ucontext->uc_mcontext; | 861 mcontext_t& mcontext = ucontext->uc_mcontext; |
| 848 sample->state = Top::current_vm_state(); | 862 sample->state = isolate->current_vm_state(); |
| 849 #if V8_HOST_ARCH_IA32 | 863 #if V8_HOST_ARCH_IA32 |
| 850 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); | 864 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]); |
| 851 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); | 865 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]); |
| 852 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); | 866 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]); |
| 853 #elif V8_HOST_ARCH_X64 | 867 #elif V8_HOST_ARCH_X64 |
| 854 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); | 868 sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]); |
| 855 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); | 869 sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]); |
| 856 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); | 870 sample->fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]); |
| 857 #elif V8_HOST_ARCH_ARM | 871 #elif V8_HOST_ARCH_ARM |
| 858 // An undefined macro evaluates to 0, so this applies to Android's Bionic also. | 872 // An undefined macro evaluates to 0, so this applies to Android's Bionic also. |
| 859 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) | 873 #if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) |
| 860 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); | 874 sample->pc = reinterpret_cast<Address>(mcontext.gregs[R15]); |
| 861 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); | 875 sample->sp = reinterpret_cast<Address>(mcontext.gregs[R13]); |
| 862 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); | 876 sample->fp = reinterpret_cast<Address>(mcontext.gregs[R11]); |
| 863 #else | 877 #else |
| 864 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); | 878 sample->pc = reinterpret_cast<Address>(mcontext.arm_pc); |
| 865 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); | 879 sample->sp = reinterpret_cast<Address>(mcontext.arm_sp); |
| 866 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); | 880 sample->fp = reinterpret_cast<Address>(mcontext.arm_fp); |
| 867 #endif | 881 #endif |
| 868 #elif V8_HOST_ARCH_MIPS | 882 #elif V8_HOST_ARCH_MIPS |
| 869 // Implement this on MIPS. | 883 // Implement this on MIPS. |
| 870 UNIMPLEMENTED(); | 884 UNIMPLEMENTED(); |
| 871 #endif | 885 #endif |
| 872 active_sampler_->SampleStack(sample); | 886 sampler->SampleStack(sample); |
| 873 active_sampler_->Tick(sample); | 887 sampler->Tick(sample); |
| 874 #endif | 888 #endif |
| 875 } | 889 } |
| 876 | 890 |
| 877 | 891 |
| 878 class Sampler::PlatformData : public Malloced { | 892 class Sampler::PlatformData : public Malloced { |
| 879 public: | 893 public: |
| 894 PlatformData() : vm_tid_(GetThreadID()) {} |
| 895 |
| 896 int vm_tid() const { return vm_tid_; } |
| 897 |
| 898 private: |
| 899 const int vm_tid_; |
| 900 }; |
| 901 |
| 902 |
| 903 class SignalSender : public Thread { |
| 904 public: |
| 880 enum SleepInterval { | 905 enum SleepInterval { |
| 881 FULL_INTERVAL, | 906 HALF_INTERVAL, |
| 882 HALF_INTERVAL | 907 FULL_INTERVAL |
| 883 }; | 908 }; |
| 884 | 909 |
| 885 explicit PlatformData(Sampler* sampler) | 910 explicit SignalSender(int interval) |
| 886 : sampler_(sampler), | 911 : Thread(NULL), vm_tgid_(getpid()), interval_(interval) {} |
| 887 signal_handler_installed_(false), | 912 |
| 888 vm_tgid_(getpid()), | 913 static void AddActiveSampler(Sampler* sampler) { |
| 889 signal_sender_launched_(false) { | 914 ScopedLock lock(mutex_); |
| 915 SamplerRegistry::AddActiveSampler(sampler); |
| 916 if (instance_ == NULL) { |
| 917 // Install a signal handler. |
| 918 struct sigaction sa; |
| 919 sa.sa_sigaction = ProfilerSignalHandler; |
| 920 sigemptyset(&sa.sa_mask); |
| 921 sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| 922 signal_handler_installed_ = |
| 923 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); |
| 924 |
| 925 // Start a thread that sends SIGPROF signal to VM threads. |
| 926 instance_ = new SignalSender(sampler->interval()); |
| 927 instance_->Start(); |
| 928 } else { |
| 929 ASSERT(instance_->interval_ == sampler->interval()); |
| 930 } |
| 890 } | 931 } |
| 891 | 932 |
| 892 void SignalSender() { | 933 static void RemoveActiveSampler(Sampler* sampler) { |
| 893 while (sampler_->IsActive()) { | 934 ScopedLock lock(mutex_); |
| 894 if (rate_limiter_.SuspendIfNecessary()) continue; | 935 SamplerRegistry::RemoveActiveSampler(sampler); |
| 895 if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { | 936 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| 896 SendProfilingSignal(); | 937 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 938 instance_->Join(); |
| 939 delete instance_; |
| 940 instance_ = NULL; |
| 941 |
| 942 // Restore the old signal handler. |
| 943 if (signal_handler_installed_) { |
| 944 sigaction(SIGPROF, &old_signal_handler_, 0); |
| 945 signal_handler_installed_ = false; |
| 946 } |
| 947 } |
| 948 } |
| 949 |
| 950 // Implement Thread::Run(). |
| 951 virtual void Run() { |
| 952 SamplerRegistry::State state = SamplerRegistry::GetState(); |
| 953 while (state != SamplerRegistry::HAS_NO_SAMPLERS) { |
| 954 bool cpu_profiling_enabled = |
| 955 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| 956 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| 957 // When CPU profiling is enabled both JavaScript and C++ code is |
| 958 // profiled. We must not suspend. |
| 959 if (!cpu_profiling_enabled) { |
| 960 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 961 } |
| 962 if (cpu_profiling_enabled && runtime_profiler_enabled) { |
| 963 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| 964 return; |
| 965 } |
| 897 Sleep(HALF_INTERVAL); | 966 Sleep(HALF_INTERVAL); |
| 898 RuntimeProfiler::NotifyTick(); | 967 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| 968 return; |
| 969 } |
| 899 Sleep(HALF_INTERVAL); | 970 Sleep(HALF_INTERVAL); |
| 900 } else { | 971 } else { |
| 901 if (sampler_->IsProfiling()) SendProfilingSignal(); | 972 if (cpu_profiling_enabled) { |
| 902 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); | 973 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, |
| 974 this)) { |
| 975 return; |
| 976 } |
| 977 } |
| 978 if (runtime_profiler_enabled) { |
| 979 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, |
| 980 NULL)) { |
| 981 return; |
| 982 } |
| 983 } |
| 903 Sleep(FULL_INTERVAL); | 984 Sleep(FULL_INTERVAL); |
| 904 } | 985 } |
| 905 } | 986 } |
| 906 } | 987 } |
| 907 | 988 |
| 908 void SendProfilingSignal() { | 989 static void DoCpuProfile(Sampler* sampler, void* raw_sender) { |
| 990 if (!sampler->IsProfiling()) return; |
| 991 SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); |
| 992 sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); |
| 993 } |
| 994 |
| 995 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| 996 if (!sampler->isolate()->IsInitialized()) return; |
| 997 sampler->isolate()->runtime_profiler()->NotifyTick(); |
| 998 } |
| 999 |
| 1000 void SendProfilingSignal(int tid) { |
| 909 if (!signal_handler_installed_) return; | 1001 if (!signal_handler_installed_) return; |
| 910 // Glibc doesn't provide a wrapper for tgkill(2). | 1002 // Glibc doesn't provide a wrapper for tgkill(2). |
| 911 syscall(SYS_tgkill, vm_tgid_, vm_tid_, SIGPROF); | 1003 syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF); |
| 912 } | 1004 } |
| 913 | 1005 |
| 914 void Sleep(SleepInterval full_or_half) { | 1006 void Sleep(SleepInterval full_or_half) { |
| 915 // Convert ms to us and subtract 100 us to compensate delays | 1007 // Convert ms to us and subtract 100 us to compensate delays |
| 916 // occuring during signal delivery. | 1008 // occuring during signal delivery. |
| 917 useconds_t interval = sampler_->interval_ * 1000 - 100; | 1009 useconds_t interval = interval_ * 1000 - 100; |
| 918 if (full_or_half == HALF_INTERVAL) interval /= 2; | 1010 if (full_or_half == HALF_INTERVAL) interval /= 2; |
| 919 int result = usleep(interval); | 1011 int result = usleep(interval); |
| 920 #ifdef DEBUG | 1012 #ifdef DEBUG |
| 921 if (result != 0 && errno != EINTR) { | 1013 if (result != 0 && errno != EINTR) { |
| 922 fprintf(stderr, | 1014 fprintf(stderr, |
| 923 "SignalSender usleep error; interval = %u, errno = %d\n", | 1015 "SignalSender usleep error; interval = %u, errno = %d\n", |
| 924 interval, | 1016 interval, |
| 925 errno); | 1017 errno); |
| 926 ASSERT(result == 0 || errno == EINTR); | 1018 ASSERT(result == 0 || errno == EINTR); |
| 927 } | 1019 } |
| 928 #endif | 1020 #endif |
| 929 USE(result); | 1021 USE(result); |
| 930 } | 1022 } |
| 931 | 1023 |
| 932 Sampler* sampler_; | 1024 const int vm_tgid_; |
| 933 bool signal_handler_installed_; | 1025 const int interval_; |
| 934 struct sigaction old_signal_handler_; | |
| 935 int vm_tgid_; | |
| 936 bool signal_sender_launched_; | |
| 937 pthread_t signal_sender_thread_; | |
| 938 RuntimeProfilerRateLimiter rate_limiter_; | 1026 RuntimeProfilerRateLimiter rate_limiter_; |
| 1027 |
| 1028 // Protects the process wide state below. |
| 1029 static Mutex* mutex_; |
| 1030 static SignalSender* instance_; |
| 1031 static bool signal_handler_installed_; |
| 1032 static struct sigaction old_signal_handler_; |
| 1033 |
| 1034 DISALLOW_COPY_AND_ASSIGN(SignalSender); |
| 939 }; | 1035 }; |
| 940 | 1036 |
| 941 | 1037 |
| 942 static void* SenderEntry(void* arg) { | 1038 Mutex* SignalSender::mutex_ = OS::CreateMutex(); |
| 943 Sampler::PlatformData* data = | 1039 SignalSender* SignalSender::instance_ = NULL; |
| 944 reinterpret_cast<Sampler::PlatformData*>(arg); | 1040 struct sigaction SignalSender::old_signal_handler_; |
| 945 data->SignalSender(); | 1041 bool SignalSender::signal_handler_installed_ = false; |
| 946 return 0; | |
| 947 } | |
| 948 | 1042 |
| 949 | 1043 |
| 950 Sampler::Sampler(int interval) | 1044 Sampler::Sampler(Isolate* isolate, int interval) |
| 951 : interval_(interval), | 1045 : isolate_(isolate), |
| 1046 interval_(interval), |
| 952 profiling_(false), | 1047 profiling_(false), |
| 953 active_(false), | 1048 active_(false), |
| 954 samples_taken_(0) { | 1049 samples_taken_(0) { |
| 955 data_ = new PlatformData(this); | 1050 data_ = new PlatformData; |
| 956 } | 1051 } |
| 957 | 1052 |
| 958 | 1053 |
| 959 Sampler::~Sampler() { | 1054 Sampler::~Sampler() { |
| 960 ASSERT(!data_->signal_sender_launched_); | 1055 ASSERT(!IsActive()); |
| 961 delete data_; | 1056 delete data_; |
| 962 } | 1057 } |
| 963 | 1058 |
| 964 | 1059 |
| 965 void Sampler::Start() { | 1060 void Sampler::Start() { |
| 966 // There can only be one active sampler at the time on POSIX | |
| 967 // platforms. | |
| 968 ASSERT(!IsActive()); | 1061 ASSERT(!IsActive()); |
| 969 vm_tid_ = GetThreadID(); | |
| 970 | |
| 971 // Request profiling signals. | |
| 972 struct sigaction sa; | |
| 973 sa.sa_sigaction = ProfilerSignalHandler; | |
| 974 sigemptyset(&sa.sa_mask); | |
| 975 sa.sa_flags = SA_RESTART | SA_SIGINFO; | |
| 976 data_->signal_handler_installed_ = | |
| 977 sigaction(SIGPROF, &sa, &data_->old_signal_handler_) == 0; | |
| 978 | |
| 979 // Start a thread that sends SIGPROF signal to VM thread. | |
| 980 // Sending the signal ourselves instead of relying on itimer provides | |
| 981 // much better accuracy. | |
| 982 SetActive(true); | 1062 SetActive(true); |
| 983 if (pthread_create( | 1063 SignalSender::AddActiveSampler(this); |
| 984 &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { | |
| 985 data_->signal_sender_launched_ = true; | |
| 986 } | |
| 987 | |
| 988 // Set this sampler as the active sampler. | |
| 989 active_sampler_ = this; | |
| 990 } | 1064 } |
| 991 | 1065 |
| 992 | 1066 |
| 993 void Sampler::Stop() { | 1067 void Sampler::Stop() { |
| 1068 ASSERT(IsActive()); |
| 1069 SignalSender::RemoveActiveSampler(this); |
| 994 SetActive(false); | 1070 SetActive(false); |
| 995 | |
| 996 // Wait for signal sender termination (it will exit after setting | |
| 997 // active_ to false). | |
| 998 if (data_->signal_sender_launched_) { | |
| 999 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); | |
| 1000 pthread_join(data_->signal_sender_thread_, NULL); | |
| 1001 data_->signal_sender_launched_ = false; | |
| 1002 } | |
| 1003 | |
| 1004 // Restore old signal handler | |
| 1005 if (data_->signal_handler_installed_) { | |
| 1006 sigaction(SIGPROF, &data_->old_signal_handler_, 0); | |
| 1007 data_->signal_handler_installed_ = false; | |
| 1008 } | |
| 1009 | |
| 1010 // This sampler is no longer the active sampler. | |
| 1011 active_sampler_ = NULL; | |
| 1012 } | 1071 } |
| 1013 | 1072 |
| 1014 | |
| 1015 #endif // ENABLE_LOGGING_AND_PROFILING | 1073 #endif // ENABLE_LOGGING_AND_PROFILING |
| 1016 | 1074 |
| 1017 } } // namespace v8::internal | 1075 } } // namespace v8::internal |
| OLD | NEW |