Skip to content

Commit 58c2eb0

Browse files
authored
Perfetto plugin - Added table for GPU counters (#57)
Added table for GPU counters. Also fixed a few SDK deprecations.
1 parent 0b3eb6f commit 58c2eb0

19 files changed

+400
-54
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using Microsoft.Performance.SDK;
7+
using Microsoft.Performance.SDK.Extensibility;
8+
using Microsoft.Performance.SDK.Extensibility.DataCooking;
9+
using Microsoft.Performance.SDK.Processing;
10+
using PerfettoCds.Pipeline.DataOutput;
11+
using PerfettoCds.Pipeline.SourceDataCookers;
12+
using PerfettoProcessor;
13+
14+
namespace PerfettoCds.Pipeline.CompositeDataCookers
15+
{
16+
/// <summary>
17+
/// Pulls data from multiple individual SQL tables and joins them to create a GPU counter event.
18+
/// </summary>
19+
public sealed class PerfettoGpuCountersEventCooker : CookedDataReflector, ICompositeDataCookerDescriptor
20+
{
21+
public static readonly DataCookerPath DataCookerPath = PerfettoPluginConstants.GpuCountersEventCookerPath;
22+
23+
public string Description => "GPU counters composite cooker";
24+
25+
public DataCookerPath Path => DataCookerPath;
26+
27+
// Declare all of the cookers that are used by this CompositeCooker.
28+
public IReadOnlyCollection<DataCookerPath> RequiredDataCookers => new[]
29+
{
30+
PerfettoPluginConstants.CounterCookerPath,
31+
PerfettoPluginConstants.GpuCounterTrackCookerPath
32+
};
33+
34+
[DataOutput]
35+
public ProcessedEventData<PerfettoGpuCountersEvent> GpuCountersEvents { get; }
36+
37+
public PerfettoGpuCountersEventCooker() : base(PerfettoPluginConstants.GpuCountersEventCookerPath)
38+
{
39+
this.GpuCountersEvents =
40+
new ProcessedEventData<PerfettoGpuCountersEvent>();
41+
}
42+
43+
public void OnDataAvailable(IDataExtensionRetrieval requiredData)
44+
{
45+
// Gather the data from all the SQL tables
46+
var counterData = requiredData.QueryOutput<ProcessedEventData<PerfettoCounterEvent>>(new DataOutputPath(PerfettoPluginConstants.CounterCookerPath, nameof(PerfettoCounterCooker.CounterEvents)));
47+
var gpuCounterTrackData = requiredData.QueryOutput<ProcessedEventData<PerfettoGpuCounterTrackEvent>>(new DataOutputPath(PerfettoPluginConstants.GpuCounterTrackCookerPath, nameof(PerfettoGpuCounterTrackCooker.GpuCounterTrackEvents)));
48+
49+
// Join them all together
50+
// Counter table contains the timestamp and all counter values
51+
// GpuCounterTrack contains the counter name
52+
var joined = from counter in counterData
53+
join gpuCounterTrack in gpuCounterTrackData on counter.TrackId equals gpuCounterTrack.Id
54+
orderby counter.Timestamp ascending
55+
select new { counter, gpuCounterTrack };
56+
57+
// Create GPU Counter events for each type (name) at each time
58+
foreach (var nameGroup in joined.GroupBy(x => x.gpuCounterTrack.Name))
59+
{
60+
string name = nameGroup.Key;
61+
62+
for(int i = 0; i < nameGroup.Count(); i++)
63+
{
64+
var ele = nameGroup.ElementAt(i);
65+
double val = ele.counter.FloatValue;
66+
var ts = ele.counter.RelativeTimestamp;
67+
68+
long nextTs = ts;
69+
if (i < nameGroup.Count() - 1)
70+
{
71+
// Need to look ahead in the future at the next event to get the timestamp so that we can calculate the duration
72+
nextTs = nameGroup.ElementAt(i + 1).counter.RelativeTimestamp;
73+
}
74+
75+
PerfettoGpuCountersEvent ev = new PerfettoGpuCountersEvent
76+
(
77+
name,
78+
val,
79+
new Timestamp(ts),
80+
new TimestampDelta(nextTs - ts)
81+
);
82+
this.GpuCountersEvents.AddEvent(ev);
83+
}
84+
}
85+
86+
this.GpuCountersEvents.FinalizeData();
87+
}
88+
}
89+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using Microsoft.Performance.SDK;
4+
using System.Collections.Generic;
5+
using Utilities;
6+
7+
namespace PerfettoCds.Pipeline.DataOutput
8+
{
9+
public readonly struct PerfettoGpuCountersEvent
10+
{
11+
/// <summary>
12+
/// Name (type) of GPU counter
13+
/// </summary>
14+
public string Name { get; }
15+
16+
/// <summary>
17+
/// Actual value of this counter at this point in time
18+
/// </summary>
19+
public double Value { get; }
20+
21+
public Timestamp StartTimestamp { get; }
22+
public TimestampDelta Duration { get; }
23+
24+
/// <summary>
25+
/// For populating the current counter values
26+
/// </summary>
27+
public PerfettoGpuCountersEvent(string name, double value, Timestamp startTimestamp, TimestampDelta duration)
28+
{
29+
this.Name = Common.StringIntern(name);
30+
this.Value = value;
31+
this.StartTimestamp = startTimestamp;
32+
this.Duration = duration;
33+
}
34+
}
35+
}

PerfettoCds/Pipeline/PerfettoPluginConstants.cs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static class PerfettoPluginConstants
2626
public const string RawCookerId = nameof(PerfettoRawCooker);
2727
public const string CounterCookerId = nameof(PerfettoCounterCooker);
2828
public const string CpuCounterTrackCookerId = nameof(PerfettoCpuCounterTrackCooker);
29+
public const string GpuCounterTrackCookerId = nameof(PerfettoGpuCounterTrackCooker);
2930
public const string ProcessCounterTrackCookerId = nameof(PerfettoProcessCounterTrackCooker);
3031
public const string CounterTrackCookerId = nameof(PerfettoCounterTrackCooker);
3132
public const string ProcessTrackCookerId = nameof(PerfettoProcessTrackCooker);
@@ -42,6 +43,7 @@ public static class PerfettoPluginConstants
4243
public const string FtraceEventCookerId = nameof(PerfettoFtraceEventCooker);
4344
public const string CpuFrequencyEventCookerId = nameof(PerfettoCpuFrequencyEventCooker);
4445
public const string CpuCountersEventCookerId = nameof(PerfettoCpuCountersEventCooker);
46+
public const string GpuCountersEventCookerId = nameof(PerfettoGpuCountersEventCooker);
4547
public const string ProcessMemoryEventCookerId = nameof(PerfettoProcessMemoryEventCooker);
4648
public const string SystemMemoryEventCookerId = nameof(PerfettoSystemMemoryEventCooker);
4749
public const string CpuSamplingEventCookerId = nameof(PerfettoCpuSamplingEventCooker);
@@ -57,6 +59,7 @@ public static class PerfettoPluginConstants
5759
public const string RawEvent = PerfettoRawEvent.Key;
5860
public const string CounterEvent = PerfettoCounterEvent.Key;
5961
public const string CpuCounterTrackEvent = PerfettoCpuCounterTrackEvent.Key;
62+
public const string GpuCounterTrackEvent = PerfettoGpuCounterTrackEvent.Key;
6063
public const string ProcessCounterTrackEvent = PerfettoProcessCounterTrackEvent.Key;
6164
public const string CounterTrackEvent = PerfettoCounterTrackEvent.Key;
6265
public const string ProcessTrackEvent = PerfettoProcessTrackEvent.Key;
@@ -73,67 +76,71 @@ public static class PerfettoPluginConstants
7376
public const string FtraceEvent = nameof(PerfettoFtraceEvent);
7477
public const string CpuFrequencyEvent = nameof(PerfettoCpuFrequencyEvent);
7578
public const string CpuCountersEvent = nameof(PerfettoCpuCountersEvent);
79+
public const string GpuCountersEvent = nameof(PerfettoGpuCountersEvent);
7680
public const string ProcessMemoryEvent = nameof(PerfettoProcessMemoryEvent);
7781
public const string SystemMemoryEvent = nameof(PerfettoSystemMemoryEvent);
7882
public const string CpuSamplingEvent = nameof(PerfettoCpuSamplingEvent);
7983

8084
// Paths for source cookers
8185
public static readonly DataCookerPath SliceCookerPath =
82-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.SliceCookerId);
86+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.SliceCookerId);
8387
public static readonly DataCookerPath ArgCookerPath =
84-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ArgCookerId);
88+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ArgCookerId);
8589
public static readonly DataCookerPath ThreadTrackCookerPath =
86-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ThreadTrackCookerId);
90+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ThreadTrackCookerId);
8791
public static readonly DataCookerPath ThreadCookerPath =
88-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ThreadCookerId);
92+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ThreadCookerId);
8993
public static readonly DataCookerPath ProcessCookerPath =
90-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessCookerId);
94+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessCookerId);
9195
public static readonly DataCookerPath SchedSliceCookerPath =
92-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.SchedSliceCookerId);
96+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.SchedSliceCookerId);
9397
public static readonly DataCookerPath AndroidLogCookerPath =
94-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.AndroidLogCookerId);
98+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.AndroidLogCookerId);
9599
public static readonly DataCookerPath RawCookerPath =
96-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.RawCookerId);
100+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.RawCookerId);
97101
public static readonly DataCookerPath CounterCookerPath =
98-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterCookerId);
102+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterCookerId);
99103
public static readonly DataCookerPath CpuCounterTrackCookerPath =
100-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CpuCounterTrackCookerId);
104+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CpuCounterTrackCookerId);
105+
public static readonly DataCookerPath GpuCounterTrackCookerPath =
106+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.GpuCounterTrackCookerId);
101107
public static readonly DataCookerPath ProcessCounterTrackCookerPath =
102-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessCounterTrackCookerId);
108+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessCounterTrackCookerId);
103109
public static readonly DataCookerPath CounterTrackCookerPath =
104-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterTrackCookerId);
110+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.CounterTrackCookerId);
105111
public static readonly DataCookerPath ProcessTrackCookerPath =
106-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessTrackCookerId);
112+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.ProcessTrackCookerId);
107113
public static readonly DataCookerPath PerfSampleCookerPath =
108-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.PerfSampleCookerId);
114+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.PerfSampleCookerId);
109115
public static readonly DataCookerPath StackProfileCallSiteCookerPath =
110-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileCallSiteCookerId);
116+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileCallSiteCookerId);
111117
public static readonly DataCookerPath StackProfileFrameCookerPath =
112-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileFrameCookerId);
118+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileFrameCookerId);
113119
public static readonly DataCookerPath StackProfileMappingCookerPath =
114-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileMappingCookerId);
120+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileMappingCookerId);
115121
public static readonly DataCookerPath StackProfileSymbolCookerPath =
116-
new DataCookerPath(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileSymbolCookerId);
122+
DataCookerPath.ForSource(PerfettoPluginConstants.ParserId, PerfettoPluginConstants.StackProfileSymbolCookerId);
117123

