Skip to content

Commit 46b1909

Browse files
authored
Merge pull request #139 from microsoft/user/hanemati/lttng-pmu-counters
Add PMU performance counters to LTTng execution events table
2 parents 774054b + a92981b commit 46b1909

5 files changed

Lines changed: 87 additions & 15 deletions

File tree

‎LTTngDataExtensions/DataOutputTypes/IExecutionEvent.cs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4+
using System.Collections.Generic;
45
using Microsoft.Performance.SDK;
56

67
namespace LTTngDataExtensions.SourceDataCookers.Thread
@@ -23,5 +24,6 @@ public interface IExecutionEvent
2324
Timestamp SwitchInTime { get; }
2425
Timestamp SwitchOutTime { get; }
2526
Timestamp NextThreadPreviousSwitchOutTime { get; }
27+
IReadOnlyDictionary<string, long> PerformanceCountersDiffByName { get; }
2628
}
2729
}

‎LTTngDataExtensions/SourceDataCookers/Thread/ContextSwitch.cs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4+
using System.Collections.Generic;
45
using Microsoft.Performance.SDK;
56
using LTTngCds.CookerData;
7+
using CtfPlayback.Metadata;
68

79
namespace LTTngDataExtensions.SourceDataCookers.Thread
810
{
@@ -23,6 +25,7 @@ public class ContextSwitch
2325
private TimestampDelta waitTime;
2426
private Timestamp switchInTime;
2527
private Timestamp nextThreadPreviousSwitchOutTime;
28+
private Dictionary<string, long> performanceCountersByName;
2629

2730
public ContextSwitch(LTTngEvent data, ThreadInfo nextThread, ThreadInfo previousThread, uint cpu)
2831
{
@@ -61,6 +64,20 @@ public ContextSwitch(LTTngEvent data, ThreadInfo nextThread, ThreadInfo previous
6164
this.previousCommand = data.Payload.ReadFieldAsArray("_prev_comm").GetValueAsString();
6265
this.switchInTime = data.Timestamp;
6366
this.nextThreadPreviousSwitchOutTime = nextThread.previousSwitchOutTime;
67+
68+
// PMU counters (e.g. _perf_cpu_instructions) are added to the stream event context by "lttng add-context -t perf:cpu:..."
69+
this.performanceCountersByName = new Dictionary<string, long>();
70+
var eventContext = data.StreamDefinedEventContext;
71+
if (eventContext != null)
72+
{
73+
foreach (var field in eventContext.FieldsByName)
74+
{
75+
if (field.Value.FieldType == CtfTypes.Integer && field.Key.Contains("perf"))
76+
{
77+
this.performanceCountersByName[field.Key] = eventContext.ReadFieldAsInt64(field.Key);
78+
}
79+
}
80+
}
6481
}
6582

6683
public uint Cpu => this.cpu;
@@ -78,5 +95,6 @@ public ContextSwitch(LTTngEvent data, ThreadInfo nextThread, ThreadInfo previous
7895
public TimestampDelta WaitTime => this.waitTime;
7996
public Timestamp SwitchInTime => this.switchInTime;
8097
public Timestamp NextThreadPreviousSwitchOutTime => this.nextThreadPreviousSwitchOutTime;
98+
public IReadOnlyDictionary<string, long> PerformanceCountersByName => this.performanceCountersByName;
8199
}
82100
}

‎LTTngDataExtensions/SourceDataCookers/Thread/ExecutionEvent.cs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ public class ExecutionEvent
2727
private Timestamp switchInTime;
2828
private Timestamp switchOutTime;
2929
private Timestamp nextThreadPreviousSwitchOutTime;
30+
private Dictionary<string, long> performanceCountersDiffByName;
3031

3132
public ExecutionEvent(ContextSwitch contextSwitch, Timestamp switchOutTime)
33+
: this(contextSwitch, null, switchOutTime)
34+
{
35+
}
36+
37+
public ExecutionEvent(ContextSwitch contextSwitch, ContextSwitch switchOutContextSwitch, Timestamp switchOutTime)
3238
{
3339
this.cpu = contextSwitch.Cpu;
3440
this.nextPid = contextSwitch.NextPid;
@@ -46,6 +52,18 @@ public ExecutionEvent(ContextSwitch contextSwitch, Timestamp switchOutTime)
4652
this.switchInTime = contextSwitch.SwitchInTime;
4753
this.switchOutTime = switchOutTime;
4854
this.nextThreadPreviousSwitchOutTime = contextSwitch.NextThreadPreviousSwitchOutTime;
55+
56+
this.performanceCountersDiffByName = new Dictionary<string, long>();
57+
if (switchOutContextSwitch != null)
58+
{
59+
foreach (var counter in contextSwitch.PerformanceCountersByName)
60+
{
61+
if (switchOutContextSwitch.PerformanceCountersByName.TryGetValue(counter.Key, out long switchOutValue))
62+
{
63+
this.performanceCountersDiffByName[counter.Key] = switchOutValue - counter.Value;
64+
}
65+
}
66+
}
4967
}
5068

5169
public void RecoverPids(Dictionary<int, int> recoveredPids)
@@ -90,5 +108,6 @@ private int reconstructPid(string pid)
90108
public Timestamp SwitchInTime => this.switchInTime;
91109
public Timestamp SwitchOutTime => this.switchOutTime;
92110
public Timestamp NextThreadPreviousSwitchOutTime => this.nextThreadPreviousSwitchOutTime;
111+
public IReadOnlyDictionary<string, long> PerformanceCountersDiffByName => this.performanceCountersDiffByName;
93112
}
94113
}

