Skip to content

Commit 6f4c894

Browse files
committed
Added profiling prototype basics
1 parent 5429203 commit 6f4c894

File tree

3 files changed

+155
-41
lines changed

3 files changed

+155
-41
lines changed

Packages/com.unity.inputsystem/InputSystem/Editor/Internal/InputSystemProfilerModule.cs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,70 +10,84 @@ namespace UnityEngine.InputSystem.Editor
1010
/// <summary>
1111
/// A profiler module that integrates Input System with the Profiler editor window.
1212
/// </summary>
13-
[ProfilerModuleMetadata("Input System")]
13+
[ProfilerModuleMetadata("Input System")]
1414
internal sealed class InputSystemProfilerModule : ProfilerModule
1515
{
1616
/// <summary>
1717
/// A profiler module detail view that extends the Profiler window and shows details for the selected frame.
1818
/// </summary>
1919
private sealed class InputSystemDetailsViewController : ProfilerModuleViewController
20-
{
21-
public InputSystemDetailsViewController(ProfilerWindow profilerWindow)
22-
: base(profilerWindow)
23-
{ }
20+
{
21+
public InputSystemDetailsViewController(ProfilerWindow profilerWindow)
22+
: base(profilerWindow)
23+
{}
2424

25+
private Label m_UpdateCountLabel;
2526
private Label m_EventCountLabel;
2627
private Label m_EventSizeLabel;
2728
private Label m_AverageLatencyLabel;
2829
private Label m_MaxLatencyLabel;
2930
private Label m_EventProcessingTimeLabel;
31+
private Label m_DeviceCountLabel;
32+
private Label m_ControlCountLabel;
33+
private Label m_StateBufferSizeLabel;
3034

3135
private Label CreateLabel()
3236
{
3337
return new Label() { style = { paddingTop = 8, paddingLeft = 8 } };
3438
}
35-
39+
3640
protected override VisualElement CreateView()
3741
{
3842
var view = new VisualElement();
3943

44+
m_UpdateCountLabel = CreateLabel();
4045
m_EventCountLabel = CreateLabel();
4146
m_EventSizeLabel = CreateLabel();
4247
m_AverageLatencyLabel = CreateLabel();
4348
m_MaxLatencyLabel = CreateLabel();
4449
m_EventProcessingTimeLabel = CreateLabel();
45-
50+
m_DeviceCountLabel = CreateLabel();
51+
m_ControlCountLabel = CreateLabel();
52+
m_StateBufferSizeLabel = CreateLabel();
53+
54+
view.Add(m_UpdateCountLabel);
4655
view.Add(m_EventCountLabel);
4756
view.Add(m_EventSizeLabel);
4857
view.Add(m_AverageLatencyLabel);
4958
view.Add(m_MaxLatencyLabel);
5059
view.Add(m_EventProcessingTimeLabel);
60+
view.Add(m_DeviceCountLabel);
61+
view.Add(m_ControlCountLabel);
62+
view.Add(m_StateBufferSizeLabel);
5163

52-
// Populate the label with the current data for the selected frame.
64+
// Populate the label with the current data for the selected frame.
5365
ReloadData();
5466

5567
// Be notified when the selected frame index in the Profiler Window changes, so we can update the label.
5668
ProfilerWindow.SelectedFrameIndexChanged += OnSelectedFrameIndexChanged;
5769

5870
return view;
5971
}
60-
72+
6173
protected override void Dispose(bool disposing)
6274
{
6375
if (disposing)
6476
{
6577
// Unsubscribe from the Profiler window event that we previously subscribed to.
6678
ProfilerWindow.SelectedFrameIndexChanged -= OnSelectedFrameIndexChanged;
6779
}
68-
80+
6981
base.Dispose(disposing);
7082
}
7183

7284
void ReloadData()
7385
{
7486
var selectedFrameIndex = System.Convert.ToInt32(ProfilerWindow.selectedFrameIndex);
75-
76-
var eventCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
87+
88+
var updateCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
89+
InputStatistics.Category.Name, InputStatistics.UpdateCountName);
90+
var eventCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
7791
InputStatistics.Category.Name, InputStatistics.EventCountName);
7892
var eventSizeBytes = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
7993
InputStatistics.Category.Name, InputStatistics.EventSizeName);
@@ -83,38 +97,52 @@ void ReloadData()
8397
InputStatistics.Category.Name, InputStatistics.MaxLatencyName);
8498
var eventProcessingTime = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
8599
InputStatistics.Category.Name, InputStatistics.EventProcessingTimeName);
100+
var stateBufferSizeBytes = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
101+
InputStatistics.Category.Name, InputStatistics.StateBufferSizeBytesName);
102+
var deviceCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
103+
InputStatistics.Category.Name, InputStatistics.DeviceCountName);
104+
var controlCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
105+
InputStatistics.Category.Name, InputStatistics.ControlCountName);
86106

