internal override unsafe Guid GetRelatedActivityID(TraceEventNativeMethods.EVENT_RECORD *eventRecord) { // Recover the EventPipeEventHeader from the payload pointer and then fetch from the header. EventPipeEventHeader *event_ = EventPipeEventHeader.HeaderFromPayloadPointer((byte *)eventRecord->UserData); return(event_->RelatedActivityID); }
/// <summary> /// Given a EventPipeEventHeader takes a EventPipeEventHeader that is specific to an event, copies it /// on top of the static information in its EVENT_RECORD which is specialized this this meta-data /// and returns a pinter to it. Thus this makes the EventPipe look like an ETW provider from /// the point of view of the upper level TraceEvent logic. /// </summary> internal TraceEventNativeMethods.EVENT_RECORD *GetEventRecordForEventData(EventPipeEventHeader * eventData) { // We have already initialize all the fields of _eventRecord that do no vary from event to event. // Now we only have to copy over the fields that are specific to particular event. _eventRecord->EventHeader.ThreadId = eventData->ThreadId; _eventRecord->EventHeader.TimeStamp = eventData->TimeStamp; _eventRecord->EventHeader.ActivityId = eventData->ActivityID; // EVENT_RECORD does not field for ReleatedActivityID (because it is rarely used). See GetRelatedActivityID; _eventRecord->UserDataLength = (ushort)eventData->PayloadSize; // TODO the extra || operator is a hack becase the runtime actually tries to emit events that // exceed this for the GC/BulkSurvivingObjectRanges (event id == 21). We supress that assert // for now but this is a real bug in the runtime's event logging. ETW can't handle payloads > 64K. Debug.Assert(_eventRecord->UserDataLength == eventData->PayloadSize || _eventRecord->EventHeader.ProviderId == ClrTraceEventParser.ProviderGuid && _eventRecord->EventHeader.Id == 21); _eventRecord->UserData = (IntPtr)eventData->Payload; int stackBytesSize = EventPipeEventHeader.StackBytesSize(eventData); // TODO remove once .NET Core has been fixed to not emit stacks on CLR method events which are just for bookeeping. if (ProviderId == ClrRundownTraceEventParser.ProviderGuid || (ProviderId == ClrTraceEventParser.ProviderGuid && (140 <= EventId && EventId <= 144 || EventId == 190))) // These are various CLR method Events. { stackBytesSize = 0; } if (0 < stackBytesSize) { // Lazy allocation (destructor frees it). if (_eventRecord->ExtendedData == null) { _eventRecord->ExtendedData = (TraceEventNativeMethods.EVENT_HEADER_EXTENDED_DATA_ITEM *)Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_HEADER_EXTENDED_DATA_ITEM)); } if ((_eventRecord->EventHeader.Flags & TraceEventNativeMethods.EVENT_HEADER_FLAG_32_BIT_HEADER) != 0) { _eventRecord->ExtendedData->ExtType = TraceEventNativeMethods.EVENT_HEADER_EXT_TYPE_STACK_TRACE32; } else { _eventRecord->ExtendedData->ExtType = TraceEventNativeMethods.EVENT_HEADER_EXT_TYPE_STACK_TRACE64; } // DataPtr should point at a EVENT_EXTENDED_ITEM_STACK_TRACE*. These have a ulong MatchID field which is NOT USED before the stack data. // Since that field is not used, I can backup the pointer by 8 bytes and synthesize a EVENT_EXTENDED_ITEM_STACK_TRACE from the raw buffer // of stack data without having to copy. _eventRecord->ExtendedData->DataSize = (ushort)(stackBytesSize + 8); _eventRecord->ExtendedData->DataPtr = (ulong)(EventPipeEventHeader.StackBytes(eventData) - 8); _eventRecord->ExtendedDataCount = 1; // Mark that we have the stack data. } else { _eventRecord->ExtendedDataCount = 0; } return(_eventRecord); }
internal TraceEventNativeMethods.EVENT_RECORD *ReadEvent(PinnedStreamReader reader) { EventPipeEventHeader *eventData = (EventPipeEventHeader *)reader.GetPointer(EventPipeEventHeader.HeaderSize); eventData = (EventPipeEventHeader *)reader.GetPointer(eventData->TotalEventSize); // now we now the real size and get read entire event // Basic sanity checks. Are the timestamps and sizes sane. Debug.Assert(sessionEndTimeQPC <= eventData->TimeStamp); Debug.Assert(sessionEndTimeQPC == 0 || eventData->TimeStamp - sessionEndTimeQPC < _QPCFreq * 24 * 3600); Debug.Assert(0 <= eventData->PayloadSize && eventData->PayloadSize <= eventData->TotalEventSize); Debug.Assert(0 < eventData->TotalEventSize && eventData->TotalEventSize < 0x20000); // TODO really should be 64K but BulkSurvivingObjectRanges needs fixing. Debug.Assert(_fileFormatVersionNumber < 3 || ((int)EventPipeEventHeader.PayloadBytes(eventData) % 4 == 0 && eventData->TotalEventSize % 4 == 0)); // ensure 4 byte alignment StreamLabel eventDataEnd = reader.Current.Add(eventData->TotalEventSize); Debug.Assert(0 <= EventPipeEventHeader.StackBytesSize(eventData) && EventPipeEventHeader.StackBytesSize(eventData) <= eventData->TotalEventSize); TraceEventNativeMethods.EVENT_RECORD *ret = null; if (eventData->IsMetadata()) { int totalEventSize = eventData->TotalEventSize; int payloadSize = eventData->PayloadSize; // Note that this skip invalidates the eventData pointer, so it is important to pull any fields out we need first. reader.Skip(EventPipeEventHeader.HeaderSize); StreamLabel metaDataEnd = reader.Current.Add(payloadSize); // Read in the header (The header does not include payload parameter information) var metaDataHeader = new EventPipeEventMetaDataHeader(reader, payloadSize, _fileFormatVersionNumber, PointerSize, _processId); _eventMetadataDictionary.Add(metaDataHeader.MetaDataId, metaDataHeader); // Tell the parser about this new event _eventParser.OnNewEventPipeEventDefinition(metaDataHeader, reader); Debug.Assert(reader.Current == metaDataEnd); // We should have read all the meta-data. int stackBytes = reader.ReadInt32(); Debug.Assert(stackBytes == 0, "Meta-data events should always have a empty stack"); } else { if (_eventMetadataDictionary.TryGetValue(eventData->MetaDataId, out var metaData)) { ret = metaData.GetEventRecordForEventData(eventData); } else { Debug.Assert(false, "Warning can't find metaData for ID " + eventData->MetaDataId.ToString("x")); } } reader.Goto(eventDataEnd); return(ret); }
private TraceEventNativeMethods.EVENT_RECORD *ReadEvent(PinnedStreamReader reader) { // Guess that the event is < 1000 bytes or whatever is left in the stream. int eventSizeGuess = Math.Min(1000, _endOfEventStream.Sub(reader.Current)); EventPipeEventHeader *eventData = (EventPipeEventHeader *)reader.GetPointer(eventSizeGuess); // Basic sanity checks. Are the timestamps and sizes sane. Debug.Assert(sessionEndTimeQPC <= eventData->TimeStamp); Debug.Assert(sessionEndTimeQPC == 0 || eventData->TimeStamp - sessionEndTimeQPC < _QPCFreq * 24 * 3600); Debug.Assert(0 <= eventData->PayloadSize && eventData->PayloadSize <= eventData->TotalEventSize); Debug.Assert(eventData->MetaDataId <= reader.Current); // IDs are the location in the of of the data, so it comes before Debug.Assert(0 < eventData->TotalEventSize && eventData->TotalEventSize < 0x20000); // TODO really should be 64K but BulkSurvivingObjectRanges needs fixing. if (eventSizeGuess < eventData->TotalEventSize) { eventData = (EventPipeEventHeader *)reader.GetPointer(eventData->TotalEventSize); } Debug.Assert(0 <= EventPipeEventHeader.StackBytesSize(eventData) && EventPipeEventHeader.StackBytesSize(eventData) <= eventData->TotalEventSize); // This asserts that the header size + payload + stackSize field + StackSize == TotalEventSize; Debug.Assert(eventData->PayloadSize + EventPipeEventHeader.HeaderSize + sizeof(int) + EventPipeEventHeader.StackBytesSize(eventData) == eventData->TotalEventSize); TraceEventNativeMethods.EVENT_RECORD *ret = null; EventPipeEventMetaData metaData; if (eventData->MetaDataId == 0) // Is this a Meta-data event? { int totalEventSize = eventData->TotalEventSize; int payloadSize = eventData->PayloadSize; StreamLabel metaDataStreamOffset = reader.Current; // Used as the 'id' for the meta-data // Note that this skip invalidates the eventData pointer, so it is important to pull any fields out we need first. reader.Skip(EventPipeEventHeader.HeaderSize); metaData = new EventPipeEventMetaData(reader, payloadSize, _fileFormatVersionNumber, PointerSize, _processId); _eventMetadataDictionary.Add(metaDataStreamOffset, metaData); _eventParser.AddTemplate(metaData); int stackBytes = reader.ReadInt32(); // Meta-data events should always have a empty stack. Debug.Assert(stackBytes == 0); // We have read all the bytes in the event Debug.Assert(reader.Current == metaDataStreamOffset.Add(totalEventSize)); } else { if (_eventMetadataDictionary.TryGetValue(eventData->MetaDataId, out metaData)) { ret = metaData.GetEventRecordForEventData(eventData); } else { Debug.Assert(false, "Warning can't find metaData for ID " + eventData->MetaDataId.ToString("x")); } reader.Skip(eventData->TotalEventSize); } return(ret); }
internal TraceEventNativeMethods.EVENT_RECORD *ReadEvent(PinnedStreamReader reader) { EventPipeEventHeader *eventData = (EventPipeEventHeader *)reader.GetPointer(EventPipeEventHeader.HeaderSize); eventData = (EventPipeEventHeader *)reader.GetPointer(eventData->TotalEventSize); // now we now the real size and get read entire event // Basic sanity checks. Are the timestamps and sizes sane. Debug.Assert(sessionEndTimeQPC <= eventData->TimeStamp); Debug.Assert(sessionEndTimeQPC == 0 || eventData->TimeStamp - sessionEndTimeQPC < _QPCFreq * 24 * 3600); Debug.Assert(0 <= eventData->PayloadSize && eventData->PayloadSize <= eventData->TotalEventSize); Debug.Assert(0 < eventData->TotalEventSize && eventData->TotalEventSize < 0x20000); // TODO really should be 64K but BulkSurvivingObjectRanges needs fixing. Debug.Assert(_fileFormatVersionNumber < 3 || ((int)EventPipeEventHeader.PayloadBytes(eventData) % 4 == 0 && eventData->TotalEventSize % 4 == 0)); // ensure 4 byte alignment StreamLabel eventDataEnd = reader.Current.Add(eventData->TotalEventSize); Debug.Assert(0 <= EventPipeEventHeader.StackBytesSize(eventData) && EventPipeEventHeader.StackBytesSize(eventData) <= eventData->TotalEventSize); TraceEventNativeMethods.EVENT_RECORD *ret = null;; if (eventData->IsMetadata()) { int totalEventSize = eventData->TotalEventSize; int payloadSize = eventData->PayloadSize; // Note that this skip invalidates the eventData pointer, so it is important to pull any fields out we need first. reader.Skip(EventPipeEventHeader.HeaderSize); var metaData = new EventPipeEventMetaData(reader, payloadSize, _fileFormatVersionNumber, PointerSize, _processId); _eventMetadataDictionary.Add(metaData.MetaDataId, metaData); _eventParser.AddTemplate(metaData); // if we don't add the templates to this parse, we are going to have unhadled events (see https://github.com/Microsoft/perfview/issues/461) int stackBytes = reader.ReadInt32(); Debug.Assert(stackBytes == 0, "Meta-data events should always have a empty stack"); } else { if (_eventMetadataDictionary.TryGetValue(eventData->MetaDataId, out var metaData)) { ret = metaData.GetEventRecordForEventData(eventData); } else { Debug.Assert(false, "Warning can't find metaData for ID " + eventData->MetaDataId.ToString("x")); } } reader.Goto(eventDataEnd); return(ret); }