mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
![Alexander Aprelev](/assets/img/avatar_default.png)
Change-Id: If097c8e8b8b7327610993327aacfeae25960f2f8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115640 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
187 lines
4.9 KiB
Dart
187 lines
4.9 KiB
Dart
// Copyright (c) 2019, 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 'dart:async';
|
|
import 'dart:isolate';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:benchmark_harness/benchmark_harness.dart'
|
|
show PrintEmitter, ScoreEmitter;
|
|
import 'package:meta/meta.dart';
|
|
|
|
class SendReceiveBytes extends AsyncBenchmarkBase {
|
|
SendReceiveBytes(String name,
|
|
{@required int this.size, @required bool this.useTransferable})
|
|
: super(name);
|
|
|
|
@override
|
|
Future<void> run() async {
|
|
await helper.run();
|
|
}
|
|
|
|
@override
|
|
Future<void> setup() async {
|
|
helper = SendReceiveHelper(size, useTransferable: useTransferable);
|
|
await helper.setup();
|
|
}
|
|
|
|
@override
|
|
Future<void> teardown() async {
|
|
await helper.finalize();
|
|
}
|
|
|
|
final bool useTransferable;
|
|
final int size;
|
|
SendReceiveHelper helper;
|
|
}
|
|
|
|
// Identical to BenchmarkBase from package:benchmark_harness but async.
|
|
abstract class AsyncBenchmarkBase {
|
|
final String name;
|
|
final ScoreEmitter emitter;
|
|
|
|
Future<void> run();
|
|
Future<void> setup();
|
|
Future<void> teardown();
|
|
|
|
const AsyncBenchmarkBase(this.name, {this.emitter = const PrintEmitter()});
|
|
|
|
// Returns the number of microseconds per call.
|
|
Future<double> measureFor(int minimumMillis) async {
|
|
final minimumMicros = minimumMillis * 1000;
|
|
int iter = 0;
|
|
final watch = Stopwatch();
|
|
watch.start();
|
|
int elapsed = 0;
|
|
while (elapsed < minimumMicros) {
|
|
await run();
|
|
elapsed = watch.elapsedMicroseconds;
|
|
iter++;
|
|
}
|
|
return elapsed / iter;
|
|
}
|
|
|
|
// Measures the score for the benchmark and returns it.
|
|
Future<double> measure() async {
|
|
await setup();
|
|
await measureFor(500); // warm-up
|
|
final result = await measureFor(4000); // actual measurement
|
|
await teardown();
|
|
return result;
|
|
}
|
|
|
|
Future<void> report() async {
|
|
emitter.emit(name, await measure());
|
|
}
|
|
}
|
|
|
|
class StartMessage {
|
|
final SendPort sendPort;
|
|
final bool useTransferable;
|
|
final int size;
|
|
|
|
StartMessage(this.sendPort, this.useTransferable, this.size);
|
|
}
|
|
|
|
// Measures how long sending and receiving of [size]-length Uint8List takes.
|
|
class SendReceiveHelper {
|
|
SendReceiveHelper(this.size, {@required bool this.useTransferable});
|
|
|
|
Future<void> setup() async {
|
|
data = new Uint8List(size);
|
|
|
|
port = ReceivePort();
|
|
inbox = StreamIterator<dynamic>(port);
|
|
workerCompleted = Completer<bool>();
|
|
workerExitedPort = ReceivePort()
|
|
..listen((_) => workerCompleted.complete(true));
|
|
worker = await Isolate.spawn(
|
|
isolate, StartMessage(port.sendPort, useTransferable, size),
|
|
onExit: workerExitedPort.sendPort);
|
|
await inbox.moveNext();
|
|
outbox = inbox.current;
|
|
}
|
|
|
|
Future<void> finalize() async {
|
|
outbox.send(null);
|
|
await workerCompleted.future;
|
|
workerExitedPort.close();
|
|
port.close();
|
|
}
|
|
|
|
// Send data to worker, wait for an answer.
|
|
Future<void> run() async {
|
|
outbox.send(packageList(data, useTransferable));
|
|
await inbox.moveNext();
|
|
final received = inbox.current;
|
|
if (useTransferable) {
|
|
final TransferableTypedData transferable = received;
|
|
transferable.materialize();
|
|
}
|
|
}
|
|
|
|
Uint8List data;
|
|
ReceivePort port;
|
|
StreamIterator<dynamic> inbox;
|
|
SendPort outbox;
|
|
Isolate worker;
|
|
Completer<bool> workerCompleted;
|
|
ReceivePort workerExitedPort;
|
|
final int size;
|
|
final bool useTransferable;
|
|
}
|
|
|
|
packageList(Uint8List data, bool useTransferable) =>
|
|
useTransferable ? TransferableTypedData.fromList(<Uint8List>[data]) : data;
|
|
|
|
Future<void> isolate(StartMessage startMessage) async {
|
|
final port = ReceivePort();
|
|
final inbox = StreamIterator<dynamic>(port);
|
|
final data = Uint8List.view(new Uint8List(startMessage.size).buffer);
|
|
|
|
startMessage.sendPort.send(port.sendPort);
|
|
while (true) {
|
|
await inbox.moveNext();
|
|
final received = inbox.current;
|
|
if (received == null) {
|
|
break;
|
|
}
|
|
if (startMessage.useTransferable) {
|
|
final TransferableTypedData transferable = received;
|
|
transferable.materialize();
|
|
}
|
|
startMessage.sendPort.send(packageList(data, startMessage.useTransferable));
|
|
}
|
|
port.close();
|
|
}
|
|
|
|
class SizeName {
|
|
const SizeName(this.size, this.name);
|
|
|
|
final int size;
|
|
final String name;
|
|
}
|
|
|
|
final List<SizeName> sizes = <SizeName>[
|
|
SizeName(1 * 1024, "1KB"),
|
|
SizeName(10 * 1024, "10KB"),
|
|
SizeName(100 * 1024, "100KB"),
|
|
SizeName(1 * 1024 * 1024, "1MB"),
|
|
SizeName(10 * 1024 * 1024, "10MB"),
|
|
SizeName(100 * 1024 * 1024, "100MB")
|
|
];
|
|
|
|
Future<void> main() async {
|
|
for (SizeName sizeName in sizes) {
|
|
await SendReceiveBytes("Isolate.SendReceiveBytes${sizeName.name}",
|
|
size: sizeName.size, useTransferable: false)
|
|
.report();
|
|
await SendReceiveBytes(
|
|
"Isolate.SendReceiveBytesTransferable${sizeName.name}",
|
|
size: sizeName.size,
|
|
useTransferable: true)
|
|
.report();
|
|
}
|
|
}
|