107+
m_UpdateCountLabel.text = $"{InputStatistics.UpdateCountName}: {updateCount}";
87108
m_EventCountLabel.text = $"{InputStatistics.EventCountName}: {eventCount}";
88109
m_EventSizeLabel.text = $"{InputStatistics.EventSizeName}: {eventSizeBytes}";
89110
m_AverageLatencyLabel.text = $"{InputStatistics.AverageLatencyName}: {averageLatency}";
90111
m_MaxLatencyLabel.text = $"{InputStatistics.MaxLatencyName}: {maxLatency}";
91112
m_EventProcessingTimeLabel.text = $"{InputStatistics.EventProcessingTimeName}: {eventProcessingTime}";
113+
m_StateBufferSizeLabel.text = $"{InputStatistics.StateBufferSizeBytesName}: {stateBufferSizeBytes}";
114+
m_DeviceCountLabel.text = $"{InputStatistics.DeviceCountName}: {deviceCount}";
115+
m_ControlCountLabel.text = $"{InputStatistics.ControlCountName}: {controlCount}";
92116
}
93-
117+
94118
void OnSelectedFrameIndexChanged(long selectedFrameIndex)
95119
{
96120
ReloadData();
97121
}
98122
}
99-
123+
100124
private static readonly ProfilerCounterDescriptor[] Counters = new ProfilerCounterDescriptor[]
101125
{
102-
new (InputStatistics.EventCountName, InputStatistics.Category),
103-
new (InputStatistics.EventSizeName, InputStatistics.Category),
104-
new (InputStatistics.AverageLatencyName, InputStatistics.Category),
105-
new (InputStatistics.MaxLatencyName, InputStatistics.Category),
106-
new (InputStatistics.EventProcessingTimeName, InputStatistics.Category),
126+
new(InputStatistics.UpdateCountName, InputStatistics.Category),
127+
new(InputStatistics.EventCountName, InputStatistics.Category),
128+
new(InputStatistics.EventSizeName, InputStatistics.Category),
129+
new(InputStatistics.StateBufferSizeBytesName, InputStatistics.Category),
130+
new(InputStatistics.AverageLatencyName, InputStatistics.Category),
131+
new(InputStatistics.MaxLatencyName, InputStatistics.Category),
132+
new(InputStatistics.EventProcessingTimeName, InputStatistics.Category),
133+
new(InputStatistics.DeviceCountName, InputStatistics.Category),
134+
new(InputStatistics.ControlCountName, InputStatistics.Category),
107135
};
108-
136+
109137
public InputSystemProfilerModule()
110138
: base(Counters)
111-
{ }
112-
139+
{}
140+
113141
public override ProfilerModuleViewController CreateDetailsViewController()
114142
{
115143
return new InputSystemDetailsViewController(ProfilerWindow);
116144
}
117145
}
118146
}
119147

120-
#endif // UNITY_EDITOR
148+
#endif // UNITY_EDITOR

Packages/com.unity.inputsystem/InputSystem/InputManager.cs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ internal partial class InputManager
8080
static readonly ProfilerMarker k_InputOnDeviceChangeMarker = new ProfilerMarker("InpustSystem.onDeviceChange");
8181
static readonly ProfilerMarker k_InputOnActionsChangeMarker = new ProfilerMarker("InpustSystem.onActionsChange");
8282

83+
private int CountControls()
84+
{
85+
var count = m_DevicesCount;
86+
for (var i = 0; i < m_DevicesCount; ++i)
87+
count += m_Devices[i].allControls.Count;
88+
return count;
89+
}
8390

8491
public InputMetrics metrics
8592
{
@@ -89,11 +96,7 @@ public InputMetrics metrics
8996

9097
result.currentNumDevices = m_DevicesCount;
9198
result.currentStateSizeInBytes = (int)m_StateBuffers.totalSize;
92-
93-
// Count controls.
94-
result.currentControlCount = m_DevicesCount;
95-
for (var i = 0; i < m_DevicesCount; ++i)
96-
result.currentControlCount += m_Devices[i].allControls.Count;
99+
result.currentControlCount = CountControls();
97100

98101
// Count layouts.
99102
result.currentLayoutCount = m_Layouts.layoutTypes.Count;
@@ -3055,6 +3058,10 @@ internal bool ShouldRunUpdate(InputUpdateType updateType)
30553058
return (updateType & mask) != 0;
30563059
}
30573060

