dart-sdk/benchmarks/TearOff/dart/TearOff.dart
Martin Kustermann af1b5b8044 [dart2wasm] Switch binaryen optimization levels from -O3 to -Os
We want dart2wasm be comparable to dart2js / dart2aot, the ladder two
are much more conservative with inlining compared to current dart2wasm.

The -O3 is described in the binaryen sources as agressive for
performance and therefore willing to compromise code size.

The -Os is more nuanced: It will perform many optimizations that are
done in -O3 (and e.g. not in -O2) but it will make inlining less
agressive.

This reduces flute compile-time by 10% and code size by 10%
This benchmark results are mixed (some things get faster, some things
slower). Naturally there'll be specialized micro benchmarks that
get hit hard by this.

Where performance matters we should rather make dart2wasm use better
inlining heuristics and annotate code with
`@pragma('wasm:prefer-inline')`

Change-Id: Idf7e75e4e385629c9cec66359efe0afe50db3e72
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352523
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
2024-02-14 13:45:13 +00:00

205 lines
4.5 KiB
Dart

// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:benchmark_harness/benchmark_harness.dart';
// Micro-benchmark for taking tear-off of instance method multiple
// times and in a loop.
class BenchTearOffInlined extends BenchmarkBase {
BenchTearOffInlined() : super('TearOff.Inlined');
int sum = 0;
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
@pragma('dart2js:prefer-inline')
void foo(int arg) {
sum += arg;
}
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
@pragma('dart2js:prefer-inline')
void callIt(void Function(int) func, int arg) {
func(arg);
}
@override
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void run() {
sum = 0;
callIt(foo, 1);
callIt(foo, 2);
callIt(foo, 3);
callIt(foo, 4);
callIt(foo, 5);
for (int i = 11; i < 20; ++i) {
callIt(foo, i);
}
callIt(foo, 6);
callIt(foo, 7);
callIt(foo, 8);
callIt(foo, 9);
callIt(foo, 10);
const int expectedSum = 20 * (20 - 1) ~/ 2;
if (sum != expectedSum) throw 'Bad result: $sum';
}
}
class BenchTearOffInlinedInTry extends BenchmarkBase {
BenchTearOffInlinedInTry() : super('TearOff.Inlined.InTry');
int sum = 0;
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
@pragma('dart2js:prefer-inline')
void foo(int arg) {
sum += arg;
}
@pragma('vm:prefer-inline')
@pragma('wasm:prefer-inline')
@pragma('dart2js:prefer-inline')
void callIt(void Function(int) func, int arg) {
func(arg);
}
@override
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void run() {
sum = 0;
try {
callIt(foo, 1);
callIt(foo, 2);
callIt(foo, 3);
callIt(foo, 4);
callIt(foo, 5);
for (int i = 11; i < 20; ++i) {
callIt(foo, i);
}
callIt(foo, 6);
callIt(foo, 7);
callIt(foo, 8);
callIt(foo, 9);
callIt(foo, 10);
} finally {
const int expectedSum = 20 * (20 - 1) ~/ 2;
if (sum != expectedSum) throw 'Bad result: $sum';
}
}
}
class BenchTearOffNotInlined extends BenchmarkBase {
BenchTearOffNotInlined() : super('TearOff.NotInlined');
int sum = 0;
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void foo(int arg) {
sum += arg;
}
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void callIt(void Function(int) func, int arg) {
func(arg);
}
@override
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void run() {
sum = 0;
callIt(foo, 1);
callIt(foo, 2);
callIt(foo, 3);
callIt(foo, 4);
callIt(foo, 5);
for (int i = 11; i < 20; ++i) {
callIt(foo, i);
}
callIt(foo, 6);
callIt(foo, 7);
callIt(foo, 8);
callIt(foo, 9);
callIt(foo, 10);
const int expectedSum = 20 * (20 - 1) ~/ 2;
if (sum != expectedSum) throw 'Bad result: $sum';
}
}
class BenchTearOffNotInlinedInTry extends BenchmarkBase {
BenchTearOffNotInlinedInTry() : super('TearOff.NotInlined.InTry');
int sum = 0;
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void foo(int arg) {
sum += arg;
}
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void callIt(void Function(int) func, int arg) {
func(arg);
}
@override
@pragma('vm:never-inline')
@pragma('wasm:never-inline')
@pragma('dart2js:never-inline')
void run() {
sum = 0;
try {
callIt(foo, 1);
callIt(foo, 2);
callIt(foo, 3);
callIt(foo, 4);
callIt(foo, 5);
for (int i = 11; i < 20; ++i) {
callIt(foo, i);
}
callIt(foo, 6);
callIt(foo, 7);
callIt(foo, 8);
callIt(foo, 9);
callIt(foo, 10);
} finally {
const int expectedSum = 20 * (20 - 1) ~/ 2;
if (sum != expectedSum) throw 'Bad result: $sum';
}
}
}
void main() {
final benchmarks = [
BenchTearOffInlined(),
BenchTearOffInlinedInTry(),
BenchTearOffNotInlined(),
BenchTearOffNotInlinedInTry(),
];
for (final benchmark in benchmarks) {
benchmark.warmup();
}
for (final benchmark in benchmarks) {
benchmark.report();
}
}