Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW: Input System Profiler Module #2038

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft

NEW: Input System Profiler Module #2038

wants to merge 7 commits into from

Conversation

ekcoh
Copy link
Collaborator

@ekcoh ekcoh commented Oct 25, 2024

Description

Made a draft implementation of a Profiler Module for the Input System based on lack of observability to work as an aid in understanding system mechanics. Hopefully could work as an embryo of something more refined if considered a good idea.

Screenshot 2024-10-25 at 13 36 23

Testing status & QA

Just a prototype at this point. Try it out and suggest or contribute to this PR to make it more useful.

Overall Product Risks

Some more work likely need to be done to InputManager.OnUpdate to make that method cleaner and this work more reliably.

Might not be possible to merge unless minimum Unity version requirement is changed to 2020.1. (Profiler package dependency)

  • Complexity: Small
  • Halo Effect: Medium

Comments to reviewers

At this point mainly looking for feedback and suggestions since this was unplanned work.

Checklist

Before review:

  • Changelog entry added.
    • Explains the change in Changed, Fixed, Added sections.
    • For API change contains an example snippet and/or migration example.
    • JIRA ticket linked, example (case %%). If it is a private issue, just add the case ID without a link.
    • Jira port for the next release set as "Resolved".
  • Tests added/changed, if applicable.
    • Functional tests Area_CanDoX, Area_CanDoX_EvenIfYIsTheCase, Area_WhenIDoX_AndYHappens_ThisIsTheResult.
    • Performance tests.
    • Integration tests.
  • Docs for new/changed API's.
    • Xmldoc cross references are set correctly.
    • Added explanation how the API works.
    • Usage code examples added.
    • The manual is updated, if needed.

During merge:

  • Commit message for squash-merge is prefixed with one of the list:
    • NEW: ___.
    • FIX: ___.
    • DOCS: ___.
    • CHANGE: ___.
    • RELEASE: 1.1.0-preview.3.

After merge:

  • Create forward/backward port if needed. If you are blocked from creating a forward port now please add a task to ISX-1444.

var controlCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
InputStatistics.Category.Name, InputStatistics.ControlCountName);

