Skip to content

Commit 107e4e4

Browse files
authored
User/ivberg/perfetto process (#91)
* Bring GUI Table Process support with arg fields & process label from Chromium. * Enhance GenericEvents to show this process label info if available. * Add Android Package table * Add rowcount logging for Perfetto sql queries. * Slightly better Unit Tests for new tables by building tables as well (data not processed yet)
1 parent dcf27dc commit 107e4e4

31 files changed

+892
-101
lines changed

PerfettoCds/PerfettoCds.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>netstandard2.1</TargetFramework>
5-
<Version>1.4.0</Version>
5+
<Version>1.5.0</Version>
66
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
77
<Authors>Microsoft</Authors>
88
<Company>Microsoft Corp.</Company>

PerfettoCds/Pipeline/Args.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
using System;
4+
using System.Collections.Generic;
5+
using System.IO;
6+
using System.Linq;
7+
using Microsoft.Performance.SDK.Processing;
8+
using PerfettoProcessor;
9+
using Utilities;
10+
11+
namespace PerfettoCds
12+
{
13+
public class Args
14+
{
15+
public List<string> ArgKeys { get; private set; }
16+
public List<object> Values { get; private set; }
17+
18+
public static Args ParseArgs(IEnumerable<PerfettoArgEvent> perfettoArgEvents)
19+
{
20+
var args = new Args();
21+
args.ArgKeys = new List<string>();
22+
args.Values = new List<object>();
23+
24+
// Each event has multiple of these "debug annotations". They get stored in lists
25+
foreach (var arg in perfettoArgEvents)
26+
{
27+
args.ArgKeys.Add(Common.StringIntern(arg.ArgKey));
28+
switch (arg.ValueType)
29+
{
30+
case "json":
31+
case "string":
32+
args.Values.Add(Common.StringIntern(arg.StringValue));
33+
break;
34+
case "bool":
35+
case "int":
36+
args.Values.Add(arg.IntValue);
37+
break;
38+
case "uint":
39+
case "pointer":
40+
args.Values.Add((uint)arg.IntValue);
41+
break;
42+
case "real":
43+
args.Values.Add(arg.RealValue);
44+
break;
45+
default:
46+
throw new Exception("Unexpected Perfetto value type");
47+
}
48+
}
49+
50+
return args;
51+
}
52+
}
53+
}

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoCpuSamplingEventCooker.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public sealed class PerfettoCpuSamplingEventCooker : CookedDataReflector, ICompo
3232
PerfettoPluginConstants.StackProfileMappingCookerPath,
3333
PerfettoPluginConstants.StackProfileSymbolCookerPath,
3434
PerfettoPluginConstants.ThreadCookerPath,
35-
PerfettoPluginConstants.ProcessCookerPath,
35+
PerfettoPluginConstants.ProcessRawCookerPath,
3636
};
3737

3838
[DataOutput]
@@ -47,7 +47,7 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
4747
{
4848
// Gather the data from all the SQL tables
4949
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
50-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
50+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessRawEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessRawCookerPath, nameof(PerfettoProcessRawCooker.ProcessEvents)));
5151

5252
var perfSampleData = requiredData.QueryOutput<ProcessedEventData<PerfettoPerfSampleEvent>>(new DataOutputPath(PerfettoPluginConstants.PerfSampleCookerPath, nameof(PerfettoPerfSampleCooker.PerfSampleEvents)));
5353
var stackProfileCallSiteData = requiredData.QueryOutput<ProcessedEventData<PerfettoStackProfileCallSiteEvent>>(new DataOutputPath(PerfettoPluginConstants.StackProfileCallSiteCookerPath, nameof(PerfettoStackProfileCallSiteCooker.StackProfileCallSiteEvents)));

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoCpuSchedEventCooker.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public sealed class PerfettoCpuSchedEventCooker : CookedDataReflector, IComposit
2828
public IReadOnlyCollection<DataCookerPath> RequiredDataCookers => new[]
2929
{
3030
PerfettoPluginConstants.ThreadCookerPath,
31-
PerfettoPluginConstants.ProcessCookerPath,
31+
PerfettoPluginConstants.ProcessRawCookerPath,
3232
PerfettoPluginConstants.SchedSliceCookerPath,
3333
PerfettoPluginConstants.FtraceEventCookerPath
3434
};
@@ -49,11 +49,11 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
4949
{
5050
// Gather the data from all the SQL tables
5151
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
52-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
52+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessRawEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessRawCookerPath, nameof(PerfettoProcessRawCooker.ProcessEvents)));
5353
PopulateCpuSchedulingEvents(requiredData, threadData, processData);
5454
}
5555

