| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library heap_map_element; | 5 library heap_map_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'dart:math'; | 9 import 'dart:math'; |
| 10 import 'observatory_element.dart'; | 10 import 'observatory_element.dart'; |
| 11 import 'package:observatory/service.dart'; | 11 import 'package:observatory/service.dart'; |
| 12 import 'package:logging/logging.dart'; | 12 import 'package:logging/logging.dart'; |
| 13 import 'package:polymer/polymer.dart'; | 13 import 'package:polymer/polymer.dart'; |
| 14 import 'package:observatory/app.dart'; | |
| 15 | 14 |
| 16 // A reference to a particular pixel of ImageData. | 15 // A reference to a particular pixel of ImageData. |
| 17 class PixelReference { | 16 class PixelReference { |
| 18 final _data; | 17 final _data; |
| 19 var _dataIndex; | 18 var _dataIndex; |
| 20 static const NUM_COLOR_COMPONENTS = 4; | 19 static const NUM_COLOR_COMPONENTS = 4; |
| 21 | 20 |
| 22 PixelReference(ImageData data, Point<int> point) | 21 PixelReference(ImageData data, Point<int> point) |
| 23 : _data = data, | 22 : _data = data, |
| 24 _dataIndex = (point.y * data.width + point.x) * NUM_COLOR_COMPONENTS; | 23 _dataIndex = (point.y * data.width + point.x) * NUM_COLOR_COMPONENTS; |
| 25 | 24 |
| 26 PixelReference._fromDataIndex(this._data, this._dataIndex); | 25 PixelReference._fromDataIndex(this._data, this._dataIndex); |
| 27 | 26 |
| 28 Point<int> get point => | 27 Point<int> get point => |
| 29 new Point(index % _data.width, index ~/ _data.width); | 28 new Point(index % _data.width, index ~/ _data.width); |
| 30 | 29 |
| 31 void set color(Iterable<int> color) { | 30 void set color(Iterable<int> color) { |
| 32 _data.data.setRange( | 31 _data.data.setRange( |
| 33 _dataIndex, _dataIndex + NUM_COLOR_COMPONENTS, color); | 32 _dataIndex, _dataIndex + NUM_COLOR_COMPONENTS, color); |
| 34 } | 33 } |
| 35 | 34 |
| 36 Iterable<int> get color => | 35 Iterable<int> get color => |
| 37 _data.data.getRange(_dataIndex, _dataIndex + NUM_COLOR_COMPONENTS); | 36 _data.data.getRange(_dataIndex, _dataIndex + NUM_COLOR_COMPONENTS); |
| 38 | 37 |
| 39 // Returns the next pixel in row-major order. | 38 // Returns the next pixel in row-major order. |
| 40 PixelReference next() => new PixelReference._fromDataIndex( | 39 PixelReference next() => new PixelReference._fromDataIndex( |
| 41 _data, _dataIndex + NUM_COLOR_COMPONENTS); | 40 _data, _dataIndex + NUM_COLOR_COMPONENTS); |
| 42 | 41 |
| 43 // The row-major index of this pixel. | 42 // The row-major index of this pixel. |
| 44 int get index => _dataIndex ~/ NUM_COLOR_COMPONENTS; | 43 int get index => _dataIndex ~/ NUM_COLOR_COMPONENTS; |
| 45 } | 44 } |
| 46 | 45 |
| 47 @CustomTag('heap-map') | 46 @CustomTag('heap-map') |
| 48 class HeapMapElement extends ObservatoryElement { | 47 class HeapMapElement extends ObservatoryElement { |
| 49 var _fragmentationCanvas; | 48 var _fragmentationCanvas; |
| 50 var _fragmentationData; | 49 var _fragmentationData; |
| 51 var _pageHeight; | 50 var _pageHeight; |
| 52 var _classIdToColor = {}; | 51 var _classIdToColor = {}; |
| 53 var _colorToClassId = {}; | 52 var _colorToClassId = {}; |
| 54 var _classIdToName = {}; | 53 var _classIdToName = {}; |
| 55 | 54 |
| 56 static final _freeColor = [255, 255, 255, 255]; | 55 static final _freeColor = [255, 255, 255, 255]; |
| 57 static final _pageSeparationColor = [0, 0, 0, 255]; | 56 static final _pageSeparationColor = [0, 0, 0, 255]; |
| 58 static const _PAGE_SEPARATION_HEIGHT = 4; | 57 static const _PAGE_SEPARATION_HEIGHT = 4; |
| 59 | 58 |
| 60 @observable String status; | 59 @observable String status; |
| 61 @published ServiceMap fragmentation; | 60 @published ServiceMap fragmentation; |
| 62 | 61 |
| 63 HeapMapElement.created() : super.created() { | 62 HeapMapElement.created() : super.created() { |
| 64 } | 63 } |
| 65 | 64 |
| 66 void enteredView() { | 65 void enteredView() { |
| 67 super.enteredView(); | 66 super.enteredView(); |
| 68 _fragmentationCanvas = shadowRoot.querySelector("#fragmentation"); | 67 _fragmentationCanvas = shadowRoot.querySelector("#fragmentation"); |
| 69 _fragmentationCanvas.onMouseMove.listen(_handleMouseMove); | 68 _fragmentationCanvas.onMouseMove.listen(_handleMouseMove); |
| 70 } | 69 } |
| 71 | 70 |
| 72 // Encode color as single integer, to enable using it as a map key. | 71 // Encode color as single integer, to enable using it as a map key. |
| 73 int _packColor(Iterable<int> color) { | 72 int _packColor(Iterable<int> color) { |
| 74 int packed = 0; | 73 int packed = 0; |
| 75 for (var component in color) { | 74 for (var component in color) { |
| 76 packed = packed * 256 + component; | 75 packed = packed * 256 + component; |
| 77 } | 76 } |
| 78 return packed; | 77 return packed; |
| 79 } | 78 } |
| 80 | 79 |
| 81 void _addClass(int classId, String name, Iterable<int> color) { | 80 void _addClass(int classId, String name, Iterable<int> color) { |
| 82 _classIdToName[classId] = name; | 81 _classIdToName[classId] = name; |
| 83 _classIdToColor[classId] = color; | 82 _classIdToColor[classId] = color; |
| 84 _colorToClassId[_packColor(color)] = classId; | 83 _colorToClassId[_packColor(color)] = classId; |
| 85 } | 84 } |
| 86 | 85 |
| 87 void _updateClassList(classList, int freeClassId) { | 86 void _updateClassList(classList, int freeClassId) { |
| 88 for (var member in classList['members']) { | 87 for (var member in classList['members']) { |
| 89 if (member['type'] != '@Class') { | 88 if (member['type'] != '@Class') { |
| 90 Logger.root.info('$member'); | 89 Logger.root.info('$member'); |
| 91 continue; | 90 continue; |
| 92 } | 91 } |
| 93 var classId = int.parse(member['id'].split('/').last); | 92 var classId = int.parse(member['id'].split('/').last); |
| 94 var color = _classIdToRGBA(classId); | 93 var color = _classIdToRGBA(classId); |
| 95 _addClass(classId, member['user_name'], color); | 94 _addClass(classId, member['user_name'], color); |
| 96 } | 95 } |
| 97 _addClass(freeClassId, 'Free', _freeColor); | 96 _addClass(freeClassId, 'Free', _freeColor); |
| 98 _addClass(0, '', _pageSeparationColor); | 97 _addClass(0, '', _pageSeparationColor); |
| 99 } | 98 } |
| 100 | 99 |
| 101 Iterable<int> _classIdToRGBA(int classId) { | 100 Iterable<int> _classIdToRGBA(int classId) { |
| 102 // TODO(koda): Pick random hue, but fixed saturation and value. | 101 // TODO(koda): Pick random hue, but fixed saturation and value. |
| 103 var rng = new Random(classId); | 102 var rng = new Random(classId); |
| 104 return [rng.nextInt(128), rng.nextInt(128), rng.nextInt(128), 255]; | 103 return [rng.nextInt(128), rng.nextInt(128), rng.nextInt(128), 255]; |
| 105 } | 104 } |
| 106 | 105 |
| 107 String _classNameAt(Point<int> point) { | 106 String _classNameAt(Point<int> point) { |
| 108 var color = new PixelReference(_fragmentationData, point).color; | 107 var color = new PixelReference(_fragmentationData, point).color; |
| 109 return _classIdToName[_colorToClassId[_packColor(color)]]; | 108 return _classIdToName[_colorToClassId[_packColor(color)]]; |
| 110 } | 109 } |
| 111 | 110 |
| 112 // TODO(koda): Find start of object. | 111 // TODO(koda): Find start of object. |
| 113 int _addressAt(Point<int> point) { | 112 int _addressAt(Point<int> point) { |
| 114 var pagePixels = _pageHeight * _fragmentationData.width; | 113 var pagePixels = _pageHeight * _fragmentationData.width; |
| 115 var index = new PixelReference(_fragmentationData, point).index; | 114 var index = new PixelReference(_fragmentationData, point).index; |
| 116 var pageIndex = index ~/ pagePixels; | 115 var pageIndex = index ~/ pagePixels; |
| 117 var pageOffset = index % pagePixels; | 116 var pageOffset = index % pagePixels; |
| 118 var pages = fragmentation['pages']; | 117 var pages = fragmentation['pages']; |
| 119 if (0 <= pageIndex && pageIndex < pages.length) { | 118 if (0 <= pageIndex && pageIndex < pages.length) { |
| 120 return int.parse(pages[pageIndex]['object_start']) + | 119 return int.parse(pages[pageIndex]['object_start']) + |
| 121 pageOffset * fragmentation['unit_size_bytes']; | 120 pageOffset * fragmentation['unit_size_bytes']; |
| 122 } else { | 121 } else { |
| 123 return 0; | 122 return 0; |
| 124 } | 123 } |
| 125 } | 124 } |
| 126 | 125 |
| 127 void _handleMouseMove(MouseEvent event) { | 126 void _handleMouseMove(MouseEvent event) { |
| 128 var addressString = '@ 0x${_addressAt(event.offset).toRadixString(16)}'; | 127 var addressString = '@ 0x${_addressAt(event.offset).toRadixString(16)}'; |
| 129 var className = _classNameAt(event.offset); | 128 var className = _classNameAt(event.offset); |
| 130 status = (className == '') ? '-' : '$className $addressString'; | 129 status = (className == '') ? '-' : '$className $addressString'; |
| 131 } | 130 } |
| 132 | 131 |
| 133 void _updateFragmentationData() { | 132 void _updateFragmentationData() { |
| 134 if (fragmentation == null || _fragmentationCanvas == null) { | 133 if (fragmentation == null || _fragmentationCanvas == null) { |
| 135 return; | 134 return; |
| 136 } | 135 } |
| 137 _updateClassList( | 136 _updateClassList( |
| 138 fragmentation['class_list'], fragmentation['free_class_id']); | 137 fragmentation['class_list'], fragmentation['free_class_id']); |
| 139 var pages = fragmentation['pages']; | 138 var pages = fragmentation['pages']; |
| 140 var width = _fragmentationCanvas.parent.client.width; | 139 var width = _fragmentationCanvas.parent.client.width; |
| 141 _pageHeight = _PAGE_SEPARATION_HEIGHT + | 140 _pageHeight = _PAGE_SEPARATION_HEIGHT + |
| 142 fragmentation['page_size_bytes'] ~/ | 141 fragmentation['page_size_bytes'] ~/ |
| 143 fragmentation['unit_size_bytes'] ~/ width; | 142 fragmentation['unit_size_bytes'] ~/ width; |
| 144 var height = _pageHeight * pages.length; | 143 var height = _pageHeight * pages.length; |
| 145 _fragmentationData = | 144 _fragmentationData = |
| 146 _fragmentationCanvas.context2D.createImageData(width, height); | 145 _fragmentationCanvas.context2D.createImageData(width, height); |
| 147 _fragmentationCanvas.width = _fragmentationData.width; | 146 _fragmentationCanvas.width = _fragmentationData.width; |
| 148 _fragmentationCanvas.height = _fragmentationData.height; | 147 _fragmentationCanvas.height = _fragmentationData.height; |
| 149 _renderPages(0); | 148 _renderPages(0); |
| 150 } | 149 } |
| 151 | 150 |
| 152 // Renders and draws asynchronously, one page at a time to avoid | 151 // Renders and draws asynchronously, one page at a time to avoid |
| 153 // blocking the UI. | 152 // blocking the UI. |
| 154 void _renderPages(int startPage) { | 153 void _renderPages(int startPage) { |
| 155 var pages = fragmentation['pages']; | 154 var pages = fragmentation['pages']; |
| 156 status = 'Loaded $startPage of ${pages.length} pages'; | 155 status = 'Loaded $startPage of ${pages.length} pages'; |
| 157 if (startPage >= pages.length) { | 156 if (startPage >= pages.length) { |
| 158 return; | 157 return; |
| 159 } | 158 } |
| 160 var startY = startPage * _pageHeight; | 159 var startY = startPage * _pageHeight; |
| 161 var pixel = new PixelReference(_fragmentationData, new Point(0, startY)); | 160 var pixel = new PixelReference(_fragmentationData, new Point(0, startY)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 194 }).whenComplete(done); | 193 }).whenComplete(done); |
| 195 } | 194 } |
| 196 | 195 |
| 197 void fragmentationChanged(oldValue) { | 196 void fragmentationChanged(oldValue) { |
| 198 // Async, in case enteredView has not yet run (observed in JS version). | 197 // Async, in case enteredView has not yet run (observed in JS version). |
| 199 new Future(() { | 198 new Future(() { |
| 200 _updateFragmentationData(); | 199 _updateFragmentationData(); |
| 201 }); | 200 }); |
| 202 } | 201 } |
| 203 } | 202 } |
| OLD | NEW |