Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 007fa10

Browse files
authored
Indicate if thread time events are in managed or native code. (#11892) (#11898)
1 parent 7230948 commit 007fa10

File tree

8 files changed

+72
-8
lines changed

8 files changed

+72
-8
lines changed

src/vm/eventpipe.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng
357357
#endif // _DEBUG
358358
}
359359

360-
void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, Thread *pTargetThread, StackContents &stackContents)
360+
void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length)
361361
{
362362
CONTRACTL
363363
{
@@ -372,7 +372,7 @@ void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, Thread *pTarget
372372
{
373373
// Specify the sampling thread as the "current thread", so that we select the right buffer.
374374
// Specify the target thread so that the event gets properly attributed.
375-
if(!s_pBufferManager->WriteEvent(pSamplingThread, *SampleProfiler::s_pThreadTimeEvent, NULL, 0, pTargetThread, &stackContents))
375+
if(!s_pBufferManager->WriteEvent(pSamplingThread, *pEvent, pData, length, pTargetThread, &stackContents))
376376
{
377377
// This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
378378
return;
@@ -384,7 +384,7 @@ void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, Thread *pTarget
384384
GCX_PREEMP();
385385

386386
// Create an instance for the synchronous path.
387-
SampleProfilerEventInstance instance(pTargetThread);
387+
SampleProfilerEventInstance instance(*pEvent, pTargetThread, pData, length);
388388
stackContents.CopyTo(instance.GetStack());
389389

390390
// Write to the EventPipeFile.

src/vm/eventpipe.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class EventPipe
191191
static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length);
192192

193193
// Write out a sample profile event.
194-
static void WriteSampleProfileEvent(Thread *pSamplingThread, Thread *pTargetThread, StackContents &stackContents);
194+
static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
195195

196196
// Get the managed call stack for the current thread.
197197
static bool WalkManagedStackForCurrentThread(StackContents &stackContents);

src/vm/eventpipeeventinstance.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ bool EventPipeEventInstance::EnsureConsistency()
198198
}
199199
#endif // _DEBUG
200200

201-
SampleProfilerEventInstance::SampleProfilerEventInstance(Thread *pThread)
202-
:EventPipeEventInstance(*SampleProfiler::s_pThreadTimeEvent, pThread->GetOSThreadId(), NULL, 0)
201+
SampleProfilerEventInstance::SampleProfilerEventInstance(EventPipeEvent &event, Thread *pThread, BYTE *pData, unsigned int length)
202+
:EventPipeEventInstance(event, pThread->GetOSThreadId(), pData, length)
203203
{
204204
LIMITED_METHOD_CONTRACT;
205205
}

src/vm/eventpipeeventinstance.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class SampleProfilerEventInstance : public EventPipeEventInstance
8080

8181
public:
8282

83-
SampleProfilerEventInstance(Thread *pThread);
83+
SampleProfilerEventInstance(EventPipeEvent &event, Thread *pThread, BYTE *pData, unsigned int length);
8484
};
8585

8686
#endif // FEATURE_PERFTRACING

src/vm/sampleprofiler.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Thread* SampleProfiler::s_pSamplingThread = NULL;
1616
const GUID SampleProfiler::s_providerID = {0x3c530d44,0x97ae,0x513a,{0x1e,0x6d,0x78,0x3e,0x8f,0x8e,0x03,0xa9}}; // {3c530d44-97ae-513a-1e6d-783e8f8e03a9}
1717
EventPipeProvider* SampleProfiler::s_pEventPipeProvider = NULL;
1818
EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL;
19+
BYTE* SampleProfiler::s_pPayloadExternal = NULL;
20+
BYTE* SampleProfiler::s_pPayloadManaged = NULL;
1921
CLREventStatic SampleProfiler::s_threadShutdownEvent;
2022
long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms
2123

@@ -43,6 +45,15 @@ void SampleProfiler::Enable()
4345
false /* NeedStack */);
4446
}
4547

