| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 cpu_profile_table_element; | 5 library cpu_profile_table_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:html'; | 8 import 'dart:html'; |
| 9 import 'package:observatory/models.dart' as M; | 9 import 'package:observatory/models.dart' as M; |
| 10 import 'package:observatory/src/elements/containers/virtual_collection.dart'; | 10 import 'package:observatory/src/elements/containers/virtual_collection.dart'; |
| 11 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart'; | 11 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart'; |
| 12 import 'package:observatory/src/elements/function_ref.dart'; | 12 import 'package:observatory/src/elements/function_ref.dart'; |
| 13 import 'package:observatory/src/elements/helpers/nav_bar.dart'; | 13 import 'package:observatory/src/elements/helpers/nav_bar.dart'; |
| 14 import 'package:observatory/src/elements/helpers/nav_menu.dart'; | 14 import 'package:observatory/src/elements/helpers/nav_menu.dart'; |
| 15 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; | 15 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 16 import 'package:observatory/src/elements/helpers/tag.dart'; | 16 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 17 import 'package:observatory/src/elements/nav/isolate_menu.dart'; | 17 import 'package:observatory/src/elements/nav/isolate_menu.dart'; |
| 18 import 'package:observatory/src/elements/nav/notify.dart'; | 18 import 'package:observatory/src/elements/nav/notify.dart'; |
| 19 import 'package:observatory/src/elements/nav/refresh.dart'; | 19 import 'package:observatory/src/elements/nav/refresh.dart'; |
| 20 import 'package:observatory/src/elements/nav/top_menu.dart'; | 20 import 'package:observatory/src/elements/nav/top_menu.dart'; |
| 21 import 'package:observatory/src/elements/nav/vm_menu.dart'; | 21 import 'package:observatory/src/elements/nav/vm_menu.dart'; |
| 22 import 'package:observatory/src/elements/sample_buffer_control.dart'; | 22 import 'package:observatory/src/elements/sample_buffer_control.dart'; |
| 23 import 'package:observatory/src/elements/stack_trace_tree_config.dart'; | 23 import 'package:observatory/src/elements/stack_trace_tree_config.dart'; |
| 24 import 'package:observatory/utils.dart'; | 24 import 'package:observatory/utils.dart'; |
| 25 | 25 |
| 26 enum _Table { | 26 enum _Table { functions, caller, callee } |
| 27 functions, | |
| 28 caller, | |
| 29 callee | |
| 30 } | |
| 31 | 27 |
| 32 enum _SortingField { | 28 enum _SortingField { exclusive, inclusive, caller, callee, method } |
| 33 exclusive, | |
| 34 inclusive, | |
| 35 caller, | |
| 36 callee, | |
| 37 method | |
| 38 } | |
| 39 | 29 |
| 40 enum _SortingDirection { | 30 enum _SortingDirection { ascending, descending } |
| 41 ascending, | |
| 42 descending | |
| 43 } | |
| 44 | 31 |
| 45 class CpuProfileTableElement extends HtmlElement implements Renderable { | 32 class CpuProfileTableElement extends HtmlElement implements Renderable { |
| 46 static const tag = const Tag<CpuProfileTableElement>('cpu-profile-table', | 33 static const tag = const Tag<CpuProfileTableElement>('cpu-profile-table', |
| 47 dependencies: const [ | 34 dependencies: const [ |
| 48 FunctionRefElement.tag, | 35 FunctionRefElement.tag, |
| 49 NavTopMenuElement.tag, | 36 NavTopMenuElement.tag, |
| 50 NavVMMenuElement.tag, | 37 NavVMMenuElement.tag, |
| 51 NavIsolateMenuElement.tag, | 38 NavIsolateMenuElement.tag, |
| 52 NavRefreshElement.tag, | 39 NavRefreshElement.tag, |
| 53 NavNotifyElement.tag, | 40 NavNotifyElement.tag, |
| 54 SampleBufferControlElement.tag, | 41 SampleBufferControlElement.tag, |
| 55 StackTraceTreeConfigElement.tag, | 42 StackTraceTreeConfigElement.tag, |
| 56 CpuProfileVirtualTreeElement.tag, | 43 CpuProfileVirtualTreeElement.tag, |
| 57 VirtualCollectionElement.tag | 44 VirtualCollectionElement.tag |
| 58 ]); | 45 ]); |
| 59 | 46 |
| 60 RenderingScheduler<CpuProfileTableElement> _r; | 47 RenderingScheduler<CpuProfileTableElement> _r; |
| 61 | 48 |
| 62 Stream<RenderedEvent<CpuProfileTableElement>> get onRendered => _r.onRendered; | 49 Stream<RenderedEvent<CpuProfileTableElement>> get onRendered => _r.onRendered; |
| 63 | 50 |
| 64 M.VM _vm; | 51 M.VM _vm; |
| 65 M.IsolateRef _isolate; | 52 M.IsolateRef _isolate; |
| 66 M.EventRepository _events; | 53 M.EventRepository _events; |
| 67 M.NotificationRepository _notifications; | 54 M.NotificationRepository _notifications; |
| 68 M.IsolateSampleProfileRepository _profiles; | 55 M.IsolateSampleProfileRepository _profiles; |
| 69 Stream<M.SampleProfileLoadingProgressEvent> _progressStream; | 56 Stream<M.SampleProfileLoadingProgressEvent> _progressStream; |
| 70 M.SampleProfileLoadingProgress _progress; | 57 M.SampleProfileLoadingProgress _progress; |
| 71 final _sortingField = <_Table, _SortingField>{ | 58 final _sortingField = <_Table, _SortingField>{ |
| 72 _Table.functions : _SortingField.exclusive, | 59 _Table.functions: _SortingField.exclusive, |
| 73 _Table.caller : _SortingField.caller, | 60 _Table.caller: _SortingField.caller, |
| 74 _Table.callee : _SortingField.callee, | 61 _Table.callee: _SortingField.callee, |
| 75 }; | 62 }; |
| 76 final _sortingDirection = <_Table, _SortingDirection>{ | 63 final _sortingDirection = <_Table, _SortingDirection>{ |
| 77 _Table.functions : _SortingDirection.descending, | 64 _Table.functions: _SortingDirection.descending, |
| 78 _Table.caller : _SortingDirection.descending, | 65 _Table.caller: _SortingDirection.descending, |
| 79 _Table.callee : _SortingDirection.descending, | 66 _Table.callee: _SortingDirection.descending, |
| 80 }; | 67 }; |
| 81 String _filter = ''; | 68 String _filter = ''; |
| 82 | 69 |
| 83 | |
| 84 M.IsolateRef get isolate => _isolate; | 70 M.IsolateRef get isolate => _isolate; |
| 85 M.NotificationRepository get notifications => _notifications; | 71 M.NotificationRepository get notifications => _notifications; |
| 86 M.IsolateSampleProfileRepository get profiles => _profiles; | 72 M.IsolateSampleProfileRepository get profiles => _profiles; |
| 87 M.VMRef get vm => _vm; | 73 M.VMRef get vm => _vm; |
| 88 | 74 |
| 89 factory CpuProfileTableElement(M.VM vm, M.IsolateRef isolate, | 75 factory CpuProfileTableElement( |
| 90 M.EventRepository events, | 76 M.VM vm, |
| 91 M.NotificationRepository notifications, | 77 M.IsolateRef isolate, |
| 92 M.IsolateSampleProfileRepository profiles, | 78 M.EventRepository events, |
| 93 {RenderingQueue queue}) { | 79 M.NotificationRepository notifications, |
| 80 M.IsolateSampleProfileRepository profiles, |
| 81 {RenderingQueue queue}) { |
| 94 assert(vm != null); | 82 assert(vm != null); |
| 95 assert(isolate != null); | 83 assert(isolate != null); |
| 96 assert(events != null); | 84 assert(events != null); |
| 97 assert(notifications != null); | 85 assert(notifications != null); |
| 98 assert(profiles != null); | 86 assert(profiles != null); |
| 99 CpuProfileTableElement e = document.createElement(tag.name); | 87 CpuProfileTableElement e = document.createElement(tag.name); |
| 100 e._r = new RenderingScheduler(e, queue: queue); | 88 e._r = new RenderingScheduler(e, queue: queue); |
| 101 e._vm = vm; | 89 e._vm = vm; |
| 102 e._isolate = isolate; | 90 e._isolate = isolate; |
| 103 e._events = events; | 91 e._events = events; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 122 children = []; | 110 children = []; |
| 123 } | 111 } |
| 124 | 112 |
| 125 void render() { | 113 void render() { |
| 126 var content = [ | 114 var content = [ |
| 127 navBar([ | 115 navBar([ |
| 128 new NavTopMenuElement(queue: _r.queue), | 116 new NavTopMenuElement(queue: _r.queue), |
| 129 new NavVMMenuElement(_vm, _events, queue: _r.queue), | 117 new NavVMMenuElement(_vm, _events, queue: _r.queue), |
| 130 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), | 118 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), |
| 131 navMenu('cpu profile (table)'), | 119 navMenu('cpu profile (table)'), |
| 132 new NavRefreshElement(queue: _r.queue) | 120 new NavRefreshElement(queue: _r.queue)..onRefresh.listen(_refresh), |
| 133 ..onRefresh.listen(_refresh), | |
| 134 new NavRefreshElement(label: 'Clear', queue: _r.queue) | 121 new NavRefreshElement(label: 'Clear', queue: _r.queue) |
| 135 ..onRefresh.listen(_clearCpuProfile), | 122 ..onRefresh.listen(_clearCpuProfile), |
| 136 new NavNotifyElement(_notifications, queue: _r.queue) | 123 new NavNotifyElement(_notifications, queue: _r.queue) |
| 137 ]), | 124 ]), |
| 138 ]; | 125 ]; |
| 139 if (_progress == null) { | 126 if (_progress == null) { |
| 140 children = content; | 127 children = content; |
| 141 return; | 128 return; |
| 142 } | 129 } |
| 143 content.add(new SampleBufferControlElement(_progress, _progressStream, | 130 content.add(new SampleBufferControlElement(_progress, _progressStream, |
| 144 showTag: false, queue: _r.queue)); | 131 showTag: false, queue: _r.queue)); |
| 145 if (_progress.status == M.SampleProfileLoadingStatus.loaded) { | 132 if (_progress.status == M.SampleProfileLoadingStatus.loaded) { |
| 146 content.add(new BRElement()); | 133 content.add(new BRElement()); |
| 147 content.addAll(_createTables()); | 134 content.addAll(_createTables()); |
| 148 content.add(new BRElement()); | 135 content.add(new BRElement()); |
| 149 content.addAll(_createTree()); | 136 content.addAll(_createTree()); |
| 150 } | 137 } |
| 151 children = content; | 138 children = content; |
| 152 } | 139 } |
| 153 | 140 |
| 154 M.ProfileFunction _selected; | 141 M.ProfileFunction _selected; |
| 155 VirtualCollectionElement _functions; | 142 VirtualCollectionElement _functions; |
| 156 VirtualCollectionElement _callers; | 143 VirtualCollectionElement _callers; |
| 157 VirtualCollectionElement _callees; | 144 VirtualCollectionElement _callees; |
| 158 | 145 |
| 159 List<Element> _createTables() { | 146 List<Element> _createTables() { |
| 160 _functions = _functions ?? new VirtualCollectionElement( | 147 _functions = _functions ?? |
| 161 _createFunction, | 148 new VirtualCollectionElement(_createFunction, _updateFunction, |
| 162 _updateFunction, | 149 createHeader: _createFunctionHeader, queue: _r.queue); |
| 163 createHeader: _createFunctionHeader, | |
| 164 queue: _r.queue | |
| 165 ); | |
| 166 _functions.items = _progress.profile.functions.toList() | 150 _functions.items = _progress.profile.functions.toList() |
| 167 ..sort(_createSorter(_Table.functions)); | 151 ..sort(_createSorter(_Table.functions)); |
| 168 _functions.takeIntoView(_selected); | 152 _functions.takeIntoView(_selected); |
| 169 _callers = _callers ?? new VirtualCollectionElement( | 153 _callers = _callers ?? |
| 170 _createCaller, | 154 new VirtualCollectionElement(_createCaller, _updateCaller, |
| 171 _updateCaller, | 155 createHeader: _createCallerHeader, queue: _r.queue); |
| 172 createHeader: _createCallerHeader, | 156 _callees = _callees ?? |
| 173 queue: _r.queue | 157 new VirtualCollectionElement(_createCallee, _updateCallee, |
| 174 ); | 158 createHeader: _createCalleeHeader, queue: _r.queue); |
| 175 _callees = _callees ?? new VirtualCollectionElement( | |
| 176 _createCallee, | |
| 177 _updateCallee, | |
| 178 createHeader: _createCalleeHeader, | |
| 179 queue: _r.queue | |
| 180 ); | |
| 181 if (_selected != null) { | 159 if (_selected != null) { |
| 182 _callers.items = _selected.callers.keys.toList() | 160 _callers.items = _selected.callers.keys.toList() |
| 183 ..sort(_createSorter(_Table.caller)); | 161 ..sort(_createSorter(_Table.caller)); |
| 184 _callees.items = _selected.callees.keys.toList() | 162 _callees.items = _selected.callees.keys.toList() |
| 185 ..sort(_createSorter(_Table.callee)); | 163 ..sort(_createSorter(_Table.callee)); |
| 186 } else { | 164 } else { |
| 187 _callers.items = const []; | 165 _callers.items = const []; |
| 188 _callees.items = const []; | 166 _callees.items = const []; |
| 189 } | 167 } |
| 190 return [ | 168 return [ |
| 191 new DivElement()..classes = ['profile-trees'] | 169 new DivElement() |
| 170 ..classes = ['profile-trees'] |
| 192 ..children = [ | 171 ..children = [ |
| 193 new DivElement()..classes = ['profile-trees-all'] | 172 new DivElement() |
| 173 ..classes = ['profile-trees-all'] |
| 194 ..children = [_functions], | 174 ..children = [_functions], |
| 195 new DivElement()..classes = ['profile-trees-current'] | 175 new DivElement() |
| 176 ..classes = ['profile-trees-current'] |
| 196 ..children = [ | 177 ..children = [ |
| 197 new DivElement()..classes = ['profile-trees-caller'] | 178 new DivElement() |
| 179 ..classes = ['profile-trees-caller'] |
| 198 ..children = [_callers], | 180 ..children = [_callers], |
| 199 new DivElement()..classes = ['profile-trees-selected'] | 181 new DivElement() |
| 182 ..classes = ['profile-trees-selected'] |
| 200 ..children = _selected == null | 183 ..children = _selected == null |
| 201 ? [new SpanElement()..text = 'No element selected'] | 184 ? [new SpanElement()..text = 'No element selected'] |
| 202 : [new FunctionRefElement(_isolate, _selected.function, | 185 : [ |
| 203 queue : _r.queue)], | 186 new FunctionRefElement(_isolate, _selected.function, |
| 204 new DivElement()..classes = ['profile-trees-callee'] | 187 queue: _r.queue) |
| 188 ], |
| 189 new DivElement() |
| 190 ..classes = ['profile-trees-callee'] |
| 205 ..children = [_callees] | 191 ..children = [_callees] |
| 206 ] | 192 ] |
| 207 ] | 193 ] |
| 208 ]; | 194 ]; |
| 209 } | 195 } |
| 210 | 196 |
| 211 Element _createFunction() { | 197 Element _createFunction() { |
| 212 final element = new DivElement() | 198 final element = new DivElement() |
| 213 ..classes = ['function-item'] | 199 ..classes = ['function-item'] |
| 214 ..children = [ | 200 ..children = [ |
| 215 new SpanElement()..classes = ['exclusive'] | 201 new SpanElement() |
| 202 ..classes = ['exclusive'] |
| 216 ..text = '0%', | 203 ..text = '0%', |
| 217 new SpanElement()..classes = ['inclusive'] | 204 new SpanElement() |
| 205 ..classes = ['inclusive'] |
| 218 ..text = '0%', | 206 ..text = '0%', |
| 219 new SpanElement()..classes = ['name'] | 207 new SpanElement()..classes = ['name'] |
| 220 ]; | 208 ]; |
| 221 element.onClick.listen((e) { | 209 element.onClick.listen((e) { |
| 222 if (e.target is AnchorElement) { | 210 if (e.target is AnchorElement) { |
| 223 return; | 211 return; |
| 224 } | 212 } |
| 225 _selected = _functions.getItemFromElement(element); | 213 _selected = _functions.getItemFromElement(element); |
| 226 _r.dirty(); | 214 _r.dirty(); |
| 227 }); | 215 }); |
| 228 return element; | 216 return element; |
| 229 } | 217 } |
| 230 | 218 |
| 231 void _updateFunction(Element e, M.ProfileFunction item, int index) { | 219 void _updateFunction(Element e, M.ProfileFunction item, int index) { |
| 232 if (item == _selected) { | 220 if (item == _selected) { |
| 233 e.classes = ['function-item', 'selected']; | 221 e.classes = ['function-item', 'selected']; |
| 234 } else { | 222 } else { |
| 235 e.classes = ['function-item']; | 223 e.classes = ['function-item']; |
| 236 } | 224 } |
| 237 e.children[0].text = Utils.formatPercentNormalized(_getExclusiveT(item)); | 225 e.children[0].text = Utils.formatPercentNormalized(_getExclusiveT(item)); |
| 238 e.children[1].text = Utils.formatPercentNormalized(_getInclusiveT(item)); | 226 e.children[1].text = Utils.formatPercentNormalized(_getInclusiveT(item)); |
| 239 e.children[2] = new FunctionRefElement(_isolate, item.function, | 227 e.children[2] = new FunctionRefElement(_isolate, item.function, |
| 240 queue: _r.queue)..classes = ['name']; | 228 queue: _r.queue)..classes = ['name']; |
| 241 } | 229 } |
| 242 | 230 |
| 243 Element _createFunctionHeader() => | 231 Element _createFunctionHeader() => new DivElement() |
| 244 new DivElement() | 232 ..classes = ['function-item'] |
| 245 ..classes = ['function-item'] | 233 ..children = [ |
| 246 ..children = [ | 234 _createHeaderButton(const ['exclusive'], 'Execution(%)', _Table.functions, |
| 247 _createHeaderButton(const ['exclusive'], 'Execution(%)', | 235 _SortingField.exclusive, _SortingDirection.descending), |
| 248 _Table.functions, | 236 _createHeaderButton(const ['inclusive'], 'Stack(%)', _Table.functions, |
| 249 _SortingField.exclusive, | 237 _SortingField.inclusive, _SortingDirection.descending), |
| 250 _SortingDirection.descending), | 238 _createHeaderButton(const ['name'], 'Method', _Table.functions, |
| 251 _createHeaderButton(const ['inclusive'], 'Stack(%)', | 239 _SortingField.method, _SortingDirection.ascending), |
| 252 _Table.functions, | 240 ]; |
| 253 _SortingField.inclusive, | |
| 254 _SortingDirection.descending), | |
| 255 _createHeaderButton(const ['name'], 'Method', | |
| 256 _Table.functions, | |
| 257 _SortingField.method, | |
| 258 _SortingDirection.ascending), | |
| 259 ]; | |
| 260 | 241 |
| 261 void _setSorting(_Table table, | 242 void _setSorting( |
| 262 _SortingField field, | 243 _Table table, _SortingField field, _SortingDirection defaultDirection) { |
| 263 _SortingDirection defaultDirection) { | 244 if (_sortingField[table] == field) { |
| 264 if (_sortingField[table] == field) { | 245 switch (_sortingDirection[table]) { |
| 265 switch (_sortingDirection[table]) { | 246 case _SortingDirection.descending: |
| 266 case _SortingDirection.descending: | 247 _sortingDirection[table] = _SortingDirection.ascending; |
| 267 _sortingDirection[table] = _SortingDirection.ascending; | 248 break; |
| 268 break; | 249 case _SortingDirection.ascending: |
| 269 case _SortingDirection.ascending: | 250 _sortingDirection[table] = _SortingDirection.descending; |
| 270 _sortingDirection[table] = _SortingDirection.descending; | 251 break; |
| 271 break; | |
| 272 } | |
| 273 } else { | |
| 274 _sortingDirection[table] = defaultDirection; | |
| 275 _sortingField[table] = field; | |
| 276 } | 252 } |
| 277 _r.dirty(); | 253 } else { |
| 254 _sortingDirection[table] = defaultDirection; |
| 255 _sortingField[table] = field; |
| 278 } | 256 } |
| 257 _r.dirty(); |
| 258 } |
| 279 | 259 |
| 280 Element _createCallee() { | 260 Element _createCallee() { |
| 281 final element = new DivElement() | 261 final element = new DivElement() |
| 282 ..classes = ['function-item'] | 262 ..classes = ['function-item'] |
| 283 ..children = [ | 263 ..children = [ |
| 284 new SpanElement()..classes = ['inclusive'] | 264 new SpanElement() |
| 265 ..classes = ['inclusive'] |
| 285 ..text = '0%', | 266 ..text = '0%', |
| 286 new SpanElement()..classes = ['name'] | 267 new SpanElement()..classes = ['name'] |
| 287 ]; | 268 ]; |
| 288 element.onClick.listen((e) { | 269 element.onClick.listen((e) { |
| 289 if (e.target is AnchorElement) { | 270 if (e.target is AnchorElement) { |
| 290 return; | 271 return; |
| 291 } | 272 } |
| 292 _selected = _callees.getItemFromElement(element); | 273 _selected = _callees.getItemFromElement(element); |
| 293 _r.dirty(); | 274 _r.dirty(); |
| 294 }); | 275 }); |
| 295 return element; | 276 return element; |
| 296 } | 277 } |
| 297 | 278 |
| 298 void _updateCallee(Element e, item, int index) { | 279 void _updateCallee(Element e, item, int index) { |
| 299 e.children[0].text = Utils.formatPercentNormalized(_getCalleeT(item)); | 280 e.children[0].text = Utils.formatPercentNormalized(_getCalleeT(item)); |
| 300 e.children[1] = new FunctionRefElement(_isolate, item.function, | 281 e.children[1] = new FunctionRefElement(_isolate, item.function, |
| 301 queue: _r.queue)..classes = ['name']; | 282 queue: _r.queue)..classes = ['name']; |
| 302 } | 283 } |
| 303 | 284 |
| 304 Element _createCalleeHeader() => | 285 Element _createCalleeHeader() => new DivElement() |
| 305 new DivElement() | 286 ..classes = ['function-item'] |
| 306 ..classes = ['function-item'] | 287 ..children = [ |
| 307 ..children = [ | 288 _createHeaderButton(const ['inclusive'], 'Callees(%)', _Table.callee, |
| 308 _createHeaderButton(const ['inclusive'], 'Callees(%)', | 289 _SortingField.callee, _SortingDirection.descending), |
| 309 _Table.callee, | 290 _createHeaderButton(const ['name'], 'Method', _Table.callee, |
| 310 _SortingField.callee, | 291 _SortingField.method, _SortingDirection.ascending), |
| 311 _SortingDirection.descending), | 292 ]; |
| 312 _createHeaderButton(const ['name'], 'Method', | |
| 313 _Table.callee, | |
| 314 _SortingField.method, | |
| 315 _SortingDirection.ascending), | |
| 316 ]; | |
| 317 | 293 |
| 318 Element _createCaller() { | 294 Element _createCaller() { |
| 319 final element = new DivElement() | 295 final element = new DivElement() |
| 320 ..classes = ['function-item'] | 296 ..classes = ['function-item'] |
| 321 ..children = [ | 297 ..children = [ |
| 322 new SpanElement()..classes = ['inclusive'] | 298 new SpanElement() |
| 299 ..classes = ['inclusive'] |
| 323 ..text = '0%', | 300 ..text = '0%', |
| 324 new SpanElement()..classes = ['name'] | 301 new SpanElement()..classes = ['name'] |
| 325 ]; | 302 ]; |
| 326 element.onClick.listen((e) { | 303 element.onClick.listen((e) { |
| 327 if (e.target is AnchorElement) { | 304 if (e.target is AnchorElement) { |
| 328 return; | 305 return; |
| 329 } | 306 } |
| 330 _selected = _callers.getItemFromElement(element); | 307 _selected = _callers.getItemFromElement(element); |
| 331 _r.dirty(); | 308 _r.dirty(); |
| 332 }); | 309 }); |
| 333 return element; | 310 return element; |
| 334 } | 311 } |
| 335 | 312 |
| 336 void _updateCaller(Element e, item, int index) { | 313 void _updateCaller(Element e, item, int index) { |
| 337 e.children[0].text = Utils.formatPercentNormalized(_getCallerT(item)); | 314 e.children[0].text = Utils.formatPercentNormalized(_getCallerT(item)); |
| 338 e.children[1] = new FunctionRefElement(_isolate, item.function, | 315 e.children[1] = new FunctionRefElement(_isolate, item.function, |
| 339 queue: _r.queue)..classes = ['name']; | 316 queue: _r.queue)..classes = ['name']; |
| 340 } | 317 } |
| 341 | 318 |
| 342 Element _createCallerHeader() => | 319 Element _createCallerHeader() => new DivElement() |
| 343 new DivElement() | 320 ..classes = ['function-item'] |
| 344 ..classes = ['function-item'] | 321 ..children = [ |
| 345 ..children = [ | 322 _createHeaderButton(const ['inclusive'], 'Callers(%)', _Table.caller, |
| 346 _createHeaderButton(const ['inclusive'], 'Callers(%)', | 323 _SortingField.caller, _SortingDirection.descending), |
| 347 _Table.caller, | 324 _createHeaderButton(const ['name'], 'Method', _Table.caller, |
| 348 _SortingField.caller, | 325 _SortingField.method, _SortingDirection.ascending), |
| 349 _SortingDirection.descending), | 326 ]; |
| 350 _createHeaderButton(const ['name'], 'Method', | |
| 351 _Table.caller, | |
| 352 _SortingField.method, | |
| 353 _SortingDirection.ascending), | |
| 354 ]; | |
| 355 | 327 |
| 356 ButtonElement _createHeaderButton(List<String> classes, | 328 ButtonElement _createHeaderButton(List<String> classes, String text, |
| 357 String text, | 329 _Table table, _SortingField field, _SortingDirection direction) => |
| 358 _Table table, | 330 new ButtonElement() |
| 359 _SortingField field, | 331 ..classes = classes |
| 360 _SortingDirection direction) => | 332 ..text = _sortingField[table] != field |
| 361 new ButtonElement()..classes = classes | 333 ? text |
| 362 ..text = _sortingField[table] != field ? text : | 334 : _sortingDirection[table] == _SortingDirection.ascending |
| 363 _sortingDirection[table] == _SortingDirection.ascending | 335 ? '$text▼' |
| 364 ? '$text▼' : '$text▲' | 336 : '$text▲' |
| 365 ..onClick.listen((_) => _setSorting(table, field, direction)); | 337 ..onClick.listen((_) => _setSorting(table, field, direction)); |
| 366 | 338 |
| 367 List<Element> _createTree() { | 339 List<Element> _createTree() { |
| 368 CpuProfileVirtualTreeElement tree; | 340 CpuProfileVirtualTreeElement tree; |
| 369 return [ | 341 return [ |
| 370 new StackTraceTreeConfigElement(showMode: false, | 342 new StackTraceTreeConfigElement( |
| 371 showDirection: false, mode: ProfileTreeMode.function, | 343 showMode: false, |
| 372 direction: M.ProfileTreeDirection.exclusive, filter: _filter, | 344 showDirection: false, |
| 373 queue: _r.queue) | 345 mode: ProfileTreeMode.function, |
| 346 direction: M.ProfileTreeDirection.exclusive, |
| 347 filter: _filter, |
| 348 queue: _r.queue) |
| 374 ..onFilterChange.listen((e) { | 349 ..onFilterChange.listen((e) { |
| 375 _filter = e.element.filter.trim(); | 350 _filter = e.element.filter.trim(); |
| 376 tree.filters = _filter.isNotEmpty | 351 tree.filters = _filter.isNotEmpty |
| 377 ? [_filterTree, (node) { return node.name.contains(_filter); }] | 352 ? [ |
| 378 : [_filterTree]; | 353 _filterTree, |
| 354 (node) { |
| 355 return node.name.contains(_filter); |
| 356 } |
| 357 ] |
| 358 : [_filterTree]; |
| 379 }), | 359 }), |
| 380 new BRElement(), | 360 new BRElement(), |
| 381 tree = new CpuProfileVirtualTreeElement(_isolate, _progress.profile, | 361 tree = new CpuProfileVirtualTreeElement(_isolate, _progress.profile, |
| 382 mode: ProfileTreeMode.function, | 362 mode: ProfileTreeMode.function, |
| 383 direction: M.ProfileTreeDirection.exclusive, | 363 direction: M.ProfileTreeDirection.exclusive, |
| 384 queue: _r.queue) | 364 queue: _r.queue) |
| 385 ..filters = _filter.isNotEmpty | 365 ..filters = _filter.isNotEmpty |
| 386 ? [_filterTree, (node) { return node.name.contains(_filter); }] | 366 ? [ |
| 367 _filterTree, |
| 368 (node) { |
| 369 return node.name.contains(_filter); |
| 370 } |
| 371 ] |
| 387 : [_filterTree] | 372 : [_filterTree] |
| 388 ]; | 373 ]; |
| 389 } | 374 } |
| 390 | 375 |
| 391 bool _filterTree(M.FunctionCallTreeNode node) => | 376 bool _filterTree(M.FunctionCallTreeNode node) => |
| 392 node.profileFunction == _selected; | 377 node.profileFunction == _selected; |
| 393 | 378 |
| 394 Future _request({bool clear: false, bool forceFetch: false}) async { | 379 Future _request({bool clear: false, bool forceFetch: false}) async { |
| 395 _progress = null; | 380 _progress = null; |
| 396 _progressStream = _profiles.get(isolate, M.SampleProfileTag.none, | 381 _progressStream = _profiles.get(isolate, M.SampleProfileTag.none, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 425 case _SortingField.inclusive: | 410 case _SortingField.inclusive: |
| 426 getter = _getInclusiveT; | 411 getter = _getInclusiveT; |
| 427 break; | 412 break; |
| 428 case _SortingField.callee: | 413 case _SortingField.callee: |
| 429 getter = _getCalleeT; | 414 getter = _getCalleeT; |
| 430 break; | 415 break; |
| 431 case _SortingField.caller: | 416 case _SortingField.caller: |
| 432 getter = _getCallerT; | 417 getter = _getCallerT; |
| 433 break; | 418 break; |
| 434 case _SortingField.method: | 419 case _SortingField.method: |
| 435 getter = (M.ProfileFunction s) => | 420 getter = (M.ProfileFunction s) => M.getFunctionFullName(s.function); |
| 436 M.getFunctionFullName(s.function); | |
| 437 break; | 421 break; |
| 438 } | 422 } |
| 439 switch (_sortingDirection[table]) { | 423 switch (_sortingDirection[table]) { |
| 440 case _SortingDirection.ascending: | 424 case _SortingDirection.ascending: |
| 441 return (a, b) => getter(a).compareTo(getter(b)); | 425 return (a, b) => getter(a).compareTo(getter(b)); |
| 442 case _SortingDirection.descending: | 426 case _SortingDirection.descending: |
| 443 return (a, b) => getter(b).compareTo(getter(a)); | 427 return (a, b) => getter(b).compareTo(getter(a)); |
| 444 } | 428 } |
| 445 } | 429 } |
| 446 | 430 |
| 447 static double _getExclusiveT(M.ProfileFunction f) => | 431 static double _getExclusiveT(M.ProfileFunction f) => |
| 448 f.normalizedExclusiveTicks; | 432 f.normalizedExclusiveTicks; |
| 449 static double _getInclusiveT(M.ProfileFunction f) => | 433 static double _getInclusiveT(M.ProfileFunction f) => |
| 450 f.normalizedInclusiveTicks; | 434 f.normalizedInclusiveTicks; |
| 451 double _getCalleeT(M.ProfileFunction f) => | 435 double _getCalleeT(M.ProfileFunction f) => |
| 452 _selected.callees[f] / _selected.callees.values.reduce((a, b) => a + b); | 436 _selected.callees[f] / _selected.callees.values.reduce((a, b) => a + b); |
| 453 double _getCallerT(M.ProfileFunction f) => | 437 double _getCallerT(M.ProfileFunction f) => |
| 454 _selected.callers[f] / _selected.callers.values.reduce((a, b) => a + b); | 438 _selected.callers[f] / _selected.callers.values.reduce((a, b) => a + b); |
| 455 } | 439 } |
| OLD | NEW |