m_UpdateCountLabel.text = $"{InputStatistics.UpdateCountName}: {updateCount}";
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a basic label list at the moment. Is it possible to pass any extra information via the profiler API? Or extract sample data to e.g. create a distribution within detail window?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a ProfilerRecorder that you can use to gather samples, which then allows you to do more statistical computations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekcoh it seems to be possible to add more complex UITK elements. I think a list can be fine for now, and then we could add a nicer UI using UITK (there's more info here , which you probably have seen; and a more more complex UI example in this package where this is the result: image

{
try
{
DoUpdate(updateType, ref eventBuffer);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs more work to extract some stuff from DoUpdate below

InputStatistics.EventSize.Value += totalEventSizeBytes;
InputStatistics.AverageLatency.Value += ((totalEventLag / totalEventCount) * 1e9);
InputStatistics.MaxLatency.Value += (maxEventLag * 1e9);
InputStatistics.EventProcessingTime.Value += eventProcessingTime * 1e9; // TODO Possible to replace Stopwatch with marker somehow?
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this last line here is an anti pattern, ideally I would like to include the Update profiler marker into the profiler module, is this possible?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During hackweek I used StopWatch. It was preallocated and reset and reused every frame and accumulated in a ProfilerCounter

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which is what it looks like you're doing here :)

@surfnerd
Copy link
Collaborator

surfnerd commented Oct 25, 2024

My first thought looking at the window is the mix of types being presented. I see Counters, Memory Size, and Times. It looks a little bit busy and hard to know what I'm looking at exactly. Overall I think this is a great idea. I wonder if there's a way we can group like values together within one window.

@ekcoh
Copy link
Collaborator Author

ekcoh commented Oct 28, 2024

My first thought looking at the window is the mix of types being presented. I see Counters, Memory Size, and Times. It looks a little bit busy and hard to know what I'm looking at exactly. Overall I think this is a great idea. I wonder if there's a way we can group like values together within one window.

Agreed, I just saw other modules were doing that and replicated it. I think there is opportunity to slip things into separate modules to handle it, e.g. Latency and Input System Counters. I wonder if execution time should even be there since its covered by the ProfilerMarkers anyway.....

Copy link
Collaborator

@jfreire-unity jfreire-unity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work in adding this functionality.
I think this could easily land in an experimental kind of namespace, almost as is. Just with small tweaks IMO.

The only issue I have is from a UI perspective. Similar to what @surfnerd mentioned, the Module UI is a bit confusing with all the Counts, Bytes, Timings.

I think we could put the Bytes and Timings statistics only in the panel label for now. In my opinion the count statistics are better suited for the "line" UI type.

Ideally, the best would be to have some kind of "Timeline" similar to what CPU has (see img below). But we don't need to be perfect for this to land as I don't think it adds a big risk. I think this would already provide benefit and we could just improve the parts that are confusing a little bit. But of course, we should ask ourselves what are trying to solve with this and see if this
image

I will try to play around a bit with this this sprint and see if I can improve anything.

/// <summary>
/// Input Statistics for Unity Profiler integration.
/// </summary>
internal static class InputStatistics
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd create a Editor/Internal/Profiler folder and but everything in there. I find odd to have this class next to a bunch of "Utilities" classes.

var controlCount = ProfilerDriver.GetFormattedCounterValue(selectedFrameIndex,
InputStatistics.Category.Name, InputStatistics.ControlCountName);

m_UpdateCountLabel.text = $"{InputStatistics.UpdateCountName}: {updateCount}";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekcoh it seems to be possible to add more complex UITK elements. I think a list can be fine for now, and then we could add a nicer UI using UITK (there's more info here , which you probably have seen; and a more more complex UI example in this package where this is the result: image

@@ -2,7 +2,8 @@
"name": "Unity.InputSystem",
"rootNamespace": "",
"references": [
"Unity.ugui"
"Unity.ugui",
"Unity.Profiling.Core"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this might create some overhead? Probably we could set a define like INPUTSYSTEM_USE_CUSTOMPROFILER or something similar, in case users don't want to have this code in their release builds.

@@ -3055,6 +3058,10 @@ internal bool ShouldRunUpdate(InputUpdateType updateType)
return (updateType & mask) != 0;
}

struct UpdateMetrics
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To remove?

Comment on lines 3494 to +3502
if (currentEventTimeInternal <= currentTime)
totalEventLag += currentTime - currentEventTimeInternal;
++m_Metrics.totalEventCount;
m_Metrics.totalEventBytes += (int)currentEventReadPtr->sizeInBytes;
{
var lag = currentTime - currentEventTimeInternal;
totalEventLag += lag;
if (lag > maxEventLag)
maxEventLag = lag;
}
++totalEventCount;
totalEventSizeBytes += (int)currentEventReadPtr->sizeInBytes;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This a bit more complex so I would extract this to a method, as OnUpdate is already big enoug.

m_Metrics.totalEventLagTime += totalEventLag;

ResetCurrentProcessedEventBytesForDevices();
// Profiler counters
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a comment that these counters are PerFrame, as we can call update more than once?
Or Maybe a prefix of something like InputStatistics.EventCountPerFrame.Value or PerUpdate, something like that.

Also if could we use ProfileRecorder for this?

"com.unity.settings-manager": "1.0.3",
"com.unity.test-framework": "1.4.5",
"com.unity.test-framework.build": "0.0.1-preview.12",
"com.unity.test-framework.performance": "3.0.3",
"com.unity.test-framework.utp-reporter": "1.1.0-preview",
"com.unity.textmeshpro": "2.1.4",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why this is removed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants