@@ -35,7 +35,8 @@ export class PerflogMetric extends Metric {
3535 * @param microMetrics Name and description of metrics provided via console.time / console.timeEnd
3636 **/
3737 constructor ( private _driverExtension : WebDriverExtension , private _setTimeout : Function ,
38- private _microMetrics : StringMap < string , any > , private _forceGc : boolean ) {
38+ private _microMetrics : StringMap < string , any > , private _forceGc : boolean ,
39+ private _captureFrames : boolean ) {
3940 super ( ) ;
4041
4142 this . _remainingEvents = [ ] ;
@@ -60,6 +61,11 @@ export class PerflogMetric extends Metric {
6061 res [ 'forcedGcAmount' ] = 'forced gc amount in kbytes' ;
6162 }
6263 }
64+ if ( this . _captureFrames ) {
65+ res [ 'meanFrameTime' ] = this . _perfLogFeatures . frameCapture ?
66+ 'mean frame time in ms (target: 16.6ms for 60fps)' :
67+ 'WARNING: Metric requested, but not supported by driver' ;
68+ }
6369 StringMapWrapper . forEach ( this . _microMetrics ,
6470 ( desc , name ) => { StringMapWrapper . set ( res , name , desc ) ; } ) ;
6571 return res ;
@@ -83,9 +89,13 @@ export class PerflogMetric extends Metric {
8389
8490 _endPlainMeasureAndMeasureForceGc ( restartMeasure : boolean ) {
8591 return this . _endMeasure ( true ) . then ( ( measureValues ) => {
92+ // disable frame capture for measurments during forced gc
93+ var originalFrameCaptureValue = this . _captureFrames ;
94+ this . _captureFrames = false ;
8695 return this . _driverExtension . gc ( )
8796 . then ( ( _ ) => this . _endMeasure ( restartMeasure ) )
8897 . then ( ( forceGcMeasureValues ) => {
98+ this . _captureFrames = originalFrameCaptureValue ;
8999 StringMapWrapper . set ( measureValues , 'forcedGcTime' , forceGcMeasureValues [ 'gcTime' ] ) ;
90100 StringMapWrapper . set ( measureValues , 'forcedGcAmount' , forceGcMeasureValues [ 'gcAmount' ] ) ;
91101 return measureValues ;
@@ -161,13 +171,21 @@ export class PerflogMetric extends Metric {
161171 if ( this . _perfLogFeatures . render ) {
162172 result [ 'renderTime' ] = 0 ;
163173 }
174+ if ( this . _captureFrames ) {
175+ result [ 'meanFrameTime' ] = 0 ;
176+ }
164177 StringMapWrapper . forEach ( this . _microMetrics , ( desc , name ) => { result [ name ] = 0 ; } ) ;
165178
166179 var markStartEvent = null ;
167180 var markEndEvent = null ;
168181 var gcTimeInScript = 0 ;
169182 var renderTimeInScript = 0 ;
170183
184+ var frameTimestamps = [ ] ;
185+ var frameTimes = [ ] ;
186+ var frameCaptureStartEvent = null ;
187+ var frameCaptureEndEvent = null ;
188+
171189 var intervalStarts : StringMap < string , any > = { } ;
172190 var intervalStartCount : StringMap < string , number > = { } ;
173191 events . forEach ( ( event ) => {
@@ -185,8 +203,37 @@ export class PerflogMetric extends Metric {
185203 } else if ( StringWrapper . equals ( ph , 'e' ) && StringWrapper . equals ( name , markName ) ) {
186204 markEndEvent = event ;
187205 }
206+
188207 if ( isPresent ( markStartEvent ) && isBlank ( markEndEvent ) &&
189208 event [ 'pid' ] === markStartEvent [ 'pid' ] ) {
209+ if ( StringWrapper . equals ( ph , 'b' ) && StringWrapper . equals ( name , _MARK_NAME_FRAME_CAPUTRE ) ) {
210+ if ( isPresent ( frameCaptureStartEvent ) ) {
211+ throw new BaseException ( 'can capture frames only once per benchmark run' ) ;
212+ }
213+ if ( ! this . _captureFrames ) {
214+ throw new BaseException (
215+ 'found start event for frame capture, but frame capture was not requested in benchpress' )
216+ }
217+ frameCaptureStartEvent = event ;
218+ } else if ( StringWrapper . equals ( ph , 'e' ) &&
219+ StringWrapper . equals ( name , _MARK_NAME_FRAME_CAPUTRE ) ) {
220+ if ( isBlank ( frameCaptureStartEvent ) ) {
221+ throw new BaseException ( 'missing start event for frame capture' ) ;
222+ }
223+ frameCaptureEndEvent = event ;
224+ }
225+
226+ if ( StringWrapper . equals ( ph , 'I' ) || StringWrapper . equals ( ph , 'i' ) ) {
227+ if ( isPresent ( frameCaptureStartEvent ) && isBlank ( frameCaptureEndEvent ) &&
228+ StringWrapper . equals ( name , 'frame' ) ) {
229+ ListWrapper . push ( frameTimestamps , event [ 'ts' ] ) ;
230+ if ( frameTimestamps . length >= 2 ) {
231+ ListWrapper . push ( frameTimes , frameTimestamps [ frameTimestamps . length - 1 ] -
232+ frameTimestamps [ frameTimestamps . length - 2 ] ) ;
233+ }
234+ }
235+ }
236+
190237 if ( StringWrapper . equals ( ph , 'B' ) || StringWrapper . equals ( ph , 'b' ) ) {
191238 if ( isBlank ( intervalStarts [ name ] ) ) {
192239 intervalStartCount [ name ] = 1 ;
@@ -227,8 +274,25 @@ export class PerflogMetric extends Metric {
227274 }
228275 }
229276 } ) ;
277+ if ( ! isPresent ( markStartEvent ) || ! isPresent ( markEndEvent ) ) {
278+ // not all events have been received, no further processing for now
279+ return null ;
280+ }
281+
282+ if ( isPresent ( markEndEvent ) && isPresent ( frameCaptureStartEvent ) &&
283+ isBlank ( frameCaptureEndEvent ) ) {
284+ throw new BaseException ( 'missing end event for frame capture' ) ;
285+ }
286+ if ( this . _captureFrames && isBlank ( frameCaptureStartEvent ) ) {
287+ throw new BaseException (
288+ 'frame capture requested in benchpress, but no start event was found' ) ;
289+ }
290+ if ( frameTimes . length > 0 ) {
291+ result [ 'meanFrameTime' ] =
292+ ListWrapper . reduce ( frameTimes , ( a , b ) => a + b , 0 ) / frameTimes . length ;
293+ }
230294 result [ 'pureScriptTime' ] = result [ 'scriptTime' ] - gcTimeInScript - renderTimeInScript ;
231- return isPresent ( markStartEvent ) && isPresent ( markEndEvent ) ? result : null ;
295+ return result ;
232296 }
233297
234298 _markName ( index ) { return `${ _MARK_NAME_PREFIX } ${ index } ` ; }
@@ -239,10 +303,19 @@ var _MAX_RETRY_COUNT = 20;
239303var _MARK_NAME_PREFIX = 'benchpress' ;
240304var _SET_TIMEOUT = new OpaqueToken ( 'PerflogMetric.setTimeout' ) ;
241305
306+ var _MARK_NAME_FRAME_CAPUTRE = 'frameCapture' ;
307+
242308var _BINDINGS = [
243309 bind ( PerflogMetric )
244- . toFactory ( ( driverExtension , setTimeout , microMetrics , forceGc ) =>
245- new PerflogMetric ( driverExtension , setTimeout , microMetrics , forceGc ) ,
246- [ WebDriverExtension , _SET_TIMEOUT , Options . MICRO_METRICS , Options . FORCE_GC ] ) ,
310+ . toFactory (
311+ ( driverExtension , setTimeout , microMetrics , forceGc , captureFrames ) =>
312+ new PerflogMetric ( driverExtension , setTimeout , microMetrics , forceGc , captureFrames ) ,
313+ [
314+ WebDriverExtension ,
315+ _SET_TIMEOUT ,
316+ Options . MICRO_METRICS ,
317+ Options . FORCE_GC ,
318+ Options . CAPTURE_FRAMES
319+ ] ) ,
247320 bind ( _SET_TIMEOUT ) . toValue ( ( fn , millis ) => TimerWrapper . setTimeout ( fn , millis ) )
248321] ;
0 commit comments