Skip to content

Conversation

@RSlysz
Copy link
Contributor

@RSlysz RSlysz commented Feb 3, 2021

Purpose of this PR

Improve performance for DebugMenu input registering system at each domain reload. FB: https://fogbugz.unity3d.com/f/cases/1311108/

I found that there is way more call to serialization (which is the bottle neck here) than needed. So I reworked the checking algorithm to use the less possible serialization. Checking was here to be sure we do not register duplicate entry. Now it is done once on all the cached entry instead of one time per new entry.
So basically we previously had a complexity of roughly O(n.m) where n was the pre existing entry amount and m the inserted entry amount. And with this change we are in O(n+k) where k is the entry that we can safely insert without creating duplicate (k < m, often 0). (Complexity is computed against serialization call to get element in the array)

Also I delayed the actual register to next editor frame. This in order to let a chance to pack in case of several class request to register an input at initialization. The costly operation of the new algorithm is the caching of pre existing entries. If we can afford to prevent being done several time, it worth it.

And finally, the InputSystem package is supported by the DebugMenu but in this case, it still try to add inputs in the asset used by the legacy system. I skipped this operation as it is not needed.

In addition, I added warnings when using InputRegistering while the InputSystem package is in use.


Testing status

In test project given with the FB above, there is 529 entries in ProjectSettings > InputManager

Before fix
image
image

After fix (without delaying next frame to have meaningful results) without InputSystem package
image
image

Tested it is totally skipped when InputSystem is in use. Tested with the project from FB https://fogbugz.unity3d.com/f/cases/1306751/ which use a lot more entry in the input asset. Times goes to ~1min (2754 entries) to almost nothing.

And DebugMenu still working after change in both project (with and without the InputSystem package).

Note: tests have been done before changing from using GetArrayElementAtIndex to Next wich use even less computation time. So expect even better results.


Comments to reviewers

Note: the perfect fix should be to have a C# API for this. Now that there is a dedicated package for this, I dunno if any development on the subject is something to think of or not.

s_PendingInputsToRegister.AddRange(entries);

//delay the call in order to do only one pass event if several different class register inputs
EditorApplication.delayCall += DelayedRegisterInput;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This line is replaced by DelayedRegisterInput(); in the test to compare algorithm in same conditions.

@RSlysz RSlysz requested a review from a team February 3, 2021 17:10
@RSlysz RSlysz marked this pull request as ready for review February 3, 2021 17:14
public static void RegisterInputs(List<InputManagerEntry> entries)
static void AddEntriesWithoutCheck(SerializedProperty spAxes, List<InputManagerEntry> newEntries)
{
int startRange = spAxes.arraySize;
Copy link
Contributor

Choose a reason for hiding this comment

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

note for next time: i got confused because expected a range here. so could you confirm startRange is basically firstEntryIndex and endRange is lastEntryIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I was refering it at range like in the list.AddRange(...) method.
So startRange = firstEntryPositionInInputListIndex and endRange = lastEntryPositionInInputListIndex

Just first/lastEntryIndex is unclear if it is in the newEntries list or in the spAxes array. So I'll keep range and add a comment.

s_PendingInputsToRegister.AddRange(entries);

//delay the call in order to do only one pass event if several different class register inputs
EditorApplication.delayCall += DelayedRegisterInput;
Copy link
Contributor

Choose a reason for hiding this comment

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

does this mean we could end up calling this function multiple times in the same frame?
also when do we unregister the call?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No it means you can call it multiple time in a frame, it will all be batched in delayed call.
Example:
Frame1, two different classes call register input

RegisterInputs(new List<InputManagerEntry>
      {
            new InputManagerEntry { name = "cmd1",  kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "left ctrl",   altBtnPositive = "joystick button 8" },
            new InputManagerEntry { name = "cmd2",  kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "backspace",   altBtnPositive = "joystick button 9" }
      });
      
      
RegisterInputs(new List<InputManagerEntry>
      {
            new InputManagerEntry { name = "cmd3",  kind = InputManagerEntry.Kind.KeyOrButton, btnPositive = "left alt",   altBtnPositive = "joystick button 1" }
      });

Delayed calls:

  • register cmd1, cmd2 and cmd3 at the same time
  • nothing to register, so exit early

So we inspected the already registered inputs only once instead of two time when done at same frame.

And for unregistering, the mechanism where not here prior and was never requested. I assume it is not needed in this case. But it can be implemented in a similar way. I assume this was done to add inputs in the InputManager.asset only and not remove them.

@RSlysz
Copy link
Contributor Author

RSlysz commented Feb 4, 2021

I have seen Martin comment on the thread of the bug that suggest to use Next instead of GetArrayElementAtIndex for better performances. I'll amend this PR with this.

@RSlysz RSlysz changed the title Hd/fix input registering domain reload Hd/fix input registering domain reload [DO NOT MERGE] Feb 4, 2021
@RSlysz RSlysz changed the title Hd/fix input registering domain reload [DO NOT MERGE] Hd/fix input registering domain reload Feb 4, 2021
Copy link
Contributor

@TomasKiniulis TomasKiniulis left a comment

Choose a reason for hiding this comment

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

Seems good! Did a validation check with user project adjusting InputManager entries. HDAdditionalCameraData stays at about 60ms now instead of about 2 sec. Haven't encountered any PR related issues.

My test results:
Before PR:
image
With PR:
image

@sebastienlagarde sebastienlagarde merged commit 0923df0 into hd/bugfix Feb 8, 2021
@sebastienlagarde sebastienlagarde deleted the hd/fix-InputRegistering-DomainReload branch February 8, 2021 15:32
@sebastienlagarde
Copy link
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants