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

Commit 49dce08

Browse files
authored
Enable Symbolic Rundown for EventPipe (#11582)
1 parent cb28a2c commit 49dce08

File tree

8 files changed

+163
-10
lines changed

8 files changed

+163
-10
lines changed

src/inc/eventtracebase.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,18 @@ enum EtwThreadFlags
103103

104104

105105
#else //defined(FEATURE_PAL)
106+
#if defined(FEATURE_PERFTRACING)
107+
#define ETW_INLINE
108+
#define ETWOnStartup(StartEventName, EndEventName)
109+
#define ETWFireEvent(EventName)
106110

111+
#define ETW_TRACING_INITIALIZED(RegHandle) (TRUE)
112+
#define ETW_EVENT_ENABLED(Context, EventDescriptor) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
113+
#define ETW_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
114+
#define ETW_TRACING_ENABLED(Context, EventDescriptor) (EventEnabled##EventDescriptor())
115+
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::Enabled() || XplatEventLogger::IsEventLoggingEnabled())
116+
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
117+
#else //defined(FEATURE_PERFTRACING)
107118
#define ETW_INLINE
108119
#define ETWOnStartup(StartEventName, EndEventName)
109120
#define ETWFireEvent(EventName)
@@ -114,7 +125,7 @@ enum EtwThreadFlags
114125
#define ETW_TRACING_ENABLED(Context, EventDescriptor) (EventEnabled##EventDescriptor())
115126
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (XplatEventLogger::IsEventLoggingEnabled())
116127
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
117-
128+
#endif // defined(FEATURE_PERFTRACING)
118129
#endif // !defined(FEATURE_PAL)
119130

120131
#else // FEATURE_EVENT_TRACE
@@ -217,6 +228,14 @@ extern BOOL g_fEEIJWStartup;
217228

218229
#define GetClrInstanceId() (static_cast<UINT16>(g_nClrInstanceId))
219230

231+
#if defined(FEATURE_PERFTRACING)
232+
class EventPipeHelper
233+
{
234+
public:
235+
static bool Enabled();
236+
};
237+
#endif // defined(FEATURE_PERFTRACING)
238+
220239
#if defined(FEATURE_EVENT_TRACE) || defined(FEATURE_EVENTSOURCE_XPLAT)
221240

222241
#include "clrconfig.h"

src/vm/eventpipe.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,19 @@ void EventPipe::Disable()
185185
LARGE_INTEGER disableTimeStamp;
186186
QueryPerformanceCounter(&disableTimeStamp);
187187
s_pBufferManager->WriteAllBuffersToFile(s_pFile, disableTimeStamp);
188+
189+
// Before closing the file, do rundown.
190+
s_pConfig->EnableRundown();
191+
192+
// Ask the runtime to emit rundown events.
193+
if(g_fEEStarted && !g_fEEShutDown)
194+
{
195+
ETW::EnumerationLog::EndRundown();
196+
}
197+
198+
// Disable the event pipe now that rundown is complete.
199+
s_pConfig->Disable();
200+
188201
if(s_pFile != NULL)
189202
{
190203
delete(s_pFile);
@@ -208,6 +221,19 @@ void EventPipe::Disable()
208221
}
209222
}
210223

224+
bool EventPipe::Enabled()
225+
{
226+
LIMITED_METHOD_CONTRACT;
227+
228+
bool enabled = false;
229+
if(s_pConfig != NULL)
230+
{
231+
enabled = s_pConfig->Enabled();
232+
}
233+
234+
return enabled;
235+
}
236+
211237
void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length)
212238
{
213239
CONTRACTL
@@ -233,14 +259,29 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng
233259
return;
234260
}
235261

236-
if(s_pBufferManager != NULL)
262+
if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL)
237263
{
238264
if(!s_pBufferManager->WriteEvent(pThread, event, pData, length))
239265
{
240266
// This is used in DEBUG to make sure that we don't log an event synchronously that we didn't log to the buffer.
241267
return;
242268
}
243269
}
270+
else if(s_pConfig->RundownEnabled())
271+
{
272+
// Write synchronously to the file.
273+
// We're under lock and blocking the disabling thread.
274+
EventPipeEventInstance instance(
275+
event,
276+
pThread->GetOSThreadId(),
277+
pData,
278+
length);
279+
280+
if(s_pFile != NULL)
281+
{
282+
s_pFile->WriteEvent(instance);
283+
}
284+
}
244285

