diff options
Diffstat (limited to 'src/vm/sampleprofiler.cpp')
-rw-r--r-- | src/vm/sampleprofiler.cpp | 79 |
1 files changed, 61 insertions, 18 deletions
diff --git a/src/vm/sampleprofiler.cpp b/src/vm/sampleprofiler.cpp index 004b3c68b0..e4721577ae 100644 --- a/src/vm/sampleprofiler.cpp +++ b/src/vm/sampleprofiler.cpp @@ -3,18 +3,24 @@ // See the LICENSE file in the project root for more information. #include "common.h" +#include "eventpipebuffermanager.h" +#include "eventpipeeventinstance.h" #include "sampleprofiler.h" #include "hosting.h" #include "threadsuspend.h" +#ifdef FEATURE_PERFTRACING + Volatile<BOOL> SampleProfiler::s_profilingEnabled = false; Thread* SampleProfiler::s_pSamplingThread = NULL; +const GUID SampleProfiler::s_providerID = {0x3c530d44,0x97ae,0x513a,{0x1e,0x6d,0x78,0x3e,0x8f,0x8e,0x03,0xa9}}; // {3c530d44-97ae-513a-1e6d-783e8f8e03a9} +EventPipeProvider* SampleProfiler::s_pEventPipeProvider = NULL; +EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL; +BYTE* SampleProfiler::s_pPayloadExternal = NULL; +BYTE* SampleProfiler::s_pPayloadManaged = NULL; CLREventStatic SampleProfiler::s_threadShutdownEvent; -#ifdef FEATURE_PAL long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms -#endif -// Synchronization of multiple callers occurs in EventPipe::Enable. void SampleProfiler::Enable() { CONTRACTL @@ -23,9 +29,31 @@ void SampleProfiler::Enable() GC_TRIGGERS; MODE_ANY; PRECONDITION(s_pSamplingThread == NULL); + // Synchronization of multiple callers occurs in EventPipe::Enable. + PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); } CONTRACTL_END; + if(s_pEventPipeProvider == NULL) + { + s_pEventPipeProvider = EventPipe::CreateProvider(s_providerID); + s_pThreadTimeEvent = s_pEventPipeProvider->AddEvent( + 0, /* eventID */ + 0, /* keywords */ + 0, /* eventVersion */ + EventPipeEventLevel::Informational, + false /* NeedStack */); + } + + if(s_pPayloadExternal == NULL) + { + s_pPayloadExternal = new BYTE[sizeof(unsigned int)]; + *((unsigned int *)s_pPayloadExternal) = static_cast<unsigned int>(SampleProfilerSampleType::External); + + s_pPayloadManaged = new BYTE[sizeof(unsigned int)]; + *((unsigned int *)s_pPayloadManaged) = static_cast<unsigned int>(SampleProfilerSampleType::Managed); + } + s_profilingEnabled = true; s_pSamplingThread = SetupUnstartedThread(); if(s_pSamplingThread->CreateNewThread(0, ThreadProc, NULL)) @@ -40,7 +68,6 @@ void SampleProfiler::Enable() } } -// Synchronization of multiple callers occurs in EventPipe::Disable. void SampleProfiler::Disable() { CONTRACTL @@ -48,6 +75,8 @@ void SampleProfiler::Disable() THROWS; GC_TRIGGERS; MODE_ANY; + // Synchronization of multiple callers occurs in EventPipe::Disable. + PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); } CONTRACTL_END; @@ -68,6 +97,12 @@ void SampleProfiler::Disable() s_threadShutdownEvent.Wait(0, FALSE /* bAlertable */); } +void SampleProfiler::SetSamplingRate(long nanoseconds) +{ + LIMITED_METHOD_CONTRACT; + s_samplingRateInNs = nanoseconds; +} + DWORD WINAPI SampleProfiler::ThreadProc(void *args) { CONTRACTL @@ -91,11 +126,7 @@ DWORD WINAPI SampleProfiler::ThreadProc(void *args) if(ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0)) { // Skip the current sample. -#ifdef FEATURE_PAL PAL_nanosleep(s_samplingRateInNs); -#else - ClrSleepEx(1, FALSE); -#endif continue; } @@ -109,15 +140,11 @@ DWORD WINAPI SampleProfiler::ThreadProc(void *args) ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */); // Wait until it's time to sample again. -#ifdef FEATURE_PAL PAL_nanosleep(s_samplingRateInNs); -#else - ClrSleepEx(1, FALSE); -#endif } } - // Destroy the sampling thread when done running. + // Destroy the sampling thread when it is done running. DestroyThread(s_pSamplingThread); s_pSamplingThread = NULL; @@ -139,17 +166,33 @@ void SampleProfiler::WalkManagedThreads() } CONTRACTL_END; - Thread *pThread = NULL; - StackContents stackContents; + Thread *pTargetThread = NULL; // Iterate over all managed threads. // Assumes that the ThreadStoreLock is held because we've suspended all threads. - while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) + while ((pTargetThread = ThreadStore::GetThreadList(pTargetThread)) != NULL) { + StackContents stackContents; + // Walk the stack and write it out as an event. - if(EventPipe::WalkManagedStackForThread(pThread, stackContents) && !stackContents.IsEmpty()) + if(EventPipe::WalkManagedStackForThread(pTargetThread, stackContents) && !stackContents.IsEmpty()) { - EventPipe::WriteSampleProfileEvent(pThread, stackContents); + // Set the payload. If the GC mode on suspension > 0, then the thread was in cooperative mode. + // Even though there are some cases where this is not managed code, we assume it is managed code here. + // If the GC mode on suspension == 0 then the thread was in preemptive mode, which we qualify as external here. + BYTE *pPayload = s_pPayloadExternal; + if(pTargetThread->GetGCModeOnSuspension()) + { + pPayload = s_pPayloadManaged; + } + + // Write the sample. + EventPipe::WriteSampleProfileEvent(s_pSamplingThread, s_pThreadTimeEvent, pTargetThread, stackContents, pPayload, c_payloadSize); } + + // Reset the GC mode. + pTargetThread->ClearGCModeOnSuspension(); } } + +#endif // FEATURE_PERFTRACING |