6f66f82625
This change forks the benchmarks for the null safety feature where there now is a null safe version at benchmarks/Foo/dart and a legacy Dart 2 version at benchmarks/Foo/dart2. This change allows benchmarks to be migrated per go/dart-nnbd-benchmark-migration. Additionally this change pins the internal benchmarks which have been moved into their own repository and is now versioned along with the Dart SDK. The dart2 implementation will be benchmarked instead of the null safe dart implementation as of this change. The null safe dart implementation will be used when null safe benchmarking is turned on. Change-Id: If039fd7100c960169f4161c1d98167aca0af2ded Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148440 Reviewed-by: Alexander Thomas <athom@google.com>
192 lines
6.1 KiB
Dart
192 lines
6.1 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.
|
|
|
|
import 'dart:async';
|
|
import 'dart:developer';
|
|
import 'dart:io';
|
|
import 'dart:isolate';
|
|
import 'dart:math' as math;
|
|
|
|
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;
|
|
|
|
const String compilerIsolateName = 'isolate-compiler';
|
|
|
|
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.sendPort);
|
|
|
|
final String wsUri;
|
|
final SendPort sendPort;
|
|
}
|
|
|
|
class SpawnMemory {
|
|
SpawnMemory(this.name, this.wsUri);
|
|
|
|
Future<void> report() async {
|
|
int maxProcessRss = 0;
|
|
final timer = Timer.periodic(const Duration(microseconds: 100), (_) {
|
|
maxProcessRss = math.max(maxProcessRss, ProcessInfo.currentRss);
|
|
});
|
|
|
|
const numberOfBenchmarks = 3;
|
|
|
|
final beforeRss = ProcessInfo.currentRss;
|
|
final beforeHeap = await currentHeapUsage(wsUri);
|
|
|
|
final iterators = <StreamIterator>[];
|
|
final continuations = <SendPort>[];
|
|
|
|
// Start all isolates & make them wait.
|
|
for (int i = 0; i < numberOfBenchmarks; i++) {
|
|
final receivePort = ReceivePort();
|
|
final startMessage = StartMessage(wsUri, receivePort.sendPort);
|
|
await Isolate.spawn(isolateCompiler, startMessage,
|
|
debugName: compilerIsolateName);
|
|
final iterator = StreamIterator(receivePort);
|
|
|
|
if (!await iterator.moveNext()) throw 'failed';
|
|
continuations.add(iterator.current as SendPort);
|
|
|
|
iterators.add(iterator);
|
|
}
|
|
|
|
final readyRss = ProcessInfo.currentRss;
|
|
final readyHeap = await currentHeapUsage(wsUri);
|
|
|
|
// Let all isolates do the dart2js compilation.
|
|
for (int i = 0; i < numberOfBenchmarks; i++) {
|
|
final iterator = iterators[i];
|
|
final continuation = continuations[i];
|
|
continuation.send(null);
|
|
if (!await iterator.moveNext()) throw 'failed';
|
|
if (iterator.current != 'done') throw 'failed';
|
|
}
|
|
|
|
final doneRss = ProcessInfo.currentRss;
|
|
final doneHeap = await currentHeapUsage(wsUri);
|
|
|
|
// Shut down helper isolates
|
|
for (int i = 0; i < numberOfBenchmarks; i++) {
|
|
final iterator = iterators[i];
|
|
final continuation = continuations[i];
|
|
continuation.send(null);
|
|
if (!await iterator.moveNext()) throw 'failed';
|
|
if (iterator.current != 'shutdown') throw 'failed';
|
|
await iterator.cancel();
|
|
}
|
|
timer.cancel();
|
|
|
|
final readyDiffRss =
|
|
math.max(0, readyRss - beforeRss) ~/ numberOfBenchmarks;
|
|
final readyDiffHeap =
|
|
math.max(0, readyHeap - beforeHeap) ~/ numberOfBenchmarks;
|
|
final doneDiffRss = math.max(0, doneRss - beforeRss) ~/ numberOfBenchmarks;
|
|
final doneDiffHeap =
|
|
math.max(0, doneHeap - beforeHeap) ~/ numberOfBenchmarks;
|
|
|
|
print("${name}RssOnStart(MemoryUse): $readyDiffRss");
|
|
print("${name}RssOnEnd(MemoryUse): $doneDiffRss");
|
|
print("${name}HeapOnStart(MemoryUse): $readyDiffHeap");
|
|
print("${name}HeapOnEnd(MemoryUse): $doneDiffHeap");
|
|
print("${name}PeakProcessRss(MemoryUse): $maxProcessRss");
|
|
}
|
|
|
|
final String name;
|
|
final String wsUri;
|
|
}
|
|
|
|
Future<void> isolateCompiler(StartMessage startMessage) async {
|
|
final port = ReceivePort();
|
|
final iterator = StreamIterator(port);
|
|
|
|
// Let main isolate know we're ready.
|
|
startMessage.sendPort.send(port.sendPort);
|
|
await iterator.moveNext();
|
|
|
|
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) {}));
|
|
|
|
// Let main isolate know we're done.
|
|
startMessage.sendPort.send('done');
|
|
await iterator.moveNext();
|
|
|
|
// Closes the port.
|
|
startMessage.sendPort.send('shutdown');
|
|
await iterator.cancel();
|
|
}
|
|
|
|
Future<int> currentHeapUsage(String wsUri) async {
|
|
final vm_service.VmService vmService =
|
|
await vm_service_io.vmServiceConnectUri(wsUri);
|
|
final groupIds = await getGroupIds(vmService);
|
|
int sum = 0;
|
|
for (final groupId in groupIds) {
|
|
final vm_service.MemoryUsage usage =
|
|
await vmService.getIsolateGroupMemoryUsage(groupId);
|
|
sum += usage.heapUsage + usage.externalUsage;
|
|
}
|
|
vmService.dispose();
|
|
return sum;
|
|
}
|
|
|
|
Future<void> main() async {
|
|
// Only if we successfully reach the end will we set 0 exit code.
|
|
exitCode = 255;
|
|
|
|
final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
|
|
final Uri observatoryUri = info.serverUri;
|
|
final String wsUri =
|
|
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
|
|
await SpawnMemory("IsolateSpawnMemory.Dart2JSDelta", wsUri).report();
|
|
|
|
// Only if we successfully reach the end will we set 0 exit code.
|
|
exitCode = 0;
|
|
}
|
|
|
|
// Returns the set of isolate groups for which we should count the heap usage.
|
|
//
|
|
// We have two cases
|
|
//
|
|
// a) --enable-isolate-groups: All isolates will be within the same isolate
|
|
// group.
|
|
//
|
|
// b) --no-enable-isolate-groups: All isolates will be within their own,
|
|
// separate isolate group.
|
|
//
|
|
// In both cases we want to sum up the heap sizes of all isolate groups.
|
|
Future<List<String>> getGroupIds(vm_service.VmService vmService) async {
|
|
final groupIds = <String>{};
|
|
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) {
|
|
groupIds.add(groupRef.id);
|
|
}
|
|
}
|
|
}
|
|
if (groupIds.isEmpty) {
|
|
throw "Could not find main isolate";
|
|
}
|
|
return groupIds.toList();
|
|
}
|