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

Unified Diff: runtime/observatory/lib/src/elements/cpu_profile.dart

Issue 2204563003: Converted Observatory cpu-profile element (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Merged with master Created 4 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 side-by-side diff with in-line comments
Download patch
Index: runtime/observatory/lib/src/elements/cpu_profile.dart
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 82f479d00e370e27122b69741a7412bd50061b6b..0b24b07481f76ea90bf9023d4ca9eb81692f6ee6 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -6,1571 +6,168 @@ library cpu_profile_element;
import 'dart:async';
import 'dart:html';
-import 'observatory_element.dart';
import 'package:observatory/models.dart' as M;
-import 'package:observatory/service.dart';
-import 'package:observatory/app.dart';
-import 'package:observatory/cpu_profile.dart';
-import 'package:observatory/elements.dart';
-import 'package:polymer/polymer.dart';
+import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/sample_buffer_control.dart';
+import 'package:observatory/src/elements/stack_trace_tree_config.dart';
+
+class CpuProfileElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<CpuProfileElement>('cpu-profile',
+ dependencies: const [
+ NavBarElement.tag,
+ NavTopMenuElement.tag,
+ NavVMMenuElement.tag,
+ NavIsolateMenuElement.tag,
+ NavMenuElement.tag,
+ NavMenuElement.tag,
+ NavRefreshElement.tag,
+ NavNotifyElement.tag,
+ SampleBufferControlElement.tag,
+ StackTraceTreeConfigElement.tag,
+ CpuProfileVirtualTreeElement.tag,
+ ]);
+
+ RenderingScheduler<CpuProfileElement> _r;
+
+ Stream<RenderedEvent<CpuProfileElement>> get onRendered => _r.onRendered;
+
+ M.VM _vm;
+ M.IsolateRef _isolate;
+ M.EventRepository _events;
+ M.NotificationRepository _notifications;
+ M.IsolateSampleProfileRepository _profiles;
+ Stream<M.SampleProfileLoadingProgressEvent> _progressStream;
+ M.SampleProfileLoadingProgress _progress;
+ M.SampleProfileTag _tag = M.SampleProfileTag.none;
+ ProfileTreeMode _mode = ProfileTreeMode.function;
+ M.ProfileTreeDirection _direction = M.ProfileTreeDirection.exclusive;
+ String _filter = '';
+
+
+ M.IsolateRef get isolate => _isolate;
+ M.NotificationRepository get notifications => _notifications;
+ M.IsolateSampleProfileRepository get profiles => _profiles;
+ M.VMRef get vm => _vm;
+
+ factory CpuProfileElement(M.VM vm, M.IsolateRef isolate,
+ M.EventRepository events,
+ M.NotificationRepository notifications,
+ M.IsolateSampleProfileRepository profiles,
+ {RenderingQueue queue}) {
+ assert(vm != null);
+ assert(isolate != null);
+ assert(events != null);
+ assert(notifications != null);
+ assert(profiles != null);
+ CpuProfileElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._vm = vm;
+ e._isolate = isolate;
+ e._events = events;
+ e._notifications = notifications;
+ e._profiles = profiles;
+ return e;
+ }
+
+ CpuProfileElement.created() : super.created();
-List<String> sorted(Set<String> attributes) {
- var list = attributes.toList();
- list.sort();
- return list;
-}
-
-abstract class ProfileTreeRow<T> extends TableTreeRow {
- final CpuProfile profile;
- final T node;
- final String selfPercent;
- final String percent;
- bool _infoBoxShown = false;
- HtmlElement infoBox;
- HtmlElement infoButton;
-
- ProfileTreeRow(TableTree tree, TableTreeRow parent,
- this.profile, this.node, double selfPercent, double percent)
- : super(tree, parent),
- selfPercent = Utils.formatPercentNormalized(selfPercent),
- percent = Utils.formatPercentNormalized(percent);
-
- static _addToMemberList(DivElement memberList, Map<String, String> items) {
- items.forEach((k, v) {
- var item = new DivElement();
- item.classes.add('memberItem');
- var name = new DivElement();
- name.classes.add('memberName');
- name.text = k;
- var value = new DivElement();
- value.classes.add('memberValue');
- value.text = v;
- item.children.add(name);
- item.children.add(value);
- memberList.children.add(item);
- });
- }
-
- makeInfoBox() {
- if (infoBox != null) {
- return;
- }
- infoBox = new DivElement();
- infoBox.classes.add('infoBox');
- infoBox.classes.add('shadow');
- infoBox.style.display = 'none';
- listeners.add(infoBox.onClick.listen((e) => e.stopPropagation()));
- }
-
- makeInfoButton() {
- infoButton = new SpanElement();
- infoButton.style.marginLeft = 'auto';
- infoButton.style.marginRight = '1em';
- infoButton.children.add(new Element.tag('icon-info-outline'));
- listeners.add(infoButton.onClick.listen((event) {
- event.stopPropagation();
- toggleInfoBox();
- }));
- }
-
- static const attributes = const {
- 'optimized' : const ['O', null, 'Optimized'],
- 'unoptimized' : const ['U', null, 'Unoptimized'],
- 'inlined' : const ['I', null, 'Inlined'],
- 'intrinsic' : const ['It', null, 'Intrinsic'],
- 'ffi' : const ['F', null, 'FFI'],
- 'dart' : const ['D', null, 'Dart'],
- 'tag' : const ['T', null, 'Tag'],
- 'native' : const ['N', null, 'Native'],
- 'stub': const ['S', null, 'Stub'],
- 'synthetic' : const ['?', null, 'Synthetic'],
- };
-
- HtmlElement newAttributeBox(String attribute) {
- List attributeDetails = attributes[attribute];
- if (attributeDetails == null) {
- print('could not find attribute $attribute');
- return null;
- }
- var element = new SpanElement();
- element.style.border = 'solid 2px #ECECEC';
- element.style.height = '100%';
- element.style.display = 'inline-block';
- element.style.textAlign = 'center';
- element.style.minWidth = '1.5em';
- element.style.fontWeight = 'bold';
- if (attributeDetails[1] != null) {
- element.style.backgroundColor = attributeDetails[1];
- }
- element.text = attributeDetails[0];
- element.title = attributeDetails[2];
- return element;
- }
-
- onHide() {
- super.onHide();
- infoBox = null;
- infoButton = null;
- }
-
- showInfoBox() {
- if ((infoButton == null) || (infoBox == null)) {
- return;
- }
- _infoBoxShown = true;
- infoBox.style.display = 'block';
- infoButton.children.clear();
- infoButton.children.add(new Element.tag('icon-info'));
- }
-
- hideInfoBox() {
- _infoBoxShown = false;
- if ((infoButton == null) || (infoBox == null)) {
- return;
- }
- infoBox.style.display = 'none';
- infoButton.children.clear();
- infoButton.children.add(new Element.tag('icon-info-outline'));
- }
-
- toggleInfoBox() {
- if (_infoBoxShown) {
- hideInfoBox();
- } else {
- showInfoBox();
- }
- }
-
- hideAllInfoBoxes() {
- final List<ProfileTreeRow> rows = tree.rows;
- for (var row in rows) {
- row.hideInfoBox();
- }
- }
-
- onClick(MouseEvent e) {
- e.stopPropagation();
- if (e.altKey) {
- bool show = !_infoBoxShown;
- hideAllInfoBoxes();
- if (show) {
- showInfoBox();
- }
- return;
- }
- super.onClick(e);
- }
-
- HtmlElement newCodeRef(ProfileCode code) {
- var codeRef = new Element.tag('code-ref');
- codeRef.ref = code.code;
- return codeRef;
- }
-
- HtmlElement newFunctionRef(ProfileFunction function) {
- var ref = new Element.tag('function-ref');
- ref.ref = function.function;
- return ref;
- }
-
- HtmlElement hr() {
- var element = new HRElement();
- return element;
- }
-
- HtmlElement div(String text) {
- var element = new DivElement();
- element.text = text;
- return element;
- }
-
- HtmlElement br() {
- return new BRElement();
- }
-
- HtmlElement span(String text) {
- var element = new SpanElement();
- element.style.minWidth = '1em';
- element.text = text;
- return element;
- }
-}
-
-class CodeProfileTreeRow extends ProfileTreeRow<CodeCallTreeNode> {
- CodeProfileTreeRow(TableTree tree, CodeProfileTreeRow parent,
- CpuProfile profile, CodeCallTreeNode node)
- : super(tree, parent, profile, node,
- node.profileCode.normalizedExclusiveTicks,
- node.percentage) {
- // fill out attributes.
- }
-
- bool hasChildren() => node.children.length > 0;
-
- void onShow() {
- super.onShow();
-
- if (children.length == 0) {
- for (var childNode in node.children) {
- var row = new CodeProfileTreeRow(tree, this, profile, childNode);
- children.add(row);
- }
- }
-
- // Fill in method column.
- var methodColumn = flexColumns[0];
- methodColumn.style.justifyContent = 'flex-start';
- methodColumn.style.position = 'relative';
-
- // Percent.
- var percentNode = new DivElement();
- percentNode.text = percent;
- percentNode.style.minWidth = '5em';
- percentNode.style.textAlign = 'right';
- percentNode.title = 'Executing: $selfPercent';
- methodColumn.children.add(percentNode);
-
- // Gap.
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- methodColumn.children.add(gap);
-
- // Code link.
- var codeRef = newCodeRef(node.profileCode);
- codeRef.style.alignSelf = 'center';
- methodColumn.children.add(codeRef);
-
- gap = new SpanElement();
- gap.style.minWidth = '1em';
- methodColumn.children.add(gap);
-
- for (var attribute in sorted(node.attributes)) {
- methodColumn.children.add(newAttributeBox(attribute));
- }
-
- makeInfoBox();
- methodColumn.children.add(infoBox);
-
- infoBox.children.add(span('Code '));
- infoBox.children.add(newCodeRef(node.profileCode));
- infoBox.children.add(span(' '));
- for (var attribute in sorted(node.profileCode.attributes)) {
- infoBox.children.add(newAttributeBox(attribute));
- }
- infoBox.children.add(br());
- infoBox.children.add(br());
- var memberList = new DivElement();
- memberList.classes.add('memberList');
- infoBox.children.add(br());
- infoBox.children.add(memberList);
- ProfileTreeRow._addToMemberList(memberList, {
- 'Exclusive ticks' : node.profileCode.formattedExclusiveTicks,
- 'Cpu time' : node.profileCode.formattedCpuTime,
- 'Inclusive ticks' : node.profileCode.formattedInclusiveTicks,
- 'Call stack time' : node.profileCode.formattedOnStackTime,
- });
-
- makeInfoButton();
- methodColumn.children.add(infoButton);
-
- // Fill in self column.
- var selfColumn = flexColumns[1];
- selfColumn.style.position = 'relative';
- selfColumn.style.alignItems = 'center';
- selfColumn.text = selfPercent;
- }
-}
-
-class FunctionProfileTreeRow extends ProfileTreeRow<FunctionCallTreeNode> {
- FunctionProfileTreeRow(TableTree tree, FunctionProfileTreeRow parent,
- CpuProfile profile, FunctionCallTreeNode node)
- : super(tree, parent, profile, node,
- node.profileFunction.normalizedExclusiveTicks,
- node.percentage) {
- // fill out attributes.
- }
-
- bool hasChildren() => node.children.length > 0;
-
- onShow() {
- super.onShow();
- if (children.length == 0) {
- for (var childNode in node.children) {
- var row = new FunctionProfileTreeRow(tree, this, profile, childNode);
- children.add(row);
- }
- }
-
- var methodColumn = flexColumns[0];
- methodColumn.style.justifyContent = 'flex-start';
-
- var codeAndFunctionColumn = new DivElement();
- codeAndFunctionColumn.classes.add('flex-column');
- codeAndFunctionColumn.style.justifyContent = 'center';
- codeAndFunctionColumn.style.width = '100%';
- methodColumn.children.add(codeAndFunctionColumn);
-
- var functionRow = new DivElement();
- functionRow.classes.add('flex-row');
- functionRow.style.position = 'relative';
- functionRow.style.justifyContent = 'flex-start';
- codeAndFunctionColumn.children.add(functionRow);
-
- // Insert the parent percentage
- var parentPercent = new SpanElement();
- parentPercent.text = percent;
- parentPercent.style.minWidth = '4em';
- parentPercent.style.alignSelf = 'center';
- parentPercent.style.textAlign = 'right';
- parentPercent.title = 'Executing: $selfPercent';
- functionRow.children.add(parentPercent);
-
- // Gap.
- var gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.text = ' ';
- functionRow.children.add(gap);
-
- var functionRef = new Element.tag('function-ref');
- functionRef.ref = node.profileFunction.function;
- functionRef.style.alignSelf = 'center';
- functionRow.children.add(functionRef);
-
- gap = new SpanElement();
- gap.style.minWidth = '1em';
- gap.text = ' ';
- functionRow.children.add(gap);
-
- for (var attribute in sorted(node.attributes)) {
- functionRow.children.add(newAttributeBox(attribute));
- }
-
- makeInfoBox();
- functionRow.children.add(infoBox);
-
- if (M.hasDartCode(node.profileFunction.function.kind)) {
- infoBox.children.add(div('Code for current node'));
- infoBox.children.add(br());
- var totalTicks = node.totalCodesTicks;
- var numCodes = node.codes.length;
- for (var i = 0; i < numCodes; i++) {
- var codeRowSpan = new DivElement();
- codeRowSpan.style.paddingLeft = '1em';
- infoBox.children.add(codeRowSpan);
- var nodeCode = node.codes[i];
- var ticks = nodeCode.ticks;
- var percentage = Utils.formatPercent(ticks, totalTicks);
- var percentageSpan = new SpanElement();
- percentageSpan.style.display = 'inline-block';
- percentageSpan.text = '$percentage';
- percentageSpan.style.minWidth = '5em';
- percentageSpan.style.textAlign = 'right';
- codeRowSpan.children.add(percentageSpan);
- var codeRef = new Element.tag('code-ref');
- codeRef.ref = nodeCode.code.code;
- codeRef.style.marginLeft = '1em';
- codeRef.style.marginRight = 'auto';
- codeRef.style.width = '100%';
- codeRowSpan.children.add(codeRef);
- }
- infoBox.children.add(hr());
- }
- infoBox.children.add(span('Function '));
- infoBox.children.add(newFunctionRef(node.profileFunction));
- infoBox.children.add(span(' '));
- for (var attribute in sorted(node.profileFunction.attributes)) {
- infoBox.children.add(newAttributeBox(attribute));
- }
- var memberList = new DivElement();
- memberList.classes.add('memberList');
- infoBox.children.add(br());
- infoBox.children.add(br());
- infoBox.children.add(memberList);
- infoBox.children.add(br());
- ProfileTreeRow._addToMemberList(memberList, {
- 'Exclusive ticks' : node.profileFunction.formattedExclusiveTicks,
- 'Cpu time' : node.profileFunction.formattedCpuTime,
- 'Inclusive ticks' : node.profileFunction.formattedInclusiveTicks,
- 'Call stack time' : node.profileFunction.formattedOnStackTime,
- });
-
- if (M.hasDartCode(node.profileFunction.function.kind)) {
- infoBox.children.add(div('Code containing function'));
- infoBox.children.add(br());
- var totalTicks = profile.sampleCount;
- var codes = node.profileFunction.profileCodes;
- var numCodes = codes.length;
- for (var i = 0; i < numCodes; i++) {
- var codeRowSpan = new DivElement();
- codeRowSpan.style.paddingLeft = '1em';
- infoBox.children.add(codeRowSpan);
- var profileCode = codes[i];
- var code = profileCode.code;
- var ticks = profileCode.inclusiveTicks;
- var percentage = Utils.formatPercent(ticks, totalTicks);
- var percentageSpan = new SpanElement();
- percentageSpan.style.display = 'inline-block';
- percentageSpan.text = '$percentage';
- percentageSpan.style.minWidth = '5em';
- percentageSpan.style.textAlign = 'right';
- percentageSpan.title = 'Inclusive ticks';
- codeRowSpan.children.add(percentageSpan);
- var codeRef = new Element.tag('code-ref');
- codeRef.ref = code;
- codeRef.style.marginLeft = '1em';
- codeRef.style.marginRight = 'auto';
- codeRef.style.width = '100%';
- codeRowSpan.children.add(codeRef);
- }
- }
-
- makeInfoButton();
- methodColumn.children.add(infoButton);
-
- // Fill in self column.
- var selfColumn = flexColumns[1];
- selfColumn.style.position = 'relative';
- selfColumn.style.alignItems = 'center';
- selfColumn.text = selfPercent;
- }
-}
-
-@CustomTag('sample-buffer-control')
-class SampleBufferControlElement extends ObservatoryElement {
- SampleBufferControlElement.created() : super.created() {
- _stopWatch.start();
- }
-
- Future<CpuProfile> reload(Isolate isolate) async {
- profile.clear();
- if (isolate == null) {
- _update(profile);
- // Notify listener.
- onSampleBufferUpdate(profile);
- return profile;
- }
- profileVM = isolate.vm.profileVM;
- if (tagSelector == null) {
- // Set default value.
- tagSelector = profileVM ? 'UserVM' : 'None';
- }
- await _changeState(kFetchingState);
- try {
- var response;
- if (allocationProfileClass != null) {
- response =
- await allocationProfileClass.getAllocationSamples(tagSelector);
- } else {
- var params = { 'tags': tagSelector };
- response = await isolate.invokeRpc('_getCpuProfile', params);
- }
- await _changeState(kLoadingState);
- profile.load(isolate, response);
- profile.buildFunctionCallerAndCallees();
- _update(profile);
- await _changeState(kLoadedState);
- // Notify listener.
- onSampleBufferUpdate(profile);
- return profile;
- } catch (e, st) {
- if (e is ServerRpcException) {
- ServerRpcException se = e;
- if (se.code == ServerRpcException.kFeatureDisabled) {
- await _changeState(kDisabledState);
- return profile;
- }
- }
- await _changeState(kExceptionState, e, st);
- rethrow;
- }
- }
-
- Future _changeState(String newState, [exception, stackTrace]) {
- if ((newState == kDisabledState) ||
- (newState == kFetchingState) ||
- (newState == kExceptionState)) {
- loadTime = '';
- fetchTime = '';
- } else if (newState == kLoadingState) {
- fetchTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
- loadTime = '';
- } else if (newState == kLoadedState) {
- loadTime = formatTimeMilliseconds(_stopWatch.elapsedMilliseconds);
- }
- state = newState;
- this.exception = exception;
- this.stackTrace = stackTrace;
- _stopWatch.reset();
- return window.animationFrame;
- }
-
- _update(CpuProfile sampleBuffer) {
- sampleCount = profile.sampleCount.toString();
- refreshTime = new DateTime.now().toString();
- stackDepth = profile.stackDepth.toString();
- sampleRate = profile.sampleRate.toStringAsFixed(0);
- if (profile.sampleCount == 0) {
- timeSpan = '0s';
- } else {
- timeSpan = formatTime(profile.timeSpan);
- }
- }
-
- void tagSelectorChanged(oldValue) {
- reload(profile.isolate);
- }
-
- Function onSampleBufferUpdate;
- @observable bool showTagSelector = true;
- @observable bool profileVM = false;
- @observable String sampleCount = '';
- @observable String refreshTime = '';
- @observable String sampleRate = '';
- @observable String stackDepth = '';
- @observable String timeSpan = '';
- @observable String fetchTime = '';
- @observable String loadTime = '';
- @observable String tagSelector;
- @observable String state = kFetchingState;
- @observable var exception;
- @observable var stackTrace;
-
- static const kDisabledState = 'kDisabled';
- static const kExceptionState = 'Exception';
- static const kFetchingState = 'kFetching';
- static const kLoadedState = 'kLoaded';
- static const kLoadingState = 'kLoading';
- static const kNotLoadedState = 'kNotLoaded';
-
- Isolate isolate;
- Class allocationProfileClass;
-
- final CpuProfile profile = new CpuProfile();
- final Stopwatch _stopWatch = new Stopwatch();
-}
-
-@CustomTag('stack-trace-tree-config')
-class StackTraceTreeConfigElement extends ObservatoryElement {
- StackTraceTreeConfigElement.created() : super.created();
-
- attached() {
- super.attached();
- var filterElement = shadowRoot.querySelector('#filterInput');
- keyDownSubscription = filterElement.onKeyDown.listen(_onKeyDown);
- blurSubscription = filterElement.onBlur.listen(_onBlur);
- }
-
- detached() {
- super.detached();
- keyDownSubscription?.cancel();
- blurSubscription?.cancel();
- }
-
- void _onKeyDown(KeyboardEvent keyEvent) {
- if (keyEvent.keyCode == 13) {
- // On enter, update the filter string.
- filterString =
- (shadowRoot.querySelector('#filterInput') as InputElement).value;
- if (onTreeConfigChange == null) {
- return;
- }
- onTreeConfigChange(modeSelector, directionSelector, filterString);
- }
- }
-
- void _onBlur(Event event) {
- // Input box has lost focus, update the display to match the active
- // filter string.
- (shadowRoot.querySelector('#filterInput') as InputElement).value =
- filterString;
- }
-
- void modeSelectorChanged(oldValue) {
- if (onTreeConfigChange == null) {
- return;
- }
- onTreeConfigChange(modeSelector, directionSelector, filterString);
- }
-
- void directionSelectorChanged(oldValue) {
- if (onTreeConfigChange == null) {
- return;
- }
- onTreeConfigChange(modeSelector, directionSelector, filterString);
- }
-
- Function onTreeConfigChange;
- StreamSubscription keyDownSubscription;
- StreamSubscription blurSubscription;
- @observable bool show = true;
- @observable bool showModeSelector = true;
- @observable bool showDirectionSelector = true;
- @observable bool showFilter = true;
- @observable String modeSelector = 'Function';
- @observable String directionSelector = 'Up';
- @observable String filterString;
-}
-
-class FunctionCallTreeNodeRow extends VirtualTreeRow {
- final CpuProfile profile;
- final FunctionCallTreeNode node;
- String selfPercent;
- String totalPercent;
- String percent;
-
- static const kHotThreshold = 0.05; // 5%.
- static const kMediumThreshold = 0.02; // 2%.
-
- double _percent(bool self) {
- if (self) {
- return node.profileFunction.normalizedExclusiveTicks;
- } else {
- return node.profileFunction.normalizedInclusiveTicks;
- }
- }
-
- bool isHot(bool self) => _percent(self) > kHotThreshold;
- bool isMedium(bool self) => _percent(self) > kMediumThreshold;
-
- String rowClass(bool self) {
- if (isHot(self)) {
- return 'hotProfile';
- } else if (isMedium(self)) {
- return 'mediumProfile';
- } else {
- return 'coldProfile';
- }
- }
-
- FunctionCallTreeNodeRow(VirtualTree tree,
- int depth,
- this.profile,
- FunctionCallTreeNode node)
- : node = node,
- super(tree, depth) {
- if ((node.profileFunction.function.kind == M.FunctionKind.tag) &&
- (node.profileFunction.normalizedExclusiveTicks == 0) &&
- (node.profileFunction.normalizedInclusiveTicks == 0)) {
- selfPercent = '';
- totalPercent = '';
- } else {
- selfPercent = Utils.formatPercentNormalized(
- node.profileFunction.normalizedExclusiveTicks);
- totalPercent = Utils.formatPercentNormalized(
- node.profileFunction.normalizedInclusiveTicks);
- }
- percent = Utils.formatPercentNormalized(node.percentage);
- }
-
- void onRender(DivElement rowDiv) {
- rowDiv.children.add(makeGap(ems:0.1));
- rowDiv.children.add(
- makeText(totalPercent,
- toolTip: 'global % on stack'));
- rowDiv.children.add(makeGap());
- rowDiv.children.add(
- makeText(selfPercent,
- toolTip: 'global % executing'));
- rowDiv.children.add(makeGap());
- rowDiv.children.add(makeIndenter(depth, colored: false));
- rowDiv.children.add(makeColorBar(depth));
- rowDiv.children.add(makeGap(ems: 1.0));
- rowDiv.children.add(makeExpander());
- rowDiv.children.add(
- makeText(percent, toolTip: 'tree node %', flexBasis: null));
- rowDiv.children.add(makeGap(ems: 0.5));
- functionRef.ref = node.profileFunction.function;
- rowDiv.children.add(functionRef);
- }
-
- var functionRef = new Element.tag('function-ref');
-
- int get childCount => node.children.length;
-
- void onShow() {
- if (children.length > 0) {
- return;
- }
- for (var childNode in node.children) {
- var row = new FunctionCallTreeNodeRow(tree, depth + 1, profile, childNode);
- children.add(row);
- }
- }
-}
-
-
-class CodeCallTreeNodeRow extends VirtualTreeRow {
- final CpuProfile profile;
- final CodeCallTreeNode node;
- String selfPercent;
- String totalPercent;
- String percent;
-
- static const kHotThreshold = 0.05; // 5%.
- static const kMediumThreshold = 0.02; // 2%.
-
- double _percent(bool self) {
- if (self) {
- return node.profileCode.normalizedExclusiveTicks;
- } else {
- return node.profileCode.normalizedInclusiveTicks;
- }
- }
-
- bool isHot(bool self) => _percent(self) > kHotThreshold;
- bool isMedium(bool self) => _percent(self) > kMediumThreshold;
-
- String rowClass(bool self) {
- if (isHot(self)) {
- return 'hotProfile';
- } else if (isMedium(self)) {
- return 'mediumProfile';
- } else {
- return 'coldProfile';
- }
- }
-
- CodeCallTreeNodeRow(VirtualTree tree,
- int depth,
- this.profile,
- CodeCallTreeNode node)
- : node = node,
- super(tree, depth) {
- if ((node.profileCode.code.kind == M.CodeKind.tag) &&
- (node.profileCode.normalizedExclusiveTicks == 0) &&
- (node.profileCode.normalizedInclusiveTicks == 0)) {
- selfPercent = '';
- totalPercent = '';
- } else {
- selfPercent = Utils.formatPercentNormalized(
- node.profileCode.normalizedExclusiveTicks);
- totalPercent = Utils.formatPercentNormalized(
- node.profileCode.normalizedInclusiveTicks);
- }
- percent = Utils.formatPercentNormalized(node.percentage);
- }
-
- void onRender(DivElement rowDiv) {
- rowDiv.children.add(makeGap(ems:0.1));
- rowDiv.children.add(
- makeText(totalPercent,
- toolTip: 'global % on stack'));
- rowDiv.children.add(makeGap());
- rowDiv.children.add(
- makeText(selfPercent,
- toolTip: 'global % executing'));
- rowDiv.children.add(makeGap());
- rowDiv.children.add(makeIndenter(depth, colored: false));
- rowDiv.children.add(makeColorBar(depth));
- rowDiv.children.add(makeGap(ems: 1.0));
- rowDiv.children.add(makeExpander());
- rowDiv.children.add(
- makeText(percent, toolTip: 'tree node %', flexBasis: null));
- rowDiv.children.add(makeGap(ems: 0.5));
- codeRef.ref = node.profileCode.code;
- rowDiv.children.add(codeRef);
- }
-
- var codeRef = new Element.tag('code-ref');
-
- int get childCount => node.children.length;
-
- void onShow() {
- if (children.length > 0) {
- return;
- }
- for (var childNode in node.children) {
- var row = new CodeCallTreeNodeRow(tree, depth + 1, profile, childNode);
- children.add(row);
- }
- }
-}
-
-/// Displays a CpuProfile
-@CustomTag('cpu-profile')
-class CpuProfileElement extends ObservatoryElement {
- CpuProfileElement.created() : super.created() {
- _updateTask = new Task(update);
- _renderTask = new Task(render);
- }
-
- attached() {
- super.attached();
- sampleBufferControlElement =
- shadowRoot.querySelector('#sampleBufferControl');
- assert(sampleBufferControlElement != null);
- sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
- stackTraceTreeConfigElement =
- shadowRoot.querySelector('#stackTraceTreeConfig');
- assert(stackTraceTreeConfigElement != null);
- stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
- cpuProfileVirtualTreeElement = shadowRoot.querySelector('#cpuProfileVirtualTree');
- assert(cpuProfileVirtualTreeElement != null);
- cpuProfileVirtualTreeElement.profile = sampleBufferControlElement.profile;
- _resizeSubscription = window.onResize.listen((_) => _updateSize());
- _updateTask.queue();
- _updateSize();
- }
-
- detached() {
- super.detached();
- if (_resizeSubscription != null) {
- _resizeSubscription.cancel();
- }
- }
-
- _updateSize() {
- var applySize = (e) {
- Rectangle rect = e.getBoundingClientRect();
- final totalHeight = window.innerHeight;
- final bottomMargin = 200;
- final mainHeight = totalHeight - bottomMargin;
- e.style.setProperty('height', '${mainHeight}px');
- };
- HtmlElement e2 = $['cpuProfileVirtualTree'];
- applySize(e2);
- }
-
- isolateChanged(oldValue) {
- _updateTask.queue();
- }
-
- update() {
- if (sampleBufferControlElement != null) {
- sampleBufferControlElement.reload(isolate);
- }
- }
-
- onSampleBufferChange(CpuProfile sampleBuffer) {
- _renderTask.queue();
- }
-
- onTreeConfigChange(String modeSelector,
- String directionSelector,
- String filterString) {
- ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
- if (directionSelector != 'Up') {
- direction = ProfileTreeDirection.Inclusive;
- }
- ProfileTreeMode mode = ProfileTreeMode.Function;
- if (modeSelector == 'Code') {
- mode = ProfileTreeMode.Code;
- }
- // Clear the filter.
- cpuProfileVirtualTreeElement.filter = null;
- if (filterString != null) {
- filterString = filterString.trim();
- if (filterString.isNotEmpty) {
- cpuProfileVirtualTreeElement.filter = (CallTreeNode node) {
- return node.name.contains(filterString);
- };
- }
- }
- cpuProfileVirtualTreeElement.direction = direction;
- cpuProfileVirtualTreeElement.mode = mode;
- _renderTask.queue();
- }
-
- Future clearCpuProfile() async {
- await isolate.invokeRpc('_clearCpuProfile', { });
- _updateTask.queue();
- return new Future.value(null);
- }
-
- Future refresh() {
- _updateTask.queue();
- return new Future.value(null);
- }
-
- render() {
- cpuProfileVirtualTreeElement.render();
- }
-
- @published Isolate isolate;
-
- StreamSubscription _resizeSubscription;
- Task _updateTask;
- Task _renderTask;
- SampleBufferControlElement sampleBufferControlElement;
- StackTraceTreeConfigElement stackTraceTreeConfigElement;
- CpuProfileVirtualTreeElement cpuProfileVirtualTreeElement;
-}
-
-class NameSortedTable extends SortedTable {
- NameSortedTable(columns) : super(columns);
@override
- dynamic getSortKeyFor(int row, int col) {
- if (col == FUNCTION_COLUMN) {
- // Use name as sort key.
- return rows[row].values[col].name;
- }
- return super.getSortKeyFor(row, col);
- }
-
- SortedTableRow rowFromIndex(int tableIndex) {
- final modelIndex = sortedRows[tableIndex];
- return rows[modelIndex];
- }
-
- static const FUNCTION_SPACER_COLUMNS = const [];
- static const FUNCTION_COLUMN = 2;
- TableRowElement _makeFunctionRow() {
- var tr = new TableRowElement();
- var cell;
-
- // Add percentage.
- cell = tr.insertCell(-1);
- cell = tr.insertCell(-1);
-
- // Add function ref.
- cell = tr.insertCell(-1);
- var functionRef = new Element.tag('function-ref');
- cell.children.add(functionRef);
-
- return tr;
- }
-
- static const CALL_SPACER_COLUMNS = const [];
- static const CALL_FUNCTION_COLUMN = 1;
- TableRowElement _makeCallRow() {
- var tr = new TableRowElement();
- var cell;
-
- // Add percentage.
- cell = tr.insertCell(-1);
- // Add function ref.
- cell = tr.insertCell(-1);
- var functionRef = new Element.tag('function-ref');
- cell.children.add(functionRef);
- return tr;
- }
-
- _updateRow(TableRowElement tr,
- int rowIndex,
- List spacerColumns,
- int refColumn) {
- var row = rows[rowIndex];
- // Set reference
- var ref = tr.children[refColumn].children[0];
- ref.ref = row.values[refColumn];
-
- for (var i = 0; i < row.values.length; i++) {
- if (spacerColumns.contains(i) || (i == refColumn)) {
- // Skip spacer columns.
- continue;
- }
- var cell = tr.children[i];
- cell.title = row.values[i].toString();
- cell.text = getFormattedValue(rowIndex, i);
- }
- }
-
- _updateTableView(HtmlElement table,
- HtmlElement makeEmptyRow(),
- void onRowClick(TableRowElement tr),
- List spacerColumns,
- int refColumn) {
- assert(table != null);
-
- // Resize DOM table.
- if (table.children.length > sortedRows.length) {
- // Shrink the table.
- var deadRows = table.children.length - sortedRows.length;
- for (var i = 0; i < deadRows; i++) {
- table.children.removeLast();
- }
- } else if (table.children.length < sortedRows.length) {
- // Grow table.
- var newRows = sortedRows.length - table.children.length;
- for (var i = 0; i < newRows; i++) {
- var row = makeEmptyRow();
- row.onClick.listen((e) {
- e.stopPropagation();
- e.preventDefault();
- onRowClick(row);
- });
- table.children.add(row);
- }
- }
-
- assert(table.children.length == sortedRows.length);
-
- // Fill table.
- for (var i = 0; i < sortedRows.length; i++) {
- var rowIndex = sortedRows[i];
- var tr = table.children[i];
- _updateRow(tr, rowIndex, spacerColumns, refColumn);
- }
- }
-}
-
-@CustomTag('cpu-profile-table')
-class CpuProfileTableElement extends ObservatoryElement {
- CpuProfileTableElement.created() : super.created() {
- _updateTask = new Task(update);
- _renderTask = new Task(render);
- var columns = [
- new SortedTableColumn.withFormatter('Executing (%)',
- Utils.formatPercentNormalized),
- new SortedTableColumn.withFormatter('In stack (%)',
- Utils.formatPercentNormalized),
- new SortedTableColumn('Method'),
- ];
- profileTable = new NameSortedTable(columns);
- profileTable.sortColumnIndex = 0;
-
- columns = [
- new SortedTableColumn.withFormatter('Callees (%)',
- Utils.formatPercentNormalized),
- new SortedTableColumn('Method')
- ];
- profileCalleesTable = new NameSortedTable(columns);
- profileCalleesTable.sortColumnIndex = 0;
-
- columns = [
- new SortedTableColumn.withFormatter('Callers (%)',
- Utils.formatPercentNormalized),
- new SortedTableColumn('Method')
- ];
- profileCallersTable = new NameSortedTable(columns);
- profileCallersTable.sortColumnIndex = 0;
- }
-
- attached() {
- super.attached();
- sampleBufferControlElement =
- shadowRoot.querySelector('#sampleBufferControl');
- assert(sampleBufferControlElement != null);
- sampleBufferControlElement.onSampleBufferUpdate = onSampleBufferChange;
- // Disable the tag selector- we always want no tags.
- sampleBufferControlElement.tagSelector = 'None';
- sampleBufferControlElement.showTagSelector = false;
- stackTraceTreeConfigElement =
- shadowRoot.querySelector('#stackTraceTreeConfig');
- assert(stackTraceTreeConfigElement != null);
- stackTraceTreeConfigElement.onTreeConfigChange = onTreeConfigChange;
- stackTraceTreeConfigElement.modeSelector = 'Function';
- stackTraceTreeConfigElement.showModeSelector = false;
- stackTraceTreeConfigElement.directionSelector = 'Down';
- stackTraceTreeConfigElement.showDirectionSelector = false;
- cpuProfileTreeElement = shadowRoot.querySelector('#cpuProfileTree');
- assert(cpuProfileTreeElement != null);
- cpuProfileTreeElement.profile = sampleBufferControlElement.profile;
- _updateTask.queue();
- _resizeSubscription = window.onResize.listen((_) => _updateSize());
- _updateSize();
- }
-
- detached() {
- super.detached();
- if (_resizeSubscription != null) {
- _resizeSubscription.cancel();
- }
- }
-
- _updateSize() {
- HtmlElement e = $['main'];
- final totalHeight = window.innerHeight;
- final top = e.offset.top;
- final bottomMargin = 32;
- final mainHeight = totalHeight - top - bottomMargin;
- e.style.setProperty('height', '${mainHeight}px');
- }
-
- isolateChanged(oldValue) {
- _updateTask.queue();
- }
-
- update() {
- _clearView();
- if (sampleBufferControlElement != null) {
- sampleBufferControlElement.reload(isolate).whenComplete(checkParameters);
- }
- }
-
- onSampleBufferChange(CpuProfile sampleBuffer) {
- _renderTask.queue();
- }
-
- onTreeConfigChange(String modeSelector,
- String directionSelector,
- String filterString) {
- ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
- if (directionSelector != 'Up') {
- direction = ProfileTreeDirection.Inclusive;
- }
- ProfileTreeMode mode = ProfileTreeMode.Function;
- if (modeSelector == 'Code') {
- mode = ProfileTreeMode.Code;
- }
- cpuProfileTreeElement.direction = direction;
- cpuProfileTreeElement.mode = mode;
- _renderTask.queue();
- }
-
- Future clearCpuProfile() async {
- await isolate.invokeRpc('_clearCpuProfile', { });
- _updateTask.queue();
- return new Future.value(null);
- }
-
- Future refresh() {
- _updateTask.queue();
- return new Future.value(null);
- }
-
- render() {
- _updateView();
- }
-
- checkParameters() {
- if (isolate == null) {
- return;
- }
- var functionId = app.locationManager.uri.queryParameters['functionId'];
- var functionName =
- app.locationManager.uri.queryParameters['functionName'];
- if (functionId == '') {
- // Fallback to searching by name.
- _focusOnFunction(_findFunction(functionName));
- } else {
- if (functionId == null) {
- _focusOnFunction(null);
- return;
- }
- isolate.getObject(functionId).then((func) => _focusOnFunction(func));
- }
- }
-
- _clearView() {
- profileTable.clearRows();
- _renderTable();
- }
-
- _updateView() {
- _buildFunctionTable();
- _renderTable();
- _updateFunctionTreeView();
- }
-
- int _findFunctionRow(ServiceFunction function) {
- for (var i = 0; i < profileTable.sortedRows.length; i++) {
- var rowIndex = profileTable.sortedRows[i];
- var row = profileTable.rows[rowIndex];
- if (row.values[NameSortedTable.FUNCTION_COLUMN] == function) {
- return i;
- }
- }
- return -1;
- }
-
- _scrollToFunction(ServiceFunction function) {
- TableSectionElement tableBody = $['profile-table'];
- var row = _findFunctionRow(function);
- if (row == -1) {
- return;
- }
- tableBody.children[row].classes.remove('shake');
- // trigger reflow.
- tableBody.children[row].offsetHeight;
- tableBody.children[row].scrollIntoView(ScrollAlignment.CENTER);
- tableBody.children[row].classes.add('shake');
- // Focus on clicked function.
- _focusOnFunction(function);
- }
-
- _clearFocusedFunction() {
- TableSectionElement tableBody = $['profile-table'];
- // Clear current focus.
- if (focusedRow != null) {
- tableBody.children[focusedRow].classes.remove('focused');
- }
- focusedRow = null;
- focusedFunction = null;
- }
-
- ServiceFunction _findFunction(String functionName) {
- for (var func in profile.functions) {
- if (func.function.name == functionName) {
- return func.function;
- }
- }
- return null;
- }
-
- _focusOnFunction(ServiceFunction function) {
- if (focusedFunction == function) {
- // Do nothing.
- return;
- }
-
- _clearFocusedFunction();
-
- if (function == null) {
- _updateFunctionTreeView();
- _clearCallTables();
- return;
- }
-
- var row = _findFunctionRow(function);
- if (row == -1) {
- _updateFunctionTreeView();
- _clearCallTables();
- return;
- }
-
- focusedRow = row;
- focusedFunction = function;
-
- TableSectionElement tableBody = $['profile-table'];
- tableBody.children[focusedRow].classes.add('focused');
- _updateFunctionTreeView();
- _buildCallersTable(focusedFunction);
- _buildCalleesTable(focusedFunction);
- }
-
- _onRowClick(TableRowElement tr) {
- var tableBody = $['profile-table'];
- var row = profileTable.rowFromIndex(tableBody.children.indexOf(tr));
- var function = row.values[NameSortedTable.FUNCTION_COLUMN];
- app.locationManager.goReplacingParameters(
- {
- 'functionId': function.id,
- 'functionName': function.vmName
- }
- );
- }
-
- _renderTable() {
- profileTable._updateTableView($['profile-table'],
- profileTable._makeFunctionRow,
- _onRowClick,
- NameSortedTable.FUNCTION_SPACER_COLUMNS,
- NameSortedTable.FUNCTION_COLUMN);
- }
-
- _buildFunctionTable() {
- for (var func in profile.functions) {
- if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
- // Skip.
- continue;
- }
- var row = [
- func.normalizedExclusiveTicks,
- func.normalizedInclusiveTicks,
- func.function,
- ];
- profileTable.addRow(new SortedTableRow(row));
- }
- profileTable.sort();
- }
-
- _renderCallTable(TableSectionElement view,
- NameSortedTable model,
- void onRowClick(TableRowElement tr)) {
- model._updateTableView(view,
- model._makeCallRow,
- onRowClick,
- NameSortedTable.CALL_SPACER_COLUMNS,
- NameSortedTable.CALL_FUNCTION_COLUMN);
- }
-
- _buildCallTable(Map<ProfileFunction, int> calls,
- NameSortedTable model) {
- model.clearRows();
- if (calls == null) {
- return;
- }
- var sum = 0;
- calls.values.forEach((i) => sum += i);
- calls.forEach((func, count) {
- var row = [
- count / sum,
- func.function,
- ];
- model.addRow(new SortedTableRow(row));
- });
- model.sort();
- }
-
- _clearCallTables() {
- _buildCallersTable(null);
- _buildCalleesTable(null);
- }
-
- _onCallersClick(TableRowElement tr) {
- var table = $['callers-table'];
- final row = profileCallersTable.rowFromIndex(table.children.indexOf(tr));
- var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
- _scrollToFunction(function);
- }
-
- _buildCallersTable(ServiceFunction function) {
- var calls = (function != null) ? function.profile.callers : null;
- var table = $['callers-table'];
- _buildCallTable(calls, profileCallersTable);
- _renderCallTable(table, profileCallersTable, _onCallersClick);
- }
-
- _onCalleesClick(TableRowElement tr) {
- var table = $['callees-table'];
- final row = profileCalleesTable.rowFromIndex(table.children.indexOf(tr));
- var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
- _scrollToFunction(function);
- }
-
- _buildCalleesTable(ServiceFunction function) {
- var calls = (function != null) ? function.profile.callees : null;
- var table = $['callees-table'];
- _buildCallTable(calls, profileCalleesTable);
- _renderCallTable(table, profileCalleesTable, _onCalleesClick);
- }
-
- _changeSort(Element target, NameSortedTable table) {
- if (target is TableCellElement) {
- if (table.sortColumnIndex != target.cellIndex) {
- table.sortColumnIndex = target.cellIndex;
- table.sortDescending = true;
- } else {
- table.sortDescending = !profileTable.sortDescending;
- }
- table.sort();
- }
- }
-
- changeSortProfile(Event e, var detail, Element target) {
- _changeSort(target, profileTable);
- _renderTable();
- }
-
- changeSortCallers(Event e, var detail, Element target) {
- _changeSort(target, profileCallersTable);
- _renderCallTable($['callers-table'], profileCallersTable, _onCallersClick);
- }
-
- changeSortCallees(Event e, var detail, Element target) {
- _changeSort(target, profileCalleesTable);
- _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick);
- }
-
- //////
- ///
- /// Function tree.
- ///
- TableTree functionTree;
- _updateFunctionTreeView() {
- cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
- return node.profileFunction.function == focusedFunction;
- };
- cpuProfileTreeElement.render();
- }
-
- @published Isolate isolate;
- @observable NameSortedTable profileTable;
- @observable NameSortedTable profileCallersTable;
- @observable NameSortedTable profileCalleesTable;
- @observable ServiceFunction focusedFunction;
- @observable int focusedRow;
-
-
- StreamSubscription _resizeSubscription;
- Task _updateTask;
- Task _renderTask;
-
- CpuProfile get profile => sampleBufferControlElement.profile;
- SampleBufferControlElement sampleBufferControlElement;
- StackTraceTreeConfigElement stackTraceTreeConfigElement;
- CpuProfileVirtualTreeElement cpuProfileTreeElement;
-}
-
-enum ProfileTreeDirection {
- Exclusive,
- Inclusive
-}
-
-enum ProfileTreeMode {
- Code,
- Function,
-}
-
-@CustomTag('cpu-profile-virtual-tree')
-class CpuProfileVirtualTreeElement extends ObservatoryElement {
- ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
- ProfileTreeMode mode = ProfileTreeMode.Function;
- CpuProfile profile;
- VirtualTree virtualTree;
- CallTreeNodeFilter filter;
- StreamSubscription _resizeSubscription;
- @observable bool show = true;
-
- CpuProfileVirtualTreeElement.created() : super.created();
-
attached() {
super.attached();
- _resizeSubscription = window.onResize.listen((_) => _updateSize());
+ _r.enable();
+ _request();
}
+ @override
detached() {
- super.detached();
- _resizeSubscription?.cancel();
- }
-
- void render() {
- _updateView();
+ super.detached(); _r.disable(notify: true);
+ children = [];
}
- showChanged(oldValue) {
- if (show) {
- virtualTree?.root?.style?.display = 'block';
- } else {
- virtualTree?.root?.style?.display = 'none';
- }
- }
-
- void _updateView() {
- _updateSize();
- virtualTree?.clear();
- virtualTree?.uninstall();
- virtualTree = null;
- bool exclusive = direction == ProfileTreeDirection.Exclusive;
- if (mode == ProfileTreeMode.Code) {
- _buildCodeTree(exclusive);
- } else {
- assert(mode == ProfileTreeMode.Function);
- _buildFunctionTree(exclusive);
- }
- virtualTree?.refresh();
- }
-
- void _updateSize() {
- var treeBody = shadowRoot.querySelector('#tree');
- assert(treeBody != null);
- int windowHeight = window.innerHeight - 32;
- treeBody.style.height = '${windowHeight}px';
- }
-
- void _buildFunctionTree(bool exclusive) {
- var treeBody = shadowRoot.querySelector('#tree');
- assert(treeBody != null);
- virtualTree = new VirtualTree(32, treeBody);
- if (profile == null) {
- return;
- }
- var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
- if (tree == null) {
- return;
- }
- if (filter != null) {
- tree = tree.filtered(filter);
- }
- for (var child in tree.root.children) {
- virtualTree.rows.add(
- new FunctionCallTreeNodeRow(virtualTree, 0, profile, child));
- }
- if (virtualTree.rows.length == 1) {
- virtualTree.rows[0].expanded = true;
- }
- }
-
- void _buildCodeTree(bool exclusive) {
- var treeBody = shadowRoot.querySelector('#tree');
- assert(treeBody != null);
- virtualTree = new VirtualTree(32, treeBody);
- if (profile == null) {
- return;
- }
- var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
- if (tree == null) {
- return;
- }
- if (filter != null) {
- tree = tree.filtered(filter);
- }
- for (var child in tree.root.children) {
- virtualTree.rows.add(
- new CodeCallTreeNodeRow(virtualTree, 0, profile, child));
- }
- if (virtualTree.rows.length == 1) {
- virtualTree.rows[0].expanded = true;
- }
- }
-}
-
-@CustomTag('cpu-profile-tree')
-class CpuProfileTreeElement extends ObservatoryElement {
- ProfileTreeDirection direction = ProfileTreeDirection.Exclusive;
- ProfileTreeMode mode = ProfileTreeMode.Function;
- CpuProfile profile;
- TableTree codeTree;
- TableTree functionTree;
- CallTreeNodeFilter functionFilter;
- @observable bool show = true;
-
- CpuProfileTreeElement.created() : super.created();
-
void render() {
- _updateView();
- }
-
- showChanged(oldValue) {
- var treeTable = shadowRoot.querySelector('#treeTable');
- assert(treeTable != null);
- treeTable.style.display = show ? 'table' : 'none';
- }
-
- void _updateView() {
- if (functionTree != null) {
- functionTree.clear();
- functionTree = null;
- }
- if (codeTree != null) {
- codeTree.clear();
- codeTree = null;
- }
- bool exclusive = direction == ProfileTreeDirection.Exclusive;
- if (mode == ProfileTreeMode.Code) {
- _buildCodeTree(exclusive);
- } else {
- assert(mode == ProfileTreeMode.Function);
- _buildFunctionTree(exclusive);
- }
- }
-
- void _buildFunctionTree(bool exclusive) {
- if (functionTree == null) {
- var tableBody = shadowRoot.querySelector('#treeBody');
- assert(tableBody != null);
- functionTree = new TableTree(tableBody, 2);
- }
- if (profile == null) {
- return;
- }
- var tree = profile.loadFunctionTree(exclusive ? 'exclusive' : 'inclusive');
- if (tree == null) {
- return;
- }
- if (functionFilter != null) {
- tree = tree.filtered(functionFilter);
- }
- var rootRow =
- new FunctionProfileTreeRow(functionTree, null, profile, tree.root);
- functionTree.initialize(rootRow);
- }
-
- void _buildCodeTree(bool exclusive) {
- if (codeTree == null) {
- var tableBody = shadowRoot.querySelector('#treeBody');
- assert(tableBody != null);
- codeTree = new TableTree(tableBody, 2);
- }
- if (profile == null) {
- return;
- }
- var tree = profile.loadCodeTree(exclusive ? 'exclusive' : 'inclusive');
- if (tree == null) {
+ var content = [
+ new NavBarElement(queue: _r.queue)
+ ..children = [
+ new NavTopMenuElement(queue: _r.queue),
+ new NavVMMenuElement(_vm, _events, queue: _r.queue),
+ new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+ new NavMenuElement('cpu profile', link: Uris.profiler(_isolate),
+ last: true, queue: _r.queue),
+ new NavRefreshElement(queue: _r.queue)
+ ..onRefresh.listen(_refresh),
+ new NavRefreshElement(label: 'Clear', queue: _r.queue)
+ ..onRefresh.listen(_clearCpuProfile),
+ new NavNotifyElement(_notifications, queue: _r.queue)
+ ],
+ ];
+ if (_progress == null) {
+ children = content;
return;
}
- var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root);
- codeTree.initialize(rootRow);
+ content.add(new SampleBufferControlElement(_progress, _progressStream,
+ selectedTag: _tag, queue: _r.queue)
+ ..onTagChange.listen((e) {
+ _tag = e.element.selectedTag;
+ _request();
+ }));
+ if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
+ CpuProfileVirtualTreeElement tree;
+ content.addAll([
+ new BRElement(),
+ new StackTraceTreeConfigElement(mode: _mode, direction: _direction,
+ filter: _filter, queue: _r.queue)
+ ..onModeChange.listen((e) {
+ _mode = tree.mode = e.element.mode;
+ })
+ ..onFilterChange.listen((e) {
+ _filter = e.element.filter.trim();
+ tree.filter = _filter.isNotEmpty
+ ? (node) { return node.name.contains(_filter); }
+ : null;
+ })
+ ..onDirectionChange.listen((e) {
+ _direction = tree.direction = e.element.direction;
+ }),
+ new BRElement(),
+ tree = new CpuProfileVirtualTreeElement(_isolate, _progress.profile,
+ queue: _r.queue)
+ ]);
+ }
+ children = content;
+ }
+
+ Future _request({bool clear: false, bool forceFetch: false}) async {
+ _progress = null;
+ _progressStream = _profiles.get(isolate, _tag, clear: clear,
+ forceFetch: forceFetch);
+ _r.dirty();
+ _progress = (await _progressStream.first).progress;
+ _r.dirty();
+ if (M.isSampleProcessRunning(_progress.status)) {
+ _progress = (await _progressStream.last).progress;
+ _r.dirty();
+ }
+ }
+
+ Future _clearCpuProfile(RefreshEvent e) async {
+ e.element.disabled = true;
+ await _request(clear: true);
+ e.element.disabled = false;
+ }
+
+ Future _refresh(e) async {
+ e.element.disabled = true;
+ await _request(forceFetch: true);
+ e.element.disabled = false;
}
}
« no previous file with comments | « runtime/observatory/lib/src/elements/class_view.html ('k') | runtime/observatory/lib/src/elements/cpu_profile.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698