118124
// Paths for composite cookers
119125
public static readonly DataCookerPath GenericEventCookerPath =
120-
new DataCookerPath(PerfettoPluginConstants.GenericEventCookerId);
126+
DataCookerPath.ForComposite(PerfettoPluginConstants.GenericEventCookerId);
121127
public static readonly DataCookerPath CpuSchedEventCookerPath =
122-
new DataCookerPath(PerfettoPluginConstants.CpuSchedEventCookerId);
128+
DataCookerPath.ForComposite(PerfettoPluginConstants.CpuSchedEventCookerId);
123129
public static readonly DataCookerPath LogcatEventCookerPath =
124-
new DataCookerPath(PerfettoPluginConstants.LogcatEventCookerId);
130+
DataCookerPath.ForComposite(PerfettoPluginConstants.LogcatEventCookerId);
125131
public static readonly DataCookerPath FtraceEventCookerPath =
126-
new DataCookerPath(PerfettoPluginConstants.FtraceEventCookerId);
132+
DataCookerPath.ForComposite(PerfettoPluginConstants.FtraceEventCookerId);
127133
public static readonly DataCookerPath CpuFrequencyEventCookerPath =
128-
new DataCookerPath(PerfettoPluginConstants.CpuFrequencyEventCookerId);
134+
DataCookerPath.ForComposite(PerfettoPluginConstants.CpuFrequencyEventCookerId);
129135
public static readonly DataCookerPath CpuCountersEventCookerPath =
130-
new DataCookerPath(PerfettoPluginConstants.CpuCountersEventCookerId);
136+
DataCookerPath.ForComposite(PerfettoPluginConstants.CpuCountersEventCookerId);
137+
public static readonly DataCookerPath GpuCountersEventCookerPath =
138+
DataCookerPath.ForComposite(PerfettoPluginConstants.GpuCountersEventCookerId);
131139
public static readonly DataCookerPath ProcessMemoryEventCookerPath =
132-
new DataCookerPath(PerfettoPluginConstants.ProcessMemoryEventCookerId);
140+
DataCookerPath.ForComposite(PerfettoPluginConstants.ProcessMemoryEventCookerId);
133141
public static readonly DataCookerPath SystemMemoryEventCookerPath =
134-
new DataCookerPath(PerfettoPluginConstants.SystemMemoryEventCookerId);
142+
DataCookerPath.ForComposite(PerfettoPluginConstants.SystemMemoryEventCookerId);
135143
public static readonly DataCookerPath CpuSamplingEventCookerPath =
136-
new DataCookerPath(PerfettoPluginConstants.CpuSamplingEventCookerId);
137-
144+
DataCookerPath.ForComposite(PerfettoPluginConstants.CpuSamplingEventCookerId);
138145
}
139146
}

