// 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. // @dart=2.9 import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; import 'dart:typed_data'; import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase; import 'package:meta/meta.dart'; import 'runtime/tests/vm/dart/export_sendAndExit_helper.dart' show sendAndExit; class JsonDecodingBenchmark { JsonDecodingBenchmark(this.name, {@required this.sample, @required this.numTasks, @required this.useSendAndExit}); Future report() async { final stopwatch = Stopwatch()..start(); // Benchmark harness counts 10 iterations as one. for (int i = 0; i < 10; i++) { final decodedFutures = []; for (int i = 0; i < numTasks; i++) { decodedFutures.add(decodeJson(useSendAndExit, sample)); } await Future.wait(decodedFutures); } print('$name(RunTime): ${stopwatch.elapsedMicroseconds} us.'); } final String name; final Uint8List sample; final int numTasks; final bool useSendAndExit; } Uint8List createSampleJson(final size) { final list = List.generate(size, (i) => i); final map = {}; for (int i = 0; i < size; i++) { map['$i'] = list; } return utf8.encode(json.encode(map)); } class JsonDecodeRequest { final bool useSendAndExit; final SendPort sendPort; final Uint8List encodedJson; const JsonDecodeRequest(this.useSendAndExit, this.sendPort, this.encodedJson); } Future decodeJson(bool useSendAndExit, Uint8List encodedJson) async { final port = ReceivePort(); final inbox = StreamIterator(port); final completer = Completer(); final workerExitedPort = RawReceivePort((v) { completer.complete(true); }); final workerErroredPort = RawReceivePort((v) { stderr.writeln('worker errored out $v'); completer.completeError(true); }); await Isolate.spawn(jsonDecodingIsolate, JsonDecodeRequest(useSendAndExit, port.sendPort, encodedJson), onError: workerErroredPort.sendPort, onExit: workerExitedPort.sendPort); await completer.future; workerExitedPort.close(); workerErroredPort.close(); await inbox.moveNext(); final decodedJson = inbox.current; port.close(); return decodedJson; } Future jsonDecodingIsolate(JsonDecodeRequest request) async { final result = json.decode(utf8.decode(request.encodedJson)); if (request.useSendAndExit) { sendAndExit(request.sendPort, result); } else { request.sendPort.send(result); } } class SyncJsonDecodingBenchmark extends BenchmarkBase { SyncJsonDecodingBenchmark(String name, {@required this.sample, @required this.iterations}) : super(name); @override void run() { int l = 0; for (int i = 0; i < iterations; i++) { final Map map = json.decode(utf8.decode(sample)); l += map.length; } assert(l > 0); } final Uint8List sample; final int iterations; } class BenchmarkConfig { BenchmarkConfig(this.suffix, this.sample); final String suffix; final Uint8List sample; } Future main() async { final jsonString = File('benchmarks/IsolateJson/dart2/sample.json').readAsStringSync(); final json250KB = utf8.encode(jsonString); // 294356 bytes final decoded = json.decode(utf8.decode(json250KB)); final decoded1MB = { '1': decoded['1'], '2': decoded['1'], '3': decoded['1'], '4': decoded['1'], }; final json1MB = utf8.encode(json.encode(decoded1MB)); // 1177397 bytes decoded['1'] = (decoded['1'] as List).sublist(0, 200); final json100KB = utf8.encode(json.encode(decoded)); // 104685 bytes decoded['1'] = (decoded['1'] as List).sublist(0, 100); final json50KB = utf8.encode(json.encode(decoded)); // 51760 bytes final configs = [ BenchmarkConfig('50KB', json50KB), BenchmarkConfig('100KB', json100KB), BenchmarkConfig('250KB', json250KB), BenchmarkConfig('1MB', json1MB), ]; for (final config in configs) { for (final iterations in [1, 4]) { await JsonDecodingBenchmark( 'IsolateJson.Decode${config.suffix}x$iterations', useSendAndExit: false, sample: config.sample, numTasks: iterations) .report(); await JsonDecodingBenchmark( 'IsolateJson.SendAndExit_Decode${config.suffix}x$iterations', useSendAndExit: true, sample: config.sample, numTasks: iterations) .report(); SyncJsonDecodingBenchmark( 'IsolateJson.SyncDecode${config.suffix}x$iterations', sample: config.sample, iterations: iterations) .report(); } } }