3061+
struct UpdateMetrics
3062+
{
3063+
}
3064+
30583065
/// <summary>
30593066
/// Process input events.
30603067
/// </summary>
@@ -3072,8 +3079,25 @@ internal bool ShouldRunUpdate(InputUpdateType updateType)
30723079
/// which buffers we activate in the update and write the event data into.
30733080
/// </remarks>
30743081
/// <exception cref="InvalidOperationException">Thrown if OnUpdate is called recursively.</exception>
3075-
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1809:AvoidExcessiveLocals", Justification = "TODO: Refactor later.")]
30763082
private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer eventBuffer)
3083+
{
3084+
try
3085+
{
3086+
DoUpdate(updateType, ref eventBuffer);
3087+
}
3088+
finally
3089+
{
3090+
// According to documentation, profile counter calls should be stripped out automatically in
3091+
// non-development builds.
3092+
InputStatistics.DeviceCount.Sample(m_DevicesCount);
3093+
InputStatistics.StateBufferSizeBytes.Sample((int)m_StateBuffers.totalSize);
3094+
InputStatistics.ControlCount.Sample(CountControls());
3095+
++InputStatistics.UpdateCount.Value;
3096+
}
3097+
}
3098+
3099+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1809:AvoidExcessiveLocals", Justification = "TODO: Refactor later.")]
3100+
private unsafe void DoUpdate(InputUpdateType updateType, ref InputEventBuffer eventBuffer)
30773101
{
30783102
// NOTE: This is *not* using try/finally as we've seen unreliability in the EndSample()
30793103
// execution (and we're not sure where it's coming from).
@@ -3630,22 +3654,22 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
36303654
}
36313655

36323656
ResetCurrentProcessedEventBytesForDevices();
3633-
3657+
36343658
// Update metrics (exposed via analytics and debugger)
36353659
var eventProcessingTime =
36363660
((double)(Stopwatch.GetTimestamp() - processingStartTime)) / Stopwatch.Frequency;
36373661
m_Metrics.totalEventCount += totalEventCount;
36383662
m_Metrics.totalEventBytes += totalEventSizeBytes;
36393663
m_Metrics.totalEventProcessingTime += eventProcessingTime;
36403664
m_Metrics.totalEventLagTime += totalEventLag;
3641-
3665+
36423666
// Profiler counters
36433667
InputStatistics.EventCount.Value += totalEventCount;
36443668
InputStatistics.EventSize.Value += totalEventSizeBytes;
36453669
InputStatistics.AverageLatency.Value += ((totalEventLag / totalEventCount) * 1e9);
36463670
InputStatistics.MaxLatency.Value += (maxEventLag * 1e9);
36473671
InputStatistics.EventProcessingTime.Value += eventProcessingTime * 1e9; // TODO Possible to replace Stopwatch with marker somehow?
3648-
3672+
36493673
m_InputEventStream.Close(ref eventBuffer);
36503674
}
36513675
catch (Exception)

