Skip to content

Commit cfd6eec

Browse files
CHANGE: Improve error logging when events get discarded (ISXB-691) (#1929)
* Check event processing after raised error Improves existing test to make sure a "full" even buffer has in fact discarded events and that they are not processed in the next update * Add total bytes processed per device in error message * Fix test * Update CHANGELOG.md * Fix formatting * Move error check to end of while loop Addresses issues where the warning is not shown even though the bytes of events processed exceed the limit. This turns the check more rigorous. * Improve string manipulation
1 parent 5ecee3e commit cfd6eec

File tree

4 files changed

+87
-12
lines changed

4 files changed

+87
-12
lines changed

Assets/Tests/InputSystem/CoreTests_Events.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,29 +2365,44 @@ public IEnumerator Events_CanTestInputDistributedOverFrames()
23652365
[Category("Events")]
23662366
public void Events_MaximumEventLoadPerUpdateIsLimited()
23672367
{
2368-
// Default setting is 5MB.
2368+
// Default limit setting is 5MB.
23692369
Assert.That(InputSystem.settings.maxEventBytesPerUpdate, Is.EqualTo(5 * 1024 * 1024));
23702370

2371+
// Limit the maximum events to be processed per update to 2 Mouse state events.
23712372
InputSystem.settings.maxEventBytesPerUpdate = StateEvent.GetEventSizeWithPayload<MouseState>() * 2;
23722373

23732374
var mouse = InputSystem.AddDevice<Mouse>();
23742375

2376+
// Queue 3 events, where the 3rd one will raise a log error.
2377+
// Only 2 events from 3 should be processed.
23752378
InputSystem.QueueStateEvent(mouse, new MouseState().WithButton(MouseButton.Left));
23762379
InputSystem.QueueStateEvent(mouse, new MouseState().WithButton(MouseButton.Right));
23772380
InputSystem.QueueStateEvent(mouse, new MouseState().WithButton(MouseButton.Middle));
23782381

23792382
var eventCount = 0;
23802383
InputSystem.onEvent += (eventPtr, device) => ++ eventCount;
23812384

2385+
var totalProcessedMouseStateEventBytes = InputSystem.settings.maxEventBytesPerUpdate;
23822386
LogAssert.Expect(LogType.Error, "Exceeded budget for maximum input event throughput per InputSystem.Update(). Discarding remaining events. "
2383-
+ "Increase InputSystem.settings.maxEventBytesPerUpdate or set it to 0 to remove the limit.");
2387+
+ "Increase InputSystem.settings.maxEventBytesPerUpdate or set it to 0 to remove the limit.\n"
2388+
+ "Total events processed by devices in last update call:\n"
2389+
+ $" - {totalProcessedMouseStateEventBytes} bytes processed by Mouse:/Mouse\n");
23842390

23852391
InputSystem.Update();
23862392

23872393
Assert.That(eventCount, Is.EqualTo(2));
23882394
Assert.That(mouse.rightButton.isPressed, Is.True);
23892395
Assert.That(mouse.middleButton.isPressed, Is.False);
23902396

2397+
// Queue 1 event after error has been raised
2398+
InputSystem.QueueStateEvent(mouse, new MouseState().WithButton(MouseButton.Right, false));
2399+
InputSystem.Update();
2400+
2401+
// Check that we have only processed the new event.
2402+
// Confirms that the 3rd event setting MouseButton.middle was discarded.
2403+
Assert.That(eventCount, Is.EqualTo(3));
2404+
Assert.That(mouse.rightButton.isPressed, Is.False);
2405+
23912406
eventCount = 0;
23922407

23932408
// Disable the limit.

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ however, it has to be formatted properly to pass verification tests.
2020
- Fixed Scheme Name in Control Scheme editor menu that gets reset when editing devices [ISXB-763](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-763).
2121
- Fixed an issue where `InputActionAsset.FindAction(string, bool)` would throw `System.NullReferenceException` instead of returning `null` if searching for a non-existent action with an explicit action path and using `throwIfNotFound: false`, e.g. searching for "Map/Action" when `InputActionMap` "Map" exists but no `InputAction` named "Action" exists within that map [ISXB-895](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-895).
2222

23+
## Added
24+
- Added additional device information when logging the error due to exceeding the maximum number of events processed
25+
set by `InputSystem.settings.maxEventsBytesPerUpdate`. This additional information is available in development builds
26+
only.
27+
2328
## [1.8.2] - 2024-04-29
2429

2530
### Added

Packages/com.unity.inputsystem/InputSystem/Devices/InputDevice.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,10 @@ internal bool disabledWhileInBackground
672672
internal DeviceFlags m_DeviceFlags;
673673
internal int m_DeviceId;
674674
internal int m_ParticipantId;
675-
internal int m_DeviceIndex; // Index in InputManager.m_Devices.
675+
// Index in InputManager.m_Devices.
676+
internal int m_DeviceIndex;
677+
// Amount of bytes processed in the current update step. Used only for logging purposes.
678+
internal uint m_CurrentProcessedEventBytesOnUpdate;
676679
internal InputDeviceDescription m_Description;
677680

678681
/// <summary>

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

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Diagnostics;
44
using System.Linq;
5+
using System.Text;
56
using Unity.Collections;
67
using UnityEngine.InputSystem.Composites;
78
using UnityEngine.InputSystem.Controls;
@@ -3062,15 +3063,6 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
30623063
// Handle events.
30633064
while (m_InputEventStream.remainingEventCount > 0)
30643065
{
3065-
if (m_Settings.maxEventBytesPerUpdate > 0 &&
3066-
totalEventBytesProcessed >= m_Settings.maxEventBytesPerUpdate)
3067-
{
3068-
Debug.LogError(
3069-
"Exceeded budget for maximum input event throughput per InputSystem.Update(). Discarding remaining events. "
3070-
+ "Increase InputSystem.settings.maxEventBytesPerUpdate or set it to 0 to remove the limit.");
3071-
break;
3072-
}
3073-
30743066
InputDevice device = null;
30753067
var currentEventReadPtr = m_InputEventStream.currentEventPtr;
30763068

@@ -3382,6 +3374,8 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
33823374

33833375
totalEventBytesProcessed += eventPtr.sizeInBytes;
33843376

3377+
device.m_CurrentProcessedEventBytesOnUpdate += eventPtr.sizeInBytes;
3378+
33853379
// Update timestamp on device.
33863380
// NOTE: We do this here and not in UpdateState() so that InputState.Change() will *NOT* change timestamps.
33873381
// Only events should. If running play mode updates in editor, we want to defer to the play mode
@@ -3464,12 +3458,18 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
34643458
}
34653459

34663460
m_InputEventStream.Advance(leaveEventInBuffer: false);
3461+
3462+
// Discard events in case the maximum event bytes per update has been exceeded
3463+
if (AreMaximumEventBytesPerUpdateExceeded(totalEventBytesProcessed))
3464+
break;
34673465
}
34683466

