internal static extern unsafe void WriteEvent(IntPtr eventHandle, uint eventID, void* pData, uint length, Guid* activityId, Guid* relatedActivityId);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
- internal static extern unsafe void WriteEventData(IntPtr eventHandle, uint eventID, EventProvider.EventData** pEventData, uint dataCount, Guid* activityId, Guid* relatedActivityId);
+ internal static extern unsafe void WriteEventData(IntPtr eventHandle, uint eventID, EventProvider.EventData* pEventData, uint dataCount, Guid* activityId, Guid* relatedActivityId);
}
}
userDataCount = userDataCount - 3;
Debug.Assert(userDataCount >= 0);
}
- EventPipeInternal.WriteEventData(eventHandle, eventID, &userData, (uint) userDataCount, activityId, relatedActivityId);
+ EventPipeInternal.WriteEventData(eventHandle, eventID, userData, (uint) userDataCount, activityId, relatedActivityId);
}
return 0;
}
eventpipeconfiguration.cpp
eventpipeevent.cpp
eventpipeeventinstance.cpp
+ eventpipeeventsource.cpp
eventpipeblock.cpp
eventpipefile.cpp
eventpipejsonfile.cpp
+ eventpipemetadatagenerator.cpp
eventpipeprovider.cpp
eventpipebuffer.cpp
eventpipebuffermanager.cpp
#endif // !FEATURE_PAL
#include "stringarraylist.h"
+#include "eventpipe.h"
#ifdef FEATURE_COMINTEROP
#include "winrttypenameconverter.h"
}
CONTRACTL_END;
+ // Send the command line to EventPipe.
+ EventPipe::SaveCommandLine(pwzAssemblyPath, argc, argv);
+
+ // Send the command line to System.Environment.
struct _gc
{
PTRARRAYREF cmdLineArgs;
#include "eventpipebuffermanager.h"
#include "eventpipeconfiguration.h"
#include "eventpipeevent.h"
+#include "eventpipeeventsource.h"
#include "eventpipefile.h"
#include "eventpipeprovider.h"
#include "eventpipesession.h"
#include "eventpipejsonfile.h"
+#include "eventtracebase.h"
#include "sampleprofiler.h"
#ifdef FEATURE_PAL
EventPipeSession* EventPipe::s_pSession = NULL;
EventPipeBufferManager* EventPipe::s_pBufferManager = NULL;
EventPipeFile* EventPipe::s_pFile = NULL;
+EventPipeEventSource* EventPipe::s_pEventSource = NULL;
+LPCWSTR EventPipe::s_pCommandLine = NULL;
#ifdef _DEBUG
EventPipeFile* EventPipe::s_pSyncFile = NULL;
EventPipeJsonFile* EventPipe::s_pJsonFile = NULL;
m_size = length;
}
-EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount)
+EventPipeEventPayload::EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount)
{
CONTRACTL
{
S_UINT32 tmp_size = S_UINT32(0);
for (unsigned int i=0; i<m_eventDataCount; i++)
{
- tmp_size += S_UINT32((*m_pEventData)[i].Size);
+ tmp_size += S_UINT32(m_pEventData[i].Size);
}
if (tmp_size.IsOverflow())
unsigned int offset = 0;
for(unsigned int i=0; i<m_eventDataCount; i++)
{
- memcpy(pDst + offset, (BYTE*)(*m_pEventData)[i].Ptr, (*m_pEventData)[i].Size);
- offset += (*m_pEventData)[i].Size;
+ memcpy(pDst + offset, (BYTE*) m_pEventData[i].Ptr, m_pEventData[i].Size);
+ offset += m_pEventData[i].Size;
}
}
}
s_pBufferManager = new EventPipeBufferManager();
+ s_pEventSource = new EventPipeEventSource();
+
// This calls into auto-generated code to initialize the runtime providers
// and events so that the EventPipe configuration lock isn't taken at runtime
InitProvidersAndEvents();
s_pBufferManager = NULL;
FlushProcessWriteBuffers();
- // Free the configuration and buffer manager.
+ // Free resources.
delete(pConfig);
delete(pBufferManager);
+ delete(s_pEventSource);
+ s_pEventSource = NULL;
+
+ // On Windows, this is just a pointer to the return value from
+ // GetCommandLineW(), so don't attempt to free it.
+#ifdef FEATURE_PAL
+ delete[](s_pCommandLine);
+ s_pCommandLine = NULL;
+#endif
}
void EventPipe::Enable(
return;
}
+ // Enable the EventPipe EventSource.
+ s_pEventSource->Enable(pSession);
+
// Take the lock before enabling tracing.
CrstHolder _crst(GetLock());
// Disable the profiler.
SampleProfiler::Disable();
+ // Log the process information event.
+ s_pEventSource->SendProcessInfo(s_pCommandLine);
+
+ // Log the runtime information event.
+ ETW::InfoLog::RuntimeInformation(ETW::InfoLog::InfoStructs::Normal);
+
// Disable tracing.
s_pConfig->Disable(s_pSession);
CONTRACTL
{
THROWS;
- GC_TRIGGERS;
+ GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
EventPipe::WriteEventInternal(event, payload, pActivityId, pRelatedActivityId);
}
-void EventPipe::WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
+void EventPipe::WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId)
{
CONTRACTL
{
}
}
+void EventPipe::SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pwzAssemblyPath != NULL);
+ PRECONDITION(argc <= 0 || argv != NULL);
+ }
+ CONTRACTL_END;
+
+ // Get the command line.
+ LPCWSTR osCommandLine = GetCommandLineW();
+
+#ifndef FEATURE_PAL
+ // On Windows, osCommandLine contains the executable and all arguments.
+ s_pCommandLine = osCommandLine;
+#else
+ // On UNIX, the PAL doesn't have the command line arguments, so we must build the command line.
+ // osCommandLine contains the full path to the executable.
+ SString commandLine(osCommandLine);
+ commandLine.Append((WCHAR)' ');
+ commandLine.Append(pwzAssemblyPath);
+
+ for(int i=0; i<argc; i++)
+ {
+ commandLine.Append((WCHAR)' ');
+ commandLine.Append(argv[i]);
+ }
+
+ // Allocate a new string for the command line.
+ SIZE_T commandLineLen = commandLine.GetCount();
+ WCHAR *pCommandLine = new WCHAR[commandLineLen + 1];
+ wcsncpy(pCommandLine, commandLine.GetUnicode(), commandLineLen);
+ pCommandLine[commandLineLen] = '\0';
+
+ s_pCommandLine = pCommandLine;
+#endif
+}
+
void QCALLTYPE EventPipeInternal::Enable(
__in_z LPCWSTR outputFile,
UINT32 circularBufferSizeInMB,
void QCALLTYPE EventPipeInternal::WriteEventData(
INT_PTR eventHandle,
UINT32 eventID,
- EventData **pEventData,
+ EventData *pEventData,
UINT32 eventDataCount,
LPCGUID pActivityId,
LPCGUID pRelatedActivityId)
class EventPipeJsonFile;
class EventPipeBuffer;
class EventPipeBufferManager;
+class EventPipeEventSource;
class EventPipeProvider;
class MethodDesc;
class SampleProfilerEventInstance;
struct EventData
{
public:
- unsigned long Ptr;
+ UINT64 Ptr;
unsigned int Size;
unsigned int Reserved;
};
{
private:
BYTE *m_pData;
- EventData **m_pEventData;
+ EventData *m_pEventData;
unsigned int m_eventDataCount;
unsigned int m_size;
bool m_allocatedData;
EventPipeEventPayload(BYTE *pData, unsigned int length);
// Build this payload to contain an array of EventData objects
- EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount);
+ EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount);
// If a buffer was allocated internally, delete it
~EventPipeEventPayload();
return m_size;
}
- EventData** GetEventDataArray() const
+ EventData* GetEventDataArray() const
{
LIMITED_METHOD_CONTRACT;
// Write out an event from an EventData array.
// Data is written as a serialized blob matching the ETW serialization conventions.
- static void WriteEvent(EventPipeEvent &event, EventData **pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
+ static void WriteEvent(EventPipeEvent &event, EventData *pEventData, unsigned int eventDataCount, LPCGUID pActivityId = NULL, LPCGUID pRelatedActivityId = NULL);
// Write out a sample profile event.
static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0);
// Get the managed call stack for the specified thread.
static bool WalkManagedStackForThread(Thread *pThread, StackContents &stackContents);
+ // Save the command line for the current process.
+ static void SaveCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv);
+
protected:
// The counterpart to WriteEvent which after the payload is constructed
static EventPipeSession *s_pSession;
static EventPipeBufferManager *s_pBufferManager;
static EventPipeFile *s_pFile;
+ static EventPipeEventSource *s_pEventSource;
+ static LPCWSTR s_pCommandLine;
#ifdef _DEBUG
static EventPipeFile *s_pSyncFile;
static EventPipeJsonFile *s_pJsonFile;
static void QCALLTYPE WriteEventData(
INT_PTR eventHandle,
UINT32 eventID,
- EventData **pEventData,
+ EventData *pEventData,
UINT32 eventDataCount,
LPCGUID pActivityId, LPCGUID pRelatedActivityId);
};
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "eventpipeeventsource.h"
+#include "eventpipe.h"
+#include "eventpipeevent.h"
+#include "eventpipemetadatagenerator.h"
+#include "eventpipeprovider.h"
+#include "eventpipesession.h"
+
+#ifdef FEATURE_PERFTRACING
+
+const WCHAR* EventPipeEventSource::s_pProviderName = W("Microsoft-DotNETCore-EventPipe");
+const WCHAR* EventPipeEventSource::s_pProcessInfoEventName = W("ProcessInfo");
+
+EventPipeEventSource::EventPipeEventSource()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_pProvider = EventPipe::CreateProvider(SL(s_pProviderName), NULL, NULL);
+
+ // Generate metadata.
+ const unsigned int numParams = 1;
+ EventPipeParameterDesc params[numParams];
+ params[0].Type = EventPipeParameterType::String;
+ params[0].Name = W("CommandLine");
+
+ size_t metadataLength = 0;
+ BYTE *pMetadata = EventPipeMetadataGenerator::GenerateEventMetadata(
+ 1, /* eventID */
+ s_pProcessInfoEventName,
+ 0, /* keywords */
+ 0, /* version */
+ EventPipeEventLevel::LogAlways,
+ params,
+ numParams,
+ metadataLength);
+
+ // Add the event.
+ m_pProcessInfoEvent = m_pProvider->AddEvent(
+ 1, /* eventID */
+ 0, /* keywords */
+ 0, /* eventVersion */
+ EventPipeEventLevel::LogAlways,
+ pMetadata,
+ (unsigned int)metadataLength);
+
+ // Delete the metadata after the event is created.
+ // The metadata blob will be copied into EventPipe-owned memory.
+ delete(pMetadata);
+}
+
+EventPipeEventSource::~EventPipeEventSource()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Delete the provider and associated events.
+ // This is called in the shutdown path which can't throw.
+ // Catch exceptions and ignore failures.
+ EX_TRY
+ {
+ EventPipe::DeleteProvider(m_pProvider);
+ }
+ EX_CATCH { }
+ EX_END_CATCH(SwallowAllExceptions);
+}
+
+void EventPipeEventSource::Enable(EventPipeSession *pSession)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(pSession != NULL);
+ }
+ CONTRACTL_END;
+
+ EventPipeSessionProvider *pSessionProvider = new EventPipeSessionProvider(
+ s_pProviderName,
+ -1,
+ EventPipeEventLevel::LogAlways);
+ pSession->AddSessionProvider(pSessionProvider);
+}
+
+void EventPipeEventSource::SendProcessInfo(LPCWSTR pCommandLine)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ EventData data[1];
+ data[0].Ptr = (UINT64) pCommandLine;
+ data[0].Size = (unsigned int)(wcslen(pCommandLine) + 1) * 2;
+ data[0].Reserved = 0;
+
+ EventPipe::WriteEvent(*m_pProcessInfoEvent, data, 1);
+}
+
+#endif // FEATURE_PERFTRACING
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPE_EVENTSOURCE_H__
+#define __EVENTPIPE_EVENTSOURCE_H__
+
+#ifdef FEATURE_PERFTRACING
+
+class EventPipeProvider;
+class EventPipeEvent;
+class EventPipeSession;
+
+class EventPipeEventSource
+{
+private:
+ const static WCHAR* s_pProviderName;
+ EventPipeProvider *m_pProvider;
+
+ const static WCHAR* s_pProcessInfoEventName;
+ EventPipeEvent *m_pProcessInfoEvent;
+
+public:
+ EventPipeEventSource();
+ ~EventPipeEventSource();
+
+ void Enable(EventPipeSession *pSession);
+ void SendProcessInfo(LPCWSTR pCommandLine);
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_EVENTSOURCE_H__
m_samplingRateInNs = SampleProfiler::GetSamplingRate();
- m_pSerializer = new FastSerializer(outputFilePath); // it creates the file stream and writes the header
+ // Create the file stream and write the header.
+ m_pSerializer = new FastSerializer(outputFilePath);
+
m_serializationLock.Init(LOCK_TYPE_DEFAULT);
m_pMetadataIds = new MapSHashWithRemove<EventPipeEvent*, unsigned int>();
- m_metadataIdCounter = 0; // we start with 0, it's always gets incremented by generator so the first id will be 1, as specified in the docs
+ // Start and 0 - The value is always incremented prior to use, so the first ID will be 1.
+ m_metadataIdCounter = 0;
- m_pSerializer->WriteObject(this); // this is the first object in the file
+ // Write the first object to the file.
+ m_pSerializer->WriteObject(this);
}
EventPipeFile::~EventPipeFile()
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "eventpipemetadatagenerator.h"
+#include "eventpipe.h"
+
+#ifdef FEATURE_PERFTRACING
+
+BYTE* EventPipeMetadataGenerator::GenerateEventMetadata(
+ unsigned int eventID,
+ LPCWSTR pEventName,
+ INT64 keywords,
+ unsigned int version,
+ EventPipeEventLevel level,
+ EventPipeParameterDesc *pParams,
+ unsigned int paramCount,
+ size_t &metadataLength)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(pEventName != NULL);
+ PRECONDITION(paramCount == 0 || pParams != NULL);
+ }
+ CONTRACTL_END;
+
+ // eventID : 4 bytes
+ // eventName : (eventName.Length + 1) * 2 bytes
+ // keywords : 8 bytes
+ // eventVersion : 4 bytes
+ // level : 4 bytes
+ // parameterCount : 4 bytes
+ size_t eventNameLength = wcslen(pEventName);
+ metadataLength = 24 + ((eventNameLength + 1) * sizeof(WCHAR));
+
+ // Each parameter has a 4 byte TypeCode + (parameterName.Length + 1) * 2 bytes.
+ for(unsigned int i=0; i<paramCount; i++)
+ {
+ _ASSERTE(pParams[i].Name != NULL);
+
+ metadataLength += (4 + ((wcslen(pParams[i].Name) + 1) * sizeof(WCHAR)));
+ }
+
+ // Allocate a metadata blob.
+ BYTE *pMetadata = new BYTE[metadataLength];
+ BYTE *pCurrent = pMetadata;
+
+ // Write the event ID.
+ *((unsigned int *)pCurrent) = eventID;
+ pCurrent += sizeof(unsigned int);
+
+ // Write the event name.
+ wcsncpy((WCHAR *)pCurrent, pEventName, eventNameLength);
+ pCurrent += eventNameLength * sizeof(WCHAR);
+ *((WCHAR *)pCurrent) = W('\0');
+ pCurrent += sizeof(WCHAR);
+
+ // Write the keywords.
+ *((INT64 *)pCurrent) = keywords;
+ pCurrent += sizeof(INT64);
+
+ // Write the version.
+ *((unsigned int *)pCurrent) = version;
+ pCurrent += sizeof(unsigned int);
+
+ // Write the level.
+ *((unsigned int *)pCurrent) = (unsigned int)level;
+ pCurrent += sizeof(unsigned int);
+
+ // Write the parameter count.
+ *((unsigned int *)pCurrent) = paramCount;
+ pCurrent += sizeof(unsigned int);
+
+ // Write the parameter descriptions.
+ for(unsigned int i=0; i<paramCount; i++)
+ {
+ EventPipeParameterDesc *pParam = &pParams[i];
+ *((unsigned int *)pCurrent) = (unsigned int)pParam->Type;
+ pCurrent += sizeof(unsigned int);
+
+ size_t parameterNameLength = wcslen(pParam->Name);
+ wcsncpy((WCHAR *)pCurrent, pParam->Name, parameterNameLength);
+ pCurrent += parameterNameLength * sizeof(WCHAR);
+ *((WCHAR *)pCurrent) = W('\0');
+ pCurrent += sizeof(WCHAR);
+ }
+
+ _ASSERTE(metadataLength == (pCurrent - pMetadata));
+
+ return pMetadata;
+}
+
+#endif // FEATURE_PERFTRACING
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __EVENTPIPE_METADATAGENERATOR_H__
+#define __EVENTPIPE_METADATAGENERATOR_H__
+
+#ifdef FEATURE_PERFTRACING
+
+enum class EventPipeEventLevel;
+
+// Represents the type of an event parameter.
+// This enum is derived from the managed TypeCode type, though
+// not all of these values are available in TypeCode.
+// For example, Guid does not exist in TypeCode.
+enum class EventPipeParameterType
+{
+ Empty = 0, // Null reference
+ Object = 1, // Instance that isn't a value
+ DBNull = 2, // Database null value
+ Boolean = 3, // Boolean
+ Char = 4, // Unicode character
+ SByte = 5, // Signed 8-bit integer
+ Byte = 6, // Unsigned 8-bit integer
+ Int16 = 7, // Signed 16-bit integer
+ UInt16 = 8, // Unsigned 16-bit integer
+ Int32 = 9, // Signed 32-bit integer
+ UInt32 = 10, // Unsigned 32-bit integer
+ Int64 = 11, // Signed 64-bit integer
+ UInt64 = 12, // Unsigned 64-bit integer
+ Single = 13, // IEEE 32-bit float
+ Double = 14, // IEEE 64-bit double
+ Decimal = 15, // Decimal
+ DateTime = 16, // DateTime
+ Guid = 17, // Guid
+ String = 18, // Unicode character string
+};
+
+// Contains the metadata associated with an EventPipe event parameter.
+struct EventPipeParameterDesc
+{
+ EventPipeParameterType Type;
+ LPCWSTR Name;
+};
+
+// Generates metadata for an event emitted by the EventPipe.
+class EventPipeMetadataGenerator
+{
+public:
+ static BYTE* GenerateEventMetadata(
+ unsigned int eventID,
+ LPCWSTR pEventName,
+ INT64 keywords,
+ unsigned int version,
+ EventPipeEventLevel level,
+ EventPipeParameterDesc *pParams,
+ unsigned int paramCount,
+ size_t &metadataLength);
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __EVENTPIPE_METADATAGENERATOR_H__
return;
}
+ if(data.ProviderName.Equals("Microsoft-DotNETCore-EventPipe"))
+ {
+ return;
+ }
+
Assert.True($"m_nextTestVerificationIndex({m_nextTestVerificationIndex}) < m_tests.Count({m_tests.Count})", m_nextTestVerificationIndex < m_tests.Count);
try
{