@@ -26,7 +26,7 @@ export namespace inputLatency {
2626 const measurementsInput = new Float32Array ( Constants . bufferLength ) ;
2727 const measurementsRender = new Float32Array ( Constants . bufferLength ) ;
2828 const measurementsInputLatency = new Float32Array ( Constants . bufferLength ) ;
29- let measurementsIndex = 0 ;
29+ let measurementsCount = 0 ;
3030
3131 export function markKeydownStart ( ) {
3232 performance . mark ( 'inputlatency/start' ) ;
@@ -64,7 +64,6 @@ export namespace inputLatency {
6464 }
6565
6666 function markRenderEnd ( ) {
67- // Only measure the first render after keyboard input
6867 performance . mark ( 'render/end' ) ;
6968 state . render = EventPhase . Finished ;
7069 record ( ) ;
@@ -77,15 +76,15 @@ export namespace inputLatency {
7776
7877 function record ( ) {
7978 // Skip recording this frame if the buffer is full
80- if ( measurementsIndex >= Constants . bufferLength ) {
79+ if ( measurementsCount >= Constants . bufferLength ) {
8180 return ;
8281 }
8382 // Selection and render must have finished to record
8483 if ( state . selection !== EventPhase . Finished || state . render !== EventPhase . Finished ) {
8584 return ;
8685 }
87- // Measures from cursor edit to the end of the task
88- window . queueMicrotask ( ( ) => {
86+ // Finish the recording, using setImmediate to ensure that layout/paint is captured
87+ setImmediate ( ( ) => {
8988 if ( state . keydown === EventPhase . Finished && state . input === EventPhase . Finished && state . selection === EventPhase . Finished && state . render === EventPhase . Finished ) {
9089 performance . mark ( 'inputlatency/end' ) ;
9190
@@ -94,26 +93,26 @@ export namespace inputLatency {
9493 performance . measure ( 'render' , 'render/start' , 'render/end' ) ;
9594 performance . measure ( 'inputlatency' , 'inputlatency/start' , 'inputlatency/end' ) ;
9695
97- measurementsKeydown [ measurementsIndex ] = performance . getEntriesByName ( 'keydown' ) [ 0 ] . duration ;
98- measurementsInput [ measurementsIndex ] = performance . getEntriesByName ( 'input' ) [ 0 ] . duration ;
99- measurementsRender [ measurementsIndex ] = performance . getEntriesByName ( 'render' ) [ 0 ] . duration ;
100- measurementsInputLatency [ measurementsIndex ] = performance . getEntriesByName ( 'inputlatency' ) [ 0 ] . duration ;
96+ measurementsKeydown [ measurementsCount ] = performance . getEntriesByName ( 'keydown' ) [ 0 ] . duration ;
97+ measurementsInput [ measurementsCount ] = performance . getEntriesByName ( 'input' ) [ 0 ] . duration ;
98+ measurementsRender [ measurementsCount ] = performance . getEntriesByName ( 'render' ) [ 0 ] . duration ;
99+ measurementsInputLatency [ measurementsCount ] = performance . getEntriesByName ( 'inputlatency' ) [ 0 ] . duration ;
101100
102101 console . info (
103- `input latency=${ measurementsInputLatency [ measurementsIndex ] . toFixed ( 1 ) } [` +
104- `keydown=${ measurementsKeydown [ measurementsIndex ] . toFixed ( 1 ) } , ` +
105- `input=${ measurementsInput [ measurementsIndex ] . toFixed ( 1 ) } , ` +
106- `render=${ measurementsRender [ measurementsIndex ] . toFixed ( 1 ) } ` +
102+ `input latency=${ measurementsInputLatency [ measurementsCount ] . toFixed ( 1 ) } [` +
103+ `keydown=${ measurementsKeydown [ measurementsCount ] . toFixed ( 1 ) } , ` +
104+ `input=${ measurementsInput [ measurementsCount ] . toFixed ( 1 ) } , ` +
105+ `render=${ measurementsRender [ measurementsCount ] . toFixed ( 1 ) } ` +
107106 `]`
108107 ) ;
109108
110- measurementsIndex ++ ;
109+ measurementsCount ++ ;
111110
112111 reset ( ) ;
113112 }
114113 } ) ;
115114 }
116-
115+ setInterval ( ( ) => console . log ( getAndClearMeasurements ( ) ) , 10000 ) ;
117116 function reset ( ) {
118117 performance . clearMarks ( 'keydown/start' ) ;
119118 performance . clearMarks ( 'keydown/end' ) ;
@@ -135,4 +134,58 @@ export namespace inputLatency {
135134 state . selection = EventPhase . Before ;
136135 }
137136
137+ export interface IInputLatencyMeasurements {
138+ keydown : IInputLatencySingleMeasurement ;
139+ input : IInputLatencySingleMeasurement ;
140+ render : IInputLatencySingleMeasurement ;
141+ total : IInputLatencySingleMeasurement ;
142+ sampleCount : number ;
143+ }
144+
145+ export interface IInputLatencySingleMeasurement {
146+ average : number ;
147+ min : number ;
148+ max : number ;
149+ }
150+
151+ export function getAndClearMeasurements ( ) : IInputLatencyMeasurements | undefined {
152+ if ( measurementsCount === 0 ) {
153+ return undefined ;
154+ }
155+
156+ // Calculate the average, min and max of each measurement
157+ const result = {
158+ keydown : createSingleMeasurement ( ) ,
159+ input : createSingleMeasurement ( ) ,
160+ render : createSingleMeasurement ( ) ,
161+ total : createSingleMeasurement ( ) ,
162+ sampleCount : measurementsCount
163+ } ;
164+ for ( let i = 0 ; i < result . sampleCount ; i ++ ) {
165+ result . keydown . average += measurementsKeydown [ i ] ;
166+ result . input . average += measurementsInput [ i ] ;
167+ result . render . average += measurementsRender [ i ] ;
168+ result . total . average += measurementsInputLatency [ i ] ;
169+ result . keydown . min = Math . min ( result . keydown . min , measurementsKeydown [ i ] ) ;
170+ result . input . min = Math . min ( result . input . min , measurementsInput [ i ] ) ;
171+ result . render . min = Math . min ( result . render . min , measurementsRender [ i ] ) ;
172+ result . total . min = Math . min ( result . total . min , measurementsInputLatency [ i ] ) ;
173+ result . keydown . max = Math . max ( result . keydown . max , measurementsKeydown [ i ] ) ;
174+ result . input . max = Math . max ( result . input . max , measurementsInput [ i ] ) ;
175+ result . render . max = Math . max ( result . render . max , measurementsRender [ i ] ) ;
176+ result . total . max = Math . max ( result . total . max , measurementsInputLatency [ i ] ) ;
177+ }
178+ result . keydown . average /= result . sampleCount ;
179+ result . input . average /= result . sampleCount ;
180+ result . render . average /= result . sampleCount ;
181+ result . total . average /= result . sampleCount ;
182+
183+ measurementsCount = 0 ;
184+ return result ;
185+ }
186+
187+ function createSingleMeasurement ( ) : IInputLatencySingleMeasurement {
188+ return { average : 0 , min : Number . MAX_VALUE , max : 0 } ;
189+ }
190+
138191}
0 commit comments