Skip to content

Commit

Permalink
Stream State Table (microsoft#2833)
Browse files Browse the repository at this point in the history
  • Loading branch information
nibanks authored Jun 22, 2022
1 parent 4f82bda commit 071baf5
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/plugins/trace/dll/DataModel/QuicPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public sealed class QuicPacket : IQuicObject
public Timestamp PacketCreate { get; internal set; }
public Timestamp PacketReceive { get; internal set; }
public Timestamp PacketDecrypt { get; internal set; }
public Timestamp PacketDecryptComplete { get; internal set; }

internal QuicPacket(ulong packetID, uint processId)
{
Expand Down
11 changes: 10 additions & 1 deletion src/plugins/trace/dll/DataModel/QuicStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public sealed class QuicStream : IQuicObject

public uint ProcessId { get; }

public ulong StreamId { get; private set; }
public ulong StreamId { get; private set; } = ulong.MaxValue;

public Timestamp InitialTimeStamp { get; private set; }

Expand Down Expand Up @@ -191,6 +191,15 @@ internal void AddEvent(QuicEvent evt, QuicState state)
Timings.UpdateToState(QuicStreamState.ProcessRecv, Connection.LastScheduleStateTimeStamp, true);
}
Timings.UpdateToState(QuicStreamState.Decrypt, Timings.RecvPacket.PacketDecrypt);

if (Timings.RecvPacket.PacketDecryptComplete == Timestamp.Zero)
{
Timings.RecvPacket.PacketDecryptComplete = evt.TimeStamp;
}
else
{
Timings.UpdateToState(QuicStreamState.ProcessRecv, Timings.RecvPacket.PacketDecryptComplete);
}
}

Timings.UpdateToState(QuicStreamState.Read, evt.TimeStamp);
Expand Down
17 changes: 15 additions & 2 deletions src/plugins/trace/dll/DataModel/QuicStreamTiming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,21 @@ public sealed class QuicStreamTiming
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>")]
public List<(QuicStreamState, Timestamp)> StateChanges = new List<(QuicStreamState, Timestamp)>();

public IEnumerable<(QuicStreamState, ulong)> StateChangeDeltas =>
StateChanges.Select(s => (s.Item1, (ulong)(s.Item2 - InitialStateTime).ToNanoseconds));
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1819:Properties should not return arrays", Justification = "<Pending>")]
public (QuicStreamState, Timestamp, TimestampDelta)[] StateChangeDeltas
{
get
{
var previousTime = InitialStateTime;
var states = new List<(QuicStreamState, Timestamp, TimestampDelta)>(StateChanges.Count);
foreach (var item in StateChanges)
{
states.Add((item.Item1, previousTime, item.Item2 - previousTime));
previousTime = item.Item2;
}
return states.ToArray();
}
}

//
// The corresponding peer's timings.
Expand Down
169 changes: 169 additions & 0 deletions src/plugins/trace/dll/Tables/QuicStreamStateTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Performance.SDK;
using Microsoft.Performance.SDK.Extensibility;
using Microsoft.Performance.SDK.Processing;
using QuicTrace.DataModel;

namespace QuicTrace.Tables
{
[Table]
public sealed class QuicStreamStateTable
{
public static readonly TableDescriptor TableDescriptor = new TableDescriptor(
Guid.Parse("{e8718744-e6b6-4db9-a1fb-ba2e9a1aaa8d}"),
"QUIC Stream States",
"QUIC Stream States",
category: "Computation",
requiredDataCookers: new List<DataCookerPath> { QuicEventCooker.CookerPath });

private static readonly ColumnConfiguration connectionColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{49c6d674-4a1a-4219-b92c-38fe0d85d6d9}"), "Connection"),
new UIHints { AggregationMode = AggregationMode.UniqueCount });

/*private static readonly ColumnConfiguration streamColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{bc726b53-becd-4ad8-903b-25186ea9e558}"), "Stream"),
new UIHints { AggregationMode = AggregationMode.UniqueCount });*/

private static readonly ColumnConfiguration streamIDColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{ea50a0d5-5a99-451e-b715-1c794f47edfa}"), "Stream ID"),
new UIHints { AggregationMode = AggregationMode.UniqueCount });

