blob: 5e0448b816eed5c03813524b44b6bb5805e6da55 [file] [log] [blame]
<!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>