@@ -546,24 +546,41 @@ public void TODO_CanSaveAndRestoreSystemInLessThan10Milliseconds() // Currently
546
546
547
547
#endif
548
548
549
- internal enum OptimizedControlsTest
549
+ internal enum OptimizationTestType
550
550
{
551
+ NoOptimization ,
551
552
OptimizedControls ,
552
- NormalControls
553
+ ReadValueCaching ,
554
+ OptimizedControlsAndReadValueCaching
553
555
}
554
556
555
- [ Test , Performance ]
556
- [ Category ( "Performance" ) ]
557
- [ TestCase ( OptimizedControlsTest . OptimizedControls ) ]
558
- [ TestCase ( OptimizedControlsTest . NormalControls ) ]
559
- public void Performance_OptimizedControls_ReadingMousePosition100kTimes ( OptimizedControlsTest testSetup )
557
+ public void SetInternalFeatureFlagsFromTestType ( OptimizationTestType testType )
560
558
{
561
- var useOptimizedControls = testSetup == OptimizedControlsTest . OptimizedControls ;
559
+ var useOptimizedControls = testType == OptimizationTestType . OptimizedControls
560
+ || testType == OptimizationTestType . OptimizedControlsAndReadValueCaching ;
561
+ var useReadValueCaching = testType == OptimizationTestType . ReadValueCaching
562
+ || testType == OptimizationTestType . OptimizedControlsAndReadValueCaching ;
563
+
562
564
InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kUseOptimizedControls , useOptimizedControls ) ;
563
- InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kUseReadValueCaching , useOptimizedControls ) ;
565
+ InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kUseReadValueCaching , useReadValueCaching ) ;
564
566
InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kParanoidReadValueCachingChecks , false ) ;
567
+ }
568
+
569
+ [ Test , Performance ]
570
+ [ Category ( "Performance" ) ]
571
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
572
+ [ TestCase ( OptimizationTestType . OptimizedControls ) ]
573
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
574
+ [ TestCase ( OptimizationTestType . OptimizedControlsAndReadValueCaching ) ]
575
+ // Isolated tests for reading from Mouse device to evaluate the performance of the optimizations.
576
+ // Does not take into account the performance of the InputSystem.Update() call.
577
+ public void Performance_OptimizedControls_ReadingMousePosition100kTimes ( OptimizationTestType testType )
578
+ {
579
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
565
580
566
581
var mouse = InputSystem . AddDevice < Mouse > ( ) ;
582
+ var useOptimizedControls = testType == OptimizationTestType . OptimizedControls
583
+ || testType == OptimizationTestType . OptimizedControlsAndReadValueCaching ;
567
584
Assert . That ( mouse . position . x . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatFloat : InputStateBlock . FormatInvalid ) ) ;
568
585
Assert . That ( mouse . position . y . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatFloat : InputStateBlock . FormatInvalid ) ) ;
569
586
Assert . That ( mouse . position . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatVector2 : InputStateBlock . FormatInvalid ) ) ;
@@ -579,17 +596,188 @@ public void Performance_OptimizedControls_ReadingMousePosition100kTimes(Optimize
579
596
. Run ( ) ;
580
597
}
581
598
599
+ [ Test , Performance ]
600
+ [ Category ( "Performance" ) ]
601
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
602
+ [ TestCase ( OptimizationTestType . OptimizedControls ) ]
603
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
604
+ [ TestCase ( OptimizationTestType . OptimizedControlsAndReadValueCaching ) ]
605
+ // Currently these tests shows that all the optimizations have a performance cost when reading from a Mouse device.
606
+ // OptimizedControls option is slower because of an extra check that is only done in Editor and Development Builds.
607
+ // ReadValueCaching option is slower because Mouse state (FastMouse) is changed every update, which means cached
608
+ // values are always stale. And currently there is a cost when caching the value.
609
+ public void Performance_OptimizedControls_ReadAndUpdateMousePosition1kTimes ( OptimizationTestType testType )
610
+ {
611
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
612
+
613
+ var mouse = InputSystem . AddDevice < Mouse > ( ) ;
614
+ InputSystem . Update ( ) ;
615
+
616
+ var useOptimizedControls = testType == OptimizationTestType . OptimizedControls
617
+ || testType == OptimizationTestType . OptimizedControlsAndReadValueCaching ;
618
+ Assert . That ( mouse . position . x . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatFloat : InputStateBlock . FormatInvalid ) ) ;
619
+ Assert . That ( mouse . position . y . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatFloat : InputStateBlock . FormatInvalid ) ) ;
620
+ Assert . That ( mouse . position . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatVector2 : InputStateBlock . FormatInvalid ) ) ;
621
+
622
+ Measure . Method ( ( ) =>
623
+ {
624
+ var pos = new Vector2 ( ) ;
625
+ for ( var i = 0 ; i < 1000 ; ++ i )
626
+ {
627
+ pos += mouse . position . ReadValue ( ) ;
628
+ InputSystem . Update ( ) ;
629
+
630
+ if ( i % 100 == 0 )
631
+ {
632
+ // Make sure there's a new different value every 100 frames.
633
+ InputSystem . QueueStateEvent ( mouse , new MouseState { position = new Vector2 ( i + 1 , i + 2 ) } ) ;
634
+ }
635
+ }
636
+ } )
637
+ . MeasurementCount ( 100 )
638
+ . WarmupCount ( 5 )
639
+ . Run ( ) ;
640
+ }
641
+
642
+ [ Test , Performance ]
643
+ [ Category ( "Performance" ) ]
644
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
645
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
646
+ // These tests shows a use case where ReadValueCaching optimization will perform better than without any
647
+ // optimization.
648
+ // It shows that there's a performance improvement when the control values being read are not changing every frame.
649
+ public void Performance_OptimizedControls_ReadAndUpdateGamepad1kTimes ( OptimizationTestType testType )
650
+ {
651
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
652
+
653
+ var gamepad = InputSystem . AddDevice < Gamepad > ( ) ;
654
+
655
+ InputSystem . Update ( ) ;
656
+
657
+ Measure . Method ( ( ) =>
658
+ {
659
+ var pos = new Vector2 ( ) ;
660
+ InputSystem . QueueStateEvent ( gamepad , new GamepadState { leftStick = new Vector2 ( 0.3f , 0.1f ) } ) ;
661
+ InputSystem . Update ( ) ;
662
+
663
+ pos = gamepad . leftStick . value ;
664
+ Assert . That ( gamepad . leftStick . m_CachedValueIsStale , Is . False ) ;
665
+
666
+ for ( var i = 0 ; i < 1000 ; ++ i )
667
+ {
668
+ InputSystem . Update ( ) ;
669
+ pos = gamepad . leftStick . value ;
670
+ Assert . That ( gamepad . leftStick . m_CachedValueIsStale , Is . False ) ;
671
+
672
+ if ( i % 100 == 0 )
673
+ {
674
+ // Make sure there's a new different value every 100 frames to mark the cached value as stale.
675
+ InputSystem . QueueStateEvent ( gamepad , new GamepadState { leftStick = new Vector2 ( i / 1000f , i / 1000f ) } ) ;
676
+ InputSystem . Update ( ) ;
677
+ }
678
+ }
679
+ } )
680
+ . MeasurementCount ( 100 )
681
+ . WarmupCount ( 10 )
682
+ . Run ( ) ;
683
+ }
684
+
685
+ [ Test , Performance ]
686
+ [ Category ( "Performance" ) ]
687
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
688
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
689
+ // This shows a use case where ReadValueCaching optimization will perform worse when controls have stale cached
690
+ // values every frame. Meaning, when control values change in every frame.
691
+ public void Performance_OptimizedControls_ReadAndUpdateGamepadNewValuesEveryFrame1kTimes ( OptimizationTestType testType )
692
+ {
693
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
694
+
695
+ var gamepad = InputSystem . AddDevice < Gamepad > ( ) ;
696
+
697
+ InputSystem . Update ( ) ;
698
+
699
+ Measure . Method ( ( ) =>
700
+ {
701
+ var pos = new Vector2 ( ) ;
702
+ InputSystem . QueueStateEvent ( gamepad , new GamepadState { leftStick = new Vector2 ( 0.1f , 0.1f ) } ) ;
703
+ InputSystem . Update ( ) ;
704
+
705
+ gamepad . leftStick . ReadValue ( ) ;
706
+ Assert . That ( gamepad . leftStick . m_CachedValueIsStale , Is . False ) ;
707
+
708
+ for ( var i = 0 ; i < 1000 ; ++ i )
709
+ {
710
+ InputSystem . Update ( ) ;
711
+ pos = gamepad . leftStick . value ;
712
+ Assert . That ( gamepad . leftStick . m_CachedValueIsStale , Is . False ) ;
713
+ // Make sure there's a new different value every frames to mark the cached value as stale.
714
+ InputSystem . QueueStateEvent ( gamepad , new GamepadState { leftStick = new Vector2 ( i / 1000f , i / 1000f ) } ) ;
715
+ }
716
+ } )
717
+ . MeasurementCount ( 100 )
718
+ . WarmupCount ( 10 )
719
+ . Run ( ) ;
720
+ }
721
+
722
+ [ Test , Performance ]
723
+ [ Category ( "Performance" ) ]
724
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
725
+ [ TestCase ( OptimizationTestType . OptimizedControls ) ]
726
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
727
+ [ TestCase ( OptimizationTestType . OptimizedControlsAndReadValueCaching ) ]
728
+ // These tests evaluate the performance when there's no read value performed and only InputSystem.Update() is called.
729
+ // Emulates a scenario where the controls are not being changed to evaluate the impact of the optimizations.
730
+ public void Performance_OptimizedControls_UpdateOnly1kTimes ( OptimizationTestType testType )
731
+ {
732
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
733
+
734
+ // This adds FastMouse, which updates state every frame and can lead to a performance cost
735
+ // when using ReadValueCaching.
736
+ var mouse = InputSystem . AddDevice < Mouse > ( ) ;
737
+ InputSystem . Update ( ) ;
738
+
739
+ Measure . Method ( ( ) =>
740
+ {
741
+ CallUpdate ( ) ;
742
+ } )
743
+ . MeasurementCount ( 100 )
744
+ . SampleGroup ( "Mouse Only" )
745
+ . WarmupCount ( 10 )
746
+ . Run ( ) ;
747
+
748
+ InputSystem . RemoveDevice ( mouse ) ;
749
+ InputSystem . AddDevice < Gamepad > ( ) ;
750
+ InputSystem . Update ( ) ;
751
+
752
+ Measure . Method ( ( ) =>
753
+ {
754
+ CallUpdate ( ) ;
755
+ } )
756
+ . MeasurementCount ( 100 )
757
+ . SampleGroup ( "Gamepad Only" )
758
+ . WarmupCount ( 10 )
759
+ . Run ( ) ;
760
+
761
+ return ;
762
+
763
+ void CallUpdate ( )
764
+ {
765
+ for ( var i = 0 ; i < 1000 ; ++ i ) InputSystem . Update ( ) ;
766
+ }
767
+ }
768
+
582
769
#if ENABLE_VR
583
770
[ Test , Performance ]
584
771
[ Category ( "Performance" ) ]
585
- [ TestCase ( OptimizedControlsTest . OptimizedControls ) ]
586
- [ TestCase ( OptimizedControlsTest . NormalControls ) ]
587
- public void Performance_OptimizedControls_ReadingPose4kTimes ( OptimizedControlsTest testSetup )
772
+ [ TestCase ( OptimizationTestType . NoOptimization ) ]
773
+ [ TestCase ( OptimizationTestType . OptimizedControls ) ]
774
+ [ TestCase ( OptimizationTestType . ReadValueCaching ) ]
775
+ [ TestCase ( OptimizationTestType . OptimizedControlsAndReadValueCaching ) ]
776
+ // Isolated tests for reading from XR Pose device to evaluate the performance of the optimizations.
777
+ // Does not take into account the performance of the InputSystem.Update() call.
778
+ public void Performance_OptimizedControls_ReadingPose4kTimes ( OptimizationTestType testType )
588
779
{
589
- var useOptimizedControls = testSetup == OptimizedControlsTest . OptimizedControls ;
590
- InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kUseOptimizedControls , useOptimizedControls ) ;
591
- InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kUseReadValueCaching , useOptimizedControls ) ;
592
- InputSystem . settings . SetInternalFeatureFlag ( InputFeatureNames . kParanoidReadValueCachingChecks , false ) ;
780
+ SetInternalFeatureFlagsFromTestType ( testType ) ;
593
781
594
782
runtime . ReportNewInputDevice ( XRTests . PoseDeviceState . CreateDeviceDescription ( ) . ToJson ( ) ) ;
595
783
@@ -598,6 +786,8 @@ public void Performance_OptimizedControls_ReadingPose4kTimes(OptimizedControlsTe
598
786
var device = InputSystem . devices [ 0 ] ;
599
787
600
788
var poseControl = device [ "posecontrol" ] as UnityEngine . InputSystem . XR . PoseControl ;
789
+ var useOptimizedControls = testType == OptimizationTestType . OptimizedControls
790
+ || testType == OptimizationTestType . OptimizedControlsAndReadValueCaching ;
601
791
Assert . That ( poseControl . optimizedControlDataType , Is . EqualTo ( useOptimizedControls ? InputStateBlock . FormatPose : InputStateBlock . FormatInvalid ) ) ;
602
792
603
793
Measure . Method ( ( ) =>
0 commit comments