blob: 2f5155a2556553e632f5c3b377287fc1bba9685d [file] [log] [blame]
// 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.
// VMOptions=--enable-isolate-groups
// VMOptions=--no-enable-isolate-groups
// Test that validates that transferables are faster than regular typed data.
import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import "package:expect/expect.dart";
const int toIsolateSize = 100 * 1024 * 1024;
const int fromIsolateSize = 100 * 1024 * 1024;
const int nIterations = 5;
int iteration = -1;
bool keepTimerRunning = false;
main() async {
keepTimerRunning = true;
print('--- standard');
iteration = nIterations;
final stopwatch = new Stopwatch()..start();
await runBatch(useTransferable: false);
final standard = stopwatch.elapsedMilliseconds;
print('--- transferable');
iteration = nIterations;
stopwatch.reset();
await runBatch(useTransferable: true);
final transferable = stopwatch.elapsedMilliseconds;
print(
'standard($standard ms)/transferable($transferable ms): ${standard / transferable}x');
keepTimerRunning = false;
}
packageList(Uint8List data, bool useTransferable) {
return useTransferable
? TransferableTypedData.fromList(<Uint8List>[data])
: data;
}
class StartMessage {
final SendPort sendPort;
final bool useTransferable;
StartMessage(this.sendPort, this.useTransferable);
}
runBatch({required bool useTransferable}) async {
Timer.run(idleTimer);
final port = ReceivePort();
final inbox = StreamIterator<dynamic>(port);
final worker = await Isolate.spawn(
isolateMain, StartMessage(port.sendPort, useTransferable),
paused: true);
final workerCompleted = Completer<bool>();
final workerExitedPort = ReceivePort()
..listen((_) => workerCompleted.complete(true));
worker.addOnExitListener(workerExitedPort.sendPort);
worker.resume(worker.pauseCapability!);
await inbox.moveNext();
final outbox = inbox.current;
final workWatch = new Stopwatch();
final data = new Uint8List(toIsolateSize);
while (iteration-- > 0) {
final packagedData = packageList(data, useTransferable);
workWatch.start();
outbox.send(packagedData);
await inbox.moveNext();
final received = inbox.current;
final receivedData = received is TransferableTypedData
? received.materialize().asUint8List()
: received;
int time = workWatch.elapsedMilliseconds;
print('${time}ms for round-trip');
workWatch.reset();
Expect.equals(data.length, receivedData.length);
}
outbox.send(null);
await workerCompleted.future;
workerExitedPort.close();
port.close();
}
Future<Null> isolateMain(StartMessage startMessage) async {
final port = new ReceivePort();
final inbox = new StreamIterator<dynamic>(port);
startMessage.sendPort.send(port.sendPort);
final data = Uint8List.view(new Uint8List(fromIsolateSize).buffer);
while (true) {
await inbox.moveNext();
final received = inbox.current;
if (received == null) {
break;
}
final receivedData =
received is TransferableTypedData ? received.materialize() : received;
final packagedData = packageList(data, startMessage.useTransferable);
startMessage.sendPort.send(packagedData);
}
port.close();
}
final Stopwatch idleWatch = new Stopwatch();
void idleTimer() {
idleWatch.stop();
final time = idleWatch.elapsedMilliseconds;
if (time > 5) print('${time}ms since last checkin');
idleWatch.reset();
idleWatch.start();
if (keepTimerRunning) {
Timer.run(idleTimer);
}
}