[vm/benchmark] Add IsolateSpawnMemory.Dart2JSDeltaRss benchmarks.

These new benchmarks better measure rss delta associated with spawning new dart2js isolate.

Also this moves IsolateSpawn heap measurement benchmarks into this group as well because
they are effectively new benchmarks.

Change-Id: Idf31f83b24713932d5ddfa096e23f36ae8195cd2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/123685
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Alexander Aprelev 2019-11-04 23:53:05 +00:00 committed by commit-bot@chromium.org
parent 91c38d00c0
commit 208f3709b9
3 changed files with 154 additions and 86 deletions

View file

@ -3,20 +3,17 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:developer';
import 'dart:isolate';
import 'dart:math';
import 'package:meta/meta.dart';
import 'package:compiler/src/dart2js.dart' as dart2js_main;
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart' as vm_service_io;
class SpawnLatencyAndMemory {
SpawnLatencyAndMemory(this.name, this.wsUri, this.groupRefId);
class SpawnLatency {
SpawnLatency(this.name);
Future<ResultMessageLatencyAndMemory> run() async {
Future<ResultMessageLatency> run() async {
final completerResult = Completer();
final receivePort = ReceivePort()..listen(completerResult.complete);
final Completer<DateTime> isolateExitedCompleter = Completer<DateTime>();
@ -26,14 +23,12 @@ class SpawnLatencyAndMemory {
});
final DateTime beforeSpawn = DateTime.now();
await Isolate.spawn(
isolateCompiler,
StartMessageLatencyAndMemory(receivePort.sendPort, beforeSpawn,
await currentHeapUsage(wsUri, groupRefId), wsUri, groupRefId),
isolateCompiler, StartMessageLatency(receivePort.sendPort, beforeSpawn),
onExit: onExitReceivePort.sendPort,
onError: onExitReceivePort.sendPort);
final DateTime afterSpawn = DateTime.now();
final ResultMessageLatencyAndMemory result = await completerResult.future;
final ResultMessageLatency result = await completerResult.future;
receivePort.close();
final DateTime isolateExited = await isolateExitedCompleter.future;
result.timeToExitUs = isolateExited.difference(beforeSpawn).inMicroseconds;
@ -44,8 +39,7 @@ class SpawnLatencyAndMemory {
return result;
}
Future<AggregatedResultMessageLatencyAndMemory> measureFor(
int minimumMillis) async {
Future<AggregatedResultMessageLatency> measureFor(int minimumMillis) async {
final minimumMicros = minimumMillis * 1000;
final watch = Stopwatch()..start();
final Metric toAfterIsolateSpawnUs = LatencyMetric("${name}ToAfterSpawn");
@ -53,32 +47,28 @@ class SpawnLatencyAndMemory {
final Metric toFinishRunningCodeUs =
LatencyMetric("${name}ToFinishRunning");
final Metric toExitUs = LatencyMetric("${name}ToExit");
final Metric deltaHeap = MemoryMetric("${name}Delta");
while (watch.elapsedMicroseconds < minimumMicros) {
final ResultMessageLatencyAndMemory result = await run();
final ResultMessageLatency result = await run();
toAfterIsolateSpawnUs.add(result.timeToIsolateSpawnUs);
toStartRunningCodeUs.add(result.timeToStartRunningCodeUs);
toFinishRunningCodeUs.add(result.timeToFinishRunningCodeUs);
toExitUs.add(result.timeToExitUs);
deltaHeap.add(result.deltaHeap);
}
return AggregatedResultMessageLatencyAndMemory(toAfterIsolateSpawnUs,
toStartRunningCodeUs, toFinishRunningCodeUs, toExitUs, deltaHeap);
return AggregatedResultMessageLatency(toAfterIsolateSpawnUs,
toStartRunningCodeUs, toFinishRunningCodeUs, toExitUs);
}
Future<AggregatedResultMessageLatencyAndMemory> measure() async {
Future<AggregatedResultMessageLatency> measure() async {
await measureFor(500); // warm-up
return measureFor(4000); // actual measurement
}
Future<void> report() async {
final AggregatedResultMessageLatencyAndMemory result = await measure();
final AggregatedResultMessageLatency result = await measure();
print(result);
}
final String name;
final String wsUri;
final String groupRefId;
RawReceivePort receivePort;
}
@ -113,27 +103,15 @@ class LatencyMetric extends Metric {
LatencyMetric(String name) : super(prefix: "$name(Latency", suffix: " us.");
}
class MemoryMetric extends Metric {
MemoryMetric(String name)
: super(prefix: "${name}Heap(MemoryUse", suffix: "");
toString() => "$prefix): ${_average()}$suffix\n";
}
class StartMessageLatencyAndMemory {
StartMessageLatencyAndMemory(
this.sendPort, this.spawned, this.rss, this.wsUri, this.groupRefId);
class StartMessageLatency {
StartMessageLatency(this.sendPort, this.spawned);
final SendPort sendPort;
final DateTime spawned;
final int rss;
final String wsUri;
final String groupRefId;
}
class ResultMessageLatencyAndMemory {
ResultMessageLatencyAndMemory(
class ResultMessageLatency {
ResultMessageLatency(
{this.timeToStartRunningCodeUs,
this.timeToFinishRunningCodeUs,
this.deltaHeap});
@ -146,29 +124,26 @@ class ResultMessageLatencyAndMemory {
int timeToExitUs;
}
class AggregatedResultMessageLatencyAndMemory {
AggregatedResultMessageLatencyAndMemory(
class AggregatedResultMessageLatency {
AggregatedResultMessageLatency(
this.toAfterIsolateSpawnUs,
this.toStartRunningCodeUs,
this.toFinishRunningCodeUs,
this.toExitUs,
this.deltaHeap,
);
String toString() => """$toAfterIsolateSpawnUs
$toStartRunningCodeUs
$toFinishRunningCodeUs
$toExitUs
$deltaHeap""";
$toExitUs""";
final Metric toAfterIsolateSpawnUs;
final Metric toStartRunningCodeUs;
final Metric toFinishRunningCodeUs;
final Metric toExitUs;
final Metric deltaHeap;
}
Future<void> isolateCompiler(StartMessageLatencyAndMemory start) async {
Future<void> isolateCompiler(StartMessageLatency start) async {
final DateTime timeRunningCodeUs = DateTime.now();
await runZoned(
() => dart2js_main.internalMain(<String>[
@ -178,52 +153,13 @@ Future<void> isolateCompiler(StartMessageLatencyAndMemory start) async {
zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {}));
final DateTime timeFinishRunningCodeUs = DateTime.now();
start.sendPort.send(ResultMessageLatencyAndMemory(
start.sendPort.send(ResultMessageLatency(
timeToStartRunningCodeUs:
timeRunningCodeUs.difference(start.spawned).inMicroseconds,
timeToFinishRunningCodeUs:
timeFinishRunningCodeUs.difference(start.spawned).inMicroseconds,
deltaHeap:
await currentHeapUsage(start.wsUri, start.groupRefId) - start.rss));
}
Future<int> currentHeapUsage(String wsUri, String groupRefId) async {
final vm_service.VmService vmService =
await vm_service_io.vmServiceConnectUri(wsUri);
final vm_service.MemoryUsage usage =
await vmService.getIsolateGroupMemoryUsage(groupRefId);
vmService.dispose();
return usage.heapUsage + usage.externalUsage;
timeFinishRunningCodeUs.difference(start.spawned).inMicroseconds));
}
Future<void> main() async {
final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
final Uri observatoryUri = info.serverUri;
final String wsUri =
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
final vm_service.VmService vmService =
await vm_service_io.vmServiceConnectUri(wsUri);
final String mainGroupRefId = await getMainGroupRefId(vmService);
vmService.dispose();
await SpawnLatencyAndMemory("IsolateSpawn.Dart2JS", wsUri, mainGroupRefId)
.report();
}
Future<String> getMainGroupRefId(vm_service.VmService vmService) async {
final vm = await vmService.getVM();
for (vm_service.IsolateGroupRef groupRef in vm.isolateGroups) {
final vm_service.IsolateGroup group =
await vmService.getIsolateGroup(groupRef.id);
for (vm_service.IsolateRef isolateRef in group.isolates) {
final isolateOrSentinel = await vmService.getIsolate(isolateRef.id);
if (isolateOrSentinel is vm_service.Isolate) {
final vm_service.Isolate isolate = isolateOrSentinel;
if (isolate.name == 'main') {
return groupRef.id;
}
}
}
}
throw "Could not find main isolate";
await SpawnLatency("IsolateSpawn.Dart2JS").report();
}

View file

@ -0,0 +1,129 @@
// 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:developer';
import 'dart:io';
import 'dart:isolate';
import 'package:compiler/src/dart2js.dart' as dart2js_main;
import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart' as vm_service_io;
class Result {
const Result(
this.rssOnStart, this.rssOnEnd, this.heapOnStart, this.heapOnEnd);
final int rssOnStart;
final int rssOnEnd;
final int heapOnStart;
final int heapOnEnd;
}
class StartMessage {
const StartMessage(this.wsUri, this.groupRefId, this.sendPort);
final String wsUri;
final String groupRefId;
final SendPort sendPort;
}
class SpawnMemory {
SpawnMemory(this.name, this.wsUri, this.groupRefId);
Future<void> report() async {
const numberOfRuns = 5;
int sumDeltaRssOnStart = 0;
int sumDeltaRssOnEnd = 0;
int sumDeltaHeapOnStart = 0;
int sumDeltaHeapOnEnd = 0;
for (int i = 0; i < numberOfRuns; i++) {
final receivePort = ReceivePort();
final beforeRss = ProcessInfo.currentRss;
final beforeHeap = await currentHeapUsage(wsUri, groupRefId);
final startMessage =
StartMessage(wsUri, groupRefId, receivePort.sendPort);
await Isolate.spawn(isolateCompiler, startMessage);
final Result result = await receivePort.first;
sumDeltaRssOnStart += result.rssOnStart - beforeRss;
sumDeltaRssOnEnd += result.rssOnEnd - beforeRss;
sumDeltaHeapOnStart += result.heapOnStart - beforeHeap;
sumDeltaHeapOnEnd += result.heapOnEnd - beforeHeap;
}
print(
"${name}RssOnStart(MemoryUse): ${sumDeltaRssOnStart ~/ numberOfRuns}");
print("${name}RssOnEnd(MemoryUse): ${sumDeltaRssOnEnd ~/ numberOfRuns}");
print(
"${name}HeapOnStart(MemoryUse): ${sumDeltaHeapOnStart ~/ numberOfRuns}");
print("${name}HeapOnEnd(MemoryUse): ${sumDeltaHeapOnEnd ~/ numberOfRuns}");
}
final String name;
final String wsUri;
final String groupRefId;
RawReceivePort receivePort;
}
Future<void> isolateCompiler(StartMessage startMessage) async {
final rssOnStart = ProcessInfo.currentRss;
final heapOnStart =
await currentHeapUsage(startMessage.wsUri, startMessage.groupRefId);
await runZoned(
() => dart2js_main.internalMain(<String>[
"benchmarks/IsolateSpawnMemory/dart/helloworld.dart",
'--libraries-spec=sdk/lib/libraries.json'
]),
zoneSpecification: ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {}));
startMessage.sendPort.send(Result(
rssOnStart,
ProcessInfo.currentRss,
heapOnStart,
await currentHeapUsage(startMessage.wsUri, startMessage.groupRefId)));
ReceivePort(); // prevent isolate from exiting to ensure Rss monotonically grows
}
Future<int> currentHeapUsage(String wsUri, String groupRefId) async {
final vm_service.VmService vmService =
await vm_service_io.vmServiceConnectUri(wsUri);
final vm_service.MemoryUsage usage =
await vmService.getIsolateGroupMemoryUsage(groupRefId);
vmService.dispose();
return usage.heapUsage + usage.externalUsage;
}
Future<void> main() async {
final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
final Uri observatoryUri = info.serverUri;
final String wsUri =
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
final vm_service.VmService vmService =
await vm_service_io.vmServiceConnectUri(wsUri);
final String mainGroupRefId = await getMainGroupRefId(vmService);
vmService.dispose();
await SpawnMemory("IsolateSpawnMemory.Dart2JSDelta", wsUri, mainGroupRefId)
.report();
}
Future<String> getMainGroupRefId(vm_service.VmService vmService) async {
final vm = await vmService.getVM();
for (vm_service.IsolateGroupRef groupRef in vm.isolateGroups) {
final vm_service.IsolateGroup group =
await vmService.getIsolateGroup(groupRef.id);
for (vm_service.IsolateRef isolateRef in group.isolates) {
final isolateOrSentinel = await vmService.getIsolate(isolateRef.id);
if (isolateOrSentinel is vm_service.Isolate) {
final vm_service.Isolate isolate = isolateOrSentinel;
if (isolate.name == 'main') {
return groupRef.id;
}
}
}
}
throw "Could not find main isolate";
}

View file

@ -0,0 +1,3 @@
main() {
print('Hello, world!');
}