private static readonly ColumnConfiguration processIdColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{109035a8-a9d7-54bf-92b4-0328d277c69e}"), "Process (ID)"),
new UIHints { AggregationMode = AggregationMode.Max });

private static readonly ColumnConfiguration nameColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{03adfc15-d217-5857-4d83-b1d84a1d16a6}"), "Name"),
new UIHints { AggregationMode = AggregationMode.UniqueCount });

private static readonly ColumnConfiguration timeColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{cae6253b-0ce6-466e-bd9f-f7dbf65bdef7}"), "Time"),
new UIHints { AggregationMode = AggregationMode.Max });

private static readonly ColumnConfiguration durationColumnConfig =
new ColumnConfiguration(
new ColumnMetadata(new Guid("{355d0868-d1e9-4fa1-a6ba-da2ff12e17eb}"), "Duration"),
new UIHints { AggregationMode = AggregationMode.Sum });

private static readonly TableConfiguration tableConfig1 =
new TableConfiguration("Timeline by Connection,Stream")
{
Columns = new[]
{
connectionColumnConfig,
streamIDColumnConfig,
nameColumnConfig,
TableConfiguration.PivotColumn,
TableConfiguration.LeftFreezeColumn,
//streamColumnConfig,
processIdColumnConfig,
TableConfiguration.RightFreezeColumn,
TableConfiguration.GraphColumn,
timeColumnConfig,
durationColumnConfig,
}
};

public static bool IsDataAvailable(IDataExtensionRetrieval tableData)
{
Debug.Assert(!(tableData is null));
var quicState = tableData.QueryOutput<QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State"));
return quicState != null && quicState.DataAvailableFlags.HasFlag(QuicDataAvailableFlags.Packet);
}

public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieval tableData)
{
Debug.Assert(!(tableBuilder is null) && !(tableData is null));

var quicState = tableData.QueryOutput<QuicState>(new DataOutputPath(QuicEventCooker.CookerPath, "State"));
if (quicState == null)
{
return;
}

var streams = quicState.Streams;
if (streams.Count == 0)
{
return;
}

var data = streams.Take(100)
.Where(s => s.StreamId != ulong.MaxValue)
.SelectMany(
s => s.Timings.StateChangeDeltas
.Select(y => (s, y.Item1, y.Item2, y.Item3))).ToArray();

var table = tableBuilder.SetRowCount(data.Length);
var dataProjection = Projection.Index(data);

table.AddColumn(connectionColumnConfig, dataProjection.Compose(ProjectConnection));
//table.AddColumn(streamColumnConfig, dataProjection.Compose(ProjectStream));
table.AddColumn(streamIDColumnConfig, dataProjection.Compose(ProjectStreamId));
table.AddColumn(processIdColumnConfig, dataProjection.Compose(ProjectProcessId));
table.AddColumn(nameColumnConfig, dataProjection.Compose(ProjectName));
table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime));
table.AddColumn(durationColumnConfig, dataProjection.Compose(ProjectDuration));

tableConfig1.AddColumnRole(ColumnRole.StartTime, timeColumnConfig);
tableConfig1.AddColumnRole(ColumnRole.Duration, durationColumnConfig);
//tableConfig1.InitialExpansionQuery = "[Series Name]:=\"Process (ID)\"";
//tableConfig1.InitialSelectionQuery = "[Series Name]:=\"Connection\" OR [Series Name]:=\"State\"";
tableBuilder.AddTableConfiguration(tableConfig1);

tableBuilder.SetDefaultTableConfiguration(tableConfig1);
}

#region Projections

private static ulong ProjectConnection((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item1.Connection!.Id;
}

private static ulong ProjectStream((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item1.Id;
}

private static ulong ProjectStreamId((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item1.StreamId;
}

private static uint ProjectProcessId((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item1.ProcessId;
}

private static string ProjectName((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item2.ToString();
}

private static Timestamp ProjectTime((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item3;
}

private static TimestampDelta ProjectDuration((QuicStream, QuicStreamState, Timestamp, TimestampDelta) data)
{
return data.Item4;
}

#endregion
}
}

0 comments on commit 071baf5

Please sign in to comment.