@@ -6,11 +6,14 @@ import 'dart:async';
6
6
import 'dart:developer' ;
7
7
import 'dart:io' ;
8
8
import 'dart:isolate' ;
9
+ import 'dart:math' as math;
9
10
10
11
import 'package:compiler/src/dart2js.dart' as dart2js_main;
11
12
import 'package:vm_service/vm_service.dart' as vm_service;
12
13
import 'package:vm_service/vm_service_io.dart' as vm_service_io;
13
14
15
+ const String compilerIsolateName = 'isolate-compiler' ;
16
+
14
17
class Result {
15
18
const Result (
16
19
this .rssOnStart, this .rssOnEnd, this .heapOnStart, this .heapOnEnd);
@@ -22,108 +25,167 @@ class Result {
22
25
}
23
26
24
27
class StartMessage {
25
- const StartMessage (this .wsUri, this .groupRefId, this . sendPort);
28
+ const StartMessage (this .wsUri, this .sendPort);
26
29
27
30
final String wsUri;
28
- final String groupRefId;
29
31
final SendPort sendPort;
30
32
}
31
33
32
34
class SpawnMemory {
33
- SpawnMemory (this .name, this .wsUri, this .groupRefId );
35
+ SpawnMemory (this .name, this .wsUri);
34
36
35
37
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);
37
47
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++ ) {
43
53
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 ();
56
88
}
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 " );
63
104
}
64
105
65
106
final String name;
66
107
final String wsUri;
67
- final String groupRefId;
68
- RawReceivePort receivePort;
69
108
}
70
109
71
110
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
+
75
118
await runZoned (
76
119
() => dart2js_main.internalMain (< String > [
77
120
"benchmarks/IsolateSpawnMemory/dart/helloworld.dart" ,
78
121
'--libraries-spec=sdk/lib/libraries.json'
79
122
]),
80
123
zoneSpecification: ZoneSpecification (
81
124
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 ();
88
133
}
89
134
90
- Future <int > currentHeapUsage (String wsUri, String groupRefId ) async {
135
+ Future <int > currentHeapUsage (String wsUri) async {
91
136
final vm_service.VmService vmService =
92
137
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
+ }
95
145
vmService.dispose ();
96
- return usage.heapUsage + usage.externalUsage ;
146
+ return sum ;
97
147
}
98
148
99
149
Future <void > main () async {
150
+ // Only if we successfully reach the end will we set 0 exit code.
151
+ exitCode = 255 ;
152
+
100
153
final ServiceProtocolInfo info = await Service .controlWebServer (enable: true );
101
154
final Uri observatoryUri = info.serverUri;
102
155
final String wsUri =
103
156
'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 ();
108
158
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 ;
111
161
}
112
162
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 > {};
114
176
final vm = await vmService.getVM ();
115
177
for (vm_service.IsolateGroupRef groupRef in vm.isolateGroups) {
116
178
final vm_service.IsolateGroup group =
117
179
await vmService.getIsolateGroup (groupRef.id);
118
180
for (vm_service.IsolateRef isolateRef in group.isolates) {
119
181
final isolateOrSentinel = await vmService.getIsolate (isolateRef.id);
120
182
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);
125
184
}
126
185
}
127
186
}
128
- throw "Could not find main isolate" ;
187
+ if (groupIds.isEmpty) {
188
+ throw "Could not find main isolate" ;
189
+ }
190
+ return groupIds.toList ();
129
191
}
0 commit comments