Skip to content

Commit 265cd97

Browse files
authored
Support in Perfetto for event Exclusive Duration (duration minus it's children) to get just time spent exclusively in that slice (function) (#94)
1 parent 855fe0b commit 265cd97

File tree

5 files changed

+151
-45
lines changed

5 files changed

+151
-45
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.5.1</Version>
5+
<Version>1.5.2</Version>
66
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
77
<Authors>Microsoft</Authors>
88
<Company>Microsoft Corp.</Company>

PerfettoCds/Pipeline/CompositeDataCookers/PerfettoGenericEventCooker.cs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33
using System;
44
using System.Collections.Generic;
5+
using System.Diagnostics;
56
using System.IO;
67
using System.Linq;
78
using System.Reflection;
@@ -14,7 +15,6 @@
1415
using PerfettoCds.Pipeline.DataOutput;
1516
using PerfettoCds.Pipeline.SourceDataCookers;
1617
using PerfettoProcessor;
17-
using Utilities;
1818

1919
namespace PerfettoCds.Pipeline.CompositeDataCookers
2020
{
@@ -182,7 +182,43 @@ from processTrackProcess in pd2.DefaultIfEmpty()
182182
select new { slice, args, threadTrack, thread, threadProcess, threadProcessProcess, processTrackProcess };
183183

184184
var longestRelTS = joined.Max(f => f.slice?.RelativeTimestamp);
185-
var longestEndTs = longestRelTS.HasValue ? new Timestamp(longestRelTS.Value) : Timestamp.MaxValue;
185+
var longestEndTs = longestRelTS.HasValue ? new Timestamp(longestRelTS.Value) : Timestamp.MaxValue;
186+
187+
Dictionary<int, long> SliceId_DurationExclusive = new Dictionary<int, long>();
188+
// Duration Exclusion calculation (Duration minus child durations)
189+
// First we need to walk all the events & their direct parent
190+
// Slices seem to be per-thread in Perfetto and thus are non-overlapping (time-wise work)
191+
// Thus we can just subtract children time
192+
foreach (var result in joined)
193+
{
194+
int? parentId = result.slice.ParentId;
195+
196+
if (!SliceId_DurationExclusive.ContainsKey(result.slice.Id))
197+
{
198+
SliceId_DurationExclusive[result.slice.Id] = result.slice.Duration;
199+
}
200+
201+
if (parentId.HasValue)
202+
{
203+
var parentPerfettoSliceEvent = sliceData[parentId.Value];
204+
if (parentPerfettoSliceEvent != null)
205+
{
206+
if (SliceId_DurationExclusive.TryGetValue(parentId.Value, out long currentParentExDuration))
207+
{
208+
// Some slices have negative duration and we don't want to increase exclusive duration of parent for this
209+
if (result.slice.Duration > 0 && currentParentExDuration > 0)
210+
{
211+
SliceId_DurationExclusive[parentId.Value] = currentParentExDuration - result.slice.Duration;
212+
}
213+
Debug.Assert(SliceId_DurationExclusive[parentId.Value] >= -1); // Verify non-overlapping otherwise duration will go negative excluding bad durations
214+
}
215+
else
216+
{
217+
SliceId_DurationExclusive.Add(parentId.Value, parentPerfettoSliceEvent.Duration);
218+
}
219+
}
220+
}
221+
}
186222

187223
// Create events out of the joined results
188224
foreach (var result in joined)
@@ -238,14 +274,14 @@ from processTrackProcess in pd2.DefaultIfEmpty()
238274
}
239275

240276
int parentTreeDepthLevel = 0;
241-
long? currentParentId = result.slice.ParentId;
277+
int? currentParentId = result.slice.ParentId;
242278
List<string> tmpParentEventNameTreeBranch = new List<string>();
243279
tmpParentEventNameTreeBranch.Add(result.slice.Name);
244280

245281
// Walk the parent tree
246282
while (currentParentId.HasValue)
247283
{
248-
var parentPerfettoSliceEvent = sliceData[(int)currentParentId.Value];
284+
var parentPerfettoSliceEvent = sliceData[currentParentId.Value];
249285
// Debug.Assert(parentPerfettoSliceEvent == null || (parentPerfettoSliceEvent.Id == currentParentId.Value)); // Should be guaranteed by slice Id ordering. Since we are relying on index being the Id
250286

251287
if (parentPerfettoSliceEvent != null)
@@ -273,9 +309,11 @@ from processTrackProcess in pd2.DefaultIfEmpty()
273309

274310
PerfettoGenericEvent ev = new PerfettoGenericEvent
275311
(
312+
result.slice.Id,
276313
result.slice.Name,
277314
result.slice.Type,
278315
new TimestampDelta(result.slice.Duration),
316+
new TimestampDelta(SliceId_DurationExclusive[result.slice.Id]),
279317
new Timestamp(result.slice.RelativeTimestamp),
280318
result.slice.Duration >= 0 ? // Duration can be not complete / negative
281319
new Timestamp(result.slice.RelativeTimestamp + result.slice.Duration) :

PerfettoCds/Pipeline/DataOutput/PerfettoGenericEvent.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@ namespace PerfettoCds.Pipeline.DataOutput
1414
public readonly struct PerfettoGenericEvent
1515
{
1616
// From Slice table
17+
public int SliceId { get; }
1718
public string EventName { get; }
1819
public string Type { get; }
20+
21+
// The duration of the event
1922
public TimestampDelta Duration { get; }
23+
24+
// The duration of the event excluding it's children
25+
public TimestampDelta DurationExclusive { get; }
26+
2027
public Timestamp StartTimestamp { get; }
2128
public Timestamp EndTimestamp { get; }
2229
public string Category { get; }
@@ -41,9 +48,12 @@ public readonly struct PerfettoGenericEvent
4148

4249
public string[] ParentEventNameTree { get; }
4350

44-
public PerfettoGenericEvent(string eventName,
51+
public PerfettoGenericEvent(
52+
int sliceId,
53+
string eventName,
4554
string type,
46-
TimestampDelta duration,
55+
TimestampDelta duration,
56+
TimestampDelta durationExclusive,
4757
Timestamp startTimestamp,
4858
Timestamp endTimestamp,
4959
string category,
@@ -57,9 +67,11 @@ public PerfettoGenericEvent(string eventName,
5767
int parentTreeDepthLevel,
5868
string[] parentEventNameTree)
5969
{
70+
SliceId = sliceId;
6071
EventName = Common.StringIntern(eventName);
6172
Type = Common.StringIntern(type);
6273
Duration = duration;
74+
DurationExclusive = durationExclusive;
6375
StartTimestamp = startTimestamp;
6476
EndTimestamp = endTimestamp;
6577
Category = Common.StringIntern(category);

0 commit comments

Comments
 (0)