blob: d611a0ef0c1a818801b5b577c510bec0b5651344 [file] [log] [blame]
// Copyright (c) 2022, 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 'util.dart';
typedef TestFunction<T, U> = List<U> Function(List<T>);
class InputOutputData<T, U> {
final List<T> input;
final List<U> output;
const InputOutputData(this.input, this.output);
}
const Strategy simpleAddStrategy = Strategy('simple-add', '''
Add entries to a list one at a time.''');
const Strategy mapToListStrategy = Strategy('mapToList', '''
Create the list via .map([...]).toList().''');
const Strategy listGenerateGrowableStrategy =
Strategy('list-generate-growable', '''
Create list via List.generate with growable = true.''');
const Strategy listGenerateNotGrowableStrategy =
Strategy('list-generate-not-growable', '''
Create list via List.generate with growable = false.''');
const Strategy listFilledGrowableStrategy = Strategy('list-filled-growable', '''
Create list via List.generate with growable = true.''');
const Strategy listFilledNotGrowableStrategy =
Strategy('list-filled-not-growable', '''
Create list via List.generate with growable = false.''');
const Scenario emptyScenario = Scenario('empty', '''
The input and output is empty.''');
const Scenario oneEntryScenario = Scenario('one', '''
The input is one entry.''');
const Scenario severalEntriesScenario = Scenario('several', '''
The input has several entries.''');
class Input {
final String content;
const Input(this.content);
}
Map<Scenario, InputOutputData<Input, String>> scenarios = {
emptyScenario: const InputOutputData([], []),
oneEntryScenario: const InputOutputData([Input("a")], ["a"]),
severalEntriesScenario: const InputOutputData(
[
Input("a"),
Input("b"),
Input("c"),
Input("d"),
Input("e"),
Input("f"),
],
[
"a",
"b",
"c",
"d",
"e",
"f",
],
),
};
class Test<T, U> {
final int size;
final Map<Strategy, TestFunction<T, U>> strategies;
const Test(this.size, this.strategies);
void _test(Registry registry, SeriesKey key, int runs, int iterations,
List<T> input, List<U> expectedResult, TestFunction<T, U> testFunction) {
for (int run = 0; run < runs; run++) {
Stopwatch sw = new Stopwatch();
for (int i = 0; i < iterations; i++) {
sw.start();
List<U> actualOutput = testFunction(input);
sw.stop();
checkEquals(actualOutput, expectedResult);
}
registry.registerData(key, size, sw.elapsedMicroseconds);
}
}
void checkEquals(List<U> a, List<U> b) {
if (a.length != b.length) throw "length for $a vs $b";
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) throw "index $i for $a vs $b";
}
}
void performTest(
{required Registry registry,
required int runs,
required int iterations,
required Map<Scenario, InputOutputData<T, U>> scenarios}) {
for (MapEntry<Scenario, InputOutputData<T, U>> scenario
in scenarios.entries) {
List<T> scenarioInput = scenario.value.input;
List<U> scenarioExpectedOutput = scenario.value.output;
for (MapEntry<Strategy, TestFunction<T, U>> entry in strategies.entries) {
_test(registry, new SeriesKey(entry.key, scenario.key), runs,
iterations, scenarioInput, scenarioExpectedOutput, entry.value);
}
}
}
}
List<Test<Input, String>> tests = [
// "size" isn't used here...
Test<Input, String>(-1, {
simpleAddStrategy: simplyAdd,
listGenerateGrowableStrategy: listGenerateGrowable,
listGenerateNotGrowableStrategy: listGenerateNotGrowable,
listFilledGrowableStrategy: listFilledGrowable,
listFilledNotGrowableStrategy: listFilledNotGrowable,
mapToListStrategy: mapToList,
}),
];
List<String> simplyAdd(List<Input> input) {
List<String> result = [];
for (int i = 0; i < input.length; i++) {
result.add(input[i].content);
}
return result;
}
List<String> listGenerateGrowable(List<Input> input) {
return List<String>.generate(input.length, (index) => input[index].content,
growable: true);
}
List<String> listGenerateNotGrowable(List<Input> input) {
return List<String>.generate(input.length, (index) => input[index].content,
growable: false);
}
List<String> listFilledGrowable(List<Input> input) {
List<String> result = List<String>.filled(input.length, "", growable: true);
for (int i = 0; i < input.length; i++) {
result[i] = input[i].content;
}
return result;
}
List<String> listFilledNotGrowable(List<Input> input) {
List<String> result = List<String>.filled(input.length, "", growable: false);
for (int i = 0; i < input.length; i++) {
result[i] = input[i].content;
}
return result;
}
List<String> mapToList(List<Input> input) {
return input.map((e) => e.content).toList();
}
void main() {
// Dry run
for (Test test in tests) {
test.performTest(
registry: new Registry(),
runs: 5,
iterations: 10,
scenarios: scenarios);
}
// Actual test
Registry registry = new Registry();
for (Test test in tests) {
test.performTest(
registry: registry, runs: 10, iterations: 100000, scenarios: scenarios);
}
SeriesSet seriesSet = registry.generateSeriesSet();
print('== Raw data ==');
for (Scenario scenario in scenarios.keys) {
print(seriesSet.getFullSpreadByScenario(scenario));
}
print('== Reduced averages ==');
SeriesSet reducedSeriesSet = seriesSet.filter((list) => removeMax(list, 3));
for (Scenario scenario in scenarios.keys) {
print(reducedSeriesSet.getAveragedSpreadByScenario(scenario));
}
}