245286
#ifdef _DEBUG
246287
{

src/vm/eventpipe.h

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77

88
#ifdef FEATURE_PERFTRACING
99

10-
#include "crst.h"
11-
#include "eventpipeprovider.h"
12-
#include "stackwalk.h"
13-
10+
class CrstStatic;
1411
class EventPipeConfiguration;
1512
class EventPipeEvent;
1613
class EventPipeFile;
@@ -19,6 +16,17 @@ class EventPipeBuffer;
1916
class EventPipeBufferManager;
2017
class MethodDesc;
2118
class SampleProfilerEventInstance;
19+
struct EventPipeProviderConfiguration;
20+
21+
// Define the event pipe callback to match the ETW callback signature.
22+
typedef void (*EventPipeCallback)(
23+
LPCGUID SourceID,
24+
ULONG IsEnabled,
25+
UCHAR Level,
26+
ULONGLONG MatchAnyKeywords,
27+
ULONGLONG MatchAllKeywords,
28+
void *FilterData,
29+
void *CallbackContext);
2230

2331
class StackContents
2432
{
@@ -168,6 +176,9 @@ class EventPipe
168176
// Disable tracing via the event pipe.
169177
static void Disable();
170178

179+
// Specifies whether or not the event pipe is enabled.
180+
static bool Enabled();
181+
171182
// Write out an event.
172183
// Data is written as a serialized blob matching the ETW serialization conventions.
173184
static void WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int length);
@@ -215,6 +226,25 @@ struct EventPipeProviderConfiguration
215226

216227
public:
217228

229+
EventPipeProviderConfiguration()
230+
{
231+
LIMITED_METHOD_CONTRACT;
232+
m_pProviderName = NULL;
233+
m_keywords = NULL;
234+
m_loggingLevel = 0;
235+
}
236+
237+
EventPipeProviderConfiguration(
238+
LPCWSTR pProviderName,
239+
UINT64 keywords,
240+
unsigned int loggingLevel)
241+
{
242+
LIMITED_METHOD_CONTRACT;
243+
m_pProviderName = pProviderName;
244+
m_keywords = keywords;
245+
m_loggingLevel = loggingLevel;
246+
}
247+
218248
LPCWSTR GetProviderName() const
219249
{
220250
LIMITED_METHOD_CONTRACT;

src/vm/eventpipebuffermanager.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,12 @@ bool EventPipeBufferList::EnsureConsistency()
760760
nodeCount++;
761761

762762
// Check for consistency of the buffer itself.
763-
_ASSERTE(pIter->EnsureConsistency());
763+
// NOTE: We can't check the last buffer because the owning thread could
764+
// be writing to it, which could result in false asserts.
765+
if(pIter->GetNext() != NULL)
766+
{
767+
_ASSERTE(pIter->EnsureConsistency());
768+
}
764769

765770
// Check for cycles.
766771
_ASSERTE(nodeCount <= m_bufferCount);

src/vm/eventpipeconfiguration.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ EventPipeConfiguration::EventPipeConfiguration()
1919
STANDARD_VM_CONTRACT;
2020

2121
m_enabled = false;
22+
m_rundownEnabled = false;
2223
m_circularBufferSizeInBytes = 1024 * 1024 * 1000; // Default to 1000MB.
2324
m_pEnabledProviderList = NULL;
2425
m_pProviderList = new SList<SListElem<EventPipeProvider*>>();
@@ -266,6 +267,7 @@ void EventPipeConfiguration::Disable()
266267
}
267268

268269
m_enabled = false;
270+
m_rundownEnabled = false;
269271

270272
// Free the enabled providers list.
271273
if(m_pEnabledProviderList != NULL)
@@ -281,6 +283,38 @@ bool EventPipeConfiguration::Enabled() const
281283
return m_enabled;
282284
}
283285

