mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:36:59 +00:00
80621fed03
Change-Id: I44047a9d7907d166a6360397d0047ce9b835e5c7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166854 Auto-Submit: Jonas Termansen <sortie@google.com> Reviewed-by: Leaf Petersen <leafp@google.com> Commit-Queue: Leaf Petersen <leafp@google.com>
170 lines
5 KiB
Dart
170 lines
5 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.
|
|
|
|
// @dart=2.9
|
|
|
|
import 'dart:async';
|
|
import 'dart:isolate';
|
|
import 'dart:math';
|
|
|
|
import 'package:meta/meta.dart';
|
|
|
|
import 'package:compiler/src/dart2js.dart' as dart2js_main;
|
|
|
|
class SpawnLatency {
|
|
SpawnLatency(this.name);
|
|
|
|
Future<ResultMessageLatency> run() async {
|
|
final completerResult = Completer();
|
|
final receivePort = ReceivePort()..listen(completerResult.complete);
|
|
final isolateExitedCompleter = Completer<DateTime>();
|
|
final onExitReceivePort = ReceivePort()
|
|
..listen((_) {
|
|
isolateExitedCompleter.complete(DateTime.now());
|
|
});
|
|
final beforeSpawn = DateTime.now();
|
|
await Isolate.spawn(
|
|
isolateCompiler, StartMessageLatency(receivePort.sendPort, beforeSpawn),
|
|
onExit: onExitReceivePort.sendPort,
|
|
onError: onExitReceivePort.sendPort);
|
|
final afterSpawn = DateTime.now();
|
|
|
|
final ResultMessageLatency result = await completerResult.future;
|
|
receivePort.close();
|
|
final DateTime isolateExited = await isolateExitedCompleter.future;
|
|
result.timeToExitUs = isolateExited.difference(beforeSpawn).inMicroseconds;
|
|
result.timeToIsolateSpawnUs =
|
|
afterSpawn.difference(beforeSpawn).inMicroseconds;
|
|
onExitReceivePort.close();
|
|
|
|
return result;
|
|
}
|
|
|
|
Future<AggregatedResultMessageLatency> measureFor(int minimumMillis) async {
|
|
final minimumMicros = minimumMillis * 1000;
|
|
final watch = Stopwatch()..start();
|
|
final Metric toAfterIsolateSpawnUs = LatencyMetric('${name}ToAfterSpawn');
|
|
final Metric toStartRunningCodeUs = LatencyMetric('${name}ToStartRunning');
|
|
final Metric toFinishRunningCodeUs =
|
|
LatencyMetric('${name}ToFinishRunning');
|
|
final Metric toExitUs = LatencyMetric('${name}ToExit');
|
|
while (watch.elapsedMicroseconds < minimumMicros) {
|
|
final result = await run();
|
|
toAfterIsolateSpawnUs.add(result.timeToIsolateSpawnUs);
|
|
toStartRunningCodeUs.add(result.timeToStartRunningCodeUs);
|
|
toFinishRunningCodeUs.add(result.timeToFinishRunningCodeUs);
|
|
toExitUs.add(result.timeToExitUs);
|
|
}
|
|
return AggregatedResultMessageLatency(toAfterIsolateSpawnUs,
|
|
toStartRunningCodeUs, toFinishRunningCodeUs, toExitUs);
|
|
}
|
|
|
|
Future<AggregatedResultMessageLatency> measure() async {
|
|
await measureFor(500); // warm-up
|
|
return measureFor(4000); // actual measurement
|
|
}
|
|
|
|
Future<void> report() async {
|
|
final result = await measure();
|
|
print(result);
|
|
}
|
|
|
|
final String name;
|
|
RawReceivePort receivePort;
|
|
}
|
|
|
|
class Metric {
|
|
Metric({@required this.prefix, @required this.suffix});
|
|
|
|
void add(int value) {
|
|
if (value > max) {
|
|
max = value;
|
|
}
|
|
sum += value;
|
|
sumOfSquares += value * value;
|
|
count++;
|
|
}
|
|
|
|
double _average() => sum / count;
|
|
double _rms() => sqrt(sumOfSquares / count);
|
|
|
|
@override
|
|
String toString() => '$prefix): ${_average()}$suffix\n'
|
|
'${prefix}Max): $max$suffix\n'
|
|
'${prefix}RMS): ${_rms()}$suffix';
|
|
|
|
final String prefix;
|
|
final String suffix;
|
|
int max = 0;
|
|
double sum = 0;
|
|
double sumOfSquares = 0;
|
|
int count = 0;
|
|
}
|
|
|
|
class LatencyMetric extends Metric {
|
|
LatencyMetric(String name) : super(prefix: '$name(Latency', suffix: ' us.');
|
|
}
|
|
|
|
class StartMessageLatency {
|
|
StartMessageLatency(this.sendPort, this.spawned);
|
|
|
|
final SendPort sendPort;
|
|
final DateTime spawned;
|
|
}
|
|
|
|
class ResultMessageLatency {
|
|
ResultMessageLatency(
|
|
{this.timeToStartRunningCodeUs,
|
|
this.timeToFinishRunningCodeUs,
|
|
this.deltaHeap});
|
|
|
|
final int timeToStartRunningCodeUs;
|
|
final int timeToFinishRunningCodeUs;
|
|
final int deltaHeap;
|
|
|
|
int timeToIsolateSpawnUs;
|
|
int timeToExitUs;
|
|
}
|
|
|
|
class AggregatedResultMessageLatency {
|
|
AggregatedResultMessageLatency(
|
|
this.toAfterIsolateSpawnUs,
|
|
this.toStartRunningCodeUs,
|
|
this.toFinishRunningCodeUs,
|
|
this.toExitUs,
|
|
);
|
|
|
|
@override
|
|
String toString() => '''$toAfterIsolateSpawnUs
|
|
$toStartRunningCodeUs
|
|
$toFinishRunningCodeUs
|
|
$toExitUs''';
|
|
|
|
final Metric toAfterIsolateSpawnUs;
|
|
final Metric toStartRunningCodeUs;
|
|
final Metric toFinishRunningCodeUs;
|
|
final Metric toExitUs;
|
|
}
|
|
|
|
Future<void> isolateCompiler(StartMessageLatency start) async {
|
|
final timeRunningCodeUs = DateTime.now();
|
|
await runZoned(
|
|
() => dart2js_main.internalMain(<String>[
|
|
'benchmarks/IsolateSpawn/dart/helloworld.dart',
|
|
'--libraries-spec=sdk/lib/libraries.json'
|
|
]),
|
|
zoneSpecification: ZoneSpecification(
|
|
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {}));
|
|
final timeFinishRunningCodeUs = DateTime.now();
|
|
start.sendPort.send(ResultMessageLatency(
|
|
timeToStartRunningCodeUs:
|
|
timeRunningCodeUs.difference(start.spawned).inMicroseconds,
|
|
timeToFinishRunningCodeUs:
|
|
timeFinishRunningCodeUs.difference(start.spawned).inMicroseconds));
|
|
}
|
|
|
|
Future<void> main() async {
|
|
await SpawnLatency('IsolateSpawn.Dart2JS').report();
|
|
}
|