| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 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/multi_dimensional_view.html"> |
| <link rel="import" href="/tracing/base/range.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; |
| } |
| </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; |
| var SAMPLE_TYPE = { |
| COMPILER: 'compiler', |
| EXTERNAL: 'external', |
| GC: 'gc', |
| NATIVEV8: '[native v8]', |
| OTHER: 'other', |
| UNKNOWN: 'unknown' |
| }; |
| |
| 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(function(event) { |
| return event instanceof tr.model.Sample; |
| }); |
| |
| samples.forEach(function(sample) { |
| builder.addPath([sample.getUserFriendlyStackTrace().reverse()], |
| [1], MultiDimensionalViewBuilder.ValueKind.SELF); |
| }); |
| |
| return builder.buildView(viewOption); |
| }, |
| |
| // Constructs function name and file name of sample |
| // if it is compiler, external, gc, other, or unknown. |
| processTypedSampleRow_: function(row) { |
| var title = row.title[0]; |
| switch (title) { |
| case SAMPLE_TYPE.COMPILER: |
| case SAMPLE_TYPE.EXTERNAL: |
| case SAMPLE_TYPE.GC: |
| case SAMPLE_TYPE.OTHER: |
| row.functionName = title; |
| row.fileName = 'N/A'; |
| return true; |
| case SAMPLE_TYPE.UNKNOWN: |
| row.functionName = SAMPLE_TYPE.UNKNOWN; |
| row.fileName = SAMPLE_TYPE.UNKNOWN; |
| return true; |
| default: |
| return false; |
| } |
| }, |
| |
| // Constructs function name and file name of native v8 sample. |
| processNativeV8SampleRow_: function(row) { |
| var title = row.title[0]; |
| if (!title.includes(SAMPLE_TYPE.NATIVEV8)) |
| return false; |
| var arr = title.split(SAMPLE_TYPE.NATIVEV8); |
| row.functionName = arr[0].trim(); |
| if (row.functionName === '') |
| row.functionName = '(anonymous function)'; |
| row.fileName = SAMPLE_TYPE.NATIVEV8; |
| var fileNameSuffix = arr[1].trim(); |
| if (fileNameSuffix !== '') |
| row.fileName += ' ' + fileNameSuffix; |
| return true; |
| }, |
| |
| // Constructs function name and file name for sample. |
| processGeneralSampleRow_: function(row) { |
| var title = row.title[0]; |
| var idx = title.lastIndexOf(' '); |
| if (idx === -1) { |
| row.functionName = title; |
| row.fileName = 'unknown'; |
| return; |
| } |
| var prefix = title.substr(0, idx); |
| var suffix = title.substr(idx + 1); |
| if (suffix.startsWith('v8/')) { |
| row.functionName = suffix; |
| row.fileName = 'unknown'; |
| } else if (suffix === '') { |
| row.functionName = prefix; |
| row.fileName = 'unknown'; |
| } else if (prefix === '') { |
| row.functionName = '(anonymous function)'; |
| row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); |
| } else { |
| row.functionName = prefix; |
| row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); |
| } |
| }, |
| |
| processSampleRows_: function(rows) { |
| rows.forEach(function(row) { |
| if (!this.processTypedSampleRow_(row) && |
| !this.processNativeV8SampleRow_(row)) |
| this.processGeneralSampleRow_(row); |
| this.processSampleRows_(row.subRows); |
| }, this); |
| }, |
| |
| 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) { return row.functionName; }, |
| width: '150px', |
| cmp: function(a, b) { |
| return a.functionName.localeCompare(b.functionName); |
| }, |
| showExpandButtons: true |
| }, |
| { |
| title: 'Location', |
| value: function(row) { return row.fileName; }, |
| width: '250px', |
| cmp: function(a, b) { |
| return a.fileName.localeCompare(b.fileName); |
| } |
| } |
| ]; |
| |
| 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.Range.PERCENT_RANGE, |
| unit: tr.b.Unit.byName.normalizedPercentage, |
| context: { minimumFractionDigits: 2, maximumFractionDigits: 2 }, |
| rightAlign: true |
| }); |
| }, |
| width: '60px', |
| cmp: function(a, b) { |
| return 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 }, |
| rightAlign: true |
| }); |
| }, |
| width: '60px', |
| cmp: function(a, b) { |
| return 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> |