56-
void PopulateCpuSchedulingEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessEvent> processData)
56+
void PopulateCpuSchedulingEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessRawEvent> processData)
5757
{
5858
var schedSliceData = requiredData.QueryOutput<ProcessedEventData<PerfettoSchedSliceEvent>>(new DataOutputPath(PerfettoPluginConstants.SchedSliceCookerPath, nameof(PerfettoSchedSliceCooker.SchedSliceEvents)));
5959

@@ -138,31 +138,31 @@ from threadProcess in pd.DefaultIfEmpty()
138138
}
139139
}
140140

141-
void PopulateCpuWakeEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessEvent> processData)
141+
void PopulateCpuWakeEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessRawEvent> processData)
142142
{
143143
var schedWakeData = requiredData.QueryOutput<ProcessedEventData<PerfettoFtraceEvent>>(new DataOutputPath(PerfettoPluginConstants.FtraceEventCookerPath, nameof(PerfettoFtraceEventCooker.FtraceEvents)))
144144
.Where(f => f.Name == "sched_wakeup");
145145

146-
Dictionary<long, PerfettoThreadEvent> tidToThreadMap = threadData
146+
Dictionary<uint, PerfettoThreadEvent> tidToThreadMap = threadData
147147
.ToLookup(t => t.Tid)
148148
.ToDictionary(tg => tg.Key, tg => tg.Last());
149-
Dictionary<long, PerfettoProcessEvent> upidToProcessMap = processData
149+
Dictionary<uint, PerfettoProcessRawEvent> upidToProcessMap = processData
150150
.ToLookup(p => p.Upid)
151151
.ToDictionary(pg => pg.Key, pg => pg.Last());
152152

153153
// Create events out of the joined results
154154
foreach (var wake in schedWakeData)
155155
{
156-
long wokenTid = long.Parse(wake.Values[1]); // This field name is pid but it is woken thread's Tid.
156+
var wokenTid = uint.Parse(wake.Values[1]); // This field name is pid but it is woken thread's Tid.
157157
PerfettoThreadEvent wokenThread = tidToThreadMap[wokenTid];
158158
string wokenThreadName = wokenThread.Name;
159-
long? wokenPid = wokenThread.Upid;
159+
var wokenPid = wokenThread.Upid;
160160
string wokenProcessName = wokenPid != null ? upidToProcessMap[wokenPid.Value].Name : wake.Values[0]; // This field name is comms but it is woken process name.
161161

162162
string wakerThreadName = wake.ThreadName;
163-
long wakerTid = wake.Tid;
163+
var wakerTid = wake.Tid;
164164
PerfettoThreadEvent wakerThread = tidToThreadMap[wakerTid];
165-
long? wakerPid = wakerThread.Upid;
165+
var wakerPid = wakerThread.Upid;
166166
string wakerProcessName = wakerPid != null ? upidToProcessMap[wakerPid.Value].Name : String.Empty;
167167

168168
PerfettoCpuWakeEvent ev = new PerfettoCpuWakeEvent

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoFrameEventCooker.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public sealed class PerfettoFrameEventCooker : CookedDataReflector, ICompositeDa
3030
public IReadOnlyCollection<DataCookerPath> RequiredDataCookers => new[]
3131
{
3232
PerfettoPluginConstants.ThreadCookerPath,
33-
PerfettoPluginConstants.ProcessCookerPath,
33+
PerfettoPluginConstants.ProcessRawCookerPath,
3434
PerfettoPluginConstants.ActualFrameCookerPath,
3535
PerfettoPluginConstants.ExpectedFrameCookerPath
3636
};
@@ -48,11 +48,11 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
4848
{
4949
// Gather the data from all the SQL tables
5050
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
51-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
51+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessRawEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessRawCookerPath, nameof(PerfettoProcessRawCooker.ProcessEvents)));
5252
PopulateFrameEvents(requiredData, threadData, processData);
5353
}
5454

