Skip to content

Commit

Permalink
Create custom IReadOnlyDictionary payload classes for known events (fix
Browse files Browse the repository at this point in the history
  • Loading branch information
verdie-g committed May 5, 2024
1 parent b1bd1bf commit b8a313b
Show file tree
Hide file tree
Showing 8 changed files with 5,427 additions and 559 deletions.
2 changes: 1 addition & 1 deletion EventPipe.Test/EventPipeReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public async Task MetadataAndEventBlockTest()
Assert.That(trace.Events[0].Metadata.Keywords, Is.EqualTo((EventKeywords)263882790666243));
Assert.That(trace.Events[0].Metadata.Version, Is.EqualTo(3));
Assert.That(trace.Events[0].Metadata.Level, Is.EqualTo(EventLevel.Informational));
Assert.That(trace.Events[0].Metadata.OpCode, Is.EqualTo(EventOpcode.Send));
Assert.That(trace.Events[0].Metadata.Opcode, Is.EqualTo(EventOpcode.Send));
Assert.That(trace.Events[0].Metadata.FieldDefinitions, Has.Count.EqualTo(5));
Assert.That(trace.Events[0].Metadata.FieldDefinitions[0].Name, Is.EqualTo("OriginatingTaskSchedulerID"));
Assert.That(trace.Events[0].Metadata.FieldDefinitions[0].TypeCode, Is.EqualTo(TypeCode.Int32));
Expand Down
4 changes: 2 additions & 2 deletions EventPipe/Event.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ public class Event
public long TimeStamp { get; }
public Guid ActivityId { get; }
public Guid RelatedActivityId { get; }
public Dictionary<string, object> Payload { get; }
public IReadOnlyDictionary<string, object> Payload { get; }
public EventMetadata Metadata { get; }
public StackTrace StackTrace { get; internal set; }

internal Event(int index, int sequenceNumber, long captureThreadId, long threadId, int stackIndex, long timeStamp,
Guid activityId, Guid relatedActivityId, Dictionary<string, object> payload, EventMetadata metadata)
Guid activityId, Guid relatedActivityId, IReadOnlyDictionary<string, object> payload, EventMetadata metadata)
{
Index = index;
SequenceNumber = sequenceNumber;
Expand Down
2 changes: 1 addition & 1 deletion EventPipe/EventMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ public record EventMetadata(
EventKeywords Keywords,
int Version,
EventLevel Level,
EventOpcode? OpCode,
EventOpcode? Opcode,
IReadOnlyList<EventFieldDefinition> FieldDefinitions);
81 changes: 27 additions & 54 deletions EventPipe/EventPipeReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Diagnostics.Tracing;
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using EventPipe.FastSerializer;

Expand Down Expand Up @@ -392,15 +391,15 @@ private void ReadCompressedEventBlob(ref FastSerializerSequenceReader reader,

// Some events (e.g. from Microsoft-Windows-DotNETRuntimeRundown) don't define any fields but still have
// a payload.
Dictionary<string, object> payload;
IReadOnlyDictionary<string, object> payload;
if (metadata.FieldDefinitions.Count == 0)
{
reader.Advance(payloadEndPosition - reader.AbsolutePosition);
payload = new Dictionary<string, object>();
}
else
{
payload = ReadEventPayload(ref reader, metadata.FieldDefinitions);
payload = ReadEventPayload(ref reader, metadata);
}

int stackIndex = _stackIndexOffset + stackId;
Expand Down Expand Up @@ -434,9 +433,9 @@ private EventMetadata ReadEventMetadata(
long metadataEndPosition)
{
int metadataId = reader.ReadInt32();
string providerName = ReadNullTerminatedUtf16String(ref reader);
string providerName = reader.ReadNullTerminatedString();
int eventId = reader.ReadInt32();
string eventName = ReadNullTerminatedUtf16String(ref reader);
string eventName = reader.ReadNullTerminatedString();
long keywords = reader.ReadInt64();
int version = reader.ReadInt32();
var level = ReadInt32AsEnum<EventLevel>(ref reader);
Expand Down Expand Up @@ -477,10 +476,10 @@ private EventMetadata ReadEventMetadata(
}
}

if (KnownEvents.All.TryGetValue(new KnownEvents.Key(providerName, eventId, version), out var knownMetadata))
if (KnownEvent.All.TryGetValue(new KnownEvent.Key(providerName, eventId, version), out var knownMetadata))
{
eventName = knownMetadata.EventName;
opCode = knownMetadata.OpCode;
opCode = knownMetadata.Opcode;
fieldDefinitions = knownMetadata.FieldDefinitions;
}

Expand Down Expand Up @@ -522,7 +521,7 @@ private EventFieldDefinition[] ReadFieldDefinitions(
subFieldDefinitions = ReadFieldDefinitions(ref reader, version);
}

string fieldName = ReadNullTerminatedUtf16String(ref reader);
string fieldName = reader.ReadNullTerminatedString();
fieldName = InternString(fieldName);

TypeCode? nullableArrayTypeCode = arrayTypeCode == default ? null : arrayTypeCode;
Expand All @@ -532,7 +531,21 @@ private EventFieldDefinition[] ReadFieldDefinitions(
return fieldDefinitions;
}

private Dictionary<string, object> ReadEventPayload(
private IReadOnlyDictionary<string, object> ReadEventPayload(
ref FastSerializerSequenceReader reader,
EventMetadata eventMetadata)
{
if (KnownEvent.All.TryGetValue(
new KnownEvent.Key(eventMetadata.ProviderName, eventMetadata.EventId, eventMetadata.Version),
out var knownEvent))
{
return knownEvent.Parse(ref reader);
}

return ReadEventPayload(ref reader, eventMetadata.FieldDefinitions);
}

private IReadOnlyDictionary<string, object> ReadEventPayload(
ref FastSerializerSequenceReader reader,
IReadOnlyList<EventFieldDefinition> fieldDefinitions)
{
Expand Down Expand Up @@ -565,61 +578,21 @@ private object ReadFieldValue(
TypeCode.SByte => Intern((sbyte)reader.ReadInt32(), _internedSByte),
TypeCode.Byte => Intern(reader.ReadByte(), _internedByte),
TypeCode.Int16 => Intern(reader.ReadInt16(), _internedInt16),
TypeCode.UInt16 => Intern((ushort)reader.ReadInt16(), _internedUInt16),
TypeCode.UInt16 => Intern(reader.ReadUInt16(), _internedUInt16),
TypeCode.Int32 => reader.ReadInt32(),
TypeCode.UInt32 => (uint)reader.ReadInt32(),
TypeCode.UInt32 => reader.ReadUInt32(),
TypeCode.Int64 => reader.ReadInt64(),
TypeCode.UInt64 => (ulong)reader.ReadInt64(),
TypeCode.UInt64 => reader.ReadUInt64(),
TypeCode.Single => reader.ReadSingle(),
TypeCode.Double => reader.ReadDouble(),
TypeCode.String => ReadNullTerminatedUtf16String(ref reader),
TypeCode.String => reader.ReadNullTerminatedString(),
_ => throw new NotSupportedException($"Type {fieldDefinition.TypeCode} is not supported")
};
}

private static string ReadNullTerminatedUtf16String(ref FastSerializerSequenceReader reader)
{
var unreadCharSpan = MemoryMarshal.Cast<byte, char>(reader.UnreadSpan);
int nullIdx = unreadCharSpan.IndexOf((char)0);
if (nullIdx == 0)
{
reader.Advance(sizeof(char));
return "";
}

if (nullIdx != -1)
{
string str = new(unreadCharSpan[..nullIdx]);
reader.Advance((nullIdx + 1) * sizeof(char));
return str;
}

// Ain't nobody got time for that.
return ReadNullTerminatedUtf16StringSlow(ref reader);
}

private static string ReadNullTerminatedUtf16StringSlow(ref FastSerializerSequenceReader reader)
{
StringBuilder sb = new();

while (true)
{
short c = reader.ReadInt16();
if (c == 0)
{
break;
}

sb.Append(Convert.ToChar(c));
}

return sb.ToString();
}

private void HandleSpecialEvent(Event evt)
{
const string rundownProvider = "Microsoft-Windows-DotNETRuntimeRundown";
if (evt.Metadata.ProviderName == rundownProvider)
if (evt.Metadata.ProviderName == KnownEvent.RundownProvider)
{
switch (evt.Metadata.EventId)
{
Expand Down
56 changes: 56 additions & 0 deletions EventPipe/FastSerializer/FastSerializerSequenceReader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Buffers;
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;

namespace EventPipe.FastSerializer;

Expand Down Expand Up @@ -56,6 +58,11 @@ public bool TryReadInt16(out short value)
return _reader.TryReadLittleEndian(out value);
}

public ushort ReadUInt16()
{
return (ushort)ReadInt16();
}

public int ReadInt32()
{
ThrowIfFalse(TryReadInt32(out int value));
Expand All @@ -67,6 +74,11 @@ public bool TryReadInt32(out int value)
return _reader.TryReadLittleEndian(out value);
}

public uint ReadUInt32()
{
return (uint)ReadInt32();
}

public long ReadInt64()
{
ThrowIfFalse(TryReadInt64(out long value));
Expand All @@ -78,6 +90,11 @@ public bool TryReadInt64(out long value)
return _reader.TryReadLittleEndian(out value);
}

public ulong ReadUInt64()
{
return (ulong)ReadInt64();
}

public float ReadSingle()
{
ThrowIfFalse(TryReadSingle(out float value));
Expand Down Expand Up @@ -129,6 +146,45 @@ public bool TryReadString(out ReadOnlySequence<byte> value)
return TryReadBytes(length, out value);
}

public string ReadNullTerminatedString()
{
var unreadCharSpan = MemoryMarshal.Cast<byte, char>(UnreadSpan);
int nullIdx = unreadCharSpan.IndexOf((char)0);
if (nullIdx == 0)
{
Advance(sizeof(char));
return "";
}

if (nullIdx != -1)
{
string str = new(unreadCharSpan[..nullIdx]);
Advance((nullIdx + 1) * sizeof(char));
return str;
}

// Ain't nobody got time for that.
return ReadNullTerminatedUtf16StringSlow(ref this);

static string ReadNullTerminatedUtf16StringSlow(ref FastSerializerSequenceReader reader)
{
StringBuilder sb = new();

while (true)
{
short c = reader.ReadInt16();
if (c == 0)
{
break;
}

sb.Append(Convert.ToChar(c));
}

return sb.ToString();
}
}

public Guid ReadGuid()
{
ThrowIfFalse(TryReadGuid(out Guid value));
Expand Down
Loading

0 comments on commit b8a313b

Please sign in to comment.