// 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'; class SendReceiveBytes extends AsyncBenchmarkBase { SendReceiveBytes( String name, { required this.size, required this.useTransferable, }) : super(name); @override Future run() async { await helper.run(); } @override Future setup() async { helper = SendReceiveHelper(size, useTransferable: useTransferable); await helper.setup(); } @override Future teardown() async { await helper.finalize(); } final bool useTransferable; final int size; late SendReceiveHelper helper; } 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 this.useTransferable}); Future setup() async { data = Uint8List(size); port = ReceivePort(); inbox = StreamIterator(port); workerCompleted = Completer(); 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 finalize() async { outbox.send(null); await workerCompleted.future; workerExitedPort.close(); port.close(); } // Send data to worker, wait for an answer. Future run() async { outbox.send(packageList(data, useTransferable)); await inbox.moveNext(); final received = inbox.current; if (useTransferable) { final TransferableTypedData transferable = received; transferable.materialize(); } } late Uint8List data; late ReceivePort port; late StreamIterator inbox; late SendPort outbox; late Isolate worker; late Completer workerCompleted; late ReceivePort workerExitedPort; final int size; final bool useTransferable; } Object packageList(Uint8List data, bool useTransferable) => useTransferable ? TransferableTypedData.fromList([data]) : data; Future isolate(StartMessage startMessage) async { final port = ReceivePort(); final inbox = StreamIterator(port); final data = Uint8List.view(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; } const List sizes = [ 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 main() async { for (final 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(); } }