mirror of
https://github.com/Kae7in/perfview
synced 2026-08-09 12:09:44 +00:00
Stop allocating when enumerating events
Previously we would allocate objects to keep track of state for more complicated LTTng events. Now we track state within the buffer so that we can refer back to sizes of arrays...eliminating the need to keep track of most state.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
{
|
||||
@@ -22,18 +23,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
Load(parser);
|
||||
}
|
||||
|
||||
internal void WriteMetadata(TextWriter output)
|
||||
{
|
||||
Trace.WriteLine(output, 0);
|
||||
Environment.WriteLine(output, 0);
|
||||
|
||||
foreach (CtfClock clock in _clocks.Values)
|
||||
clock.WriteLine(output, 0);
|
||||
|
||||
foreach (CtfStream stream in Streams)
|
||||
stream.WriteLine(output, 0);
|
||||
}
|
||||
|
||||
public void Load(CtfMetadataParser parser)
|
||||
{
|
||||
Dictionary<string, CtfMetadataType> typeAlias = new Dictionary<string, CtfMetadataType>();
|
||||
@@ -125,7 +114,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
output.WriteLine("{0} Byte order: {1}", ind, ByteOrder);
|
||||
output.WriteLine("{0} Header:", ind);
|
||||
|
||||
Header.WriteLine(output, null, indent + 4);
|
||||
output.WriteLine();
|
||||
}
|
||||
|
||||
@@ -180,23 +168,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
foreach (CtfEvent evt in _events)
|
||||
evt.ResolveReferences(typealias);
|
||||
}
|
||||
|
||||
internal void WriteLine(TextWriter output, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
output.WriteLine("{0}Stream {1}:", ind, ID);
|
||||
output.WriteLine("{0} Header:", ind);
|
||||
EventHeader.WriteLine(output, null, indent + 8);
|
||||
|
||||
output.WriteLine("{0} PacketContext:", ind);
|
||||
PacketContext.WriteLine(output, null, indent + 8);
|
||||
|
||||
output.WriteLine("{0} Events:", ind);
|
||||
foreach (CtfEvent evt in _events)
|
||||
evt.WriteLine(output, null, indent + 8);
|
||||
|
||||
output.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -218,16 +189,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
public string TracerName { get; private set; }
|
||||
public int TracerMajor { get; private set; }
|
||||
public int TracerMinor { get; private set; }
|
||||
|
||||
internal void WriteLine(TextWriter output, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
output.WriteLine("{0}Environment:", ind);
|
||||
output.WriteLine("{0} Host name: {1}", ind, HostName);
|
||||
output.WriteLine("{0} Domain: {1}", ind, Domain);
|
||||
output.WriteLine("{0} Tracer: {1} ({2}.{3})", ind, TracerName, TracerMajor, TracerMinor);
|
||||
output.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,17 +211,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
public string Name { get; private set; }
|
||||
public ulong Offset { get; private set; }
|
||||
public Guid UUID { get; private set; }
|
||||
|
||||
internal void WriteLine(TextWriter output, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
output.WriteLine("{0}Clock:", ind);
|
||||
output.WriteLine("{0} Name: {1}", ind, Name);
|
||||
output.WriteLine("{0} Description: {1}", ind, Description);
|
||||
output.WriteLine("{0} UUID: {1}", ind, UUID);
|
||||
output.WriteLine("{0} Offset: {1}", ind, Offset);
|
||||
output.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -281,7 +231,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
get
|
||||
{
|
||||
if (_size == SizeUninitialized)
|
||||
_size = Fields.GetSize();
|
||||
_size = Definition.GetSize();
|
||||
|
||||
Debug.Assert(_size >= SizeIndeterminate);
|
||||
return _size;
|
||||
@@ -292,14 +242,14 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
public string Name { get; private set; }
|
||||
public int Stream { get; private set; }
|
||||
public uint LogLevel { get; private set; }
|
||||
public CtfStruct Fields { get; private set; }
|
||||
public CtfStruct Definition { get; private set; }
|
||||
public bool IsPacked
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isPacked.HasValue)
|
||||
{
|
||||
var fields = Fields.Fields;
|
||||
var fields = Definition.Fields;
|
||||
_isPacked = fields.Length == 3 && fields[2].Name == "___data__";
|
||||
}
|
||||
|
||||
@@ -314,43 +264,12 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
Stream = bag.GetInt("stream_id");
|
||||
LogLevel = bag.GetUInt("loglevel");
|
||||
|
||||
Fields = bag.GetStruct("fields");
|
||||
Definition = bag.GetStruct("fields");
|
||||
}
|
||||
|
||||
internal void ResolveReferences(Dictionary<string, CtfMetadataType> typealias)
|
||||
{
|
||||
Fields.ResolveReference(typealias);
|
||||
}
|
||||
|
||||
internal void WriteLine(TextWriter output, object[] values, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
output.WriteLine("{0}Event {1}:", ind, ID);
|
||||
output.WriteLine("{0} Name: {1}", ind, Name);
|
||||
output.WriteLine("{0} LogLevel: {1}", ind, LogLevel);
|
||||
|
||||
var actualFields = Fields.Fields;
|
||||
if (actualFields.Length > 0)
|
||||
{
|
||||
output.WriteLine("{0} Fields:", ind);
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
foreach (CtfField field in actualFields)
|
||||
field.WriteLine(output, null, indent + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < actualFields.Length; i++)
|
||||
actualFields[i].WriteLine(output, values[i], indent + 8);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine("{0} No fields.", ind);
|
||||
}
|
||||
|
||||
output.WriteLine();
|
||||
Definition.ResolveReference(typealias);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -360,7 +279,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
public int GetFieldOffset(string name)
|
||||
{
|
||||
return Fields.GetFieldOffset(name);
|
||||
return Definition.GetFieldOffset(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
static Regex s_struct = new Regex(@"^\s*struct\s(\{|\w+)");
|
||||
static Regex s_float = new Regex(@"floating_point +\{");
|
||||
|
||||
static CtfString s_string = new CtfString();
|
||||
|
||||
private Stream _stream;
|
||||
|
||||
public CtfMetadataLegacyParser(string filename)
|
||||
@@ -255,7 +253,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
string typeName = typeGroup.ToString().Trim();
|
||||
if (typeName == "string")
|
||||
type = s_string;
|
||||
type = new CtfString();
|
||||
else
|
||||
type = new CtfUnresolvedType(typeName);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
{
|
||||
@@ -54,6 +55,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
abstract class CtfMetadataType
|
||||
{
|
||||
public int BitOffset { get; set; }
|
||||
public abstract int Align { get; }
|
||||
|
||||
public CtfTypes CtfType { get; protected set; }
|
||||
@@ -64,15 +66,9 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
}
|
||||
|
||||
internal abstract CtfMetadataType ResolveReference(Dictionary<string, CtfMetadataType> typealias);
|
||||
|
||||
internal abstract void Write(TextWriter output, object value, int indent);
|
||||
internal virtual void WriteLine(TextWriter output, object value, int indent)
|
||||
{
|
||||
Write(output, value, indent);
|
||||
output.WriteLine();
|
||||
}
|
||||
|
||||
public abstract int GetSize();
|
||||
|
||||
public abstract object Read(byte[] buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -110,12 +106,12 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
return typealias[Name];
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
public override int GetSize()
|
||||
{
|
||||
output.Write("{0}{1}", new string(' ', indent), Name);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override int GetSize()
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
@@ -151,30 +147,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
Type = Type.ResolveReference(typealias);
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
output.Write("{0}{1}[{2}]", new string(' ', indent), Type, Index);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
output.Write("{ ");
|
||||
|
||||
output.Write(string.Join(", ", (object[])value));
|
||||
|
||||
output.Write(" }");
|
||||
}
|
||||
}
|
||||
|
||||
public int GetLength(CtfStruct strct, object[] values)
|
||||
{
|
||||
int len;
|
||||
if (int.TryParse(Index, out len))
|
||||
return len;
|
||||
|
||||
return strct.GetFieldValue<int>(values, Index);
|
||||
}
|
||||
|
||||
|
||||
public override int GetSize()
|
||||
{
|
||||
@@ -188,6 +160,11 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
return size * len;
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
class CtfFloat : CtfMetadataType
|
||||
@@ -212,24 +189,22 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
public string ByteOrder { get; private set; }
|
||||
public int Exp { get; private set; }
|
||||
|
||||
public int Mant { get; private set; }
|
||||
internal override CtfMetadataType ResolveReference(Dictionary<string, CtfMetadataType> typealias)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
output.Write("{0}float", new string(' ', indent));
|
||||
if (value != null)
|
||||
output.Write(" " + value.ToString());
|
||||
}
|
||||
|
||||
public override int GetSize()
|
||||
{
|
||||
return Exp + Mant;
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
// TODO: We don't support reading floats.
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
class CtfInteger : CtfMetadataType
|
||||
@@ -269,21 +244,126 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
{
|
||||
return this;
|
||||
}
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
output.Write("{0}{1}int{2}", new string(' ', indent), Signed ? "" : "u", Size);
|
||||
if (value != null)
|
||||
output.Write(" " + value.ToString());
|
||||
}
|
||||
|
||||
public override int GetSize()
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
|
||||
public static T ReadInt<T>(CtfMetadataType type, byte[] buffer, int bitOffset) where T : IConvertible
|
||||
{
|
||||
if (type.CtfType == CtfTypes.Enum)
|
||||
type = ((CtfEnum)type).Type;
|
||||
|
||||
CtfInteger intType = (CtfInteger)type;
|
||||
object result = intType.Read(buffer, bitOffset);
|
||||
object converted = ((IConvertible)result).ToType(typeof(T), null);
|
||||
return (T)converted;
|
||||
}
|
||||
|
||||
public object Read(byte[] buffer, int bitOffset)
|
||||
{
|
||||
if (Size > 64)
|
||||
throw new NotImplementedException();
|
||||
|
||||
Debug.Assert((bitOffset % Align) == 0);
|
||||
int byteOffset = bitOffset / 8;
|
||||
|
||||
bool fastPath = (bitOffset % 8) == 0 && (Size % 8) == 0;
|
||||
if (fastPath)
|
||||
{
|
||||
if (Size == 32)
|
||||
{
|
||||
if (Signed)
|
||||
return ((IConvertible)BitConverter.ToInt32(buffer, byteOffset));
|
||||
|
||||
return BitConverter.ToUInt32(buffer, byteOffset);
|
||||
}
|
||||
|
||||
if (Size == 8)
|
||||
{
|
||||
if (Signed)
|
||||
return (sbyte)buffer[byteOffset];
|
||||
|
||||
return buffer[byteOffset];
|
||||
}
|
||||
|
||||
if (Size == 64)
|
||||
{
|
||||
if (Signed)
|
||||
return BitConverter.ToInt64(buffer, byteOffset);
|
||||
|
||||
return BitConverter.ToUInt64(buffer, byteOffset);
|
||||
}
|
||||
|
||||
Debug.Assert(Size == 16);
|
||||
if (Signed)
|
||||
return BitConverter.ToInt16(buffer, byteOffset);
|
||||
|
||||
return BitConverter.ToUInt16(buffer, byteOffset);
|
||||
}
|
||||
|
||||
|
||||
// Sloooow path for misaligned integers
|
||||
int bits = Size;
|
||||
ulong value = 0;
|
||||
|
||||
int byteLen = IntHelpers.AlignUp(bits, 8) / 8;
|
||||
|
||||
for (int i = 0; i < byteLen; i++)
|
||||
value = unchecked((value << 8) | buffer[byteOffset + byteLen - i - 1]);
|
||||
|
||||
value >>= bitOffset;
|
||||
value &= (ulong)((1 << bits) - 1);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
ulong signBit = (1u << (bits - 1));
|
||||
|
||||
if ((value & signBit) != 0)
|
||||
value |= ulong.MaxValue << bits;
|
||||
}
|
||||
|
||||
|
||||
if (Size > 32)
|
||||
{
|
||||
if (Signed)
|
||||
return (long)value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Size > 16)
|
||||
{
|
||||
if (Signed)
|
||||
return (int)value;
|
||||
|
||||
return (uint)value;
|
||||
}
|
||||
|
||||
if (Size > 8)
|
||||
{
|
||||
if (Signed)
|
||||
return (short)value;
|
||||
|
||||
return (ushort)value;
|
||||
}
|
||||
|
||||
if (Signed)
|
||||
return (sbyte)value;
|
||||
|
||||
return (byte)value;
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
return Read(buffer, BitOffset);
|
||||
}
|
||||
}
|
||||
|
||||
class CtfString : CtfMetadataType
|
||||
{
|
||||
public int Length { get; set; }
|
||||
public override int Align
|
||||
{
|
||||
get
|
||||
@@ -308,20 +388,16 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
if (value != null)
|
||||
output.Write(ind + '"' + value.ToString() + '"');
|
||||
else
|
||||
output.Write("{0}string", ind);
|
||||
}
|
||||
|
||||
|
||||
public override int GetSize()
|
||||
{
|
||||
return CtfEvent.SizeIndeterminate;
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
return Encoding.Unicode.GetString(buffer, BitOffset >> 3, Length);
|
||||
}
|
||||
}
|
||||
|
||||
class CtfEnum : CtfMetadataType
|
||||
@@ -349,15 +425,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
Type = Type.ResolveReference(typealias);
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
if (value == null)
|
||||
output.Write("{0}enum {{ {1} }}", ind, string.Join(", ", Values));
|
||||
else
|
||||
output.Write("{0} - {1}", GetName(((IConvertible)value).ToInt32(null)), value);
|
||||
}
|
||||
|
||||
internal string GetName(int value)
|
||||
{
|
||||
foreach (CtfNamedRange range in Values)
|
||||
@@ -371,6 +439,17 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
{
|
||||
return Type.GetSize();
|
||||
}
|
||||
|
||||
internal CtfNamedRange GetValue(string name)
|
||||
{
|
||||
return Values.Where(p => p.Name == name).Single();
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
int value = CtfInteger.ReadInt<int>(Type, buffer, BitOffset);
|
||||
return GetName(value);
|
||||
}
|
||||
}
|
||||
|
||||
class CtfStruct : CtfMetadataType
|
||||
@@ -409,27 +488,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
_resolved = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
output.WriteLine("{0}struct", new string(' ', indent));
|
||||
output.WriteLine(new string(' ', indent) + "{");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
foreach (CtfField field in Fields)
|
||||
field.WriteLine(output, null, indent + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
object[] values = (object[])value;
|
||||
for (int i = 0; i < Fields.Length; i++)
|
||||
Fields[i].WriteLine(output, values[i], indent + 4);
|
||||
}
|
||||
|
||||
output.Write(new string(' ', indent) + "}");
|
||||
}
|
||||
|
||||
|
||||
internal CtfField GetField(string name)
|
||||
{
|
||||
for (int index = 0; index < Fields.Length; index++)
|
||||
@@ -439,34 +498,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
return null;
|
||||
}
|
||||
|
||||
internal T GetFieldValue<T>(object[] result, string name)
|
||||
{
|
||||
int index = GetFieldIndex(name);
|
||||
return GetFieldValue<T>(result, index);
|
||||
}
|
||||
|
||||
internal T GetFieldValue<T>(object[] result, int index)
|
||||
{
|
||||
object o = result[index];
|
||||
if (!(o is T))
|
||||
o = ((IConvertible)o).ToType(typeof(T), null);
|
||||
|
||||
return (T)o;
|
||||
}
|
||||
|
||||
internal int GetFieldIndex(string name)
|
||||
{
|
||||
int index = 0;
|
||||
for (; index < Fields.Length; index++)
|
||||
if (Fields[index].Name == name)
|
||||
break;
|
||||
|
||||
if (index == Fields.Length)
|
||||
throw new ArgumentException("name");
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public override int GetSize()
|
||||
{
|
||||
int size = 0;
|
||||
@@ -499,6 +530,11 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
class CtfVariant : CtfMetadataType
|
||||
@@ -532,26 +568,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
return this;
|
||||
}
|
||||
|
||||
internal override void Write(TextWriter output, object value, int indent)
|
||||
{
|
||||
string ind = new string(' ', indent);
|
||||
output.WriteLine("{0}variant <{1}>", ind, Switch);
|
||||
output.WriteLine(ind + "{");
|
||||
|
||||
foreach (CtfField field in Union)
|
||||
field.WriteLine(output, null, indent + 4);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
if (value is object[])
|
||||
output.WriteLine("{0}{{ {1} }}", ind, string.Join(", ", (object[])value));
|
||||
else
|
||||
output.Write(ind + value);
|
||||
}
|
||||
|
||||
output.Write(ind + "}");
|
||||
}
|
||||
|
||||
internal CtfField GetVariant(string name)
|
||||
{
|
||||
return Union.Where(f => f.Name == name).Single();
|
||||
@@ -575,10 +591,16 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public override object Read(byte[] buffer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
class CtfField
|
||||
{
|
||||
public int BitOffset { get; set; }
|
||||
public CtfMetadataType Type { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
@@ -598,23 +620,9 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
Type = Type.ResolveReference(typealias);
|
||||
}
|
||||
|
||||
internal void Write(TextWriter output, object value, int indent)
|
||||
internal object Read(byte[] buffer)
|
||||
{
|
||||
if (Type.CtfType == CtfTypes.Array)
|
||||
{
|
||||
Type.Write(output, value, indent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type.Write(output, null, indent);
|
||||
output.Write(" {0} = {1};", Name, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal void WriteLine(TextWriter output, object value, int indent)
|
||||
{
|
||||
Write(output, value, indent);
|
||||
output.WriteLine();
|
||||
return Type.Read(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+174
-283
@@ -82,14 +82,42 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
public IEnumerable<CtfEventHeader> EnumerateEventHeaders()
|
||||
{
|
||||
CtfStruct header = _streamDefinition.EventHeader;
|
||||
CtfEnum id = (CtfEnum)header.GetField("id").Type;
|
||||
CtfVariant v = (CtfVariant)header.GetField("v").Type;
|
||||
CtfStruct extended = (CtfStruct)v.GetVariant("extended").Type;
|
||||
CtfStruct compact = (CtfStruct)v.GetVariant("compact").Type;
|
||||
CtfInteger extendedId = (CtfInteger)extended.GetField("id").Type;
|
||||
CtfInteger extendedTimestamp = (CtfInteger)extended.GetField("timestamp").Type;
|
||||
CtfInteger compactTimestamp = (CtfInteger)((CtfStruct)v.GetVariant("compact").Type).GetField("timestamp").Type;
|
||||
|
||||
CtfInteger pid = null;
|
||||
CtfInteger tid = null;
|
||||
CtfArray processName = null;
|
||||
string lastProcessName = "";
|
||||
int processLen = 0;
|
||||
CtfStruct eventContext = _streamDefinition.EventContext;
|
||||
if (eventContext != null)
|
||||
{
|
||||
pid = (CtfInteger)eventContext.GetField("_vpid")?.Type;
|
||||
tid = (CtfInteger)eventContext.GetField("_vtid")?.Type;
|
||||
processName = (CtfArray)eventContext.GetField("_procname")?.Type;
|
||||
|
||||
// We only handle ascii process names, which seems to be the only thing lttng provides.
|
||||
if (processName != null)
|
||||
{
|
||||
processLen = int.Parse(processName.Index);
|
||||
Debug.Assert(processName.Type.GetSize() == 8);
|
||||
|
||||
if (processName.Type.GetSize() != 8)
|
||||
processName = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint extendedIdValue = (uint)id.GetValue("extended").End;
|
||||
|
||||
ulong lowMask = 0, highMask = 0, overflowBit = 0;
|
||||
ulong lastTimestamp = 0;
|
||||
|
||||
StringBuilder processName = new StringBuilder();
|
||||
|
||||
while (!_eof)
|
||||
{
|
||||
if (_readHeader)
|
||||
@@ -97,32 +125,29 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
|
||||
_header.Clear();
|
||||
ResetBuffer();
|
||||
|
||||
object[] result = ReadStruct(header);
|
||||
ReadStruct(header);
|
||||
if (_eof)
|
||||
break;
|
||||
|
||||
|
||||
ulong timestamp;
|
||||
CtfEnum en = (CtfEnum)header.GetField("id").Type;
|
||||
uint event_id = header.GetFieldValue<uint>(result, "id");
|
||||
uint event_id = CtfInteger.ReadInt<uint>(id.Type, _buffer, id.BitOffset);
|
||||
|
||||
result = header.GetFieldValue<object[]>(result, "v");
|
||||
if (en.GetName((int)event_id) == "extended")
|
||||
if (event_id == extendedIdValue)
|
||||
{
|
||||
event_id = extended.GetFieldValue<uint>(result, "id");
|
||||
timestamp = extended.GetFieldValue<ulong>(result, "timestamp");
|
||||
event_id = CtfInteger.ReadInt<uint>(extendedId, _buffer, extendedId.BitOffset);
|
||||
timestamp = CtfInteger.ReadInt<ulong>(extendedTimestamp, _buffer, extendedTimestamp.BitOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (overflowBit == 0)
|
||||
{
|
||||
CtfInteger compactTimestamp = (CtfInteger)compact.GetField("timestamp").Type;
|
||||
overflowBit = (1ul << compactTimestamp.Size);
|
||||
lowMask = overflowBit - 1;
|
||||
highMask = ~lowMask;
|
||||
}
|
||||
|
||||
ulong uint27timestamp = compact.GetFieldValue<ulong>(result, "timestamp");
|
||||
|
||||
ulong uint27timestamp = CtfInteger.ReadInt<ulong>(compactTimestamp, _buffer, compactTimestamp.BitOffset);
|
||||
ulong prevLowerBits = lastTimestamp & lowMask;
|
||||
|
||||
if (prevLowerBits < uint27timestamp)
|
||||
@@ -141,27 +166,40 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
CtfEvent evt = _streamDefinition.Events[(int)event_id];
|
||||
_header.Event = evt;
|
||||
_header.Timestamp = timestamp;
|
||||
|
||||
CtfStruct eventContext = _streamDefinition.EventContext;
|
||||
|
||||
if (eventContext != null)
|
||||
{
|
||||
result = ReadStruct(eventContext);
|
||||
_header.Pid = eventContext.GetFieldValue<int>(result, "_vpid");
|
||||
_header.Tid = eventContext.GetFieldValue<int>(result, "_vtid");
|
||||
ReadStruct(eventContext);
|
||||
|
||||
int procnameIndex = eventContext.GetFieldIndex("_procname");
|
||||
object[] procname = (object[])(result[procnameIndex]);
|
||||
processName.Clear();
|
||||
for (int i = 0; i < 17; i++)
|
||||
if (pid != null)
|
||||
_header.Pid = CtfInteger.ReadInt<int>(pid, _buffer, pid.BitOffset);
|
||||
|
||||
if (tid != null)
|
||||
_header.Tid = CtfInteger.ReadInt<int>(tid, _buffer, tid.BitOffset);
|
||||
|
||||
bool matches = true;
|
||||
int processNameOffset = processName.BitOffset >> 3;
|
||||
|
||||
if (_buffer[processNameOffset] == 0)
|
||||
{
|
||||
sbyte b = (sbyte)procname[i];
|
||||
if (b == 0)
|
||||
break;
|
||||
lastProcessName = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = 0;
|
||||
for (; len < processLen && _buffer[processNameOffset + len] != 0; len++)
|
||||
{
|
||||
if (len >= lastProcessName.Length)
|
||||
matches = false;
|
||||
else
|
||||
matches &= lastProcessName[len] == _buffer[processNameOffset + len];
|
||||
}
|
||||
|
||||
processName.Append((char)b);
|
||||
if (!matches || len != lastProcessName.Length)
|
||||
lastProcessName = Encoding.UTF8.GetString(_buffer, processName.BitOffset >> 3, len);
|
||||
}
|
||||
|
||||
_header.ProcessName = processName.ToString();
|
||||
_header.ProcessName = lastProcessName;
|
||||
}
|
||||
|
||||
_readHeader = true;
|
||||
@@ -174,27 +212,6 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
_bitOffset = 0;
|
||||
_bufferLength = 0;
|
||||
}
|
||||
|
||||
|
||||
public object[] ReadEvent(CtfEvent evt)
|
||||
{
|
||||
if (!_readHeader)
|
||||
throw new InvalidOperationException("Must read an event's header before reading an event's data.");
|
||||
|
||||
object[] result = null;
|
||||
if (evt.IsPacked)
|
||||
{
|
||||
ReadPackedEvent();
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetBuffer();
|
||||
result = ReadStruct(evt.Fields);
|
||||
}
|
||||
|
||||
_readHeader = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void ReadEventIntoBuffer(CtfEvent evt)
|
||||
{
|
||||
@@ -208,11 +225,7 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
else
|
||||
{
|
||||
ResetBuffer();
|
||||
|
||||
if (evt.IsFixedSize)
|
||||
ReadBits(evt.Size);
|
||||
else
|
||||
ReadStruct(evt.Fields);
|
||||
ReadStruct(evt.Definition);
|
||||
}
|
||||
|
||||
_readHeader = false;
|
||||
@@ -229,171 +242,153 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
ResetBuffer();
|
||||
ReadBits(8 * len);
|
||||
}
|
||||
|
||||
|
||||
public object[] ReadStruct(CtfStruct strct)
|
||||
|
||||
public void ReadStruct(CtfStruct strct)
|
||||
{
|
||||
var fields = strct.Fields;
|
||||
|
||||
object[] result = new object[fields.Length];
|
||||
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
result[i] = ReadType(strct, result, fields[i].Type);
|
||||
|
||||
return result;
|
||||
ReadTypeIntoBuffer(strct, fields[i].Type);
|
||||
}
|
||||
|
||||
private object ReadType(CtfStruct strct, object[] result, CtfMetadataType type)
|
||||
public void ReadTypeIntoBuffer(CtfStruct context, CtfMetadataType type)
|
||||
{
|
||||
Align(type.Align);
|
||||
|
||||
type.BitOffset = _bitOffset;
|
||||
|
||||
if (type.CtfType == CtfTypes.Enum)
|
||||
{
|
||||
type = ((CtfEnum)type).Type;
|
||||
type.BitOffset = _bitOffset;
|
||||
}
|
||||
else if (type.CtfType != CtfTypes.Struct && type.CtfType != CtfTypes.Variant)
|
||||
{
|
||||
int size = type.GetSize();
|
||||
if (size != CtfEvent.SizeIndeterminate)
|
||||
{
|
||||
ReadBits(size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type.CtfType)
|
||||
{
|
||||
case CtfTypes.Array:
|
||||
CtfArray array = (CtfArray)type;
|
||||
int len = array.GetLength(strct, result);
|
||||
|
||||
object[] ret = new object[len];
|
||||
var indexType = context.GetField(array.Index).Type;
|
||||
int len = CtfInteger.ReadInt<int>(indexType, _buffer, indexType.BitOffset);
|
||||
|
||||
for (int j = 0; j < len; j++)
|
||||
ret[j] = ReadType(null, null, array.Type);
|
||||
|
||||
return ret;
|
||||
|
||||
case CtfTypes.Enum:
|
||||
return ReadType(strct, result, ((CtfEnum)type).Type);
|
||||
int elemSize = array.Type.GetSize();
|
||||
if (elemSize == CtfEvent.SizeIndeterminate)
|
||||
{
|
||||
for (int j = 0; j < len; j++)
|
||||
ReadTypeIntoBuffer(null, array.Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < len; j++)
|
||||
{
|
||||
Align(type.Align);
|
||||
ReadBits(elemSize);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CtfTypes.Float:
|
||||
CtfFloat flt = (CtfFloat)type;
|
||||
ReadBits(flt.Exp + flt.Mant);
|
||||
return 0f; // TODO: Not implemented.
|
||||
break;
|
||||
|
||||
case CtfTypes.Integer:
|
||||
CtfInteger ctfInt = (CtfInteger)type;
|
||||
return ReadInteger(ctfInt);
|
||||
ReadBits(ctfInt.Size);
|
||||
break;
|
||||
|
||||
case CtfTypes.String:
|
||||
Debug.Assert((_bitOffset % 8) == 0);
|
||||
int startOffset = _bitOffset >> 3;
|
||||
int offset = startOffset;
|
||||
|
||||
ReadBits(8);
|
||||
bool ascii = ((CtfString)type).IsAscii;
|
||||
return ReadString(ascii);
|
||||
if (ascii)
|
||||
{
|
||||
while (_buffer[offset++] != 0)
|
||||
ReadBits(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte b = _buffer[offset];
|
||||
while (b != 0)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
ReadBits(8);
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
ReadBits(16);
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
ReadBits(24);
|
||||
break;
|
||||
}
|
||||
|
||||
offset = ReadBits(8) >> 3;
|
||||
b = _buffer[offset];
|
||||
}
|
||||
}
|
||||
|
||||
int bufferLen = (_bitOffset >> 3) - startOffset;
|
||||
|
||||
Encoding encoding = ascii ? Encoding.ASCII : Encoding.UTF8;
|
||||
|
||||
byte[] newArr = Encoding.Convert(encoding, Encoding.Unicode, _buffer, startOffset, bufferLen);
|
||||
((CtfString)type).Length = bufferLen;
|
||||
|
||||
if (_buffer.Length < _bufferLength + newArr.Length)
|
||||
{
|
||||
byte[] buffer = ReallocateBuffer(_bufferLength + newArr.Length);
|
||||
System.Buffer.BlockCopy(buffer, 0, _buffer, 0, _bufferLength);
|
||||
}
|
||||
|
||||
System.Buffer.BlockCopy(newArr, 0, _buffer, startOffset, newArr.Length);
|
||||
_bufferLength = startOffset + newArr.Length;
|
||||
_bitOffset = _bufferLength * 8;
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case CtfTypes.Struct:
|
||||
return ReadStruct((CtfStruct)type);
|
||||
ReadStruct((CtfStruct)type);
|
||||
break;
|
||||
|
||||
case CtfTypes.Variant:
|
||||
CtfVariant var = (CtfVariant)type;
|
||||
|
||||
int i = strct.GetFieldIndex(var.Switch);
|
||||
CtfField field = strct.Fields[i];
|
||||
CtfField field = context.GetField(var.Switch);
|
||||
CtfEnum enumType = (CtfEnum)field.Type;
|
||||
|
||||
int value = strct.GetFieldValue<int>(result, i);
|
||||
int value = CtfInteger.ReadInt<int>(enumType, _buffer, enumType.BitOffset);
|
||||
string name = enumType.GetName(value);
|
||||
|
||||
field = var.Union.Where(f => f.Name == name).Single();
|
||||
return ReadType(strct, result, field.Type);
|
||||
field = var.GetVariant(name);
|
||||
ReadTypeIntoBuffer(null, field.Type);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private object ReadInteger(CtfInteger ctfInt)
|
||||
{
|
||||
if (ctfInt.Size > 64)
|
||||
throw new NotImplementedException();
|
||||
|
||||
Align(ctfInt.Align);
|
||||
int bitOffset = ReadBits(ctfInt.Size);
|
||||
int byteOffset = bitOffset / 8;
|
||||
|
||||
bool fastPath = (_bitOffset % 8) == 0 && (ctfInt.Size % 8) == 0;
|
||||
if (fastPath)
|
||||
{
|
||||
if (ctfInt.Size == 32)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return BitConverter.ToInt32(_buffer, byteOffset);
|
||||
|
||||
return BitConverter.ToUInt32(_buffer, byteOffset);
|
||||
}
|
||||
|
||||
if (ctfInt.Size == 8)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return (sbyte)_buffer[byteOffset];
|
||||
|
||||
return _buffer[byteOffset];
|
||||
}
|
||||
|
||||
if (ctfInt.Size == 64)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return BitConverter.ToInt64(_buffer, byteOffset);
|
||||
|
||||
return BitConverter.ToUInt64(_buffer, byteOffset);
|
||||
}
|
||||
|
||||
Debug.Assert(ctfInt.Size == 16);
|
||||
if (ctfInt.Signed)
|
||||
return BitConverter.ToInt16(_buffer, byteOffset);
|
||||
|
||||
return BitConverter.ToUInt16(_buffer, byteOffset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Sloooow path for misaligned integers
|
||||
int bits = ctfInt.Size;
|
||||
ulong value = 0;
|
||||
|
||||
int byteLen = IntHelpers.AlignUp(bits, 8) / 8;
|
||||
|
||||
for (int i = 0; i < byteLen; i++)
|
||||
value = unchecked((value << 8) | _buffer[byteOffset + byteLen - i - 1]);
|
||||
|
||||
value >>= bitOffset;
|
||||
value &= (ulong)((1 << bits) - 1);
|
||||
|
||||
if (ctfInt.Signed)
|
||||
{
|
||||
ulong signBit = (1u << (bits - 1));
|
||||
|
||||
if ((value & signBit) != 0)
|
||||
value |= ulong.MaxValue << bits;
|
||||
}
|
||||
|
||||
|
||||
if (ctfInt.Size > 32)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return (long)value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
if (ctfInt.Size > 16)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return (int)value;
|
||||
|
||||
return (uint)value;
|
||||
}
|
||||
|
||||
if (ctfInt.Size > 8)
|
||||
{
|
||||
if (ctfInt.Signed)
|
||||
return (short)value;
|
||||
|
||||
return (ushort)value;
|
||||
}
|
||||
|
||||
if (ctfInt.Signed)
|
||||
return (sbyte)value;
|
||||
|
||||
return (byte)value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -475,109 +470,5 @@ namespace Microsoft.Diagnostics.Tracing.Ctf
|
||||
_eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] _stringBuffer = new byte[1024];
|
||||
internal string ReadString(bool ascii)
|
||||
{
|
||||
byte b = ReadByte();
|
||||
if (b == 0)
|
||||
{
|
||||
if (_buffer.Length < _bufferLength + 2)
|
||||
{
|
||||
byte[] buffer = ReallocateBuffer(_bufferLength + 2);
|
||||
System.Buffer.BlockCopy(buffer, 0, _buffer, 0, _bufferLength);
|
||||
}
|
||||
|
||||
_buffer[_bufferLength++] = 0;
|
||||
_buffer[_bufferLength++] = 0;
|
||||
_bitOffset += 16;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
_stringBuffer[i++] = b;
|
||||
if (ascii)
|
||||
{
|
||||
while (b != 0)
|
||||
{
|
||||
if (i >= _stringBuffer.Length - 4)
|
||||
{
|
||||
byte[] tmp = _stringBuffer;
|
||||
_stringBuffer = new byte[_stringBuffer.Length + 1024];
|
||||
System.Buffer.BlockCopy(tmp, 0, _stringBuffer, 0, tmp.Length);
|
||||
}
|
||||
|
||||
b = _stringBuffer[i++] = ReadByte();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (b != 0)
|
||||
{
|
||||
if (i >= _stringBuffer.Length - 4)
|
||||
{
|
||||
byte[] tmp = _stringBuffer;
|
||||
_stringBuffer = new byte[_stringBuffer.Length + 1024];
|
||||
System.Buffer.BlockCopy(tmp, 0, _stringBuffer, 0, tmp.Length);
|
||||
}
|
||||
|
||||
b >>= 4;
|
||||
|
||||
switch (b)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
break;
|
||||
|
||||
case 0xf:
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
_stringBuffer[i++] = ReadByte();
|
||||
break;
|
||||
}
|
||||
|
||||
b = _stringBuffer[i++] = ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
Encoding encoding = ascii ? Encoding.ASCII : Encoding.UTF8;
|
||||
|
||||
string s = encoding.GetString(_stringBuffer, 0, i - 1);
|
||||
byte[] newArr = Encoding.Convert(encoding, Encoding.Unicode, _stringBuffer, 0, i);
|
||||
|
||||
if (_buffer.Length < _bufferLength + newArr.Length)
|
||||
{
|
||||
byte[] buffer = ReallocateBuffer(_bufferLength + newArr.Length);
|
||||
System.Buffer.BlockCopy(buffer, 0, _buffer, 0, _bufferLength);
|
||||
}
|
||||
|
||||
System.Buffer.BlockCopy(newArr, 0, _buffer, _bufferLength, newArr.Length);
|
||||
_bufferLength += newArr.Length;
|
||||
_bitOffset += newArr.Length * 8;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private byte ReadByte()
|
||||
{
|
||||
int c = _stream.ReadByte();
|
||||
if (c == -1)
|
||||
{
|
||||
_eof = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (byte)c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,6 +492,9 @@ namespace Microsoft.Diagnostics.Tracing
|
||||
CtfEvent evt = header.Event;
|
||||
lastTimestamp = header.Timestamp;
|
||||
|
||||
entry.Reader.ReadEventIntoBuffer(evt);
|
||||
events++;
|
||||
|
||||
#if DEBUG
|
||||
if (_debugOut != null)
|
||||
{
|
||||
@@ -499,18 +502,11 @@ namespace Microsoft.Diagnostics.Tracing
|
||||
_debugOut.WriteLine($" Process: {header.ProcessName}");
|
||||
_debugOut.WriteLine($" File: {entry.FileName}");
|
||||
_debugOut.WriteLine($" File Offset: {entry.Channel.FileOffset}");
|
||||
_debugOut.WriteLine($" Event #{events}");
|
||||
object[] result = entry.Reader.ReadEvent(evt);
|
||||
evt.WriteLine(_debugOut, result, 4);
|
||||
_debugOut.WriteLine($" Event #{events}: {evt.Name}");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
entry.Reader.ReadEventIntoBuffer(evt);
|
||||
events++;
|
||||
|
||||
ETWMapping etw = GetTraceEvent(evt);
|
||||
|
||||
if (etw.IsNull)
|
||||
continue;
|
||||
|
||||
@@ -518,6 +514,7 @@ namespace Microsoft.Diagnostics.Tracing
|
||||
TraceEvent traceEvent = Lookup(hdr);
|
||||
traceEvent.eventRecord = hdr;
|
||||
traceEvent.userData = entry.Reader.BufferPtr;
|
||||
traceEvent.EventTypeUserData = evt;
|
||||
|
||||
traceEvent.DebugValidate();
|
||||
Dispatch(traceEvent);
|
||||
|
||||
Reference in New Issue
Block a user