Chromium Code Reviews| Index: runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart |
| diff --git a/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart b/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart |
| index 3e7322e75108ffaf8f3931705ecf6baf954a1ecd..a51471e3b26160eaf95862392859c76dc6288fe6 100644 |
| --- a/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart |
| +++ b/runtime/bin/vmservice/client/lib/src/elements/isolate_profile.dart |
| @@ -17,10 +17,9 @@ class ProfileCodeTrieNodeTreeRow extends TableTreeRow { |
| @reflectable final CodeTrieNode node; |
| @reflectable Code get code => node.code; |
| - static String formatPercent(num a, num total) { |
| - var percent = 100.0 * (a / total); |
| - return '${percent.toStringAsFixed(2)}%'; |
| - } |
| + @reflectable String tipKind = ''; |
| + @reflectable String tipTicks = ''; |
| + @reflectable String tipTime = ''; |
|
turnidge
2014/04/17 20:18:54
Is the popup tip something that should be in a cus
Cutch
2014/04/17 22:12:39
I'd like that at some point.
|
| ProfileCodeTrieNodeTreeRow(this.profile, this.root, this.node, |
| ProfileCodeTrieNodeTreeRow parent) |
| @@ -28,13 +27,30 @@ class ProfileCodeTrieNodeTreeRow extends TableTreeRow { |
| assert(root != null); |
| assert(node != null); |
| var totalSamples = root.count; |
| - // When the row is created, fill out the columns. |
| - if (parent == null) { |
| - columns.add(formatPercent(node.count, root.count)); |
| + tipTicks = '${node.count}'; |
| + var period = profile['period']; |
| + var MICROSECONDS_PER_SECOND = 1000000.0; |
| + var seconds = (period * node.count) / MICROSECONDS_PER_SECOND; // seconds |
| + tipTime = Utils.formatTimePrecise(seconds); |
| + if (code.kind == CodeKind.Tag) { |
| + columns.add(Utils.formatPercent(node.count, root.count)); |
| + columns.add(Utils.formatPercent(node.count, root.count)); |
| + tipKind = 'Tag (category)'; |
| } else { |
| - columns.add(formatPercent(node.count, parent.node.count)); |
| + if (code.kind == CodeKind.Collected) { |
| + tipKind = 'Code is gone (collected)'; |
| + } else if (code.kind == CodeKind.Reused) { |
| + tipKind = 'Code is gone (collected then overwritten)'; |
| + } else { |
| + tipKind = '${code.kind} (Function)'; |
| + } |
| + if (parent == null) { |
| + columns.add(Utils.formatPercent(node.count, root.count)); |
| + } else { |
| + columns.add(Utils.formatPercent(node.count, parent.node.count)); |
| + } |
| + columns.add(Utils.formatPercent(node.code.exclusiveTicks, totalSamples)); |
| } |
| - columns.add(formatPercent(node.code.exclusiveTicks, totalSamples)); |
| } |
| bool shouldDisplayChild(CodeTrieNode childNode, double threshold) { |
| @@ -61,75 +77,19 @@ class ProfileCodeTrieNodeTreeRow extends TableTreeRow { |
| } |
| } |
| -class ProfileCallerTreeRow extends TableTreeRow { |
| - final ServiceMap profile; |
| - @reflectable final Code code; |
| - |
| - static String formatPercent(num a, num total) { |
| - var percent = 100.0 * (a / total); |
| - return '${percent.toStringAsFixed(2)}%'; |
| - } |
| - |
| - ProfileCallerTreeRow(this.profile, this.code, ProfileCallerTreeRow parent) : |
| - super(parent) { |
| - assert(profile != null); |
| - assert(code != null); |
| - var totalSamples = profile['samples']; |
| - // When the row is created, fill out the columns. |
| - if (parent == null) { |
| - var root = profile.isolate.tagRoot(); |
| - var totalAttributedCalls = root.callersCount(code); |
| - var totalParentCalls = root.sumCallersCount(); |
| - columns.add(formatPercent(totalAttributedCalls, totalParentCalls)); |
| - } else { |
| - var totalAttributedCalls = parent.code.callersCount(code); |
| - var totalParentCalls = parent.code.sumCallersCount(); |
| - columns.add(formatPercent(totalAttributedCalls, totalParentCalls)); |
| - } |
| - columns.add(formatPercent(code.exclusiveTicks, totalSamples)); |
| - } |
| - |
| - bool shouldDisplayChild(CodeCallCount childNode, totalSamples, |
| - double threshold) { |
| - var callerPercent = code.callersCount(childNode.code) / |
| - code.sumCallersCount(); |
| - return (callerPercent > threshold) || |
| - ((childNode.code.exclusiveTicks / totalSamples) > threshold); |
| - } |
| - |
| - void onShow() { |
| - var threshold = profile['threshold']; |
| - var totalSamples = profile['samples']; |
| - if (children.length > 0) { |
| - // Child rows already created. |
| - return; |
| - } |
| - for (var codeCaller in code.callers) { |
| - if (!shouldDisplayChild(codeCaller, totalSamples, threshold)) { |
| - continue; |
| - } |
| - var row = new ProfileCallerTreeRow(profile, codeCaller.code, this); |
| - children.add(row); |
| - } |
| - } |
| - |
| - void onHide() { |
| - } |
| -} |
| - |
| /// Displays an IsolateProfile |
| @CustomTag('isolate-profile') |
| class IsolateProfileElement extends ObservatoryElement { |
| IsolateProfileElement.created() : super.created(); |
| @published ServiceMap profile; |
| - @observable bool callGraphChecked; |
| @observable bool hideTagsChecked; |
| @observable String sampleCount = ''; |
| @observable String refreshTime = ''; |
| @observable String sampleRate = ''; |
| @observable String sampleDepth = ''; |
| @observable String displayCutoff = ''; |
| - @reflectable double displayThreshold = 0.0001; // 0.5%. |
| + @observable String timeSpan = ''; |
| + @reflectable double displayThreshold = 0.0002; // 0.02%. |
| final _id = '#tableTree'; |
| TableTree tree; |
| @@ -147,16 +107,13 @@ class IsolateProfileElement extends ObservatoryElement { |
| sampleDepth = profile['depth'].toString(); |
| var period = profile['period']; |
| sampleRate = (MICROSECONDS_PER_SECOND / period).toStringAsFixed(0); |
| + timeSpan = formatTime(profile['timeSpan']); |
| displayCutoff = '${(displayThreshold * 100.0).toString()}%'; |
| profile.isolate.processProfile(profile); |
| profile['threshold'] = displayThreshold; |
| _update(); |
| } |
| - void callGraphCheckedChanged(oldValue) { |
| - _update(); |
| - } |
| - |
| void enteredView() { |
| tree = new TableTree(); |
| @@ -186,25 +143,10 @@ class IsolateProfileElement extends ObservatoryElement { |
| _buildTree(); |
| } |
| - void _buildCallersTree() { |
| - assert(profile != null); |
| - var root = profile.isolate.tagRoot(); |
| - if (root == null) { |
| - Logger.root.warning('No profile root tag.'); |
| - } |
| - try { |
| - tree.initialize(new ProfileCallerTreeRow(profile, root, null)); |
| - } catch (e, stackTrace) { |
| - Logger.root.warning('_buildCallersTree', e, stackTrace); |
| - } |
| - |
| - notifyPropertyChange(#tree, null, tree); |
| - } |
| - |
| void _buildStackTree() { |
| var root = profile.isolate.profileTrieRoot; |
| if (root == null) { |
| - Logger.root.warning('No profile trie root.'); |
| + return; |
| } |
| try { |
| tree.initialize( |
| @@ -216,11 +158,7 @@ class IsolateProfileElement extends ObservatoryElement { |
| } |
| void _buildTree() { |
| - if ((callGraphChecked) != null && callGraphChecked) { |
| - _buildCallersTree(); |
| - } else { |
| - _buildStackTree(); |
| - } |
| + _buildStackTree(); |
| } |
| @observable String padding(TableTreeRow row) { |
| @@ -228,8 +166,10 @@ class IsolateProfileElement extends ObservatoryElement { |
| } |
| @observable String coloring(TableTreeRow row) { |
| - const colors = const ['active', 'success', 'warning', 'danger', 'info']; |
| - var index = row.depth % colors.length; |
| + const colors = const ['color0', 'color1', 'color2', 'color4', 'color5', |
|
turnidge
2014/04/17 20:18:54
What happened to color3?
We should probably name
Cutch
2014/04/17 22:12:39
Fixed.
|
| + 'color6', 'color7', 'color8']; |
| + var d = row.depth - 1; |
| + var index = d % colors.length; |
| return colors[index]; |
| } |
| @@ -244,7 +184,11 @@ class IsolateProfileElement extends ObservatoryElement { |
| var row = target.parent; |
| if (row is TableRowElement) { |
| // Subtract 1 to get 0 based indexing. |
| - tree.toggle(row.rowIndex - 1); |
| + try { |
| + tree.toggle(row.rowIndex - 1); |
| + } catch (e, stackTrace) { |
| + Logger.root.warning('toggleExpanded', e, stackTrace); |
| + } |
| } |
| } |
| } |