Add the ability to run web_benchmarks with Wasm (#5611)

This uses the same run flags that the flutter benchmark tests use:
https://github.com/flutter/flutter/blob/master/dev/devicelab/lib/tasks/web_benchmarks.dart#L36-L40

CC @kevmoo
This commit is contained in:
Kenzie Davisson
2023-12-07 17:30:30 -08:00
committed by GitHub
parent 17108a8506
commit 671bd3f271
7 changed files with 86 additions and 11 deletions

View File

@ -1,3 +1,12 @@
## 1.0.0
* **Breaking change:** replace the `useCanvasKit` parameter in the `serveWebBenchmark`
method with a new parameter `compilationOptions`, which allows you to:
* specify the web renderer to use for the benchmark app (html, canvaskit, or skwasm)
* specify whether to use WebAssembly to build the benchmark app
* **Breaking change:** `serveWebBenchmark` now uses `canvaskit` instead of `html` as the
default web renderer.
## 0.1.0+11 ## 0.1.0+11
* Migrates benchmark recorder from `dart:html` to `package:web` to support WebAssembly. * Migrates benchmark recorder from `dart:html` to `package:web` to support WebAssembly.

View File

@ -53,15 +53,18 @@ Future<void> runBenchmarks(
final Uri currentUri = Uri.parse(window.location.href); final Uri currentUri = Uri.parse(window.location.href);
// Create a new URI with the current 'page' value set to [initialPage] to // Create a new URI with the current 'page' value set to [initialPage] to
// ensure the benchmark app is reloaded at the proper location. // ensure the benchmark app is reloaded at the proper location.
final Uri newUri = Uri( final String newUri = Uri(
scheme: currentUri.scheme, scheme: currentUri.scheme,
host: currentUri.host, host: currentUri.host,
port: currentUri.port, port: currentUri.port,
path: initialPage, path: initialPage,
); ).toString();
// Reloading the window will trigger the next benchmark to run. // Reloading the window will trigger the next benchmark to run.
window.location.replace(newUri.toString()); await _client.printToConsole(
'Client preparing to reload the window to: "$newUri"',
);
window.location.replace(newUri);
} }
Future<void> _runBenchmark(String? benchmarkName) async { Future<void> _runBenchmark(String? benchmarkName) async {

View File

@ -9,9 +9,11 @@ import 'package:logging/logging.dart';
import 'src/benchmark_result.dart'; import 'src/benchmark_result.dart';
import 'src/common.dart'; import 'src/common.dart';
import 'src/compilation_options.dart';
import 'src/runner.dart'; import 'src/runner.dart';
export 'src/benchmark_result.dart'; export 'src/benchmark_result.dart';
export 'src/compilation_options.dart';
/// The default port number used by the local benchmark server. /// The default port number used by the local benchmark server.
const int defaultBenchmarkServerPort = 9999; const int defaultBenchmarkServerPort = 9999;
@ -43,12 +45,12 @@ const int defaultChromeDebugPort = 10000;
Future<BenchmarkResults> serveWebBenchmark({ Future<BenchmarkResults> serveWebBenchmark({
required io.Directory benchmarkAppDirectory, required io.Directory benchmarkAppDirectory,
required String entryPoint, required String entryPoint,
required bool useCanvasKit,
int benchmarkServerPort = defaultBenchmarkServerPort, int benchmarkServerPort = defaultBenchmarkServerPort,
int chromeDebugPort = defaultChromeDebugPort, int chromeDebugPort = defaultChromeDebugPort,
bool headless = true, bool headless = true,
bool treeShakeIcons = true, bool treeShakeIcons = true,
String initialPage = defaultInitialPage, String initialPage = defaultInitialPage,
CompilationOptions compilationOptions = const CompilationOptions(),
}) async { }) async {
// Reduce logging level. Otherwise, package:webkit_inspection_protocol is way too spammy. // Reduce logging level. Otherwise, package:webkit_inspection_protocol is way too spammy.
Logger.root.level = Level.INFO; Logger.root.level = Level.INFO;
@ -56,10 +58,10 @@ Future<BenchmarkResults> serveWebBenchmark({
return BenchmarkServer( return BenchmarkServer(
benchmarkAppDirectory: benchmarkAppDirectory, benchmarkAppDirectory: benchmarkAppDirectory,
entryPoint: entryPoint, entryPoint: entryPoint,
useCanvasKit: useCanvasKit,
benchmarkServerPort: benchmarkServerPort, benchmarkServerPort: benchmarkServerPort,
chromeDebugPort: chromeDebugPort, chromeDebugPort: chromeDebugPort,
headless: headless, headless: headless,
compilationOptions: compilationOptions,
treeShakeIcons: treeShakeIcons, treeShakeIcons: treeShakeIcons,
initialPage: initialPage, initialPage: initialPage,
).run(); ).run();

View File

@ -0,0 +1,38 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// Compilation options for bulding a Flutter web app.
///
/// This object holds metadata that is used to determine how the benchmark app
/// should be built.
class CompilationOptions {
/// Creates a [CompilationOptions] object.
const CompilationOptions({
this.renderer = WebRenderer.canvaskit,
this.useWasm = false,
});
/// The renderer to use for the build.
final WebRenderer renderer;
/// Whether to build the app with dart2wasm.
final bool useWasm;
@override
String toString() {
return '(renderer: ${renderer.name}, compiler: ${useWasm ? 'dart2wasm' : 'dart2js'})';
}
}
/// The possible types of web renderers Flutter can build for.
enum WebRenderer {
/// The HTML web renderer.
html,
/// The CanvasKit web renderer.
canvaskit,
/// The SKIA Wasm web renderer.
skwasm,
}

View File

@ -18,6 +18,7 @@ import 'package:shelf_static/shelf_static.dart';
import 'benchmark_result.dart'; import 'benchmark_result.dart';
import 'browser.dart'; import 'browser.dart';
import 'common.dart'; import 'common.dart';
import 'compilation_options.dart';
/// The default port number used by the local benchmark server. /// The default port number used by the local benchmark server.
const int defaultBenchmarkServerPort = 9999; const int defaultBenchmarkServerPort = 9999;
@ -50,11 +51,11 @@ class BenchmarkServer {
BenchmarkServer({ BenchmarkServer({
required this.benchmarkAppDirectory, required this.benchmarkAppDirectory,
required this.entryPoint, required this.entryPoint,
required this.useCanvasKit,
required this.benchmarkServerPort, required this.benchmarkServerPort,
required this.chromeDebugPort, required this.chromeDebugPort,
required this.headless, required this.headless,
required this.treeShakeIcons, required this.treeShakeIcons,
this.compilationOptions = const CompilationOptions(),
this.initialPage = defaultInitialPage, this.initialPage = defaultInitialPage,
}); });
@ -72,8 +73,8 @@ class BenchmarkServer {
/// the app. /// the app.
final String entryPoint; final String entryPoint;
/// Whether to build the app in CanvasKit mode. /// The compilation options to use for building the benchmark web app.
final bool useCanvasKit; final CompilationOptions compilationOptions;
/// The port this benchmark server serves the app on. /// The port this benchmark server serves the app on.
final int benchmarkServerPort; final int benchmarkServerPort;
@ -109,13 +110,20 @@ class BenchmarkServer {
"flutter executable is not runnable. Make sure it's in the PATH."); "flutter executable is not runnable. Make sure it's in the PATH.");
} }
final DateTime startTime = DateTime.now();
print('Building Flutter web app $compilationOptions...');
final io.ProcessResult buildResult = await _processManager.run( final io.ProcessResult buildResult = await _processManager.run(
<String>[ <String>[
'flutter', 'flutter',
'build', 'build',
'web', 'web',
if (compilationOptions.useWasm) ...<String>[
'--wasm',
'--wasm-opt=debug',
'--omit-type-checks',
],
'--web-renderer=${compilationOptions.renderer.name}',
'--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true', '--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true',
if (useCanvasKit) '--dart-define=FLUTTER_WEB_USE_SKIA=true',
if (!treeShakeIcons) '--no-tree-shake-icons', if (!treeShakeIcons) '--no-tree-shake-icons',
'--profile', '--profile',
'-t', '-t',
@ -124,6 +132,12 @@ class BenchmarkServer {
workingDirectory: benchmarkAppDirectory.path, workingDirectory: benchmarkAppDirectory.path,
); );
final int buildTime = Duration(
milliseconds: DateTime.now().millisecondsSinceEpoch -
startTime.millisecondsSinceEpoch,
).inSeconds;
print('Build took ${buildTime}s to complete.');
if (buildResult.exitCode != 0) { if (buildResult.exitCode != 0) {
io.stderr.writeln(buildResult.stdout); io.stderr.writeln(buildResult.stdout);
io.stderr.writeln(buildResult.stderr); io.stderr.writeln(buildResult.stderr);

View File

@ -2,7 +2,7 @@ name: web_benchmarks
description: A benchmark harness for performance-testing Flutter apps in Chrome. description: A benchmark harness for performance-testing Flutter apps in Chrome.
repository: https://github.com/flutter/packages/tree/main/packages/web_benchmarks repository: https://github.com/flutter/packages/tree/main/packages/web_benchmarks
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+web_benchmarks%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+web_benchmarks%22
version: 0.1.0+11 version: 1.0.0
environment: environment:
sdk: ">=3.2.0 <4.0.0" sdk: ">=3.2.0 <4.0.0"

View File

@ -25,19 +25,28 @@ Future<void> main() async {
initialPage: 'index.html#about', initialPage: 'index.html#about',
); );
}, timeout: Timeout.none); }, timeout: Timeout.none);
test('Can run a web benchmark with wasm', () async {
await _runBenchmarks(
benchmarkNames: <String>['simple'],
entryPoint: 'lib/benchmarks/runner_simple.dart',
compilationOptions: const CompilationOptions(useWasm: true),
);
}, timeout: Timeout.none);
} }
Future<void> _runBenchmarks({ Future<void> _runBenchmarks({
required List<String> benchmarkNames, required List<String> benchmarkNames,
required String entryPoint, required String entryPoint,
String initialPage = defaultInitialPage, String initialPage = defaultInitialPage,
CompilationOptions compilationOptions = const CompilationOptions(),
}) async { }) async {
final BenchmarkResults taskResult = await serveWebBenchmark( final BenchmarkResults taskResult = await serveWebBenchmark(
benchmarkAppDirectory: Directory('testing/test_app'), benchmarkAppDirectory: Directory('testing/test_app'),
entryPoint: entryPoint, entryPoint: entryPoint,
useCanvasKit: false,
treeShakeIcons: false, treeShakeIcons: false,
initialPage: initialPage, initialPage: initialPage,
compilationOptions: compilationOptions,
); );
for (final String benchmarkName in benchmarkNames) { for (final String benchmarkName in benchmarkNames) {