Skip to content

Add the ability to run web_benchmarks with Wasm #5611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/web_benchmarks/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

* Migrates benchmark recorder from `dart:html` to `package:web` to support WebAssembly.
Expand Down
9 changes: 6 additions & 3 deletions packages/web_benchmarks/lib/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,18 @@ Future<void> runBenchmarks(
final Uri currentUri = Uri.parse(window.location.href);
// Create a new URI with the current 'page' value set to [initialPage] to
// ensure the benchmark app is reloaded at the proper location.
final Uri newUri = Uri(
final String newUri = Uri(
scheme: currentUri.scheme,
host: currentUri.host,
port: currentUri.port,
path: initialPage,
);
).toString();

// 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 {
Expand Down
6 changes: 4 additions & 2 deletions packages/web_benchmarks/lib/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import 'package:logging/logging.dart';

import 'src/benchmark_result.dart';
import 'src/common.dart';
import 'src/compilation_options.dart';
import 'src/runner.dart';

export 'src/benchmark_result.dart';
export 'src/compilation_options.dart';

/// The default port number used by the local benchmark server.
const int defaultBenchmarkServerPort = 9999;
Expand Down Expand Up @@ -43,23 +45,23 @@ const int defaultChromeDebugPort = 10000;
Future<BenchmarkResults> serveWebBenchmark({
required io.Directory benchmarkAppDirectory,
required String entryPoint,
required bool useCanvasKit,
int benchmarkServerPort = defaultBenchmarkServerPort,
int chromeDebugPort = defaultChromeDebugPort,
bool headless = true,
bool treeShakeIcons = true,
String initialPage = defaultInitialPage,
CompilationOptions compilationOptions = const CompilationOptions(),
}) async {
// Reduce logging level. Otherwise, package:webkit_inspection_protocol is way too spammy.
Logger.root.level = Level.INFO;

return BenchmarkServer(
benchmarkAppDirectory: benchmarkAppDirectory,
entryPoint: entryPoint,
useCanvasKit: useCanvasKit,
benchmarkServerPort: benchmarkServerPort,
chromeDebugPort: chromeDebugPort,
headless: headless,
compilationOptions: compilationOptions,
treeShakeIcons: treeShakeIcons,
initialPage: initialPage,
).run();
Expand Down
38 changes: 38 additions & 0 deletions packages/web_benchmarks/lib/src/compilation_options.dart
Original file line number Diff line number Diff line change
@@ -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,
}
22 changes: 18 additions & 4 deletions packages/web_benchmarks/lib/src/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import 'package:shelf_static/shelf_static.dart';
import 'benchmark_result.dart';
import 'browser.dart';
import 'common.dart';
import 'compilation_options.dart';

/// The default port number used by the local benchmark server.
const int defaultBenchmarkServerPort = 9999;
Expand Down Expand Up @@ -50,11 +51,11 @@ class BenchmarkServer {
BenchmarkServer({
required this.benchmarkAppDirectory,
required this.entryPoint,
required this.useCanvasKit,
required this.benchmarkServerPort,
required this.chromeDebugPort,
required this.headless,
required this.treeShakeIcons,
this.compilationOptions = const CompilationOptions(),
this.initialPage = defaultInitialPage,
});

Expand All @@ -72,8 +73,8 @@ class BenchmarkServer {
/// the app.
final String entryPoint;

/// Whether to build the app in CanvasKit mode.
final bool useCanvasKit;
/// The compilation options to use for building the benchmark web app.
final CompilationOptions compilationOptions;

/// The port this benchmark server serves the app on.
final int benchmarkServerPort;
Expand Down Expand Up @@ -109,13 +110,20 @@ class BenchmarkServer {
"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(
<String>[
'flutter',
'build',
'web',
if (compilationOptions.useWasm) ...<String>[
'--wasm',
'--wasm-opt=debug',
'--omit-type-checks',
],
'--web-renderer=${compilationOptions.renderer.name}',
'--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true',
if (useCanvasKit) '--dart-define=FLUTTER_WEB_USE_SKIA=true',
if (!treeShakeIcons) '--no-tree-shake-icons',
'--profile',
'-t',
Expand All @@ -124,6 +132,12 @@ class BenchmarkServer {
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) {
io.stderr.writeln(buildResult.stdout);
io.stderr.writeln(buildResult.stderr);
Expand Down
2 changes: 1 addition & 1 deletion packages/web_benchmarks/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: web_benchmarks
description: A benchmark harness for performance-testing Flutter apps in Chrome.
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
version: 0.1.0+11
version: 1.0.0

environment:
sdk: ">=3.2.0 <4.0.0"
Expand Down
11 changes: 10 additions & 1 deletion packages/web_benchmarks/testing/web_benchmarks_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,28 @@ Future<void> main() async {
initialPage: 'index.html#about',
);
}, 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({
required List<String> benchmarkNames,
required String entryPoint,
String initialPage = defaultInitialPage,
CompilationOptions compilationOptions = const CompilationOptions(),
}) async {
final BenchmarkResults taskResult = await serveWebBenchmark(
benchmarkAppDirectory: Directory('testing/test_app'),
entryPoint: entryPoint,
useCanvasKit: false,
treeShakeIcons: false,
initialPage: initialPage,
compilationOptions: compilationOptions,
);

for (final String benchmarkName in benchmarkNames) {
Expand Down