Packages/com.unity.inputsystem/InputSystem/Utilities/InputStatistics.cs

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,47 +7,109 @@ namespace UnityEngine.InputSystem
77
/// </summary>
88
internal static class InputStatistics
99
{
10-
public static readonly ProfilerCategory Category = ProfilerCategory.Input;
10+
/// <summary>
11+
/// The Profiler Category to be used.
12+
/// </summary>
13+
internal static readonly ProfilerCategory Category = ProfilerCategory.Input;
1114

12-
public const string EventCountName = "Input Event Count";
13-
public const string EventSizeName = "Input Event Size";
14-
public const string AverageLatencyName = "Average Latency";
15-
public const string MaxLatencyName = "Max Latency";
16-
public const string EventProcessingTimeName = "Event Processing Time";
15+
internal const string EventCountName = "Total Input Event Count";
16+
internal const string EventSizeName = "Total Input Event Size";
17+
internal const string AverageLatencyName = "Average Input Latency";
18+
internal const string MaxLatencyName = "Max Input Latency";
19+
internal const string EventProcessingTimeName = "Total Input Event Processing Time";
20+
internal const string DeviceCountName = "Input Device Count";
21+
internal const string ControlCountName = "Active Control Count";
22+
internal const string CurrentStateMemoryBytesName = "Current State Memory Bytes";
23+
internal const string StateBufferSizeBytesName = "Total State Buffer Size";
24+
internal const string UpdateCountName = "Update Count";
1725

1826
/// <summary>
19-
/// Counter reflecting the number of input events.
27+
/// Counter reflecting the number of input events.
2028
/// </summary>
29+
/// <remarks>
30+
/// We use ProfilerCounterValue instead of ProfilerCounter since there may be multiple Input System updates
31+
/// per frame and we want it to accumulate for the profilers perspective on what a frame is but auto-reset
32+
/// when outside the profilers perspective of a frame.
33+
/// </remarks>
2134
public static readonly ProfilerCounterValue<int> EventCount = new ProfilerCounterValue<int>(
2235
Category, EventCountName, ProfilerMarkerDataUnit.Count,
2336
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
24-
37+
2538
/// <summary>
2639
/// Counter reflecting the accumulated input event size in bytes.
2740
/// </summary>
41+
/// <remarks>
42+
/// We use ProfilerCounterValue instead of ProfilerCounter since there may be multiple Input System updates
43+
/// per frame and we want it to accumulate for the profilers perspective on what a frame is but auto-reset
44+
/// when outside the profilers perspective of a frame.
45+
/// </remarks>
2846
public static readonly ProfilerCounterValue<int> EventSize = new ProfilerCounterValue<int>(
2947
Category, EventSizeName, ProfilerMarkerDataUnit.Bytes,
3048
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
3149

3250
/// <summary>
3351
/// Counter value reflecting the average input latency.
3452
/// </summary>
53+
/// <remarks>
54+
/// We use ProfilerCounterValue instead of ProfilerCounter since there may be multiple Input System updates
55+
/// per frame and we want it to accumulate for the profilers perspective on what a frame is but auto-reset
56+
/// when outside the profilers perspective of a frame.
57+
/// </remarks>
3558
public static readonly ProfilerCounterValue<double> AverageLatency = new ProfilerCounterValue<double>(
3659
Category, AverageLatencyName, ProfilerMarkerDataUnit.TimeNanoseconds,
3760
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
3861

3962
/// <summary>
4063
/// Counter value reflecting the maximum input latency.
4164
/// </summary>
65+
/// <remarks>
66+
/// We use ProfilerCounterValue instead of ProfilerCounter since there may be multiple Input System updates
67+
/// per frame and we want it to accumulate for the profilers perspective on what a frame is but auto-reset
68+
/// when outside the profilers perspective of a frame.
69+
/// </remarks>
4270
public static readonly ProfilerCounterValue<double> MaxLatency = new ProfilerCounterValue<double>(
4371
Category, MaxLatencyName, ProfilerMarkerDataUnit.TimeNanoseconds,
4472
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
4573

4674
/// <summary>
4775
/// Counter value reflecting the accumulated event processing time (Update) during a rendering frame.
4876
/// </summary>
77+
/// <remarks>
78+
/// We use ProfilerCounterValue instead of ProfilerCounter since there may be multiple Input System updates
79+
/// per frame and we want it to accumulate for the profilers perspective on what a frame is but auto-reset
80+
/// when outside the profilers perspective of a frame.
81+
/// </remarks>
4982
public static readonly ProfilerCounterValue<double> EventProcessingTime = new ProfilerCounterValue<double>(
5083
Category, EventProcessingTimeName, ProfilerMarkerDataUnit.TimeNanoseconds,
5184
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
85+
86+
/// <summary>
87+
/// The number of devices currently added to the Input System.
88+
/// </summary>
89+
public static readonly ProfilerCounter<int> DeviceCount = new ProfilerCounter<int>(
90+
Category, DeviceCountName, ProfilerMarkerDataUnit.Count);
91+
92+
/// <summary>
93+
/// The total number of device controls currently in the Input System.
94+
/// </summary>
95+
public static readonly ProfilerCounter<int> ControlCount = new ProfilerCounter<int>(
96+
Category, ControlCountName, ProfilerMarkerDataUnit.Count);
97+
98+
/// <summary>
99+
/// The total state buffer size in bytes.
100+
/// </summary>
101+
public static readonly ProfilerCounter<int> StateBufferSizeBytes = new ProfilerCounter<int>(
102+
Category, StateBufferSizeBytesName, ProfilerMarkerDataUnit.Bytes);
103+
104+
/// <summary>
105+
/// The total update count.
106+
/// </summary>
107+
/// <remarks>
108+
/// Update may get called multiple times, e.g. either via manual updates, dynamic update, fixed update
109+
/// or editor update while running in the editor.
110+
/// </remarks>
111+
public static readonly ProfilerCounterValue<int> UpdateCount = new ProfilerCounterValue<int>(
112+
Category, UpdateCountName, ProfilerMarkerDataUnit.Count,
113+
ProfilerCounterOptions.FlushOnEndOfFrame | ProfilerCounterOptions.ResetToZeroOnFlush);
52114
}
53-
}
115+
}

0 commit comments

Comments
 (0)