summaryrefslogtreecommitdiff
path: root/src/vm/sampleprofiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/sampleprofiler.cpp')
-rw-r--r--src/vm/sampleprofiler.cpp79
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