286+
bool EventPipeConfiguration::RundownEnabled() const
287+
{
288+
LIMITED_METHOD_CONTRACT;
289+
return m_rundownEnabled;
290+
}
291+
292+
void EventPipeConfiguration::EnableRundown()
293+
{
294+
CONTRACTL
295+
{
296+
THROWS;
297+
GC_NOTRIGGER;
298+
MODE_ANY;
299+
// Lock must be held by EventPipe::Disable.
300+
PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread());
301+
}
302+
CONTRACTL_END;
303+
304+
// Build the rundown configuration.
305+
_ASSERTE(m_pEnabledProviderList == NULL);
306+
const unsigned int numRundownProviders = 2;
307+
EventPipeProviderConfiguration rundownProviders[numRundownProviders];
308+
rundownProviders[0] = EventPipeProviderConfiguration(W("e13c0d23-ccbc-4e12-931b-d9cc2eee27e4"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Public provider.
309+
rundownProviders[1] = EventPipeProviderConfiguration(W("a669021c-c450-4609-a035-5af59af4df18"), 0x80020138, static_cast<unsigned int>(EventPipeEventLevel::Verbose)); // Rundown provider.
310+
311+
// Enable rundown.
312+
m_rundownEnabled = true;
313+
314+
// Enable tracing. The circular buffer size doesn't matter because we're going to write all events synchronously during rundown.
315+
Enable(1 /* circularBufferSizeInMB */, rundownProviders, numRundownProviders);
316+
}
317+
284318
EventPipeEventInstance* EventPipeConfiguration::BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, BYTE *pPayloadData, unsigned int payloadLength)
285319
{
286320
CONTRACTL
@@ -351,14 +385,16 @@ EventPipeEnabledProviderList::EventPipeEnabledProviderList(
351385
}
352386
CONTRACTL_END;
353387

388+
m_pProviders = NULL;
389+
m_pCatchAllProvider = NULL;
390+
m_numProviders = 0;
391+
354392
// Test COMPLUS variable to enable tracing at start-up.
355393
// If tracing is enabled at start-up create the catch-all provider and always return it.
356394
if((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerformanceTracing) & 1) == 1)
357395
{
358396
m_pCatchAllProvider = new EventPipeEnabledProvider();
359397
m_pCatchAllProvider->Set(NULL, 0xFFFFFFFF, EventPipeEventLevel::Verbose);
360-
m_pProviders = NULL;
361-
m_numProviders = 0;
362398
return;
363399
}
364400

src/vm/eventpipeconfiguration.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ class EventPipeConfiguration
6262
// Get the status of the event pipe.
6363
bool Enabled() const;
6464

65+
// Determine if rundown is enabled.
66+
bool RundownEnabled() const;
67+
68+
// Enable the well-defined symbolic rundown configuration.
69+
void EnableRundown();
70+
6571
// Get the event used to write metadata to the event stream.
6672
EventPipeEventInstance* BuildEventMetadataEvent(EventPipeEventInstance &sourceInstance, BYTE *pPayloadData = NULL, unsigned int payloadLength = 0);
6773

@@ -92,6 +98,9 @@ class EventPipeConfiguration
9298
// The provider ID for the configuration event pipe provider.
9399
// This provider is used to emit configuration events.
94100
static const GUID s_configurationProviderID;
101+
102+
// True if rundown is enabled.
103+
Volatile<bool> m_rundownEnabled;
95104
};
96105

97106
class EventPipeEnabledProviderList

src/vm/eventpipeprovider.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#ifdef FEATURE_PERFTRACING
99

10+
#include "eventpipe.h"
1011
#include "eventpipeconfiguration.h"
1112
#include "slist.h"
1213

src/vm/eventtrace.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ BOOL IsRundownNgenKeywordEnabledAndNotSuppressed()
197197
{
198198
LIMITED_METHOD_CONTRACT;
199199

200-
return
200+
return
201+
#ifdef FEATURE_PERFTRACING
202+
EventPipeHelper::Enabled() ||
203+
#endif // FEATURE_PERFTRACING
201204
(
202205
ETW_TRACING_CATEGORY_ENABLED(
203206
MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_Context,
@@ -7385,3 +7388,12 @@ VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *do
73857388
}
73867389

73877390
#endif // !FEATURE_REDHAWK
7391+
7392+
#ifdef FEATURE_PERFTRACING
7393+
#include "eventpipe.h"
7394+
bool EventPipeHelper::Enabled()
7395+
{
7396+
LIMITED_METHOD_CONTRACT;
7397+
return EventPipe::Enabled();
7398+
}
7399+
#endif // FEATURE_PERFTRACING

0 commit comments

Comments
 (0)