‎LTTngDataExtensions/SourceDataCookers/Thread/LTTngThreadDataCooker.cs‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -577,19 +577,6 @@ void ProcessThreadMetadata(LTTngEvent data, ThreadInfo thread)
577577
public void ProcessContextSwitch(LTTngEvent data, LTTngContext context)
578578
{
579579
int prevTid = data.Payload.ReadFieldAsInt32("_prev_tid");
580-
if (lastContextSwitch.TryGetValue(context.CurrentCpu, out ContextSwitch previousContextSwitch))
581-
{
582-
if (prevTid == previousContextSwitch.NextTid)
583-
{
584-
processedExecutionEvents.Add(new ExecutionEvent(previousContextSwitch, data.Timestamp));
585-
}
586-
else
587-
{
588-
///If we missed context switch events,
589-
processedExecutionEvents.Add(new ExecutionEvent(previousContextSwitch, previousContextSwitch.SwitchInTime));
590-
}
591-
592-
}
593580
int nextTid = data.Payload.ReadFieldAsInt32("_next_tid");
594581
ThreadInfo.ThreadState switchOutState;
595582
var prevStateValue = data.Payload.FieldsByName["_prev_state"];
@@ -620,17 +607,34 @@ public void ProcessContextSwitch(LTTngEvent data, LTTngContext context)
620607
}
621608

622609
ThreadInfo nextThread;
610+
ContextSwitch currentContextSwitch;
623611
if (runningThreads.TryGetValue(nextTid, out nextThread))
624612
{
625-
lastContextSwitch[context.CurrentCpu] = new ContextSwitch(data, nextThread, prevThread, context.CurrentCpu);
613+
currentContextSwitch = new ContextSwitch(data, nextThread, prevThread, context.CurrentCpu);
626614
nextThread.SwitchIn(data.Timestamp);
627615
}
628616
else
629617
{
630618
nextThread = new ThreadInfo(nextTid, data.Timestamp, ThreadInfo.ThreadState.TASK_RUNNING);
631-
lastContextSwitch[context.CurrentCpu] = new ContextSwitch(data, nextThread, prevThread, context.CurrentCpu);
619+
currentContextSwitch = new ContextSwitch(data, nextThread, prevThread, context.CurrentCpu);
632620
this.AddNewThread(nextThread);
633621
}
622+
623+
// The execution event for the previous context switch is completed here so the PMU counter deltas can be computed against this switch-out.
624+
if (lastContextSwitch.TryGetValue(context.CurrentCpu, out ContextSwitch previousContextSwitch))
625+
{
626+
if (prevTid == previousContextSwitch.NextTid)
627+
{
628+
processedExecutionEvents.Add(new ExecutionEvent(previousContextSwitch, currentContextSwitch, data.Timestamp));
629+
}
630+
else
631+
{
632+
///If we missed context switch events,
633+
processedExecutionEvents.Add(new ExecutionEvent(previousContextSwitch, previousContextSwitch.SwitchInTime));
634+
}
635+
}
636+
637+
lastContextSwitch[context.CurrentCpu] = currentContextSwitch;
634638
}
635639

