Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: runtime/observatory/lib/src/elements/memory/graph.dart

Issue 2996803002: Add current rss and embedder name to Observatory (Closed)
Patch Set: Rebase and Merge Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
123 void render() { 126 void render() {
124 if (_previewed != null || _hovered != null) return; 127 if (_previewed != null || _hovered != null) return;
125 128
129 // cache data of hoverboards
130 final ts = new List<DateTime>.from(_ts);
131 final vmSamples = new List<List<int>>.from(_vmSamples);
132 final isolateFreeSamples = new List<List<int>>.from(_isolateFreeSamples);
133 final isolateUsedSamples = new List<List<int>>.from(_isolateUsedSamples);
134
126 final now = _ts.last; 135 final now = _ts.last;
127 final nativeComponents = 1; 136 final nativeComponents = 1;
128 final legend = new DivElement(); 137 final legend = new DivElement();
129 final host = new DivElement(); 138 final host = new DivElement();
130 final theme = new MemoryChartTheme(1); 139 final theme = new MemoryChartTheme(1);
131 children = [theme.style, legend, host]; 140 children = [theme.style, legend, host];
132 final rect = host.getBoundingClientRect(); 141 final rect = host.getBoundingClientRect();
133 142
134 final series = 143 final series =
135 new List<int>.generate(_isolateIndex.length * 2 + 1, (i) => i + 1); 144 new List<int>.generate(_isolateIndex.length * 2 + 1, (i) => i + 1);
136 // The stacked line chart sorts from top to bottom 145 // The stacked line chart sorts from top to bottom
137 final columns = [ 146 final columns = [
138 new ChartColumnSpec( 147 new ChartColumnSpec(
139 formatter: _formatTimeAxis, type: ChartColumnSpec.TYPE_NUMBER), 148 formatter: _formatTimeAxis, type: ChartColumnSpec.TYPE_NUMBER),
140 new ChartColumnSpec(label: 'Native', formatter: Utils.formatSize) 149 new ChartColumnSpec(label: 'Native', formatter: Utils.formatSize)
141 ]..addAll(_isolateName.keys.expand((id) => [ 150 ]..addAll(_isolateName.keys.expand((id) => [
142 new ChartColumnSpec(formatter: Utils.formatSize), 151 new ChartColumnSpec(formatter: Utils.formatSize),
143 new ChartColumnSpec(label: _label(id), formatter: Utils.formatSize) 152 new ChartColumnSpec(label: _label(id), formatter: Utils.formatSize)
144 ])); 153 ]));
145 // The stacked line chart sorts from top to bottom 154 // The stacked line chart sorts from top to bottom
146 final rows = new List.generate(_ts.length, (sampleIndex) { 155 final rows = new List.generate(_ts.length, (sampleIndex) {
147 final free = _isolateFreeSamples[sampleIndex]; 156 final free = isolateFreeSamples[sampleIndex];
148 final used = _isolateUsedSamples[sampleIndex]; 157 final used = isolateUsedSamples[sampleIndex];
158 final isolates = _isolateIndex.keys.expand((key) {
159 final isolateIndex = _isolateIndex[key];
160 return <int>[free[isolateIndex], used[isolateIndex]];
161 });
149 return [ 162 return [
150 _ts[sampleIndex].difference(now).inMicroseconds, 163 ts[sampleIndex].difference(now).inMicroseconds,
151 _vmSamples[sampleIndex] 164 vmSamples[sampleIndex][1] ?? 1000000
152 ]..addAll(_isolateIndex.keys.expand((key) { 165 ]..addAll(isolates);
153 final isolateIndex = _isolateIndex[key];
154 return [free[isolateIndex], used[isolateIndex]];
155 }));
156 }); 166 });
157 167
158 final scale = new LinearScale()..domain = [(-_window).inMicroseconds, 0]; 168 final scale = new LinearScale()..domain = [(-_window).inMicroseconds, 0];
159 final axisConfig = new ChartAxisConfig()..scale = scale; 169 final axisConfig = new ChartAxisConfig()..scale = scale;
160 final sMemory = 170 final sMemory =
161 new ChartSeries('Memory', series, new StackedLineChartRenderer()); 171 new ChartSeries('Memory', series, new StackedLineChartRenderer());
162 final config = new ChartConfig([sMemory], [0]) 172 final config = new ChartConfig([sMemory], [0])
163 ..legend = new ChartLegend(legend) 173 ..legend = new ChartLegend(legend)
164 ..registerDimensionAxis(0, axisConfig); 174 ..registerDimensionAxis(0, axisConfig);
165 config.minimumSize = new Rect(rect.width, rect.height); 175 config.minimumSize = new Rect(rect.width, rect.height);
166 final data = new ChartData(columns, rows); 176 final data = new ChartData(columns, rows);
167 final state = new ChartState(isMultiSelect: true) 177 final state = new ChartState(isMultiSelect: true)
168 ..changes.listen(_handleEvent); 178 ..changes.listen(_handleEvent);
169 final area = new CartesianArea(host, data, config, state: state) 179 final area = new CartesianArea(host, data, config, state: state)
170 ..theme = theme; 180 ..theme = theme;
171 area.addChartBehavior(new Hovercard(builder: (int column, int row) { 181 area.addChartBehavior(new Hovercard(builder: (int column, int row) {
172 final data = rows[row];
173 if (column == 1) { 182 if (column == 1) {
174 return _formatNativeOvercard(data[1]); 183 final data = vmSamples[row];
184 return _formatNativeOvercard(data[0], data[1]);
175 } 185 }
176 final isolate = _seenIsolates[column - 2]; 186 final isolate = _seenIsolates[column - 2];
177 final index = _isolateIndex[isolate.id] * 2 + 2; 187 final index = _isolateIndex[isolate.id];
178 return _formatIsolateOvercard(isolate.name, data[index], data[index + 1]); 188 final free = isolateFreeSamples[row][index];
189 final used = isolateUsedSamples[row][index];
190 return _formatIsolateOvercard(isolate.name, free, used);
179 })); 191 }));
180 area.draw(); 192 area.draw();
181 193
182 if (_selected != null) { 194 if (_selected != null) {
183 state.select(_selected); 195 state.select(_selected);
184 if (_selected > 1) { 196 if (_selected > 1) {
185 state.select(_selected + 1); 197 state.select(_selected + 1);
186 } 198 }
187 } 199 }
188 } 200 }
189 201
190 String _formatTimeAxis(num ms) => 202 String _formatTimeAxis(num ms) =>
191 Utils.formatDuration(new Duration(microseconds: ms.toInt()), 203 Utils.formatDuration(new Duration(microseconds: ms.toInt()),
192 precision: DurationComponent.Seconds); 204 precision: DurationComponent.Seconds);
193 205
194 bool _running = false; 206 bool _running = false;
195 207
196 Future _refresh({M.IsolateRef gcIsolate}) async { 208 Future _refresh({M.IsolateRef gcIsolate}) async {
197 if (_running) return; 209 if (_running) return;
198 _running = true; 210 _running = true;
199 final now = new DateTime.now(); 211 final now = new DateTime.now();
200 final start = now.subtract(_window); 212 final start = now.subtract(_window);
213 final vm = await _vms.get(_vm);
201 // The Service classes order isolates from the older to the newer 214 // The Service classes order isolates from the older to the newer
202 final isolates = 215 final isolates =
203 (await Future.wait(_vm.isolates.map(_isolates.get))).reversed.toList(); 216 (await Future.wait(vm.isolates.map(_isolates.get))).reversed.toList();
204 while (_ts.first.isBefore(start)) { 217 while (_ts.first.isBefore(start)) {
205 _ts.removeAt(0); 218 _ts.removeAt(0);
206 _vmSamples.removeAt(0); 219 _vmSamples.removeAt(0);
207 _isolateUsedSamples.removeAt(0); 220 _isolateUsedSamples.removeAt(0);
208 _isolateFreeSamples.removeAt(0); 221 _isolateFreeSamples.removeAt(0);
209 } 222 }
210 223
211 if (_ts.first.isAfter(start)) { 224 if (_ts.first.isAfter(start)) {
212 _ts.insert(0, start); 225 _ts.insert(0, start);
213 _vmSamples.insert(0, _vmSamples.first); 226 _vmSamples.insert(0, _vmSamples.first);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 _isolateUsedSamples.last[index] + _isolateFreeSamples.last[index]; 261 _isolateUsedSamples.last[index] + _isolateFreeSamples.last[index];
249 isolateFreeSample[index] = 0; 262 isolateFreeSample[index] = 0;
250 } else { 263 } else {
251 isolateUsedSample[index] = _used(isolate); 264 isolateUsedSample[index] = _used(isolate);
252 isolateFreeSample[index] = _free(isolate); 265 isolateFreeSample[index] = _free(isolate);
253 } 266 }
254 }); 267 });
255 _isolateUsedSamples.add(isolateUsedSample); 268 _isolateUsedSamples.add(isolateUsedSample);
256 _isolateFreeSamples.add(isolateFreeSample); 269 _isolateFreeSamples.add(isolateFreeSample);
257 270
258 _vmSamples.add(vm.heapAllocatedMemoryUsage); 271 _vmSamples.add(<int>[vm.currentRSS, vm.heapAllocatedMemoryUsage]);
259 272
260 _ts.add(now); 273 _ts.add(now);
261 } 274 }
262 final List<int> isolateUsedSample = new List<int>.filled(length, 0); 275 final List<int> isolateUsedSample = new List<int>.filled(length, 0);
263 final List<int> isolateFreeSample = new List<int>.filled(length, 0); 276 final List<int> isolateFreeSample = new List<int>.filled(length, 0);
264 isolates.forEach((M.Isolate isolate) { 277 isolates.forEach((M.Isolate isolate) {
265 _isolateName[isolate.id] = isolate.name; 278 _isolateName[isolate.id] = isolate.name;
266 final index = _isolateIndex[isolate.id]; 279 final index = _isolateIndex[isolate.id];
267 isolateUsedSample[index] = _used(isolate); 280 isolateUsedSample[index] = _used(isolate);
268 isolateFreeSample[index] = _free(isolate); 281 isolateFreeSample[index] = _free(isolate);
269 }); 282 });
270 _isolateUsedSamples.add(isolateUsedSample); 283 _isolateUsedSamples.add(isolateUsedSample);
271 _isolateFreeSamples.add(isolateFreeSample); 284 _isolateFreeSamples.add(isolateFreeSample);
272 285
273 _vmSamples.add(vm.heapAllocatedMemoryUsage); 286 _vmSamples.add(<int>[vm.currentRSS, vm.heapAllocatedMemoryUsage]);
274 287
275 _ts.add(now); 288 _ts.add(now);
276 _r.dirty(); 289 _r.dirty();
277 _running = false; 290 _running = false;
278 } 291 }
279 292
280 void _handleEvent(records) => records.forEach((record) { 293 void _handleEvent(records) => records.forEach((record) {
281 if (record is ChartSelectionChangeRecord) { 294 if (record is ChartSelectionChangeRecord) {
282 var selected = record.add; 295 var selected = record.add;
283 if (selected == null) { 296 if (selected == null) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 final index = _isolateIndex[isolateId]; 331 final index = _isolateIndex[isolateId];
319 final name = _isolateName[isolateId]; 332 final name = _isolateName[isolateId];
320 final free = _isolateFreeSamples.last[index]; 333 final free = _isolateFreeSamples.last[index];
321 final used = _isolateUsedSamples.last[index]; 334 final used = _isolateUsedSamples.last[index];
322 final usedStr = Utils.formatSize(used); 335 final usedStr = Utils.formatSize(used);
323 final capacity = free + used; 336 final capacity = free + used;
324 final capacityStr = Utils.formatSize(capacity); 337 final capacityStr = Utils.formatSize(capacity);
325 return '${name} ($usedStr / $capacityStr)'; 338 return '${name} ($usedStr / $capacityStr)';
326 } 339 }
327 340
328 static HtmlElement _formatNativeOvercard(int heap) => new DivElement() 341 static HtmlElement _formatNativeOvercard(int currentRSS, int heap) =>
329 ..children = [
330 new DivElement() 342 new DivElement()
331 ..classes = ['hovercard-title']
332 ..text = 'Native',
333 new DivElement()
334 ..classes = ['hovercard-measure', 'hovercard-multi']
335 ..children = [ 343 ..children = [
336 new DivElement() 344 new DivElement()
337 ..classes = ['hovercard-measure-label'] 345 ..classes = ['hovercard-title']
338 ..text = 'Heap', 346 ..text = 'Native',
339 new DivElement() 347 new DivElement()
340 ..classes = ['hovercard-measure-value'] 348 ..classes = ['hovercard-measure', 'hovercard-multi']
341 ..text = Utils.formatSize(heap), 349 ..children = [
342 ] 350 new DivElement()
343 ]; 351 ..classes = ['hovercard-measure-label']
352 ..text = 'Total Memory Usage',
353 new DivElement()
354 ..classes = ['hovercard-measure-value']
355 ..text = currentRSS != null
356 ? Utils.formatSize(currentRSS)
357 : "unavailable",
358 ],
359 new DivElement()
360 ..classes = ['hovercard-measure', 'hovercard-multi']
361 ..children = [
362 new DivElement()
363 ..classes = ['hovercard-measure-label']
364 ..text = 'Native Heap',
365 new DivElement()
366 ..classes = ['hovercard-measure-value']
367 ..text = heap != null ? Utils.formatSize(heap) : "unavailable",
368 ]
369 ];
344 370
345 static HtmlElement _formatIsolateOvercard(String name, int free, int used) { 371 static HtmlElement _formatIsolateOvercard(String name, int free, int used) {
346 final capacity = free + used; 372 final capacity = free + used;
347 return new DivElement() 373 return new DivElement()
348 ..children = [ 374 ..children = [
349 new DivElement() 375 new DivElement()
350 ..classes = ['hovercard-title'] 376 ..classes = ['hovercard-title']
351 ..text = name, 377 ..text = name,
352 new DivElement() 378 new DivElement()
353 ..classes = ['hovercard-measure', 'hovercard-multi'] 379 ..classes = ['hovercard-measure', 'hovercard-multi']
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 </defs> 453 </defs>
428 '''; 454 ''';
429 455
430 StyleElement get style => new StyleElement() 456 StyleElement get style => new StyleElement()
431 ..text = ''' 457 ..text = '''
432 memory-graph svg .stacked-line-rdr-line:nth-child(2n+${_offset+1}) 458 memory-graph svg .stacked-line-rdr-line:nth-child(2n+${_offset+1})
433 path:nth-child(1) { 459 path:nth-child(1) {
434 filter: url(#stroke-grid); 460 filter: url(#stroke-grid);
435 }'''; 461 }''';
436 } 462 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/elements/memory/dashboard.dart ('k') | runtime/observatory/lib/src/elements/vm_view.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698