ff87171f6c
Change-Id: Ied900f7d85addabc586823139aa78b879be035ea Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425182 Auto-Submit: Bob Nystrom <rnystrom@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Lasse Nielsen <lrn@google.com>
127 lines
3.6 KiB
Dart
127 lines
3.6 KiB
Dart
// Copyright (c) 2020, 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.
|
|
//
|
|
// Benchmark for UTF-8 decoding
|
|
|
|
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:benchmark_harness/benchmark_harness.dart';
|
|
|
|
import 'datext_latin1_10k.dart';
|
|
import 'entext_ascii_10k.dart';
|
|
import 'netext_3_10k.dart';
|
|
import 'rutext_2_10k.dart';
|
|
import 'sktext_10k.dart';
|
|
import 'zhtext_10k.dart';
|
|
|
|
class Utf8Decode extends BenchmarkBase {
|
|
final String language;
|
|
final String text;
|
|
final int size;
|
|
final bool allowMalformed;
|
|
late List<Uint8List> chunks;
|
|
int totalInputSize = 0;
|
|
int totalOutputSize = 0;
|
|
|
|
static String _makeName(String language, int size, bool allowMalformed) {
|
|
String name = 'Utf8Decode.$language.';
|
|
name += size >= 1000000
|
|
? '${size ~/ 1000000}M'
|
|
: size >= 1000
|
|
? '${size ~/ 1000}k'
|
|
: '$size';
|
|
if (allowMalformed) name += '.malformed';
|
|
return name;
|
|
}
|
|
|
|
Utf8Decode(this.language, this.text, this.size, this.allowMalformed)
|
|
: super(_makeName(language, size, allowMalformed));
|
|
|
|
@override
|
|
void setup() {
|
|
final Uint8List data = utf8.encode(text);
|
|
if (data.length != 10000) {
|
|
throw 'Expected input data of exactly 10000 bytes.';
|
|
}
|
|
if (size < data.length) {
|
|
// Split into chunks.
|
|
chunks = <Uint8List>[];
|
|
int startPos = 0;
|
|
for (int pos = size; pos < data.length; pos += size) {
|
|
int endPos = pos;
|
|
while ((data[endPos] & 0xc0) == 0x80) {
|
|
endPos--;
|
|
}
|
|
chunks.add(Uint8List.fromList(data.sublist(startPos, endPos)));
|
|
startPos = endPos;
|
|
}
|
|
chunks.add(Uint8List.fromList(data.sublist(startPos, data.length)));
|
|
totalInputSize = data.length;
|
|
totalOutputSize = text.length;
|
|
} else if (size > data.length) {
|
|
// Repeat data to the desired length.
|
|
final Uint8List expanded = Uint8List(size);
|
|
for (int i = 0; i < size; i++) {
|
|
expanded[i] = data[i % data.length];
|
|
}
|
|
chunks = <Uint8List>[expanded];
|
|
totalInputSize = size;
|
|
totalOutputSize = text.length * size ~/ data.length;
|
|
} else {
|
|
// Use data as is.
|
|
chunks = <Uint8List>[data];
|
|
totalInputSize = data.length;
|
|
totalOutputSize = text.length;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void run() {
|
|
int lengthSum = 0;
|
|
for (int i = 0; i < chunks.length; i++) {
|
|
final String s = utf8.decode(chunks[i], allowMalformed: allowMalformed);
|
|
lengthSum += s.length;
|
|
}
|
|
if (lengthSum != totalOutputSize) {
|
|
throw 'Output length doesn\'t match expected.';
|
|
}
|
|
}
|
|
|
|
@override
|
|
void exercise() {
|
|
// Only a single run per measurement.
|
|
run();
|
|
}
|
|
|
|
@override
|
|
double measure() {
|
|
// Report time per input byte.
|
|
return super.measure() / totalInputSize;
|
|
}
|
|
|
|
@override
|
|
void report() {
|
|
// Report time in nanoseconds.
|
|
final double score = measure() * 1000.0;
|
|
print('$name(RunTime): $score ns.');
|
|
}
|
|
}
|
|
|
|
void main(List<String> args) {
|
|
const texts = {'en': en, 'da': da, 'sk': sk, 'ru': ru, 'ne': ne, 'zh': zh};
|
|
final bool testMalformed = args.isNotEmpty && args.first == 'malformed';
|
|
final benchmarks = [
|
|
// Only benchmark with allowMalformed: false unless specified otherwise.
|
|
for (bool allowMalformed in [false, if (testMalformed) true])
|
|
for (int size in [10, 10000, 10000000])
|
|
for (String language in texts.keys)
|
|
() => Utf8Decode(language, texts[language]!, size, allowMalformed),
|
|
];
|
|
|
|
for (var bm in benchmarks) {
|
|
bm().report();
|
|
}
|
|
}
|