48+
if(s_pPayloadExternal == NULL)
49+
{
50+
s_pPayloadExternal = new BYTE[sizeof(unsigned int)];
51+
*((unsigned int *)s_pPayloadExternal) = static_cast<unsigned int>(SampleProfilerSampleType::External);
52+
53+
s_pPayloadManaged = new BYTE[sizeof(unsigned int)];
54+
*((unsigned int *)s_pPayloadManaged) = static_cast<unsigned int>(SampleProfilerSampleType::Managed);
55+
}
56+
4657
s_profilingEnabled = true;
4758
s_pSamplingThread = SetupUnstartedThread();
4859
if(s_pSamplingThread->CreateNewThread(0, ThreadProc, NULL))
@@ -166,8 +177,21 @@ void SampleProfiler::WalkManagedThreads()
166177
// Walk the stack and write it out as an event.
167178
if(EventPipe::WalkManagedStackForThread(pTargetThread, stackContents) && !stackContents.IsEmpty())
168179
{
169-
EventPipe::WriteSampleProfileEvent(s_pSamplingThread, pTargetThread, stackContents);
180+
// Set the payload. If the GC mode on suspension > 0, then the thread was in cooperative mode.
181+
// Even though there are some cases where this is not managed code, we assume it is managed code here.
182+
// If the GC mode on suspension == 0 then the thread was in preemptive mode, which we qualify as external here.
183+
BYTE *pPayload = s_pPayloadExternal;
184+
if(pTargetThread->GetGCModeOnSuspension())
185+
{
186+
pPayload = s_pPayloadManaged;
187+
}
188+
189+
// Write the sample.
190+
EventPipe::WriteSampleProfileEvent(s_pSamplingThread, s_pThreadTimeEvent, pTargetThread, stackContents, pPayload, c_payloadSize);
170191
}
192+
193+
// Reset the GC mode.
194+
pTargetThread->ClearGCModeOnSuspension();
171195
}
172196
}
173197

src/vm/sampleprofiler.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
#include "common.h"
1111
#include "eventpipe.h"
1212

13+
enum class SampleProfilerSampleType
14+
{
15+
Error = 0,
16+
External = 1,
17+
Managed = 2
18+
};
19+
1320
class SampleProfiler
1421
{
1522

@@ -47,6 +54,13 @@ class SampleProfiler
4754
static EventPipeProvider *s_pEventPipeProvider;
4855
static EventPipeEvent *s_pThreadTimeEvent;
4956

57+
// Event payloads.
58+
// External represents a sample in external or native code.
59+
// Managed represents a sample in managed code.
60+
static BYTE *s_pPayloadExternal;
61+
static BYTE *s_pPayloadManaged;
62+
static const unsigned int c_payloadSize = sizeof(unsigned int);
63+
5064
// Thread shutdown event for synchronization between Disable() and the sampling thread.
5165
static CLREventStatic s_threadShutdownEvent;
5266

src/vm/threads.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5346,6 +5346,10 @@ class Thread: public IUnknown
53465346
// Whether or not the thread is currently writing an event.
53475347
Volatile<bool> m_eventWriteInProgress;
53485348

5349+
// SampleProfiler thread state. This is set on suspension and cleared before restart.
5350+
// True if the thread was in cooperative mode. False if it was in preemptive when the suspension started.
5351+
Volatile<ULONG> m_gcModeOnSuspension;
5352+
53495353
public:
53505354
EventPipeBufferList* GetEventPipeBufferList()
53515355
{
@@ -5370,6 +5374,23 @@ class Thread: public IUnknown
53705374
LIMITED_METHOD_CONTRACT;
53715375
m_eventWriteInProgress = value;
53725376
}
5377+
5378+
bool GetGCModeOnSuspension()
5379+
{
5380+
LIMITED_METHOD_CONTRACT;
5381+
return m_gcModeOnSuspension;
5382+
}
5383+
5384+
void SaveGCModeOnSuspension()
5385+
{
5386+
LIMITED_METHOD_CONTRACT;
5387+
m_gcModeOnSuspension = m_fPreemptiveGCDisabled;
5388+
}
5389+
5390+
void ClearGCModeOnSuspension()
5391+
{
5392+
m_gcModeOnSuspension = 0;
5393+
}
53735394
#endif // FEATURE_PERFTRACING
53745395

53755396
#ifdef FEATURE_HIJACK

src/vm/threadsuspend.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7514,6 +7514,11 @@ void HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
75147514
if (pThread->PreemptiveGCDisabled() != TRUE)
75157515
return;
75167516

7517+
#ifdef FEATURE_PERFTRACING
7518+
// Mark that the thread is currently in managed code.
7519+
pThread->SaveGCModeOnSuspension();
7520+
#endif // FEATURE_PERFTRACING
7521+
75177522
PCODE ip = GetIP(interruptedContext);
75187523

75197524
// This function can only be called when the interrupted thread is in

0 commit comments

Comments
 (0)