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);
        }
Esempio n. 5
0
        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);
        }