// 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; sum -= expectedSum; } if (sum != 0) 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; sum -= expectedSum; } if (sum != 0) 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(); } }