5492cfd1bc
This ensures that `_Enum.index` is always available for switch strength reduction optimizations. Most real programs use the index of at least one `enum`, so the field is not usually elided. This change makes small tests and benchmarks behave more like real programs where these optimizations happen. Bug: #51657 CoreLibraryReviewExempt: dart2js specific annotation Change-Id: If98e483d7cce265e823fd574565089e328215cca Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446481 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
158 lines
4.0 KiB
Dart
158 lines
4.0 KiB
Dart
// Copyright (c) 2023, 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.
|
|
|
|
/// This benchmark compares a large switch statement on various kinds of
|
|
/// values. The switch statement is part of a finite-state-machine (FSM)
|
|
/// recognizer.
|
|
///
|
|
/// There are four copies of the same code, differing only by importing
|
|
/// different declarations of the type `State` which makes the same constant
|
|
/// names available using different types.
|
|
///
|
|
/// The switch dispatch on the following types is benchmarked:
|
|
///
|
|
/// - a compact range of `int` values,
|
|
/// - an enum,
|
|
/// - a class that is a bit like an `enum` but not declared as an enum,
|
|
/// - strings.
|
|
///
|
|
/// The actual state-machine is somewhat aritificial. It recognizes a character
|
|
/// string of '0' and '1' character 'bits' that encode a valid UTF-8 string. The
|
|
/// state machine has 48 states and minimal logic in most states, so that as
|
|
/// much time as possible is executing the switch dispatch.
|
|
///
|
|
/// The data is passed to the recogizer as a Uint8List to minimize the time to
|
|
/// access the bytes of the ASCII '0' / '1' character input sequence.
|
|
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:benchmark_harness/benchmark_harness.dart';
|
|
import 'package:expect/expect.dart';
|
|
|
|
import 'match_class.dart' as match_class;
|
|
import 'match_enum.dart' as match_enum;
|
|
import 'match_int.dart' as match_int;
|
|
import 'match_string.dart' as match_string;
|
|
|
|
class Benchmark extends BenchmarkBase {
|
|
final bool Function(Uint8List) match;
|
|
|
|
Benchmark(String kind, this.match) : super('SwitchFSM.$kind');
|
|
|
|
void validation() {
|
|
void check(String s, bool expected) {
|
|
Expect.equals(expected, match(convert(s)), '"$s"');
|
|
}
|
|
|
|
check('', true);
|
|
check('0', false);
|
|
check('00', false);
|
|
check('000', false);
|
|
check('0000', false);
|
|
check('00000', false);
|
|
check('000000', false);
|
|
check('0000000', false);
|
|
check('00000000', true);
|
|
check('01010101', true);
|
|
check('10000000', false);
|
|
check('001010101', false);
|
|
check(
|
|
'11000000'
|
|
'00000000',
|
|
false,
|
|
);
|
|
check(
|
|
'11000000'
|
|
'10111111',
|
|
true,
|
|
);
|
|
check(
|
|
'11000000'
|
|
'11111111',
|
|
false,
|
|
);
|
|
check(
|
|
'11100000'
|
|
'00000000'
|
|
'00000000',
|
|
false,
|
|
);
|
|
check(
|
|
'11100000'
|
|
'10000000'
|
|
'00000000',
|
|
false,
|
|
);
|
|
check(
|
|
'11100000'
|
|
'10111111'
|
|
'10111111',
|
|
true,
|
|
);
|
|
check(
|
|
'11110111'
|
|
'10111111'
|
|
'10111111'
|
|
'01111111',
|
|
false,
|
|
);
|
|
check(
|
|
'11110111'
|
|
'10111111'
|
|
'10111111'
|
|
'10111111',
|
|
true,
|
|
);
|
|
Expect.equals(testInputLength, testInput.length);
|
|
}
|
|
|
|
static const testInputLength = 1000;
|
|
static final Uint8List testInput = convert(makeTestInput(testInputLength));
|
|
|
|
static String makeTestInput(int length) {
|
|
// The test input uses most states of the FSM. It is repeated and padded to
|
|
// make the length 1000.
|
|
final testPattern =
|
|
''
|
|
'11110111101111111011111110111111'
|
|
'111011111011111110111111'
|
|
'1101111110111111';
|
|
final paddingPattern = '00000000';
|
|
final repeats = testPattern * (length ~/ testPattern.length);
|
|
final padding =
|
|
paddingPattern * ((length - repeats.length) ~/ paddingPattern.length);
|
|
return repeats + padding;
|
|
}
|
|
|
|
static Uint8List convert(String s) => Uint8List.fromList(s.codeUnits);
|
|
|
|
@override
|
|
void run() {
|
|
Expect.equals(true, match(testInput));
|
|
}
|
|
}
|
|
|
|
enum SomeEnum { element }
|
|
|
|
void main() {
|
|
final benchmarks = [
|
|
Benchmark('enum', match_enum.match),
|
|
Benchmark('int', match_int.match),
|
|
Benchmark('class', match_class.match),
|
|
Benchmark('string', match_string.match),
|
|
];
|
|
|
|
for (final benchmark in benchmarks) {
|
|
benchmark.validation();
|
|
}
|
|
|
|
for (final benchmark in benchmarks) {
|
|
benchmark.warmup();
|
|
}
|
|
|
|
for (final benchmark in benchmarks) {
|
|
benchmark.report();
|
|
}
|
|
}
|