55-
void PopulateFrameEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessEvent> processData)
55+
void PopulateFrameEvents(IDataExtensionRetrieval requiredData, ProcessedEventData<PerfettoThreadEvent> threadData, ProcessedEventData<PerfettoProcessRawEvent> processData)
5656
{
5757
var actualFrameData = requiredData.QueryOutput<ProcessedEventData<PerfettoActualFrameEvent>>(new DataOutputPath(PerfettoPluginConstants.ActualFrameCookerPath, nameof(PerfettoActualFrameCooker.ActualFrameEvents)));
5858
var expectedFrameData = requiredData.QueryOutput<ProcessedEventData<PerfettoExpectedFrameEvent>>(new DataOutputPath(PerfettoPluginConstants.ExpectedFrameCookerPath, nameof(PerfettoExpectedFrameCooker.ExpectedFrameEvents)));

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoFtraceEventCooker.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public sealed class PerfettoFtraceEventCooker : CookedDataReflector, ICompositeD
3030
{
3131
PerfettoPluginConstants.RawCookerPath,
3232
PerfettoPluginConstants.ThreadCookerPath,
33-
PerfettoPluginConstants.ProcessCookerPath,
33+
PerfettoPluginConstants.ProcessRawCookerPath,
3434
PerfettoPluginConstants.ArgCookerPath
3535
};
3636

@@ -54,7 +54,7 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
5454
// Gather the data from all the SQL tables
5555
var rawData = requiredData.QueryOutput<ProcessedEventData<PerfettoRawEvent>>(new DataOutputPath(PerfettoPluginConstants.RawCookerPath, nameof(PerfettoRawCooker.RawEvents)));
5656
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
57-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
57+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessRawEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessRawCookerPath, nameof(PerfettoProcessRawCooker.ProcessEvents)));
5858
var argsData = requiredData.QueryOutput<ProcessedEventData<PerfettoArgEvent>>(new DataOutputPath(PerfettoPluginConstants.ArgCookerPath, nameof(PerfettoArgCooker.ArgEvents)));
5959

6060
// Join them all together

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoGenericEventCooker.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public sealed class PerfettoGenericEventCooker : CookedDataReflector, IComposite
6161
PerfettoPluginConstants.ArgCookerPath,
6262
PerfettoPluginConstants.ThreadTrackCookerPath,
6363
PerfettoPluginConstants.ThreadCookerPath,
64-
PerfettoPluginConstants.ProcessCookerPath,
64+
PerfettoPluginConstants.ProcessEventCookerPath,
6565
PerfettoPluginConstants.ProcessTrackCookerPath
6666
};
6767

@@ -154,7 +154,7 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
154154
var argData = requiredData.QueryOutput<ProcessedEventData<PerfettoArgEvent>>(new DataOutputPath(PerfettoPluginConstants.ArgCookerPath, nameof(PerfettoArgCooker.ArgEvents)));
155155
var threadTrackData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadTrackEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadTrackCookerPath, nameof(PerfettoThreadTrackCooker.ThreadTrackEvents)));
156156
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
157-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
157+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessEventCookerPath, nameof(PerfettoProcessEventCooker.ProcessEvents)));
158158
var processTrackData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessTrackEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessTrackCookerPath, nameof(PerfettoProcessTrackCooker.ProcessTrackEvents)));
159159

160160
// Join them all together
@@ -173,11 +173,13 @@ join thread in threadData on threadTrack?.Utid equals thread.Utid into td
173173
from thread in td.DefaultIfEmpty()
174174
join threadProcess in processData on thread?.Upid equals threadProcess.Upid into pd
175175
from threadProcess in pd.DefaultIfEmpty()
176+
join threadProcessProcess in processData on threadProcess?.Upid equals threadProcessProcess.Upid into pd1
177+
from threadProcessProcess in pd1.DefaultIfEmpty()
176178
join processTrack in processTrackData on slice.TrackId equals processTrack.Id into ptd
177179
from processTrack in ptd.DefaultIfEmpty()
178-
join process in processData on processTrack?.Upid equals process.Upid into pd2
179-
from process in pd2.DefaultIfEmpty()
180-
select new { slice, args, threadTrack, thread, threadProcess, process };
180+
join processTrackProcess in processData on processTrack?.Upid equals processTrackProcess.Upid into pd2
181+
from processTrackProcess in pd2.DefaultIfEmpty()
182+
select new { slice, args, threadTrack, thread, threadProcess, threadProcessProcess, processTrackProcess };
181183

