Skip to content

Commit f922ed0

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
[vm/concurrency] Update IsolateSpawnMemory benchmark
Ensure to count heap sizes of all isolate groups, since AOT works with --enable-isolate-groups, JIT without. Make the benchmark work in phases to make numbers more stable. Add a max-process-rss metric to see peak memory during duration of the entire benchmark. Change-Id: I481b2cb8b666885b5c2b9c53fff1177accd01830 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126724 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent f7941eb commit f922ed0

File tree

1 file changed

+116
-54
lines changed

1 file changed

+116
-54
lines changed

benchmarks/IsolateSpawnMemory/dart/IsolateSpawnMemory.dart

Lines changed: 116 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ import 'dart:async';
66
import 'dart:developer';
77
import 'dart:io';
88
import 'dart:isolate';
9+
import 'dart:math' as math;
910

1011
import 'package:compiler/src/dart2js.dart' as dart2js_main;
1112
import 'package:vm_service/vm_service.dart' as vm_service;
1213
import 'package:vm_service/vm_service_io.dart' as vm_service_io;
1314

15+
const String compilerIsolateName = 'isolate-compiler';
16+
1417
class Result {
1518
const Result(
1619
this.rssOnStart, this.rssOnEnd, this.heapOnStart, this.heapOnEnd);
@@ -22,108 +25,167 @@ class Result {
2225
}
2326

2427
class StartMessage {
25-
const StartMessage(this.wsUri, this.groupRefId, this.sendPort);
28+
const StartMessage(this.wsUri, this.sendPort);
2629

2730
final String wsUri;
28-
final String groupRefId;
2931
final SendPort sendPort;
3032
}
3133

3234
class SpawnMemory {
33-
SpawnMemory(this.name, this.wsUri, this.groupRefId);
35+
SpawnMemory(this.name, this.wsUri);
3436

3537
Future<void> report() async {
36-
const numberOfRuns = 3;
38+
int maxProcessRss = 0;
39+
final timer = Timer.periodic(const Duration(microseconds: 100), (_) {
40+
maxProcessRss = math.max(maxProcessRss, ProcessInfo.currentRss);
41+
});
42+
43+
const numberOfBenchmarks = 3;
44+
45+
final beforeRss = ProcessInfo.currentRss;
46+
final beforeHeap = await currentHeapUsage(wsUri);
3747

38-
int sumDeltaRssOnStart = 0;
39-
int sumDeltaRssOnEnd = 0;
40-
int sumDeltaHeapOnStart = 0;
41-
int sumDeltaHeapOnEnd = 0;
42-
for (int i = 0; i < numberOfRuns; i++) {
48+
final iterators = <StreamIterator>[];
49+
final continuations = <SendPort>[];
50+
51+
// Start all isolates & make them wait.
52+
for (int i = 0; i < numberOfBenchmarks; i++) {
4353
final receivePort = ReceivePort();
44-
final beforeRss = ProcessInfo.currentRss;
45-
final beforeHeap = await currentHeapUsage(wsUri, groupRefId);
46-
47-
final startMessage =
48-
StartMessage(wsUri, groupRefId, receivePort.sendPort);
49-
await Isolate.spawn(isolateCompiler, startMessage);
50-
51-
final Result result = await receivePort.first;
52-
sumDeltaRssOnStart += result.rssOnStart - beforeRss;
53-
sumDeltaRssOnEnd += result.rssOnEnd - beforeRss;
54-
sumDeltaHeapOnStart += result.heapOnStart - beforeHeap;
55-
sumDeltaHeapOnEnd += result.heapOnEnd - beforeHeap;
54+
final startMessage = StartMessage(wsUri, receivePort.sendPort);
55+
await Isolate.spawn(isolateCompiler, startMessage,
56+
debugName: compilerIsolateName);
57+
final iterator = StreamIterator(receivePort);
58+
59+
if (!await iterator.moveNext()) throw 'failed';
60+
continuations.add(iterator.current as SendPort);
61+
62+
iterators.add(iterator);
63+
}
64+
65+
final readyRss = ProcessInfo.currentRss;
66+
final readyHeap = await currentHeapUsage(wsUri);
67+
68+
// Let all isolates do the dart2js compilation.
69+
for (int i = 0; i < numberOfBenchmarks; i++) {
70+
final iterator = iterators[i];
71+
final continuation = continuations[i];
72+
continuation.send(null);
73+
if (!await iterator.moveNext()) throw 'failed';
74+
if (iterator.current != 'done') throw 'failed';
75+
}
76+
77+
final doneRss = ProcessInfo.currentRss;
78+
final doneHeap = await currentHeapUsage(wsUri);
79+
80+
// Shut down helper isolates
81+
for (int i = 0; i < numberOfBenchmarks; i++) {
82+
final iterator = iterators[i];
83+
final continuation = continuations[i];
84+
continuation.send(null);
85+
if (!await iterator.moveNext()) throw 'failed';
86+
if (iterator.current != 'shutdown') throw 'failed';
87+
await iterator.cancel();
5688
}
57-
print(
58-
"${name}RssOnStart(MemoryUse): ${sumDeltaRssOnStart ~/ numberOfRuns}");
59-
print("${name}RssOnEnd(MemoryUse): ${sumDeltaRssOnEnd ~/ numberOfRuns}");
60-
print(
61-
"${name}HeapOnStart(MemoryUse): ${sumDeltaHeapOnStart ~/ numberOfRuns}");
62-
print("${name}HeapOnEnd(MemoryUse): ${sumDeltaHeapOnEnd ~/ numberOfRuns}");
89+
timer.cancel();
90+
91+
final readyDiffRss =
92+
math.max(0, readyRss - beforeRss) ~/ numberOfBenchmarks;
93+
final readyDiffHeap =
94+
math.max(0, readyHeap - beforeHeap) ~/ numberOfBenchmarks;
95+
final doneDiffRss = math.max(0, doneRss - beforeRss) ~/ numberOfBenchmarks;
96+
final doneDiffHeap =
97+
math.max(0, doneHeap - beforeHeap) ~/ numberOfBenchmarks;
98+
99+
print("${name}RssOnStart(MemoryUse): $readyDiffRss");
100+
print("${name}RssOnEnd(MemoryUse): $doneDiffRss");
101+
print("${name}HeapOnStart(MemoryUse): $readyDiffHeap");
102+
print("${name}HeapOnEnd(MemoryUse): $doneDiffHeap");
103+
print("${name}PeakProcessRss(MemoryUse): $maxProcessRss");
63104
}
64105

65106
final String name;
66107
final String wsUri;
67-
final String groupRefId;
68-
RawReceivePort receivePort;
69108
}
70109

71110
Future<void> isolateCompiler(StartMessage startMessage) async {
72-
final rssOnStart = ProcessInfo.currentRss;
73-
final heapOnStart =
74-
await currentHeapUsage(startMessage.wsUri, startMessage.groupRefId);
111+
final port = ReceivePort();
112+
final iterator = StreamIterator(port);
113+
114+
// Let main isolate know we're ready.
115+
startMessage.sendPort.send(port.sendPort);
116+
await iterator.moveNext();
117+
75118
await runZoned(
76119
() => dart2js_main.internalMain(<String>[
77120
"benchmarks/IsolateSpawnMemory/dart/helloworld.dart",
78121
'--libraries-spec=sdk/lib/libraries.json'
79122
]),
80123
zoneSpecification: ZoneSpecification(
81124
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {}));
82-
startMessage.sendPort.send(Result(
83-
rssOnStart,
84-
ProcessInfo.currentRss,
85-
heapOnStart,
86-
await currentHeapUsage(startMessage.wsUri, startMessage.groupRefId)));
87-
ReceivePort(); // prevent isolate from exiting to ensure Rss monotonically grows
125+
126+
// Let main isolate know we're done.
127+
startMessage.sendPort.send('done');
128+
await iterator.moveNext();
129+
130+
// Closes the port.
131+
startMessage.sendPort.send('shutdown');
132+
await iterator.cancel();
88133
}
89134

90-
Future<int> currentHeapUsage(String wsUri, String groupRefId) async {
135+
Future<int> currentHeapUsage(String wsUri) async {
91136
final vm_service.VmService vmService =
92137
await vm_service_io.vmServiceConnectUri(wsUri);
93-
final vm_service.MemoryUsage usage =
94-
await vmService.getIsolateGroupMemoryUsage(groupRefId);
138+
final groupIds = await getGroupIds(vmService);
139+
int sum = 0;
140+
for (final groupId in groupIds) {
141+
final vm_service.MemoryUsage usage =
142+
await vmService.getIsolateGroupMemoryUsage(groupId);
143+
sum += usage.heapUsage + usage.externalUsage;
144+
}
95145
vmService.dispose();
96-
return usage.heapUsage + usage.externalUsage;
146+
return sum;
97147
}
98148

99149
Future<void> main() async {
150+
// Only if we successfully reach the end will we set 0 exit code.
151+
exitCode = 255;
152+
100153
final ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
101154
final Uri observatoryUri = info.serverUri;
102155
final String wsUri =
103156
'ws://${observatoryUri.authority}${observatoryUri.path}ws';
104-
final vm_service.VmService vmService =
105-
await vm_service_io.vmServiceConnectUri(wsUri);
106-
final String mainGroupRefId = await getMainGroupRefId(vmService);
107-
vmService.dispose();
157+
await SpawnMemory("IsolateSpawnMemory.Dart2JSDelta", wsUri).report();
108158

109-
await SpawnMemory("IsolateSpawnMemory.Dart2JSDelta", wsUri, mainGroupRefId)
110-
.report();
159+
// Only if we successfully reach the end will we set 0 exit code.
160+
exitCode = 0;
111161
}
112162

113-
Future<String> getMainGroupRefId(vm_service.VmService vmService) async {
163+
// Returns the set of isolate groups for which we should count the heap usage.
164+
//
165+
// We have two cases
166+
//
167+
// a) --enable-isolate-groups: All isolates will be within the same isolate
168+
// group.
169+
//
170+
// b) --no-enable-isolate-groups: All isolates will be within their own,
171+
// separate isolate group.
172+
//
173+
// In both cases we want to sum up the heap sizes of all isolate groups.
174+
Future<List<String>> getGroupIds(vm_service.VmService vmService) async {
175+
final groupIds = <String>{};
114176
final vm = await vmService.getVM();
115177
for (vm_service.IsolateGroupRef groupRef in vm.isolateGroups) {
116178
final vm_service.IsolateGroup group =
117179
await vmService.getIsolateGroup(groupRef.id);
118180
for (vm_service.IsolateRef isolateRef in group.isolates) {
119181
final isolateOrSentinel = await vmService.getIsolate(isolateRef.id);
120182
if (isolateOrSentinel is vm_service.Isolate) {
121-
final vm_service.Isolate isolate = isolateOrSentinel;
122-
if (isolate.name == 'main') {
123-
return groupRef.id;
124-
}
183+
groupIds.add(groupRef.id);
125184
}
126185
}
127186
}
128-
throw "Could not find main isolate";
187+
if (groupIds.isEmpty) {
188+
throw "Could not find main isolate";
189+
}
190+
return groupIds.toList();
129191
}

0 commit comments

Comments
 (0)