| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/base/math/range.html"> |
| <link rel="import" href="/tracing/base/multi_dimensional_view.html"> |
| <link rel="import" href="/tracing/base/unit.html"> |
| <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> |
| <link rel="import" href="/tracing/ui/base/table.html"> |
| <link rel="import" href="/tracing/value/ui/scalar_span.html"> |
| |
| <dom-module id='tr-ui-a-multi-sample-sub-view'> |
| <template> |
| <style> |
| :host { display: block; } |
| #control { |
| background-color: #e6e6e6; |
| background-image: -webkit-gradient(linear, 0 0, 0 100%, |
| from(#E5E5E5), to(#D1D1D1)); |
| flex: 0 0 auto; |
| overflow-x: auto; |
| } |
| #control::-webkit-scrollbar { height: 0px; } |
| #control { |
| font-size: 12px; |
| display: flex; |
| flex-direction: row; |
| align-items: stretch; |
| margin: 1px; |
| margin-right: 2px; |
| } |
| tr-ui-b-table { |
| font-size: 12px; |
| } |
| </style> |
| <div id="control"> |
| Sample View Option |
| </div> |
| <tr-ui-b-table id="table"> |
| </tr-ui-b-table> |
| </template> |
| </dom-module> |
| <script> |
| 'use strict'; |
| |
| (function() { |
| var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder; |
| |
| Polymer({ |
| is: 'tr-ui-a-multi-sample-sub-view', |
| behaviors: [tr.ui.analysis.AnalysisSubView], |
| |
| created: function() { |
| this.viewOption_ = undefined; |
| this.selection_ = undefined; |
| }, |
| |
| ready: function() { |
| var viewSelector = tr.ui.b.createSelector( |
| this, 'viewOption', 'tracing.ui.analysis.multi_sample_sub_view', |
| MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW, |
| [ |
| { |
| label: 'Top-down (Tree)', |
| value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW |
| }, |
| { |
| label: 'Top-down (Heavy)', |
| value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW |
| }, |
| { |
| label: 'Bottom-up (Heavy)', |
| value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW |
| } |
| ]); |
| Polymer.dom(this.$.control).appendChild(viewSelector); |
| this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; |
| }, |
| |
| get selection() { |
| return this.selection_; |
| }, |
| |
| set selection(selection) { |
| this.selection_ = selection; |
| this.updateContents_(); |
| }, |
| |
| get viewOption() { |
| return this.viewOption_; |
| }, |
| |
| set viewOption(viewOption) { |
| this.viewOption_ = viewOption; |
| this.updateContents_(); |
| }, |
| |
| createSamplingSummary_: function(selection, viewOption) { |
| var builder = new MultiDimensionalViewBuilder( |
| 1 /* dimensions */, 1 /* valueCount */); |
| var samples = selection.filter( |
| event => event instanceof tr.model.Sample); |
| |
| samples.forEach(function(sample) { |
| builder.addPath([sample.userFriendlyStack.reverse()], |
| [1], MultiDimensionalViewBuilder.ValueKind.SELF); |
| }); |
| |
| return builder.buildView(viewOption); |
| }, |
| |
| processSampleRows_: function(rows) { |
| for (var row of rows) { |
| var title = row.title[0]; |
| var results = /(.*) (Deoptimized reason: .*)/.exec(title); |
| if (results !== null) { |
| row.deoptReason = results[2]; |
| title = results[1]; |
| } |
| results = /(.*) url: (.*)/.exec(title); |
| if (results !== null) { |
| row.functionName = results[1]; |
| row.url = results[2]; |
| if (row.functionName === '') { |
| row.functionName = '(anonymous function)'; |
| } |
| if (row.url === '') { |
| row.url = 'unknown'; |
| } |
| } else { |
| row.functionName = title; |
| row.url = 'unknown'; |
| } |
| this.processSampleRows_(row.subRows); |
| } |
| }, |
| |
| updateContents_: function() { |
| if (this.selection === undefined) { |
| this.$.table.tableColumns = []; |
| this.$.table.tableRows = []; |
| this.$.table.rebuild(); |
| return; |
| } |
| |
| var samplingData = this.createSamplingSummary_( |
| this.selection, this.viewOption); |
| var total = samplingData.values[0].total; |
| var columns = [ |
| this.createPercentColumn_('Total', total), |
| this.createSamplesColumn_('Total'), |
| this.createPercentColumn_('Self', total), |
| this.createSamplesColumn_('Self'), |
| { |
| title: 'Function Name', |
| value: function(row) { |
| // For function that got deoptimized, show function name |
| // as red italic with a tooltip |
| if (row.deoptReason !== undefined) { |
| var spanEl = tr.ui.b.createSpan({ |
| italic: true, |
| color: '#F44336', |
| tooltip: row.deoptReason |
| }); |
| spanEl.innerText = row.functionName; |
| return spanEl; |
| } |
| return row.functionName; |
| }, |
| width: '150px', |
| cmp: (a, b) => a.functionName.localeCompare(b.functionName), |
| showExpandButtons: true |
| }, |
| { |
| title: 'Location', |
| value: function(row) { return row.url; }, |
| width: '250px', |
| cmp: (a, b) => a.url.localeCompare(b.url), |
| } |
| ]; |
| |
| this.processSampleRows_(samplingData.subRows); |
| this.$.table.tableColumns = columns; |
| this.$.table.sortColumnIndex = 1; /* Total samples */ |
| this.$.table.sortDescending = true; |
| this.$.table.tableRows = samplingData.subRows; |
| this.$.table.rebuild(); |
| }, |
| |
| createPercentColumn_: function(title, samplingDataTotal) { |
| var field = title.toLowerCase(); |
| return { |
| title: title + ' percent', |
| value: function(row) { |
| return tr.v.ui.createScalarSpan( |
| row.values[0][field] / samplingDataTotal, { |
| customContextRange: tr.b.math.Range.PERCENT_RANGE, |
| unit: tr.b.Unit.byName.normalizedPercentage, |
| context: { minimumFractionDigits: 2, maximumFractionDigits: 2 }, |
| }); |
| }, |
| width: '60px', |
| cmp: (a, b) => a.values[0][field] - b.values[0][field] |
| }; |
| }, |
| |
| createSamplesColumn_: function(title) { |
| var field = title.toLowerCase(); |
| return { |
| title: title + ' samples', |
| value: function(row) { |
| return tr.v.ui.createScalarSpan(row.values[0][field], { |
| unit: tr.b.Unit.byName.unitlessNumber, |
| context: { maximumFractionDigits: 0 }, |
| }); |
| }, |
| width: '60px', |
| cmp: (a, b) => a.values[0][field] - b.values[0][field] |
| }; |
| } |
| }); |
| |
| tr.ui.analysis.AnalysisSubView.register( |
| 'tr-ui-a-multi-sample-sub-view', |
| tr.model.Sample, |
| { |
| multi: true, |
| title: 'Samples', |
| }); |
| })(); |
| </script> |