182184
var longestRelTS = joined.Max(f => f.slice?.RelativeTimestamp);
183185
var longestEndTs = longestRelTS.HasValue ? new Timestamp(longestRelTS.Value) : Timestamp.MaxValue;
@@ -188,6 +190,8 @@ from process in pd2.DefaultIfEmpty()
188190
MaximumEventFieldCount = Math.Max(MaximumEventFieldCount, result.args.Count());
189191

190192
string provider = string.Empty;
193+
194+
// TODO - Replace with Args.ParseArgs
191195
List<string> argKeys = new List<string>();
192196
List<string> values = new List<string>();
193197
// Each event has multiple of these "debug annotations". They get stored in lists
@@ -230,6 +234,7 @@ from process in pd2.DefaultIfEmpty()
230234
}
231235

232236
string processName = string.Empty;
237+
string processLabel = string.Empty;
233238
string threadName = string.Empty;
234239
if (result.thread != null)
235240
{
@@ -241,9 +246,18 @@ from process in pd2.DefaultIfEmpty()
241246
{
242247
processName = $"{result.threadProcess.Name} ({result.threadProcess.Pid})";
243248
}
244-
else if (result.process != null)
249+
else if (result.processTrackProcess != null)
250+
{
251+
processName = $"{result.processTrackProcess.Name} ({result.processTrackProcess.Pid})";
252+
}
253+
254+
if (result.threadProcessProcess != null)
255+
{
256+
processLabel = result.threadProcessProcess.Label;
257+
}
258+
else if (result.processTrackProcess != null)
245259
{
246-
processName = $"{result.process.Name} ({result.process.Pid})";
260+
processLabel = result.processTrackProcess.Label;
247261
}
248262

249263
int parentTreeDepthLevel = 0;
@@ -293,6 +307,7 @@ from process in pd2.DefaultIfEmpty()
293307
values,
294308
argKeys,
295309
processName,
310+
processLabel,
296311
threadName,
297312
provider,
298313
result.threadTrack,

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoLogcatEventCooker.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public sealed class PerfettoLogcatEventCooker : CookedDataReflector, ICompositeD
2828
{
2929
PerfettoPluginConstants.AndroidLogCookerPath,
3030
PerfettoPluginConstants.ThreadCookerPath,
31-
PerfettoPluginConstants.ProcessCookerPath
31+
PerfettoPluginConstants.ProcessRawCookerPath
3232
};
3333

3434
[DataOutput]
@@ -50,7 +50,7 @@ public void OnDataAvailable(IDataExtensionRetrieval requiredData)
5050
{
5151
// Gather the data from all the SQL tables
5252
var threadData = requiredData.QueryOutput<ProcessedEventData<PerfettoThreadEvent>>(new DataOutputPath(PerfettoPluginConstants.ThreadCookerPath, nameof(PerfettoThreadCooker.ThreadEvents)));
53-
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessCookerPath, nameof(PerfettoProcessCooker.ProcessEvents)));
53+
var processData = requiredData.QueryOutput<ProcessedEventData<PerfettoProcessRawEvent>>(new DataOutputPath(PerfettoPluginConstants.ProcessRawCookerPath, nameof(PerfettoProcessRawCooker.ProcessEvents)));
5454
var androidLogData = requiredData.QueryOutput<ProcessedEventData<PerfettoAndroidLogEvent>>(new DataOutputPath(PerfettoPluginConstants.AndroidLogCookerPath, nameof(PerfettoAndroidLogCooker.AndroidLogEvents)));
5555

5656
// Join them all together

0 commit comments

Comments
 (0)