PerfettoCds/Pipeline/PerfettoSourceParser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ void EventCallback(PerfettoSqlEvent ev)
168168
new PerfettoAndroidLogEvent(),
169169
new PerfettoRawEvent(),
170170
new PerfettoCpuCounterTrackEvent(),
171+
new PerfettoGpuCounterTrackEvent(),
171172
new PerfettoCounterEvent(),
172173
new PerfettoProcessCounterTrackEvent(),
173174
new PerfettoCounterTrackEvent(),
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using Microsoft.Performance.SDK;
4+
using Microsoft.Performance.SDK.Extensibility;
5+
using Microsoft.Performance.SDK.Extensibility.DataCooking;
6+
using Microsoft.Performance.SDK.Extensibility.DataCooking.SourceDataCooking;
7+
using Microsoft.Performance.SDK.Processing;
8+
using System.Collections.Generic;
9+
using System.Threading;
10+
using PerfettoCds.Pipeline.Events;
11+
using PerfettoProcessor;
12+
13+
namespace PerfettoCds.Pipeline.SourceDataCookers
14+
{
15+
/// <summary>
16+
/// Cooks the data from the GpuCounterTrack table in Perfetto traces
17+
/// </summary>
18+
public sealed class PerfettoGpuCounterTrackCooker : BaseSourceDataCooker<PerfettoSqlEventKeyed, PerfettoSourceParser, string>
19+
{
20+
public override string Description => "Processes events from the GpuCounterTrack Perfetto SQL table";
21+
22+
//
23+
// The data this cooker outputs. Tables or other cookers can query for this data
24+
// via the SDK runtime
25+
//
26+
[DataOutput]
27+
public ProcessedEventData<PerfettoGpuCounterTrackEvent> GpuCounterTrackEvents { get; }
28+
29+
// Instructs runtime to only send events with the given keys this data cooker
30+
public override ReadOnlyHashSet<string> DataKeys =>
31+
new ReadOnlyHashSet<string>(new HashSet<string> { PerfettoPluginConstants.GpuCounterTrackEvent });
32+
33+
public PerfettoGpuCounterTrackCooker() : base(PerfettoPluginConstants.GpuCounterTrackCookerPath)
34+
{
35+
this.GpuCounterTrackEvents = new ProcessedEventData<PerfettoGpuCounterTrackEvent>();
36+
}
37+
38+
public override DataProcessingResult CookDataElement(PerfettoSqlEventKeyed perfettoEvent, PerfettoSourceParser context, CancellationToken cancellationToken)
39+
{
40+
this.GpuCounterTrackEvents.AddEvent((PerfettoGpuCounterTrackEvent)perfettoEvent.SqlEvent);
41+
42+
return DataProcessingResult.Processed;
43+
}
44+
45+
public override void EndDataCooking(CancellationToken cancellationToken)
46+
{
47+
base.EndDataCooking(cancellationToken);
48+
this.GpuCounterTrackEvents.FinalizeData();
49+
}
50+
}
51+
}

PerfettoCds/Pipeline/Tables/PerfettoCpuCountersTable.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class PerfettoCpuCountersTable
2121
"CPU Counters (coarse)",
2222
"Displays coarse CPU usage based on /proc/stat counters",
2323
"Perfetto - System",
24+
defaultLayout: TableLayoutStyle.GraphAndTable,
2425
requiredDataCookers: new List<DataCookerPath> { PerfettoPluginConstants.CpuCountersEventCookerPath }
2526
);
2627

@@ -142,7 +143,6 @@ public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieva
142143
TableConfiguration.GraphColumn, // Columns after this get graphed
143144
TotalCpuUsagePercentColumn
144145
},
145-
Layout = TableLayoutStyle.GraphAndTable,
146146
ChartType = ChartType.Line
147147
};
148148
cpuUsageConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);
@@ -169,7 +169,6 @@ public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieva
169169
IrqPercentColumn,
170170
SoftIrqPercentColumn,
171171
},
172-
Layout = TableLayoutStyle.GraphAndTable,
173172
ChartType = ChartType.Line
174173
};
175174
allCountersConfig.AddColumnRole(ColumnRole.StartTime, StartTimestampColumn.Metadata.Guid);

0 commit comments

Comments
 (0)