636640
public void ProcessThreadExit(LTTngEvent data)

‎LTTngDataExtensions/Tables/ExecutionEventTable.cs‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,26 @@ public class ExecutionEventTable
108108
new ColumnMetadata(new Guid("{5AB96EE5-FE5C-45AE-9BA2-965EFF4833D8}"), "Last Switch-Out Time"),
109109
new UIHints { Width = 80, });
110110

111+
private static readonly ColumnConfiguration instructionCountColumn =
112+
new ColumnConfiguration(
113+
new ColumnMetadata(new Guid("{63447522-514D-4F7D-81E0-544E0670BB1D}"), "Instruction Count"),
114+
new UIHints { Width = 80, });
115+
116+
private static readonly ColumnConfiguration lastLevelCacheMissesColumn =
117+
new ColumnConfiguration(
118+
new ColumnMetadata(new Guid("{7EB3DBFA-B1CA-4CB7-9D70-66E0BEFA0F32}"), "LLC Misses"),
119+
new UIHints { Width = 80, });
120+
121+
private static readonly ColumnConfiguration cpuCycleColumn =
122+
new ColumnConfiguration(
123+
new ColumnMetadata(new Guid("{AC255EA6-BA80-4A7D-BCF5-710B6B3618A9}"), "CPU Cycle"),
124+
new UIHints { Width = 80, });
125+
126+
private static readonly ColumnConfiguration cacheMissesColumn =
127+
new ColumnConfiguration(
128+
new ColumnMetadata(new Guid("{6BBB2F84-4215-46CF-9C92-FA79DB8DE55C}"), "Cache Misses"),
129+
new UIHints { Width = 80, });
130+
111131
private static readonly ColumnConfiguration cpuUsageInViewportPreset = new ColumnConfiguration(
112132
new ColumnMetadata(new Guid("{0cf6ffa6-2f41-4460-a201-718c37cbf413}"), "CPU Usage (in view)"),
113133
new UIHints
@@ -271,6 +291,10 @@ public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieva
271291
table.AddColumn(switchInTimeColumn, switchInTime);
272292
table.AddColumn(switchOutTimeColumn, switchOutTime);
273293
table.AddColumn(previousPidColumn, Projection.CreateUsingFuncAdaptor((i) => threads[i].PreviousPid));
294+
table.AddColumn(instructionCountColumn, Projection.CreateUsingFuncAdaptor((i) => GetPerformanceCounterDiff(threads[i], "_perf_cpu_instructions")));
295+
table.AddColumn(lastLevelCacheMissesColumn, Projection.CreateUsingFuncAdaptor((i) => GetPerformanceCounterDiff(threads[i], "_perf_cpu_LLC_load_misses")));
296+
table.AddColumn(cpuCycleColumn, Projection.CreateUsingFuncAdaptor((i) => GetPerformanceCounterDiff(threads[i], "_perf_cpu_cpu_cycles")));
297+
table.AddColumn(cacheMissesColumn, Projection.CreateUsingFuncAdaptor((i) => GetPerformanceCounterDiff(threads[i], "_perf_cpu_cache_misses")));
274298
table.AddColumn(nextCommandColumn, Projection.CreateUsingFuncAdaptor((i) => threads[i].NextImage));
275299
table.AddColumn(previousCommandColumn, Projection.CreateUsingFuncAdaptor((i) => threads[i].PreviousImage));
276300

@@ -294,6 +318,11 @@ public static void BuildTable(ITableBuilder tableBuilder, IDataExtensionRetrieva
294318
table.AddColumn(cpuUsagePreset, cpuUsageColumn);
295319
table.AddColumn(percentCpuUsagePreset, percentCpuUsageColumn);
296320
}
321+
322+
private static long GetPerformanceCounterDiff(IExecutionEvent executionEvent, string counterName)
323+
{
324+
return executionEvent.PerformanceCountersDiffByName.TryGetValue(counterName, out long value) ? value : 0;
325+
}
297326
}
298327

299328
struct ReduceTimeSinceLastDiff

0 commit comments

Comments
 (0)