34693467
m_Metrics.totalEventProcessingTime +=
34703468
((double)(Stopwatch.GetTimestamp() - processingStartTime)) / Stopwatch.Frequency;
34713469
m_Metrics.totalEventLagTime += totalEventLag;
34723470

3471+
ResetCurrentProcessedEventBytesForDevices();
3472+
34733473
m_InputEventStream.Close(ref eventBuffer);
34743474
}
34753475
catch (Exception)
@@ -3493,6 +3493,58 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
34933493
m_CurrentUpdate = default;
34943494
}
34953495

3496+
bool AreMaximumEventBytesPerUpdateExceeded(uint totalEventBytesProcessed)
3497+
{
3498+
if (m_Settings.maxEventBytesPerUpdate > 0 &&
3499+
totalEventBytesProcessed >= m_Settings.maxEventBytesPerUpdate)
3500+
{
3501+
var eventsProcessedByDeviceLog = String.Empty;
3502+
// Only log the events processed by devices in last update call if we are in debug mode.
3503+
// This is to avoid the slightest overhead in release builds of having to iterate over all devices and
3504+
// reset the byte count, by the end of every update call with ResetCurrentProcessedEventBytesForDevices().
3505+
if (Debug.isDebugBuild)
3506+
eventsProcessedByDeviceLog = $"Total events processed by devices in last update call:\n{MakeStringWithEventsProcessedByDevice()}";
3507+
3508+
Debug.LogError(
3509+
"Exceeded budget for maximum input event throughput per InputSystem.Update(). Discarding remaining events. "
3510+
+ "Increase InputSystem.settings.maxEventBytesPerUpdate or set it to 0 to remove the limit.\n"
3511+
+ eventsProcessedByDeviceLog);
3512+
3513+
return true;
3514+
}
3515+
3516+
return false;
3517+
}
3518+
3519+
private string MakeStringWithEventsProcessedByDevice()
3520+
{
3521+
var eventsProcessedByDeviceLog = new StringBuilder();
3522+
for (int i = 0; i < m_DevicesCount; i++)
3523+
{
3524+
var deviceToLog = devices[i];
3525+
if (deviceToLog != null && deviceToLog.m_CurrentProcessedEventBytesOnUpdate > 0)
3526+
eventsProcessedByDeviceLog.Append($" - {deviceToLog.m_CurrentProcessedEventBytesOnUpdate} bytes processed by {deviceToLog}\n");
3527+
}
3528+
return eventsProcessedByDeviceLog.ToString();
3529+
}
3530+
3531+
// Reset the number of bytes processed by devices in the current update, for debug builds.
3532+
// This is to avoid the slightest overhead in release builds of having to iterate over all devices connected.
3533+
private void ResetCurrentProcessedEventBytesForDevices()
3534+
{
3535+
if (Debug.isDebugBuild)
3536+
{
3537+
for (var i = 0; i < m_DevicesCount; i++)
3538+
{
3539+
var device = m_Devices[i];
3540+
if (device != null && device.m_CurrentProcessedEventBytesOnUpdate > 0)
3541+
{
3542+
device.m_CurrentProcessedEventBytesOnUpdate = 0;
3543+
}
3544+
}
3545+
}
3546+
}
3547+
34963548
// Only do this check in editor in hope that it will be sufficient to catch any misuse during development.
34973549
[Conditional("UNITY_EDITOR")]
34983550
void CheckAllDevicesOptimizedControlsHaveValidState()

0 commit comments

Comments
 (0)