-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathIsolateSpawnMemory.dart
190 lines (157 loc) · 5.71 KB
/
IsolateSpawnMemory.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// 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:vm_service/vm_service.dart' as vm_service;
import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../../../pkg/vm/bin/gen_kernel.dart' as gen_kernel;
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 gen_kernel 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(
() => gen_kernel.compile(<String>[
'benchmarks/IsolateSpawn/dart/helloworld.dart',
'benchmarks/IsolateSpawn/dart/helloworld.dart.dill',
]),
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 vmService = await vm_service_io.vmServiceConnectUri(wsUri);
final groupIds = await getGroupIds(vmService);
int sum = 0;
for (final groupId in groupIds) {
final usage = await vmService.getIsolateGroupMemoryUsage(groupId);
sum += usage.heapUsage! + usage.externalUsage!;
}
unawaited(vmService.dispose());
return sum;
}
Future<void> main() async {
// Only if we successfully reach the end will we set 0 exit code.
exitCode = 255;
final info = await Service.controlWebServer(enable: true);
final observatoryUri = info.serverUri!;
final 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.
Future<List<String>> getGroupIds(vm_service.VmService vmService) async {
final groupIds = <String>{};
final vm = await vmService.getVM();
for (final groupRef in vm.isolateGroups!) {
final group = await vmService.getIsolateGroup(groupRef.id!);
for (final isolateRef in group.isolates!) {
try {
await vmService.getIsolate(isolateRef.id!);
groupIds.add(groupRef.id!);
break;
} on vm_service.SentinelException catch (_) {
// Skip groups with only sentinels.
}
}
}
if (groupIds.isEmpty) {
throw 'Could not find main isolate';
}
return groupIds.toList();
}