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 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 } | 166 } |
167 | 167 |
168 | 168 |
169 namespace v8 { | 169 namespace v8 { |
170 namespace internal { | 170 namespace internal { |
171 | 171 |
172 double ceiling(double x) { | 172 double ceiling(double x) { |
173 return ceil(x); | 173 return ceil(x); |
174 } | 174 } |
175 | 175 |
| 176 |
| 177 static Mutex* limit_mutex = NULL; |
| 178 |
| 179 |
176 #ifdef _WIN64 | 180 #ifdef _WIN64 |
177 typedef double (*ModuloFunction)(double, double); | 181 typedef double (*ModuloFunction)(double, double); |
178 | 182 |
179 // Defined in codegen-x64.cc. | 183 // Defined in codegen-x64.cc. |
180 ModuloFunction CreateModuloFunction(); | 184 ModuloFunction CreateModuloFunction(); |
181 | 185 |
182 double modulo(double x, double y) { | 186 double modulo(double x, double y) { |
183 static ModuloFunction function = CreateModuloFunction(); | 187 static ModuloFunction function = CreateModuloFunction(); |
184 return function(x, y); | 188 return function(x, y); |
185 } | 189 } |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 | 537 |
534 | 538 |
535 void OS::Setup() { | 539 void OS::Setup() { |
536 // Seed the random number generator. | 540 // Seed the random number generator. |
537 // Convert the current time to a 64-bit integer first, before converting it | 541 // Convert the current time to a 64-bit integer first, before converting it |
538 // to an unsigned. Going directly can cause an overflow and the seed to be | 542 // to an unsigned. Going directly can cause an overflow and the seed to be |
539 // set to all ones. The seed will be identical for different instances that | 543 // set to all ones. The seed will be identical for different instances that |
540 // call this setup code within the same millisecond. | 544 // call this setup code within the same millisecond. |
541 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); | 545 uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
542 srand(static_cast<unsigned int>(seed)); | 546 srand(static_cast<unsigned int>(seed)); |
| 547 limit_mutex = CreateMutex(); |
543 } | 548 } |
544 | 549 |
545 | 550 |
546 // Returns the accumulated user time for thread. | 551 // Returns the accumulated user time for thread. |
547 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { | 552 int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { |
548 FILETIME dummy; | 553 FILETIME dummy; |
549 uint64_t usertime; | 554 uint64_t usertime; |
550 | 555 |
551 // Get the amount of time that the thread has executed in user mode. | 556 // Get the amount of time that the thread has executed in user mode. |
552 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy, | 557 if (!GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &dummy, |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 } | 674 } |
670 } | 675 } |
671 | 676 |
672 | 677 |
673 bool OS::Remove(const char* path) { | 678 bool OS::Remove(const char* path) { |
674 return (DeleteFileA(path) != 0); | 679 return (DeleteFileA(path) != 0); |
675 } | 680 } |
676 | 681 |
677 | 682 |
678 // Open log file in binary mode to avoid /n -> /r/n conversion. | 683 // Open log file in binary mode to avoid /n -> /r/n conversion. |
679 const char* OS::LogFileOpenMode = "wb"; | 684 const char* const OS::LogFileOpenMode = "wb"; |
680 | 685 |
681 | 686 |
682 // Print (debug) message to console. | 687 // Print (debug) message to console. |
683 void OS::Print(const char* format, ...) { | 688 void OS::Print(const char* format, ...) { |
684 va_list args; | 689 va_list args; |
685 va_start(args, format); | 690 va_start(args, format); |
686 VPrint(format, args); | 691 VPrint(format, args); |
687 va_end(args); | 692 va_end(args); |
688 } | 693 } |
689 | 694 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 // We keep the lowest and highest addresses mapped as a quick way of | 763 // We keep the lowest and highest addresses mapped as a quick way of |
759 // determining that pointers are outside the heap (used mostly in assertions | 764 // determining that pointers are outside the heap (used mostly in assertions |
760 // and verification). The estimate is conservative, ie, not all addresses in | 765 // and verification). The estimate is conservative, ie, not all addresses in |
761 // 'allocated' space are actually allocated to our heap. The range is | 766 // 'allocated' space are actually allocated to our heap. The range is |
762 // [lowest, highest), inclusive on the low and and exclusive on the high end. | 767 // [lowest, highest), inclusive on the low and and exclusive on the high end. |
763 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); | 768 static void* lowest_ever_allocated = reinterpret_cast<void*>(-1); |
764 static void* highest_ever_allocated = reinterpret_cast<void*>(0); | 769 static void* highest_ever_allocated = reinterpret_cast<void*>(0); |
765 | 770 |
766 | 771 |
767 static void UpdateAllocatedSpaceLimits(void* address, int size) { | 772 static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| 773 ASSERT(limit_mutex != NULL); |
| 774 ScopedLock lock(limit_mutex); |
| 775 |
768 lowest_ever_allocated = Min(lowest_ever_allocated, address); | 776 lowest_ever_allocated = Min(lowest_ever_allocated, address); |
769 highest_ever_allocated = | 777 highest_ever_allocated = |
770 Max(highest_ever_allocated, | 778 Max(highest_ever_allocated, |
771 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); | 779 reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size)); |
772 } | 780 } |
773 | 781 |
774 | 782 |
775 bool OS::IsOutsideAllocatedSpace(void* pointer) { | 783 bool OS::IsOutsideAllocatedSpace(void* pointer) { |
776 if (pointer < lowest_ever_allocated || pointer >= highest_ever_allocated) | 784 if (pointer < lowest_ever_allocated || pointer >= highest_ever_allocated) |
777 return true; | 785 return true; |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 // VirtualAlloc rounds allocated size to page size automatically. | 836 // VirtualAlloc rounds allocated size to page size automatically. |
829 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize())); | 837 size_t msize = RoundUp(requested, static_cast<int>(GetPageSize())); |
830 intptr_t address = 0; | 838 intptr_t address = 0; |
831 | 839 |
832 // Windows XP SP2 allows Data Excution Prevention (DEP). | 840 // Windows XP SP2 allows Data Excution Prevention (DEP). |
833 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; | 841 int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; |
834 | 842 |
835 // For exectutable pages try and randomize the allocation address | 843 // For exectutable pages try and randomize the allocation address |
836 if (prot == PAGE_EXECUTE_READWRITE && | 844 if (prot == PAGE_EXECUTE_READWRITE && |
837 msize >= static_cast<size_t>(Page::kPageSize)) { | 845 msize >= static_cast<size_t>(Page::kPageSize)) { |
838 address = (V8::RandomPrivate() << kPageSizeBits) | 846 address = (V8::RandomPrivate(Isolate::Current()) << kPageSizeBits) |
839 | kAllocationRandomAddressMin; | 847 | kAllocationRandomAddressMin; |
840 address &= kAllocationRandomAddressMax; | 848 address &= kAllocationRandomAddressMax; |
841 } | 849 } |
842 | 850 |
843 LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address), | 851 LPVOID mbase = VirtualAlloc(reinterpret_cast<void *>(address), |
844 msize, | 852 msize, |
845 MEM_COMMIT | MEM_RESERVE, | 853 MEM_COMMIT | MEM_RESERVE, |
846 prot); | 854 prot); |
847 if (mbase == NULL && address != 0) | 855 if (mbase == NULL && address != 0) |
848 mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot); | 856 mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot); |
849 | 857 |
850 if (mbase == NULL) { | 858 if (mbase == NULL) { |
851 LOG(StringEvent("OS::Allocate", "VirtualAlloc failed")); | 859 LOG(ISOLATE, StringEvent("OS::Allocate", "VirtualAlloc failed")); |
852 return NULL; | 860 return NULL; |
853 } | 861 } |
854 | 862 |
855 ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment())); | 863 ASSERT(IsAligned(reinterpret_cast<size_t>(mbase), OS::AllocateAlignment())); |
856 | 864 |
857 *allocated = msize; | 865 *allocated = msize; |
858 UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize)); | 866 UpdateAllocatedSpaceLimits(mbase, static_cast<int>(msize)); |
859 return mbase; | 867 return mbase; |
860 } | 868 } |
861 | 869 |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1184 0, // hFile | 1192 0, // hFile |
1185 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName | 1193 reinterpret_cast<PSTR>(module_entry.szExePath), // ImageName |
1186 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName | 1194 reinterpret_cast<PSTR>(module_entry.szModule), // ModuleName |
1187 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll | 1195 reinterpret_cast<DWORD64>(module_entry.modBaseAddr), // BaseOfDll |
1188 module_entry.modBaseSize); // SizeOfDll | 1196 module_entry.modBaseSize); // SizeOfDll |
1189 if (base == 0) { | 1197 if (base == 0) { |
1190 int err = GetLastError(); | 1198 int err = GetLastError(); |
1191 if (err != ERROR_MOD_NOT_FOUND && | 1199 if (err != ERROR_MOD_NOT_FOUND && |
1192 err != ERROR_INVALID_HANDLE) return false; | 1200 err != ERROR_INVALID_HANDLE) return false; |
1193 } | 1201 } |
1194 LOG(SharedLibraryEvent( | 1202 LOG(i::Isolate::Current(), |
| 1203 SharedLibraryEvent( |
1195 module_entry.szExePath, | 1204 module_entry.szExePath, |
1196 reinterpret_cast<unsigned int>(module_entry.modBaseAddr), | 1205 reinterpret_cast<unsigned int>(module_entry.modBaseAddr), |
1197 reinterpret_cast<unsigned int>(module_entry.modBaseAddr + | 1206 reinterpret_cast<unsigned int>(module_entry.modBaseAddr + |
1198 module_entry.modBaseSize))); | 1207 module_entry.modBaseSize))); |
1199 cont = _Module32NextW(snapshot, &module_entry); | 1208 cont = _Module32NextW(snapshot, &module_entry); |
1200 } | 1209 } |
1201 CloseHandle(snapshot); | 1210 CloseHandle(snapshot); |
1202 | 1211 |
1203 symbols_loaded = true; | 1212 symbols_loaded = true; |
1204 return true; | 1213 return true; |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1443 // Entry point for threads. The supplied argument is a pointer to the thread | 1452 // Entry point for threads. The supplied argument is a pointer to the thread |
1444 // object. The entry function dispatches to the run method in the thread | 1453 // object. The entry function dispatches to the run method in the thread |
1445 // object. It is important that this function has __stdcall calling | 1454 // object. It is important that this function has __stdcall calling |
1446 // convention. | 1455 // convention. |
1447 static unsigned int __stdcall ThreadEntry(void* arg) { | 1456 static unsigned int __stdcall ThreadEntry(void* arg) { |
1448 Thread* thread = reinterpret_cast<Thread*>(arg); | 1457 Thread* thread = reinterpret_cast<Thread*>(arg); |
1449 // This is also initialized by the last parameter to _beginthreadex() but we | 1458 // This is also initialized by the last parameter to _beginthreadex() but we |
1450 // don't know which thread will run first (the original thread or the new | 1459 // don't know which thread will run first (the original thread or the new |
1451 // one) so we initialize it here too. | 1460 // one) so we initialize it here too. |
1452 thread->thread_handle_data()->tid_ = GetCurrentThreadId(); | 1461 thread->thread_handle_data()->tid_ = GetCurrentThreadId(); |
| 1462 Thread::SetThreadLocal(Isolate::isolate_key(), thread->isolate()); |
1453 thread->Run(); | 1463 thread->Run(); |
1454 return 0; | 1464 return 0; |
1455 } | 1465 } |
1456 | 1466 |
1457 | 1467 |
1458 // Initialize thread handle to invalid handle. | 1468 // Initialize thread handle to invalid handle. |
1459 ThreadHandle::ThreadHandle(ThreadHandle::Kind kind) { | 1469 ThreadHandle::ThreadHandle(ThreadHandle::Kind kind) { |
1460 data_ = new PlatformData(kind); | 1470 data_ = new PlatformData(kind); |
1461 } | 1471 } |
1462 | 1472 |
(...skipping 23 matching lines...) Expand all Loading... |
1486 class Thread::PlatformData : public Malloced { | 1496 class Thread::PlatformData : public Malloced { |
1487 public: | 1497 public: |
1488 explicit PlatformData(HANDLE thread) : thread_(thread) {} | 1498 explicit PlatformData(HANDLE thread) : thread_(thread) {} |
1489 HANDLE thread_; | 1499 HANDLE thread_; |
1490 }; | 1500 }; |
1491 | 1501 |
1492 | 1502 |
1493 // Initialize a Win32 thread object. The thread has an invalid thread | 1503 // Initialize a Win32 thread object. The thread has an invalid thread |
1494 // handle until it is started. | 1504 // handle until it is started. |
1495 | 1505 |
1496 Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) { | 1506 Thread::Thread(Isolate* isolate) |
| 1507 : ThreadHandle(ThreadHandle::INVALID), |
| 1508 isolate_(isolate) { |
1497 data_ = new PlatformData(kNoThread); | 1509 data_ = new PlatformData(kNoThread); |
1498 set_name("v8:<unknown>"); | 1510 set_name("v8:<unknown>"); |
1499 } | 1511 } |
1500 | 1512 |
1501 | 1513 |
1502 Thread::Thread(const char* name) : ThreadHandle(ThreadHandle::INVALID) { | 1514 Thread::Thread(Isolate* isolate, const char* name) |
| 1515 : ThreadHandle(ThreadHandle::INVALID), |
| 1516 isolate_(isolate) { |
1503 data_ = new PlatformData(kNoThread); | 1517 data_ = new PlatformData(kNoThread); |
1504 set_name(name); | 1518 set_name(name); |
1505 } | 1519 } |
1506 | 1520 |
1507 | 1521 |
1508 void Thread::set_name(const char* name) { | 1522 void Thread::set_name(const char* name) { |
1509 OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name)); | 1523 OS::StrNCpy(Vector<char>(name_, sizeof(name_)), name, strlen(name)); |
1510 name_[sizeof(name_) - 1] = '\0'; | 1524 name_[sizeof(name_) - 1] = '\0'; |
1511 } | 1525 } |
1512 | 1526 |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1833 | 1847 |
1834 Socket* OS::CreateSocket() { | 1848 Socket* OS::CreateSocket() { |
1835 return new Win32Socket(); | 1849 return new Win32Socket(); |
1836 } | 1850 } |
1837 | 1851 |
1838 | 1852 |
1839 #ifdef ENABLE_LOGGING_AND_PROFILING | 1853 #ifdef ENABLE_LOGGING_AND_PROFILING |
1840 | 1854 |
1841 // ---------------------------------------------------------------------------- | 1855 // ---------------------------------------------------------------------------- |
1842 // Win32 profiler support. | 1856 // Win32 profiler support. |
1843 // | |
1844 // On win32 we use a sampler thread with high priority to sample the program | |
1845 // counter for the profiled thread. | |
1846 | 1857 |
1847 class Sampler::PlatformData : public Malloced { | 1858 class Sampler::PlatformData : public Malloced { |
1848 public: | 1859 public: |
1849 explicit PlatformData(Sampler* sampler) { | |
1850 sampler_ = sampler; | |
1851 sampler_thread_ = INVALID_HANDLE_VALUE; | |
1852 profiled_thread_ = INVALID_HANDLE_VALUE; | |
1853 } | |
1854 | |
1855 Sampler* sampler_; | |
1856 HANDLE sampler_thread_; | |
1857 HANDLE profiled_thread_; | |
1858 RuntimeProfilerRateLimiter rate_limiter_; | |
1859 | |
1860 // Sampler thread handler. | |
1861 void Runner() { | |
1862 while (sampler_->IsActive()) { | |
1863 if (rate_limiter_.SuspendIfNecessary()) continue; | |
1864 Sample(); | |
1865 Sleep(sampler_->interval_); | |
1866 } | |
1867 } | |
1868 | |
1869 void Sample() { | |
1870 if (sampler_->IsProfiling()) { | |
1871 // Context used for sampling the register state of the profiled thread. | |
1872 CONTEXT context; | |
1873 memset(&context, 0, sizeof(context)); | |
1874 | |
1875 TickSample sample_obj; | |
1876 TickSample* sample = CpuProfiler::TickSampleEvent(); | |
1877 if (sample == NULL) sample = &sample_obj; | |
1878 | |
1879 static const DWORD kSuspendFailed = static_cast<DWORD>(-1); | |
1880 if (SuspendThread(profiled_thread_) == kSuspendFailed) return; | |
1881 sample->state = Top::current_vm_state(); | |
1882 | |
1883 context.ContextFlags = CONTEXT_FULL; | |
1884 if (GetThreadContext(profiled_thread_, &context) != 0) { | |
1885 #if V8_HOST_ARCH_X64 | |
1886 sample->pc = reinterpret_cast<Address>(context.Rip); | |
1887 sample->sp = reinterpret_cast<Address>(context.Rsp); | |
1888 sample->fp = reinterpret_cast<Address>(context.Rbp); | |
1889 #else | |
1890 sample->pc = reinterpret_cast<Address>(context.Eip); | |
1891 sample->sp = reinterpret_cast<Address>(context.Esp); | |
1892 sample->fp = reinterpret_cast<Address>(context.Ebp); | |
1893 #endif | |
1894 sampler_->SampleStack(sample); | |
1895 sampler_->Tick(sample); | |
1896 } | |
1897 ResumeThread(profiled_thread_); | |
1898 } | |
1899 if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); | |
1900 } | |
1901 }; | |
1902 | |
1903 | |
1904 // Entry point for sampler thread. | |
1905 static unsigned int __stdcall SamplerEntry(void* arg) { | |
1906 Sampler::PlatformData* data = | |
1907 reinterpret_cast<Sampler::PlatformData*>(arg); | |
1908 data->Runner(); | |
1909 return 0; | |
1910 } | |
1911 | |
1912 | |
1913 // Initialize a profile sampler. | |
1914 Sampler::Sampler(int interval) | |
1915 : interval_(interval), | |
1916 profiling_(false), | |
1917 active_(false), | |
1918 samples_taken_(0) { | |
1919 data_ = new PlatformData(this); | |
1920 } | |
1921 | |
1922 | |
1923 Sampler::~Sampler() { | |
1924 delete data_; | |
1925 } | |
1926 | |
1927 | |
1928 // Start profiling. | |
1929 void Sampler::Start() { | |
1930 // Do not start multiple threads for the same sampler. | |
1931 ASSERT(!IsActive()); | |
1932 | |
1933 // Get a handle to the calling thread. This is the thread that we are | 1860 // Get a handle to the calling thread. This is the thread that we are |
1934 // going to profile. We need to make a copy of the handle because we are | 1861 // going to profile. We need to make a copy of the handle because we are |
1935 // going to use it in the sampler thread. Using GetThreadHandle() will | 1862 // going to use it in the sampler thread. Using GetThreadHandle() will |
1936 // not work in this case. We're using OpenThread because DuplicateHandle | 1863 // not work in this case. We're using OpenThread because DuplicateHandle |
1937 // for some reason doesn't work in Chrome's sandbox. | 1864 // for some reason doesn't work in Chrome's sandbox. |
1938 data_->profiled_thread_ = OpenThread(THREAD_GET_CONTEXT | | 1865 PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | |
1939 THREAD_SUSPEND_RESUME | | 1866 THREAD_SUSPEND_RESUME | |
1940 THREAD_QUERY_INFORMATION, | 1867 THREAD_QUERY_INFORMATION, |
1941 false, | 1868 false, |
1942 GetCurrentThreadId()); | 1869 GetCurrentThreadId())) {} |
1943 BOOL ok = data_->profiled_thread_ != NULL; | |
1944 if (!ok) return; | |
1945 | 1870 |
1946 // Start sampler thread. | 1871 ~PlatformData() { |
1947 unsigned int tid; | 1872 if (profiled_thread_ != NULL) { |
1948 SetActive(true); | 1873 CloseHandle(profiled_thread_); |
1949 data_->sampler_thread_ = reinterpret_cast<HANDLE>( | 1874 profiled_thread_ = NULL; |
1950 _beginthreadex(NULL, 0, SamplerEntry, data_, 0, &tid)); | 1875 } |
1951 // Set thread to high priority to increase sampling accuracy. | 1876 } |
1952 SetThreadPriority(data_->sampler_thread_, THREAD_PRIORITY_TIME_CRITICAL); | 1877 |
| 1878 HANDLE profiled_thread() { return profiled_thread_; } |
| 1879 |
| 1880 private: |
| 1881 HANDLE profiled_thread_; |
| 1882 }; |
| 1883 |
| 1884 |
| 1885 class SamplerThread : public Thread { |
| 1886 public: |
| 1887 explicit SamplerThread(int interval) : Thread(NULL), interval_(interval) {} |
| 1888 |
| 1889 static void AddActiveSampler(Sampler* sampler) { |
| 1890 ScopedLock lock(mutex_); |
| 1891 SamplerRegistry::AddActiveSampler(sampler); |
| 1892 if (instance_ == NULL) { |
| 1893 instance_ = new SamplerThread(sampler->interval()); |
| 1894 instance_->Start(); |
| 1895 } else { |
| 1896 ASSERT(instance_->interval_ == sampler->interval()); |
| 1897 } |
| 1898 } |
| 1899 |
| 1900 static void RemoveActiveSampler(Sampler* sampler) { |
| 1901 ScopedLock lock(mutex_); |
| 1902 SamplerRegistry::RemoveActiveSampler(sampler); |
| 1903 if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| 1904 RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| 1905 instance_->Join(); |
| 1906 delete instance_; |
| 1907 instance_ = NULL; |
| 1908 } |
| 1909 } |
| 1910 |
| 1911 // Implement Thread::Run(). |
| 1912 virtual void Run() { |
| 1913 SamplerRegistry::State state = SamplerRegistry::GetState(); |
| 1914 while (state != SamplerRegistry::HAS_NO_SAMPLERS) { |
| 1915 bool cpu_profiling_enabled = |
| 1916 (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| 1917 bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| 1918 // When CPU profiling is enabled both JavaScript and C++ code is |
| 1919 // profiled. We must not suspend. |
| 1920 if (!cpu_profiling_enabled) { |
| 1921 if (rate_limiter_.SuspendIfNecessary()) continue; |
| 1922 } |
| 1923 if (cpu_profiling_enabled) { |
| 1924 if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| 1925 return; |
| 1926 } |
| 1927 } |
| 1928 if (runtime_profiler_enabled) { |
| 1929 if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| 1930 return; |
| 1931 } |
| 1932 } |
| 1933 OS::Sleep(interval_); |
| 1934 } |
| 1935 } |
| 1936 |
| 1937 static void DoCpuProfile(Sampler* sampler, void* raw_sampler_thread) { |
| 1938 if (!sampler->isolate()->IsInitialized()) return; |
| 1939 if (!sampler->IsProfiling()) return; |
| 1940 SamplerThread* sampler_thread = |
| 1941 reinterpret_cast<SamplerThread*>(raw_sampler_thread); |
| 1942 sampler_thread->SampleContext(sampler); |
| 1943 } |
| 1944 |
| 1945 static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| 1946 if (!sampler->isolate()->IsInitialized()) return; |
| 1947 sampler->isolate()->runtime_profiler()->NotifyTick(); |
| 1948 } |
| 1949 |
| 1950 void SampleContext(Sampler* sampler) { |
| 1951 HANDLE profiled_thread = sampler->platform_data()->profiled_thread(); |
| 1952 if (profiled_thread == NULL) return; |
| 1953 |
| 1954 // Context used for sampling the register state of the profiled thread. |
| 1955 CONTEXT context; |
| 1956 memset(&context, 0, sizeof(context)); |
| 1957 |
| 1958 TickSample sample_obj; |
| 1959 TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate()); |
| 1960 if (sample == NULL) sample = &sample_obj; |
| 1961 |
| 1962 static const DWORD kSuspendFailed = static_cast<DWORD>(-1); |
| 1963 if (SuspendThread(profiled_thread) == kSuspendFailed) return; |
| 1964 sample->state = sampler->isolate()->current_vm_state(); |
| 1965 |
| 1966 context.ContextFlags = CONTEXT_FULL; |
| 1967 if (GetThreadContext(profiled_thread, &context) != 0) { |
| 1968 #if V8_HOST_ARCH_X64 |
| 1969 sample->pc = reinterpret_cast<Address>(context.Rip); |
| 1970 sample->sp = reinterpret_cast<Address>(context.Rsp); |
| 1971 sample->fp = reinterpret_cast<Address>(context.Rbp); |
| 1972 #else |
| 1973 sample->pc = reinterpret_cast<Address>(context.Eip); |
| 1974 sample->sp = reinterpret_cast<Address>(context.Esp); |
| 1975 sample->fp = reinterpret_cast<Address>(context.Ebp); |
| 1976 #endif |
| 1977 sampler->SampleStack(sample); |
| 1978 sampler->Tick(sample); |
| 1979 } |
| 1980 ResumeThread(profiled_thread); |
| 1981 } |
| 1982 |
| 1983 const int interval_; |
| 1984 RuntimeProfilerRateLimiter rate_limiter_; |
| 1985 |
| 1986 // Protects the process wide state below. |
| 1987 static Mutex* mutex_; |
| 1988 static SamplerThread* instance_; |
| 1989 |
| 1990 DISALLOW_COPY_AND_ASSIGN(SamplerThread); |
| 1991 }; |
| 1992 |
| 1993 |
| 1994 Mutex* SamplerThread::mutex_ = OS::CreateMutex(); |
| 1995 SamplerThread* SamplerThread::instance_ = NULL; |
| 1996 |
| 1997 |
| 1998 Sampler::Sampler(Isolate* isolate, int interval) |
| 1999 : isolate_(isolate), |
| 2000 interval_(interval), |
| 2001 profiling_(false), |
| 2002 active_(false), |
| 2003 samples_taken_(0) { |
| 2004 data_ = new PlatformData; |
1953 } | 2005 } |
1954 | 2006 |
1955 | 2007 |
1956 // Stop profiling. | 2008 Sampler::~Sampler() { |
1957 void Sampler::Stop() { | 2009 ASSERT(!IsActive()); |
1958 // Seting active to false triggers termination of the sampler | 2010 delete data_; |
1959 // thread. | |
1960 SetActive(false); | |
1961 | |
1962 // Wait for sampler thread to terminate. | |
1963 Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); | |
1964 WaitForSingleObject(data_->sampler_thread_, INFINITE); | |
1965 | |
1966 // Release the thread handles | |
1967 CloseHandle(data_->sampler_thread_); | |
1968 CloseHandle(data_->profiled_thread_); | |
1969 } | 2011 } |
1970 | 2012 |
1971 | 2013 |
| 2014 void Sampler::Start() { |
| 2015 ASSERT(!IsActive()); |
| 2016 SetActive(true); |
| 2017 SamplerThread::AddActiveSampler(this); |
| 2018 } |
| 2019 |
| 2020 |
| 2021 void Sampler::Stop() { |
| 2022 ASSERT(IsActive()); |
| 2023 SamplerThread::RemoveActiveSampler(this); |
| 2024 SetActive(false); |
| 2025 } |
| 2026 |
1972 #endif // ENABLE_LOGGING_AND_PROFILING | 2027 #endif // ENABLE_LOGGING_AND_PROFILING |
1973 | 2028 |
1974 } } // namespace v8::internal | 2029 } } // namespace v8::internal |
OLD | NEW |