11using Bridge . State ;
22using RLBot . Flat ;
33
4+ using Deltas = ( float GameTimeDelta , float ArrivalDelta ) ;
5+
46namespace RLBotCS . ManagerTools ;
57
68public class PerfMonitor
@@ -25,13 +27,13 @@ public class PerfMonitor
2527 B = 0 ,
2628 } ;
2729
28- private readonly CircularBuffer < float > _rlbotSamples = new ( _maxSamples ) ;
30+ private readonly CircularBuffer < Deltas > _rlbotSamples = new ( _maxSamples ) ;
2931 private readonly SortedDictionary < string , CircularBuffer < bool > > _samples = new ( ) ;
3032 private float time = 0 ;
3133
32- public void AddRLBotSample ( float timeDiff )
34+ public void AddRLBotSample ( Deltas deltas )
3335 {
34- _rlbotSamples . AddLast ( timeDiff ) ;
36+ _rlbotSamples . AddLast ( deltas ) ;
3537 }
3638
3739 public void AddSample ( string name , bool gotInput )
@@ -49,18 +51,48 @@ public void RemoveBot(string name)
4951 _samples . Remove ( name ) ;
5052 }
5153
54+ public static float GetPercentile ( IEnumerable < float > data , float p )
55+ {
56+ var sorted = data . OrderBy ( x => x ) . ToList ( ) ;
57+ int n = sorted . Count ;
58+ if ( n == 0 ) return default ;
59+
60+ double rank = p * ( n - 1 ) ;
61+ int lower = ( int ) Math . Floor ( rank ) ;
62+ int upper = ( int ) Math . Ceiling ( rank ) ;
63+
64+ return ( float ) ( sorted [ lower ] + ( rank - lower ) * ( sorted [ upper ] - sorted [ lower ] ) ) ;
65+ }
66+
5267 public void RenderSummary ( Rendering rendering , GameState gameState , float deltaTime )
5368 {
5469 time += deltaTime ;
5570 if ( time < _timeSkip )
5671 return ;
5772 time = 0 ;
5873
59- float averageTimeDiff = _rlbotSamples . Count > 0 ? _rlbotSamples . Iter ( ) . Average ( ) : 1 ;
60- float timeDiffPercentage = 1 / ( 120f * averageTimeDiff ) ;
6174
62- string message = $ "RLBot: { timeDiffPercentage * 100 : 0.0} %";
63- bool shouldRender = timeDiffPercentage < 0.9999 || timeDiffPercentage > 1.0001 ;
75+ var arrivalDeltas = _rlbotSamples . Iter ( ) . Select ( t => t . ArrivalDelta ) ;
76+ var gameTimeDeltas = _rlbotSamples . Iter ( ) . Select ( t => t . GameTimeDelta ) ;
77+
78+ float averageTickDelta = gameTimeDeltas . Sum ( ) / _maxSamples ;
79+ float averageTickRate = 1f / averageTickDelta ;
80+
81+ // Find deltas larger than expected at 60hz, allowing 10% margin
82+ float misses60 = arrivalDeltas
83+ . Count ( d =>
84+ ( d - ( 1f / 60f ) ) > ( 0.1f / 60f ) ) ;
85+
86+ // Find deltas larger than expected at 120hz, allowing 10% margin
87+ float misses120 = arrivalDeltas
88+ . Count ( d =>
89+ ( d - ( 1f / 120f ) ) > ( 0.1f / 120f ) ) ;
90+
91+ string message = $ """
92+ RLBot @ { averageTickRate : 0} hz { ( 1f - misses60 / 120f ) * 100f : 0} %|{ ( 1f - misses120 / 120f ) * 100f : 0} %
93+ p95 { GetPercentile ( arrivalDeltas , 0.95f ) * 1000f : 0.0} ms p99 { GetPercentile ( arrivalDeltas , 0.99f ) * 1000f : 0.0} ms
94+ """ ;
95+ bool shouldRender = misses120 > 1 ;
6496
6597 foreach ( var ( name , samples ) in _samples )
6698 {
0 commit comments