|  | // 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<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; | 
|  | 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<void> setup() async { | 
|  | data = 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(); | 
|  | } | 
|  | } | 
|  |  | 
|  | late Uint8List data; | 
|  | late ReceivePort port; | 
|  | late StreamIterator<dynamic> inbox; | 
|  | late SendPort outbox; | 
|  | late Isolate worker; | 
|  | late Completer<bool> workerCompleted; | 
|  | late ReceivePort workerExitedPort; | 
|  | final int size; | 
|  | final bool useTransferable; | 
|  | } | 
|  |  | 
|  | Object 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(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<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 (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(); | 
|  | } | 
|  | } |