OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// This Element is part of MemoryDashboardElement. | 5 /// This Element is part of MemoryDashboardElement. |
6 /// | 6 /// |
7 /// The Element periodically interrogates the VM to log the memory usage of each | 7 /// The Element periodically interrogates the VM to log the memory usage of each |
8 /// Isolate and of the Native Memory. | 8 /// Isolate and of the Native Memory. |
9 /// | 9 /// |
10 /// For each isolate it is shown the Used and Free heap (new and old are merged | 10 /// For each isolate it is shown the Used and Free heap (new and old are merged |
(...skipping 23 matching lines...) Expand all Loading... |
34 | 34 |
35 RenderingScheduler<MemoryGraphElement> _r; | 35 RenderingScheduler<MemoryGraphElement> _r; |
36 | 36 |
37 final StreamController<IsolateSelectedEvent> _onIsolateSelected = | 37 final StreamController<IsolateSelectedEvent> _onIsolateSelected = |
38 new StreamController<IsolateSelectedEvent>(); | 38 new StreamController<IsolateSelectedEvent>(); |
39 | 39 |
40 Stream<RenderedEvent<MemoryGraphElement>> get onRendered => _r.onRendered; | 40 Stream<RenderedEvent<MemoryGraphElement>> get onRendered => _r.onRendered; |
41 Stream<IsolateSelectedEvent> get onIsolateSelected => | 41 Stream<IsolateSelectedEvent> get onIsolateSelected => |
42 _onIsolateSelected.stream; | 42 _onIsolateSelected.stream; |
43 | 43 |
44 M.VM _vm; | 44 M.VMRef _vm; |
| 45 M.VMRepository _vms; |
45 M.IsolateRepository _isolates; | 46 M.IsolateRepository _isolates; |
46 M.EventRepository _events; | 47 M.EventRepository _events; |
47 StreamSubscription _onGCSubscription; | 48 StreamSubscription _onGCSubscription; |
48 StreamSubscription _onResizeSubscription; | 49 StreamSubscription _onResizeSubscription; |
49 StreamSubscription _onConnectionClosedSubscription; | 50 StreamSubscription _onConnectionClosedSubscription; |
50 Timer _onTimer; | 51 Timer _onTimer; |
51 | 52 |
52 M.VM get vm => _vm; | 53 M.VMRef get vm => _vm; |
53 | 54 |
54 factory MemoryGraphElement( | 55 factory MemoryGraphElement(M.VMRef vm, M.VMRepository vms, |
55 M.VM vm, M.IsolateRepository isolates, M.EventRepository events, | 56 M.IsolateRepository isolates, M.EventRepository events, |
56 {RenderingQueue queue}) { | 57 {RenderingQueue queue}) { |
57 assert(vm != null); | 58 assert(vm != null); |
| 59 assert(vms != null); |
58 assert(isolates != null); | 60 assert(isolates != null); |
59 assert(events != null); | 61 assert(events != null); |
60 MemoryGraphElement e = document.createElement(tag.name); | 62 MemoryGraphElement e = document.createElement(tag.name); |
61 e._r = new RenderingScheduler(e, queue: queue); | 63 e._r = new RenderingScheduler(e, queue: queue); |
62 e._vm = vm; | 64 e._vm = vm; |
| 65 e._vms = vms; |
63 e._isolates = isolates; | 66 e._isolates = isolates; |
64 e._events = events; | 67 e._events = events; |
65 return e; | 68 return e; |
66 } | 69 } |
67 | 70 |
68 MemoryGraphElement.created() : super.created() { | 71 MemoryGraphElement.created() : super.created() { |
69 final now = new DateTime.now(); | 72 final now = new DateTime.now(); |
70 var sample = now.subtract(_window); | 73 var sample = now.subtract(_window); |
71 while (sample.isBefore(now)) { | 74 while (sample.isBefore(now)) { |
72 _ts.add(sample); | 75 _ts.add(sample); |
73 _vmSamples.add(0); | 76 _vmSamples.add(<int>[0, 0]); |
74 _isolateUsedSamples.add([]); | 77 _isolateUsedSamples.add([]); |
75 _isolateFreeSamples.add([]); | 78 _isolateFreeSamples.add([]); |
76 sample = sample.add(_period); | 79 sample = sample.add(_period); |
77 } | 80 } |
78 _ts.add(now); | 81 _ts.add(now); |
79 _vmSamples.add(0); | 82 _vmSamples.add(<int>[0, 0]); |
80 _isolateUsedSamples.add([]); | 83 _isolateUsedSamples.add([]); |
81 _isolateFreeSamples.add([]); | 84 _isolateFreeSamples.add([]); |
82 } | 85 } |
83 | 86 |
84 static const Duration _period = const Duration(seconds: 2); | 87 static const Duration _period = const Duration(seconds: 2); |
85 static const Duration _window = const Duration(minutes: 2); | 88 static const Duration _window = const Duration(minutes: 2); |
86 | 89 |
87 @override | 90 @override |
88 attached() { | 91 attached() { |
89 super.attached(); | 92 super.attached(); |
(...skipping 12 matching lines...) Expand all Loading... |
102 super.detached(); | 105 super.detached(); |
103 _r.disable(notify: true); | 106 _r.disable(notify: true); |
104 children = []; | 107 children = []; |
105 _onGCSubscription.cancel(); | 108 _onGCSubscription.cancel(); |
106 _onConnectionClosedSubscription.cancel(); | 109 _onConnectionClosedSubscription.cancel(); |
107 _onResizeSubscription.cancel(); | 110 _onResizeSubscription.cancel(); |
108 _onTimer.cancel(); | 111 _onTimer.cancel(); |
109 } | 112 } |
110 | 113 |
111 final List<DateTime> _ts = <DateTime>[]; | 114 final List<DateTime> _ts = <DateTime>[]; |
112 final List<int> _vmSamples = <int>[]; | 115 final List<List<int>> _vmSamples = <List<int>>[]; |
113 final List<M.IsolateRef> _seenIsolates = <M.IsolateRef>[]; | 116 final List<M.IsolateRef> _seenIsolates = <M.IsolateRef>[]; |
114 final List<List<int>> _isolateUsedSamples = <List<int>>[]; | 117 final List<List<int>> _isolateUsedSamples = <List<int>>[]; |
115 final List<List<int>> _isolateFreeSamples = <List<int>>[]; | 118 final List<List<int>> _isolateFreeSamples = <List<int>>[]; |
116 final Map<String, int> _isolateIndex = <String, int>{}; | 119 final Map<String, int> _isolateIndex = <String, int>{}; |
117 final Map<String, String> _isolateName = <String, String>{}; | 120 final Map<String, String> _isolateName = <String, String>{}; |
118 | 121 |
119 var _selected; | 122 var _selected; |
120 var _previewed; | 123 var _previewed; |
121 var _hovered; | 124 var _hovered; |
122 | 125 |
(...skipping 16 matching lines...) Expand all Loading... |
139 formatter: _formatTimeAxis, type: ChartColumnSpec.TYPE_NUMBER), | 142 formatter: _formatTimeAxis, type: ChartColumnSpec.TYPE_NUMBER), |
140 new ChartColumnSpec(label: 'Native', formatter: Utils.formatSize) | 143 new ChartColumnSpec(label: 'Native', formatter: Utils.formatSize) |
141 ]..addAll(_isolateName.keys.expand((id) => [ | 144 ]..addAll(_isolateName.keys.expand((id) => [ |
142 new ChartColumnSpec(formatter: Utils.formatSize), | 145 new ChartColumnSpec(formatter: Utils.formatSize), |
143 new ChartColumnSpec(label: _label(id), formatter: Utils.formatSize) | 146 new ChartColumnSpec(label: _label(id), formatter: Utils.formatSize) |
144 ])); | 147 ])); |
145 // The stacked line chart sorts from top to bottom | 148 // The stacked line chart sorts from top to bottom |
146 final rows = new List.generate(_ts.length, (sampleIndex) { | 149 final rows = new List.generate(_ts.length, (sampleIndex) { |
147 final free = _isolateFreeSamples[sampleIndex]; | 150 final free = _isolateFreeSamples[sampleIndex]; |
148 final used = _isolateUsedSamples[sampleIndex]; | 151 final used = _isolateUsedSamples[sampleIndex]; |
| 152 final isolates = _isolateIndex.keys.expand((key) { |
| 153 final isolateIndex = _isolateIndex[key]; |
| 154 return <int>[free[isolateIndex], used[isolateIndex]]; |
| 155 }); |
149 return [ | 156 return [ |
150 _ts[sampleIndex].difference(now).inMicroseconds, | 157 _ts[sampleIndex].difference(now).inMicroseconds, |
151 _vmSamples[sampleIndex] | 158 _vmSamples[sampleIndex][1] |
152 ]..addAll(_isolateIndex.keys.expand((key) { | 159 ]..addAll(isolates); |
153 final isolateIndex = _isolateIndex[key]; | |
154 return [free[isolateIndex], used[isolateIndex]]; | |
155 })); | |
156 }); | 160 }); |
157 | 161 |
158 final scale = new LinearScale()..domain = [(-_window).inMicroseconds, 0]; | 162 final scale = new LinearScale()..domain = [(-_window).inMicroseconds, 0]; |
159 final axisConfig = new ChartAxisConfig()..scale = scale; | 163 final axisConfig = new ChartAxisConfig()..scale = scale; |
160 final sMemory = | 164 final sMemory = |
161 new ChartSeries('Memory', series, new StackedLineChartRenderer()); | 165 new ChartSeries('Memory', series, new StackedLineChartRenderer()); |
162 final config = new ChartConfig([sMemory], [0]) | 166 final config = new ChartConfig([sMemory], [0]) |
163 ..legend = new ChartLegend(legend) | 167 ..legend = new ChartLegend(legend) |
164 ..registerDimensionAxis(0, axisConfig); | 168 ..registerDimensionAxis(0, axisConfig); |
165 config.minimumSize = new Rect(rect.width, rect.height); | 169 config.minimumSize = new Rect(rect.width, rect.height); |
(...skipping 22 matching lines...) Expand all Loading... |
188 Utils.formatDuration(new Duration(microseconds: ms.toInt()), | 192 Utils.formatDuration(new Duration(microseconds: ms.toInt()), |
189 precision: DurationComponent.Seconds); | 193 precision: DurationComponent.Seconds); |
190 | 194 |
191 bool _running = false; | 195 bool _running = false; |
192 | 196 |
193 Future _refresh({M.IsolateRef gcIsolate}) async { | 197 Future _refresh({M.IsolateRef gcIsolate}) async { |
194 if (_running) return; | 198 if (_running) return; |
195 _running = true; | 199 _running = true; |
196 final now = new DateTime.now(); | 200 final now = new DateTime.now(); |
197 final start = now.subtract(_window); | 201 final start = now.subtract(_window); |
| 202 final vm = await _vms.get(_vm); |
198 // The Service classes order isolates from the older to the newer | 203 // The Service classes order isolates from the older to the newer |
199 final isolates = | 204 final isolates = |
200 (await Future.wait(_vm.isolates.map(_isolates.get))).reversed.toList(); | 205 (await Future.wait(vm.isolates.map(_isolates.get))).reversed.toList(); |
201 while (_ts.first.isBefore(start)) { | 206 while (_ts.first.isBefore(start)) { |
202 _ts.removeAt(0); | 207 _ts.removeAt(0); |
203 _vmSamples.removeAt(0); | 208 _vmSamples.removeAt(0); |
204 _isolateUsedSamples.removeAt(0); | 209 _isolateUsedSamples.removeAt(0); |
205 _isolateFreeSamples.removeAt(0); | 210 _isolateFreeSamples.removeAt(0); |
206 } | 211 } |
207 | 212 |
208 if (_ts.first.isAfter(start)) { | 213 if (_ts.first.isAfter(start)) { |
209 _ts.insert(0, start); | 214 _ts.insert(0, start); |
210 _vmSamples.insert(0, _vmSamples.first); | 215 _vmSamples.insert(0, _vmSamples.first); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 _isolateUsedSamples.last[index] + _isolateFreeSamples.last[index]; | 250 _isolateUsedSamples.last[index] + _isolateFreeSamples.last[index]; |
246 isolateFreeSample[index] = 0; | 251 isolateFreeSample[index] = 0; |
247 } else { | 252 } else { |
248 isolateUsedSample[index] = _used(isolate); | 253 isolateUsedSample[index] = _used(isolate); |
249 isolateFreeSample[index] = _free(isolate); | 254 isolateFreeSample[index] = _free(isolate); |
250 } | 255 } |
251 }); | 256 }); |
252 _isolateUsedSamples.add(isolateUsedSample); | 257 _isolateUsedSamples.add(isolateUsedSample); |
253 _isolateFreeSamples.add(isolateFreeSample); | 258 _isolateFreeSamples.add(isolateFreeSample); |
254 | 259 |
255 _vmSamples.add(vm.heapAllocatedMemoryUsage); | 260 _vmSamples.add(<int>[vm.currentRSS, vm.heapAllocatedMemoryUsage]); |
256 | 261 |
257 _ts.add(now); | 262 _ts.add(now); |
258 } | 263 } |
259 final List<int> isolateUsedSample = new List<int>.filled(length, 0); | 264 final List<int> isolateUsedSample = new List<int>.filled(length, 0); |
260 final List<int> isolateFreeSample = new List<int>.filled(length, 0); | 265 final List<int> isolateFreeSample = new List<int>.filled(length, 0); |
261 isolates.forEach((M.Isolate isolate) { | 266 isolates.forEach((M.Isolate isolate) { |
262 _isolateName[isolate.id] = isolate.name; | 267 _isolateName[isolate.id] = isolate.name; |
263 final index = _isolateIndex[isolate.id]; | 268 final index = _isolateIndex[isolate.id]; |
264 isolateUsedSample[index] = _used(isolate); | 269 isolateUsedSample[index] = _used(isolate); |
265 isolateFreeSample[index] = _free(isolate); | 270 isolateFreeSample[index] = _free(isolate); |
266 }); | 271 }); |
267 _isolateUsedSamples.add(isolateUsedSample); | 272 _isolateUsedSamples.add(isolateUsedSample); |
268 _isolateFreeSamples.add(isolateFreeSample); | 273 _isolateFreeSamples.add(isolateFreeSample); |
269 | 274 |
270 _vmSamples.add(vm.heapAllocatedMemoryUsage); | 275 _vmSamples.add(<int>[vm.currentRSS, vm.heapAllocatedMemoryUsage]); |
271 | 276 |
272 _ts.add(now); | 277 _ts.add(now); |
273 _r.dirty(); | 278 _r.dirty(); |
274 _running = false; | 279 _running = false; |
275 } | 280 } |
276 | 281 |
277 void _handleEvent(records) => records.forEach((record) { | 282 void _handleEvent(records) => records.forEach((record) { |
278 if (record is ChartSelectionChangeRecord) { | 283 if (record is ChartSelectionChangeRecord) { |
279 var selected = record.add; | 284 var selected = record.add; |
280 if (selected == null) { | 285 if (selected == null) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 Element _formatNativeOvercard(int row) => new DivElement() | 330 Element _formatNativeOvercard(int row) => new DivElement() |
326 ..children = [ | 331 ..children = [ |
327 new DivElement() | 332 new DivElement() |
328 ..classes = ['hovercard-title'] | 333 ..classes = ['hovercard-title'] |
329 ..text = 'Native', | 334 ..text = 'Native', |
330 new DivElement() | 335 new DivElement() |
331 ..classes = ['hovercard-measure', 'hovercard-multi'] | 336 ..classes = ['hovercard-measure', 'hovercard-multi'] |
332 ..children = [ | 337 ..children = [ |
333 new DivElement() | 338 new DivElement() |
334 ..classes = ['hovercard-measure-label'] | 339 ..classes = ['hovercard-measure-label'] |
335 ..text = 'Heap', | 340 ..text = 'Total Memory Usage', |
336 new DivElement() | 341 new DivElement() |
337 ..classes = ['hovercard-measure-value'] | 342 ..classes = ['hovercard-measure-value'] |
338 ..text = Utils.formatSize(_vmSamples[row]), | 343 ..text = _vmSamples[row][0] != null |
| 344 ? "unavailable" |
| 345 : Utils.formatSize(_vmSamples[row][0]), |
| 346 ], |
| 347 new DivElement() |
| 348 ..classes = ['hovercard-measure', 'hovercard-multi'] |
| 349 ..children = [ |
| 350 new DivElement() |
| 351 ..classes = ['hovercard-measure-label'] |
| 352 ..text = 'Native Heap', |
| 353 new DivElement() |
| 354 ..classes = ['hovercard-measure-value'] |
| 355 ..text = Utils.formatSize(_vmSamples[row][1]), |
339 ] | 356 ] |
340 ]; | 357 ]; |
341 | 358 |
342 Element _formatIsolateOvercard(String isolateId, int row) { | 359 Element _formatIsolateOvercard(String isolateId, int row) { |
343 final index = _isolateIndex[isolateId]; | 360 final index = _isolateIndex[isolateId]; |
344 final free = _isolateFreeSamples[row][index]; | 361 final free = _isolateFreeSamples[row][index]; |
345 final used = _isolateUsedSamples[row][index]; | 362 final used = _isolateUsedSamples[row][index]; |
346 final capacity = free + used; | 363 final capacity = free + used; |
347 return new DivElement() | 364 return new DivElement() |
348 ..children = [ | 365 ..children = [ |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 </defs> | 444 </defs> |
428 '''; | 445 '''; |
429 | 446 |
430 StyleElement get style => new StyleElement() | 447 StyleElement get style => new StyleElement() |
431 ..text = ''' | 448 ..text = ''' |
432 memory-graph svg .stacked-line-rdr-line:nth-child(2n+${_offset+1}) | 449 memory-graph svg .stacked-line-rdr-line:nth-child(2n+${_offset+1}) |
433 path:nth-child(1) { | 450 path:nth-child(1) { |
434 filter: url(#stroke-grid); | 451 filter: url(#stroke-grid); |
435 }'''; | 452 }'''; |
436 } | 453 } |
OLD | NEW |