@@ -7,6 +7,7 @@ import 'dart:convert' show LineSplitter, json, utf8;
7
7
import 'dart:io' ;
8
8
import 'dart:math' as math;
9
9
10
+ import 'package:flutter_devicelab/tasks/track_widget_creation_enabled_task.dart' ;
10
11
import 'package:meta/meta.dart' ;
11
12
import 'package:path/path.dart' as path;
12
13
@@ -82,12 +83,20 @@ TaskFunction createCubicBezierPerfTest() {
82
83
).run;
83
84
}
84
85
86
+ TaskFunction createCubicBezierPerfSkSLWarmupTest () {
87
+ return PerfTestWithSkSL (
88
+ '${flutterDirectory .path }/dev/benchmarks/macrobenchmarks' ,
89
+ 'test_driver/cubic_bezier_perf.dart' ,
90
+ 'cubic_bezier_perf' ,
91
+ ).run;
92
+ }
93
+
85
94
TaskFunction createBackdropFilterPerfTest ({bool needsMeasureCpuGpu = false }) {
86
95
return PerfTest (
87
96
'${flutterDirectory .path }/dev/benchmarks/macrobenchmarks' ,
88
97
'test_driver/backdrop_filter_perf.dart' ,
89
98
'backdrop_filter_perf' ,
90
- needsMeasureCpuGPu : needsMeasureCpuGpu,
99
+ needsMeasureCpuGpu : needsMeasureCpuGpu,
91
100
).run;
92
101
}
93
102
@@ -96,7 +105,7 @@ TaskFunction createPostBackdropFilterPerfTest({bool needsMeasureCpuGpu = false})
96
105
'${flutterDirectory .path }/dev/benchmarks/macrobenchmarks' ,
97
106
'test_driver/post_backdrop_filter_perf.dart' ,
98
107
'post_backdrop_filter_perf' ,
99
- needsMeasureCpuGPu : needsMeasureCpuGpu,
108
+ needsMeasureCpuGpu : needsMeasureCpuGpu,
100
109
).run;
101
110
}
102
111
@@ -105,7 +114,7 @@ TaskFunction createSimpleAnimationPerfTest({bool needsMeasureCpuGpu = false}) {
105
114
'${flutterDirectory .path }/dev/benchmarks/macrobenchmarks' ,
106
115
'test_driver/simple_animation_perf.dart' ,
107
116
'simple_animation_perf' ,
108
- needsMeasureCpuGPu : needsMeasureCpuGpu,
117
+ needsMeasureCpuGpu : needsMeasureCpuGpu,
109
118
).run;
110
119
}
111
120
@@ -114,7 +123,7 @@ TaskFunction createAnimatedPlaceholderPerfTest({bool needsMeasureCpuGpu = false}
114
123
'${flutterDirectory .path }/dev/benchmarks/macrobenchmarks' ,
115
124
'test_driver/animated_placeholder_perf.dart' ,
116
125
'animated_placeholder_perf' ,
117
- needsMeasureCpuGPu : needsMeasureCpuGpu,
126
+ needsMeasureCpuGpu : needsMeasureCpuGpu,
118
127
).run;
119
128
}
120
129
@@ -266,7 +275,7 @@ class PerfTest {
266
275
this .testDirectory,
267
276
this .testTarget,
268
277
this .timelineFileName, {
269
- this .needsMeasureCpuGPu = false ,
278
+ this .needsMeasureCpuGpu = false ,
270
279
this .testDriver,
271
280
});
272
281
@@ -279,9 +288,19 @@ class PerfTest {
279
288
/// The test file to run on the host.
280
289
final String testDriver;
281
290
/// Whether to collect CPU and GPU metrics.
282
- final bool needsMeasureCpuGPu ;
291
+ final bool needsMeasureCpuGpu ;
283
292
284
293
Future <TaskResult > run () {
294
+ return internalRun ();
295
+ }
296
+
297
+ @protected
298
+ Future <TaskResult > internalRun ({
299
+ bool keepRunning = false ,
300
+ bool cacheSkSL = false ,
301
+ String existingApp,
302
+ String writeSkslFileName,
303
+ }) {
285
304
return inDirectory <TaskResult >(testDirectory, () async {
286
305
final Device device = await devices.workingDevice;
287
306
await device.unlock ();
@@ -295,7 +314,13 @@ class PerfTest {
295
314
'-t' ,
296
315
testTarget,
297
316
if (testDriver != null )
298
- '--driver' , testDriver,
317
+ ...< String > ['--driver' , testDriver],
318
+ if (existingApp != null )
319
+ ...< String > ['--use-existing-app' , existingApp],
320
+ if (writeSkslFileName != null )
321
+ ...< String > ['--write-sksl-on-exit' , writeSkslFileName],
322
+ if (cacheSkSL) '--cache-sksl' ,
323
+ if (keepRunning) '--keep-app-running' ,
299
324
'-d' ,
300
325
deviceId,
301
326
]);
@@ -310,7 +335,7 @@ class PerfTest {
310
335
);
311
336
}
312
337
313
- if (needsMeasureCpuGPu ) {
338
+ if (needsMeasureCpuGpu ) {
314
339
await inDirectory <void >('$testDirectory /build' , () async {
315
340
data.addAll (await measureIosCpuGpu (deviceId: deviceId));
316
341
});
@@ -328,13 +353,117 @@ class PerfTest {
328
353
'average_vsync_transitions_missed' ,
329
354
'90th_percentile_vsync_transitions_missed' ,
330
355
'99th_percentile_vsync_transitions_missed' ,
331
- if (needsMeasureCpuGPu ) 'cpu_percentage' ,
332
- if (needsMeasureCpuGPu ) 'gpu_percentage' ,
356
+ if (needsMeasureCpuGpu ) 'cpu_percentage' ,
357
+ if (needsMeasureCpuGpu ) 'gpu_percentage' ,
333
358
]);
334
359
});
335
360
}
336
361
}
337
362
363
+ class PerfTestWithSkSL extends PerfTest {
364
+ PerfTestWithSkSL (
365
+ String testDirectory,
366
+ String testTarget,
367
+ String timelineFileName, {
368
+ bool needsMeasureCpuGpu = false ,
369
+ String testDriver,
370
+ }) : super (
371
+ testDirectory,
372
+ testTarget,
373
+ timelineFileName,
374
+ needsMeasureCpuGpu: needsMeasureCpuGpu,
375
+ testDriver: testDriver,
376
+ );
377
+
378
+ @override
379
+ Future <TaskResult > run () async {
380
+ return inDirectory <TaskResult >(testDirectory, () async {
381
+ // Some initializations
382
+ _device = await devices.workingDevice;
383
+ _flutterPath = path.join (flutterDirectory.path, 'bin' , 'flutter' );
384
+
385
+ // Prepare the SkSL by running the driver test.
386
+ await _generateSkSL ();
387
+
388
+ // Build the app with SkSL artifacts and run that app
389
+ final String observatoryUri = await _buildAndRun ();
390
+
391
+ // Attach to the running app and run the final driver test to get metrics.
392
+ final TaskResult result = await internalRun (
393
+ existingApp: observatoryUri,
394
+ );
395
+
396
+ _runProcess.kill ();
397
+ await _runProcess.exitCode;
398
+
399
+ return result;
400
+ });
401
+ }
402
+
403
+ Future <void > _generateSkSL () async {
404
+ await super .internalRun (
405
+ keepRunning: true ,
406
+ cacheSkSL: true ,
407
+ writeSkslFileName: _skslJsonFileName,
408
+ );
409
+ }
410
+
411
+ // Return the VMService URI.
412
+ Future <String > _buildAndRun () async {
413
+ await flutter ('build' , options: < String > [
414
+ // TODO(liyuqian): also supports iOS once https://github.com/flutter/flutter/issues/53115 is fully closed.
415
+ 'apk' ,
416
+ '--profile' ,
417
+ '--bundle-sksl-path' , _skslJsonFileName,
418
+ '-t' , testTarget,
419
+ ]);
420
+
421
+ if (File (_vmserviceFileName).existsSync ()) {
422
+ File (_vmserviceFileName).deleteSync ();
423
+ }
424
+
425
+ _runProcess = await startProcess (
426
+ _flutterPath,
427
+ < String > [
428
+ 'run' ,
429
+ '--verbose' ,
430
+ '--profile' ,
431
+ '-d' , _device.deviceId,
432
+ '-t' , testTarget,
433
+ '--endless-trace-buffer' ,
434
+ '--use-application-binary' ,
435
+ '$testDirectory /build/app/outputs/flutter-apk/app-profile.apk' ,
436
+ '--vmservice-out-file' , _vmserviceFileName,
437
+ ],
438
+ );
439
+
440
+ final Stream <List <int >> broadcastOut = _runProcess.stdout.asBroadcastStream ();
441
+ _forwardStream (broadcastOut, 'run stdout' );
442
+ _forwardStream (_runProcess.stderr, 'run stderr' );
443
+
444
+ final File file = await waitForFile (_vmserviceFileName);
445
+ return file.readAsStringSync ();
446
+ }
447
+
448
+ String get _skslJsonFileName => '$testDirectory /flutter_01.sksl.json' ;
449
+ String get _vmserviceFileName => '$testDirectory /$_kVmserviceOutFileName ' ;
450
+
451
+ Stream <String > _transform (Stream <List <int >> stream) =>
452
+ stream.transform <String >(utf8.decoder).transform <String >(const LineSplitter ());
453
+
454
+ void _forwardStream (Stream <List <int >> stream, String label) {
455
+ _transform (stream).listen ((String line) {
456
+ print ('$label : $line ' );
457
+ });
458
+ }
459
+
460
+ String _flutterPath;
461
+ Device _device;
462
+ Process _runProcess;
463
+
464
+ static const String _kVmserviceOutFileName = 'vmservice.out' ;
465
+ }
466
+
338
467
/// Measures how long it takes to compile a Flutter app to JavaScript and how
339
468
/// big the compiled code is.
340
469
class WebCompileTest {
0 commit comments