mirror of
https://github.com/dart-lang/sdk
synced 2024-09-30 03:58:31 +00:00
[benchmarks] Add benchmark to measure dart2js string pool cost
Change-Id: I15099af08526444c2e01da46b9939f2435547c90 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201981 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
2c22f0db29
commit
09b75a3d53
137
benchmarks/StringPool/dart/StringPool.dart
Normal file
137
benchmarks/StringPool/dart/StringPool.dart
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) 2021, 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';
|
||||
|
||||
import 'version1a.dart';
|
||||
import 'version1b.dart';
|
||||
import 'version2.dart';
|
||||
|
||||
// ## Organization
|
||||
//
|
||||
// version1a.dart is the same version1b.dart except for renaming of functions.
|
||||
//
|
||||
// Both contain the same ~1500 distinct large string literals. An application
|
||||
// will be smaller if compiled with sharing of the string constant values
|
||||
// between the corresponding functions in version1a.dart and version1b.dart.
|
||||
//
|
||||
// version2.dart has the same general pattern as version1{a,b}.dart, but with
|
||||
// unique string literals. As these literals have only one occurrence in the
|
||||
// program, they will not be pooled for access from multiple functions.
|
||||
//
|
||||
// StringPool100.dart is a separate benchmark program that, after tree-shaking,
|
||||
// has a 'small' string pool of ~100 strings rather than the ~1500 strings in
|
||||
// this file. This has to be a separate program since the string pool generated
|
||||
// by dart2js is for the whole-program (or whole deferred fragment).
|
||||
//
|
||||
// ## Interpretation
|
||||
//
|
||||
// Displayed results are normalized by the number of String literals accessed.
|
||||
//
|
||||
// StringPool.N.pooled uses N strings from the string pool.
|
||||
// StringPool.N.unpooled uses N strings without string pooling.
|
||||
//
|
||||
// Comparing StringPool.1500.{pooled,unpooled} gives an indication of the cost
|
||||
// of a large string pool.
|
||||
//
|
||||
// Comparing StringPool.100.{pooled,unpooled} gives an indication of the cost
|
||||
// of a small string pool.
|
||||
//
|
||||
// Comparing StringPool.{100,1500}.pooled gives an indication of the cost
|
||||
// of a large string pool compared to a small string pool.
|
||||
|
||||
const kStringLiteralsPerRun = 100000;
|
||||
|
||||
typedef Gen = List<String> Function(String);
|
||||
|
||||
abstract class StringPoolBase extends BenchmarkBase {
|
||||
StringPoolBase(String name) : super('StringPool.$name');
|
||||
|
||||
// A list of functions that generate a list of strings.
|
||||
List<Gen> get functions;
|
||||
|
||||
// The input list of generators is padded to a fixed length with one of the
|
||||
// generators.
|
||||
List<Gen> get _functions => __functions ?? complete(List.of(functions), 50);
|
||||
List<Gen>? __functions;
|
||||
|
||||
List<Gen> complete(List<Gen> list, int targetLength) {
|
||||
while (list.length != targetLength) {
|
||||
// The List is stretched using the same function so that one function is
|
||||
// similarly hot and potentially JIT-ed in the `.1500.` and `.100.`
|
||||
// benchmarks.
|
||||
list.add(list.first);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@override
|
||||
void run() {
|
||||
int count = 0;
|
||||
LOOP:
|
||||
while (true) {
|
||||
for (final f in _functions) {
|
||||
final result = f(name);
|
||||
sink = result;
|
||||
count += result.length - 1; // First string is parameter
|
||||
if (count >= kStringLiteralsPerRun) break LOOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void exercise() {
|
||||
// Run once instead of default 10 times since we do a lot of work in `run`.
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
class V1 extends StringPoolBase {
|
||||
V1() : super('1500.pooled');
|
||||
|
||||
@override
|
||||
late final functions = version1ax1500();
|
||||
}
|
||||
|
||||
class V1Copy extends StringPoolBase {
|
||||
V1Copy() : super('1500.pooled.copy');
|
||||
|
||||
@override
|
||||
late final functions = version1bx1500();
|
||||
}
|
||||
|
||||
class V2 extends StringPoolBase {
|
||||
V2() : super('1500.unpooled');
|
||||
|
||||
@override
|
||||
late final functions = version2x1500();
|
||||
}
|
||||
|
||||
dynamic sink;
|
||||
|
||||
void main() {
|
||||
// Compare results of V1 and V1Copy to ensure both classes and their reachable
|
||||
// functions are in the program.
|
||||
V1()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink1a = sink;
|
||||
V1Copy()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink1b = sink;
|
||||
if (sink1a.length != sink1b.length) throw StateError('Not same length');
|
||||
|
||||
V2()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink2 = sink;
|
||||
if (sink1a.length != sink2.length) throw StateError('Not same length');
|
||||
|
||||
V1().report();
|
||||
V2().report();
|
||||
}
|
56
benchmarks/StringPool/dart/StringPool100.dart
Normal file
56
benchmarks/StringPool/dart/StringPool100.dart
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2021, 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.
|
||||
|
||||
// See `StringPool.dart` for comments.
|
||||
|
||||
import 'StringPool.dart' show StringPoolBase, sink;
|
||||
import 'version1a.dart';
|
||||
import 'version1b.dart';
|
||||
import 'version2.dart';
|
||||
|
||||
class V1 extends StringPoolBase {
|
||||
V1() : super('100.pooled');
|
||||
|
||||
@override
|
||||
late final functions = version1ax100();
|
||||
}
|
||||
|
||||
class V1Copy extends StringPoolBase {
|
||||
V1Copy() : super('100.pooled.copy');
|
||||
|
||||
@override
|
||||
late final functions = version1bx100();
|
||||
}
|
||||
|
||||
class V2 extends StringPoolBase {
|
||||
V2() : super('100.unpooled');
|
||||
|
||||
@override
|
||||
late final functions = version2x100();
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Compare results of V1 and V1Copy to ensure both are in the program.
|
||||
V1()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink1a = sink;
|
||||
V1Copy()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink1b = sink;
|
||||
if (sink1a.length != sink1b.length) throw StateError('Not same length');
|
||||
|
||||
V2()
|
||||
..setup()
|
||||
..run()
|
||||
..run();
|
||||
final sink2 = sink;
|
||||
if (sink1a.length != sink2.length) throw StateError('Not same length');
|
||||
|
||||
V1().report();
|
||||
V2().report();
|
||||
}
|
1619
benchmarks/StringPool/dart/version1a.dart
Normal file
1619
benchmarks/StringPool/dart/version1a.dart
Normal file
File diff suppressed because it is too large
Load diff
1619
benchmarks/StringPool/dart/version1b.dart
Normal file
1619
benchmarks/StringPool/dart/version1b.dart
Normal file
File diff suppressed because it is too large
Load diff
1617
benchmarks/StringPool/dart/version2.dart
Normal file
1617
benchmarks/StringPool/dart/version2.dart
Normal file
File diff suppressed because it is too large
Load diff
11
benchmarks/StringPool/dart2/StringPool.dart
Normal file
11
benchmarks/StringPool/dart2/StringPool.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2021, 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.
|
||||
|
||||
// @dart=2.7
|
||||
|
||||
import '../dart/StringPool.dart' as primary;
|
||||
|
||||
void main() {
|
||||
primary.main();
|
||||
}
|
11
benchmarks/StringPool/dart2/StringPool100.dart
Normal file
11
benchmarks/StringPool/dart2/StringPool100.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) 2021, 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.
|
||||
|
||||
// @dart=2.7
|
||||
|
||||
import '../dart/StringPool100.dart' as primary;
|
||||
|
||||
void main() {
|
||||
primary.main();
|
||||
}
|
Loading…
Reference in a new issue