public unsafe void ProcessSequencePointBlock(byte[] sequencePointBytes) { const int SizeOfTimestampAndThreadCount = 12; const int SizeOfThreadIdAndSequenceNumber = 12; if (sequencePointBytes.Length < SizeOfTimestampAndThreadCount) { Debug.Assert(false, "Bad sequence point block length"); return; } long timestamp = BitConverter.ToInt64(sequencePointBytes, 0); int threadCount = BitConverter.ToInt32(sequencePointBytes, 8); if (sequencePointBytes.Length < SizeOfTimestampAndThreadCount + threadCount * SizeOfThreadIdAndSequenceNumber) { Debug.Assert(false, "Bad sequence point block length"); return; } SortAndDispatch(timestamp); foreach (EventCacheThread thread in _threads.Values) { Debug.Assert(thread.Events.Count == 0, "There shouldn't be any pending events after a sequence point"); thread.Events.Clear(); thread.Events.TrimExcess(); } int cursor = SizeOfTimestampAndThreadCount; for (int i = 0; i < threadCount; i++) { long captureThreadId = BitConverter.ToInt64(sequencePointBytes, cursor); int sequenceNumber = BitConverter.ToInt32(sequencePointBytes, cursor + 8); if (!_threads.TryGetValue(captureThreadId, out EventCacheThread thread)) { if (sequenceNumber > 0) { OnEventsDropped?.Invoke(sequenceNumber); } thread = new EventCacheThread(); thread.SequenceNumber = sequenceNumber; AddThread(captureThreadId, thread); } else { int droppedEvents = unchecked (sequenceNumber - thread.SequenceNumber); if (droppedEvents > 0) { OnEventsDropped?.Invoke(droppedEvents); } else { // When a thread id is recycled the sequenceNumber can abruptly reset to 1 which // makes droppedEvents go negative Debug.Assert(droppedEvents == 0 || sequenceNumber == 1); } thread.SequenceNumber = sequenceNumber; } cursor += SizeOfThreadIdAndSequenceNumber; } }
public unsafe void ProcessEventBlock(byte[] eventBlockData) { // parse the header if (eventBlockData.Length < 20) { Debug.Assert(false, "Expected EventBlock of at least 20 bytes"); return; } ushort headerSize = BitConverter.ToUInt16(eventBlockData, 0); if (headerSize < 20 || headerSize > eventBlockData.Length) { Debug.Assert(false, "Invalid EventBlock header size"); return; } ushort flags = BitConverter.ToUInt16(eventBlockData, 2); bool useHeaderCompression = (flags & (ushort)EventBlockFlags.HeaderCompression) != 0; // parse the events PinnedBuffer buffer = new PinnedBuffer(eventBlockData); byte * cursor = (byte *)buffer.PinningHandle.AddrOfPinnedObject(); byte * end = cursor + eventBlockData.Length; cursor += headerSize; EventMarker eventMarker = new EventMarker(buffer); long timestamp = 0; EventPipeEventHeader.ReadFromFormatV4(cursor, useHeaderCompression, ref eventMarker.Header); if (!_threads.TryGetValue(eventMarker.Header.CaptureThreadId, out EventCacheThread thread)) { thread = new EventCacheThread(); thread.SequenceNumber = eventMarker.Header.SequenceNumber - 1; AddThread(eventMarker.Header.CaptureThreadId, thread); } eventMarker = new EventMarker(buffer); while (cursor < end) { EventPipeEventHeader.ReadFromFormatV4(cursor, useHeaderCompression, ref eventMarker.Header); bool isSortedEvent = eventMarker.Header.IsSorted; timestamp = eventMarker.Header.TimeStamp; int sequenceNumber = eventMarker.Header.SequenceNumber; if (isSortedEvent) { thread.LastCachedEventTimestamp = timestamp; // sorted events are the only time the captureThreadId should change long captureThreadId = eventMarker.Header.CaptureThreadId; if (!_threads.TryGetValue(captureThreadId, out thread)) { thread = new EventCacheThread(); thread.SequenceNumber = sequenceNumber - 1; AddThread(captureThreadId, thread); } } int droppedEvents = (int)Math.Min(int.MaxValue, sequenceNumber - thread.SequenceNumber - 1); if (droppedEvents > 0) { OnEventsDropped?.Invoke(droppedEvents); } else { // When a thread id is recycled the sequenceNumber can abruptly reset to 1 which // makes droppedEvents go negative Debug.Assert(droppedEvents == 0 || sequenceNumber == 1); } thread.SequenceNumber = sequenceNumber; if (isSortedEvent) { SortAndDispatch(timestamp); OnEvent?.Invoke(ref eventMarker.Header); } else { thread.Events.Enqueue(eventMarker); } cursor += eventMarker.Header.TotalNonHeaderSize + eventMarker.Header.HeaderSize; EventMarker lastEvent = eventMarker; eventMarker = new EventMarker(buffer); eventMarker.Header = lastEvent.Header; } thread.LastCachedEventTimestamp = timestamp; }