From c6a607ace7c7ca3a9f107e02cc0cf155a677e7b9 Mon Sep 17 00:00:00 2001 From: Mukul Sabharwal Date: Sun, 6 Sep 2020 17:42:18 -0700 Subject: [PATCH] Add support for Classic ETW providers in NetPerf --- .../EventPipe/EventPipeEventSource.cs | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/TraceEvent/EventPipe/EventPipeEventSource.cs b/src/TraceEvent/EventPipe/EventPipeEventSource.cs index 56cf22ab6..2f864249b 100644 --- a/src/TraceEvent/EventPipe/EventPipeEventSource.cs +++ b/src/TraceEvent/EventPipe/EventPipeEventSource.cs @@ -2,6 +2,7 @@ using Microsoft.Diagnostics.Tracing.EventPipe; using Microsoft.Diagnostics.Tracing.Parsers; using Microsoft.Diagnostics.Tracing.Parsers.Clr; +using Microsoft.Diagnostics.Tracing.Parsers.Kernel; using Microsoft.Diagnostics.Tracing.Session; using System; using System.Collections.Generic; @@ -30,6 +31,39 @@ public unsafe class EventPipeEventSource : TraceEventDispatcher, IFastSerializab { public EventPipeEventSource(string fileName) : this(new PinnedStreamReader(fileName, 0x20000), fileName) { + // NOTE: Copied from ETWTraceEventSource.cs + + var kernelParser = new KernelTraceEventParser(this, KernelTraceEventParser.ParserTrackingOptions.None); + + kernelParser.ProcessStartGroup += delegate (ProcessTraceData data) + { + // Get just the file name without the extension. Can't use the 'Path' class because + // it tests to make certain it does not have illegal chars etc. Since KernelImageFileName + // is not a true user mode path, we can get failures. + string path = data.KernelImageFileName; + int startIdx = path.LastIndexOf('\\'); + if (0 <= startIdx) + { + startIdx++; + } + else + { + startIdx = 0; + } + + int endIdx = path.LastIndexOf('.'); + if (endIdx <= startIdx) + { + endIdx = path.Length; + } + + _processNameForID[data.ProcessID] = path.Substring(startIdx, endIdx - startIdx); + }; + + kernelParser.ProcessEndGroup += delegate (ProcessTraceData data) + { + _processNameForID.Remove(data.ProcessID); + }; } public EventPipeEventSource(Stream stream) : this(new PinnedStreamReader(stream), "stream") @@ -162,7 +196,7 @@ public override bool Process() internal EventCache EventCache { get; private set; } internal StackCache StackCache { get; private set; } - internal override string ProcessName(int processID, long timeQPC) => string.Format("Process({0})", processID); + internal override string ProcessName(int processID, long timeQPC) => _processNameForID.TryGetValue(processID, out var retVal) ? retVal : $"Process({processID})"; internal void ReadAndDispatchEvent(PinnedStreamReader reader, bool useHeaderCompression) { @@ -179,6 +213,12 @@ internal void DispatchEventRecord(TraceEventNativeMethods.EVENT_RECORD* eventRec Debug.Assert(sessionEndTimeQPC == 0 || eventRecord->EventHeader.TimeStamp - sessionEndTimeQPC < _QPCFreq * 24 * 3600); var traceEvent = Lookup(eventRecord); + + if (traceEvent.NeedsFixup) + { + traceEvent.FixupData(); + } + Dispatch(traceEvent); sessionEndTimeQPC = eventRecord->EventHeader.TimeStamp; } @@ -288,6 +328,12 @@ void ReadEventHeader(byte* headerPtr, bool useHeaderCompression, ref EventPipeEv metaDataHeader.Opcode = reader.ReadByte(); SetOpcode(eventTemplate, metaDataHeader.Opcode); } + else if (tag == EventPipeMetadataTag.WindowsClassicEventProviderGuid) + { + Debug.Assert(tagLength == 16); + metaDataHeader.SetClassicProviderGuid(reader.ReadGuid()); + SetClassicProviderId(eventTemplate, metaDataHeader.ProviderId); + } // Skip any remaining bytes or unknown tags reader.Goto(tagEndLabel); @@ -470,6 +516,12 @@ private void ParseEventParameters(DynamicTraceEventData template, EventPipeEvent return; } + private void SetClassicProviderId(DynamicTraceEventData template, in Guid guid) + { + template.taskGuid = guid; + template.lookupAsClassic = true; + } + private void SetOpcode(DynamicTraceEventData template, int opcode) { template.opcode = (TraceEventOpcode)opcode; @@ -825,6 +877,7 @@ private static void GetOpcodeFromEventName(string eventName, out int opcode, out #if SUPPORT_V1_V2 private StreamLabel _endOfEventStream; #endif + private Dictionary _processNameForID = new Dictionary(); private Dictionary _eventMetadataDictionary = new Dictionary(); private Deserializer _deserializer; private Dictionary _metadataTemplates = @@ -996,7 +1049,8 @@ internal enum NetTraceFieldLayoutVersion internal enum EventPipeMetadataTag { Opcode = 1, - ParameterPayloadV2 = 2 + ParameterPayloadV2 = 2, + WindowsClassicEventProviderGuid = 3 } /// @@ -1161,6 +1215,13 @@ public EventPipeEventMetaDataHeader(PinnedStreamReader reader, int length, Event return _eventRecord; } + internal void SetClassicProviderGuid(in Guid providerId) + { + _eventRecord->EventHeader.Flags |= TraceEventNativeMethods.EVENT_HEADER_FLAG_CLASSIC_HEADER; + _eventRecord->EventHeader.Id = 0; + _eventRecord->EventHeader.ProviderId = providerId; + } + /// /// This is a number that is unique to this meta-data blob. It is expected to be a small integer /// that starts at 1 (since 0 is reserved) and increases from there (thus an array can be used).