public void ProcessStackBlock(byte[] stackBlock) { PinnedBuffer buffer = new PinnedBuffer(stackBlock); if (stackBlock.Length < 8) { Debug.Assert(false, "Bad stack block size"); return; } int cursor = 0; int firstStackId = BitConverter.ToInt32(stackBlock, cursor); cursor += 4; int countStackIds = BitConverter.ToInt32(stackBlock, cursor); cursor += 4; int nextStackId = firstStackId; while (cursor < stackBlock.Length) { StackMarker marker = new StackMarker(); marker.BackingBuffer = buffer; int stackId = nextStackId++; marker.StackBytesSize = BitConverter.ToInt32(stackBlock, cursor); cursor += 4; if (cursor + marker.StackBytesSize <= stackBlock.Length) { marker.StackBytes = buffer.PinningHandle.AddrOfPinnedObject() + cursor; cursor += marker.StackBytesSize; _stacks.Add(stackId, marker); } else { Debug.Assert(false, "Stack size exceeds stack block region"); break; } } Debug.Assert(nextStackId == firstStackId + countStackIds); }
public EventMarker(PinnedBuffer buffer) { Buffer = buffer; }
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; }