From: Brian Robbins Date: Wed, 21 Mar 2018 20:31:04 +0000 (-0700) Subject: Add More Process Information to EventPipe Traces (#17080) X-Git-Tag: accepted/tizen/unified/20190422.045933~2558 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b82063e24b34c875891916a1bbc01728b9022bf3;p=platform%2Fupstream%2Fcoreclr.git Add More Process Information to EventPipe Traces (#17080) --- diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs index 57c3b8f..58091be 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs @@ -175,6 +175,6 @@ namespace System.Diagnostics.Tracing 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); } } diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs index adda1b6..42061df 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipeEventProvider.cs @@ -75,7 +75,7 @@ namespace System.Diagnostics.Tracing 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; } diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index dec64f7..cb75a09 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -184,9 +184,11 @@ set(VM_SOURCES_WKS eventpipeconfiguration.cpp eventpipeevent.cpp eventpipeeventinstance.cpp + eventpipeeventsource.cpp eventpipeblock.cpp eventpipefile.cpp eventpipejsonfile.cpp + eventpipemetadatagenerator.cpp eventpipeprovider.cpp eventpipebuffer.cpp eventpipebuffermanager.cpp diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp index 5b31c8a..2b67f19 100644 --- a/src/vm/corhost.cpp +++ b/src/vm/corhost.cpp @@ -43,6 +43,7 @@ #endif // !FEATURE_PAL #include "stringarraylist.h" +#include "eventpipe.h" #ifdef FEATURE_COMINTEROP #include "winrttypenameconverter.h" @@ -368,6 +369,10 @@ void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv) } CONTRACTL_END; + // Send the command line to EventPipe. + EventPipe::SaveCommandLine(pwzAssemblyPath, argc, argv); + + // Send the command line to System.Environment. struct _gc { PTRARRAYREF cmdLineArgs; diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index 910dee5..ade5dbc 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -9,10 +9,12 @@ #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 @@ -27,6 +29,8 @@ EventPipeConfiguration* EventPipe::s_pConfig = NULL; 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; @@ -57,7 +61,7 @@ EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length) m_size = length; } -EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned int eventDataCount) +EventPipeEventPayload::EventPipeEventPayload(EventData *pEventData, unsigned int eventDataCount) { CONTRACTL { @@ -75,7 +79,7 @@ EventPipeEventPayload::EventPipeEventPayload(EventData **pEventData, unsigned in S_UINT32 tmp_size = S_UINT32(0); for (unsigned int i=0; iEnable(pSession); + // Take the lock before enabling tracing. CrstHolder _crst(GetLock()); @@ -360,6 +378,12 @@ void EventPipe::Disable() // 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); @@ -447,7 +471,7 @@ EventPipeProvider* EventPipe::CreateProvider(const SString &providerName, EventP CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -509,7 +533,7 @@ void EventPipe::WriteEvent(EventPipeEvent &event, BYTE *pData, unsigned int leng 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 { @@ -901,6 +925,47 @@ void EventPipe::GetConfigurationFromEnvironment(SString &outputPath, EventPipeSe } } +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; iAddEvent( + 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 diff --git a/src/vm/eventpipeeventsource.h b/src/vm/eventpipeeventsource.h new file mode 100644 index 0000000..67adb43 --- /dev/null +++ b/src/vm/eventpipeeventsource.h @@ -0,0 +1,33 @@ +// 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__ diff --git a/src/vm/eventpipefile.cpp b/src/vm/eventpipefile.cpp index 3346ee5..907a5dc 100644 --- a/src/vm/eventpipefile.cpp +++ b/src/vm/eventpipefile.cpp @@ -51,13 +51,17 @@ EventPipeFile::EventPipeFile( 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(); - 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() diff --git a/src/vm/eventpipemetadatagenerator.cpp b/src/vm/eventpipemetadatagenerator.cpp new file mode 100644 index 0000000..3b17e41 --- /dev/null +++ b/src/vm/eventpipemetadatagenerator.cpp @@ -0,0 +1,97 @@ +// 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; iType; + 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 diff --git a/src/vm/eventpipemetadatagenerator.h b/src/vm/eventpipemetadatagenerator.h new file mode 100644 index 0000000..2886fce --- /dev/null +++ b/src/vm/eventpipemetadatagenerator.h @@ -0,0 +1,63 @@ +// 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__ diff --git a/tests/src/tracing/tracevalidation/tracelogging/EventSourceTest.cs b/tests/src/tracing/tracevalidation/tracelogging/EventSourceTest.cs index 4ef9eb2..79969ea 100644 --- a/tests/src/tracing/tracevalidation/tracelogging/EventSourceTest.cs +++ b/tests/src/tracing/tracevalidation/tracelogging/EventSourceTest.cs @@ -72,6 +72,11 @@ namespace Tracing.Tests.Common 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 {