| Index: runtime/observatory/lib/src/elements/cpu_profile_table.dart
|
| diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
|
| similarity index 55%
|
| copy from runtime/observatory/lib/src/elements/cpu_profile.dart
|
| copy to runtime/observatory/lib/src/elements/cpu_profile_table.dart
|
| index 82f479d00e370e27122b69741a7412bd50061b6b..2a76e17bc9275de1f03424cbbb7fbba50c566724 100644
|
| --- a/runtime/observatory/lib/src/elements/cpu_profile.dart
|
| +++ b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
|
| @@ -2,16 +2,20 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -library cpu_profile_element;
|
| +library cpu_profile_table_element;
|
|
|
| import 'dart:async';
|
| import 'dart:html';
|
| import 'observatory_element.dart';
|
| -import 'package:observatory/models.dart' as M;
|
| +import 'sample_buffer_control.dart';
|
| +import 'stack_trace_tree_config.dart';
|
| +import 'cpu_profile/virtual_tree.dart';
|
| import 'package:observatory/service.dart';
|
| import 'package:observatory/app.dart';
|
| import 'package:observatory/cpu_profile.dart';
|
| import 'package:observatory/elements.dart';
|
| +import 'package:observatory/models.dart' as M;
|
| +import 'package:observatory/repositories.dart';
|
| import 'package:polymer/polymer.dart';
|
|
|
| List<String> sorted(Set<String> attributes) {
|
| @@ -435,467 +439,6 @@ class FunctionProfileTreeRow extends ProfileTreeRow<FunctionCallTreeNode> {
|
| }
|
| }
|
|
|
| -@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
|
| @@ -1006,6 +549,8 @@ class NameSortedTable extends SortedTable {
|
|
|
| @CustomTag('cpu-profile-table')
|
| class CpuProfileTableElement extends ObservatoryElement {
|
| +
|
| +
|
| CpuProfileTableElement.created() : super.created() {
|
| _updateTask = new Task(update);
|
| _renderTask = new Task(render);
|
| @@ -1038,24 +583,6 @@ class CpuProfileTableElement extends ObservatoryElement {
|
|
|
| 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();
|
| @@ -1081,30 +608,44 @@ class CpuProfileTableElement extends ObservatoryElement {
|
| _updateTask.queue();
|
| }
|
|
|
| - update() {
|
| + update() async {
|
| _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;
|
| + if (isolate == null) {
|
| + return;
|
| }
|
| - ProfileTreeMode mode = ProfileTreeMode.Function;
|
| - if (modeSelector == 'Code') {
|
| - mode = ProfileTreeMode.Code;
|
| + final stream = _repository.get(isolate, M.SampleProfileTag.none);
|
| + var progress = (await stream.first).progress;
|
| + shadowRoot.querySelector('#sampleBufferControl').children = [
|
| + sampleBufferControlElement =
|
| + new SampleBufferControlElement(progress, stream, showTag: false,
|
| + selectedTag: M.SampleProfileTag.none, queue: app.queue)
|
| + ];
|
| + if (M.isSampleProcessRunning(progress.status)) {
|
| + progress = (await stream.last).progress;
|
| + }
|
| + if (progress.status == M.SampleProfileLoadingStatus.loaded) {
|
| + _profile = progress.profile;
|
| + shadowRoot.querySelector('#stackTraceTreeConfig').children = [
|
| + stackTraceTreeConfigElement =
|
| + new StackTraceTreeConfigElement(showMode: false,
|
| + showDirection: false, mode: ProfileTreeMode.function,
|
| + direction: M.ProfileTreeDirection.exclusive, queue: app.queue)
|
| + ..onModeChange.listen((e) {
|
| + cpuProfileTreeElement.mode = e.element.mode;
|
| + _renderTask.queue();
|
| + })
|
| + ..onDirectionChange.listen((e) {
|
| + cpuProfileTreeElement.direction = e.element.direction;
|
| + _renderTask.queue();
|
| + })
|
| + ..onFilterChange.listen((e) =>_renderTask.queue())
|
| + ];
|
| + shadowRoot.querySelector('#cpuProfileTree').children = [
|
| + cpuProfileTreeElement =
|
| + new CpuProfileVirtualTreeElement(isolate, _profile,
|
| + queue: app.queue)
|
| + ];
|
| }
|
| - cpuProfileTreeElement.direction = direction;
|
| - cpuProfileTreeElement.mode = mode;
|
| _renderTask.queue();
|
| }
|
|
|
| @@ -1190,7 +731,7 @@ class CpuProfileTableElement extends ObservatoryElement {
|
| }
|
|
|
| ServiceFunction _findFunction(String functionName) {
|
| - for (var func in profile.functions) {
|
| + for (var func in _profile.functions) {
|
| if (func.function.name == functionName) {
|
| return func.function;
|
| }
|
| @@ -1250,7 +791,7 @@ class CpuProfileTableElement extends ObservatoryElement {
|
| }
|
|
|
| _buildFunctionTable() {
|
| - for (var func in profile.functions) {
|
| + for (var func in _profile.functions) {
|
| if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
|
| // Skip.
|
| continue;
|
| @@ -1359,10 +900,12 @@ class CpuProfileTableElement extends ObservatoryElement {
|
| ///
|
| TableTree functionTree;
|
| _updateFunctionTreeView() {
|
| + if (cpuProfileTreeElement == null) {
|
| + return;
|
| + }
|
| cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
|
| return node.profileFunction.function == focusedFunction;
|
| };
|
| - cpuProfileTreeElement.render();
|
| }
|
|
|
| @published Isolate isolate;
|
| @@ -1377,200 +920,10 @@ class CpuProfileTableElement extends ObservatoryElement {
|
| Task _updateTask;
|
| Task _renderTask;
|
|
|
| - CpuProfile get profile => sampleBufferControlElement.profile;
|
| + IsolateSampleProfileRepository _repository =
|
| + new IsolateSampleProfileRepository();
|
| + CpuProfile _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());
|
| - }
|
| -
|
| - detached() {
|
| - super.detached();
|
| - _resizeSubscription?.cancel();
|
| - }
|
| -
|
| - void render() {
|
| - _updateView();
|
| - }
|
| -
|
| - 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) {
|
| - return;
|
| - }
|
| - var rootRow = new CodeProfileTreeRow(codeTree, null, profile, tree.root);
|
| - codeTree.initialize(rootRow);
|
| - }
|
| -}
|
|
|