blob: b3a852c60298a328dffb0fdbf0e77b0a70dccfd8 [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/base.html">
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/base/unit.html">
<link rel="import" href="/tracing/model/event_set.html">
<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
<link rel="import" href="/tracing/ui/analysis/stack_frame.html">
<link rel="import" href="/tracing/ui/base/table.html">
<link rel="import" href="/tracing/ui/base/ui.html">
<link rel="import" href="/tracing/value/ui/scalar_span.html">
<dom-module id='tr-ui-a-single-event-sub-view'>
<template>
<style>
:host {
display: flex;
flex-direction: column;
}
#table {
flex: 1 1 auto;
align-self: stretch;
}
</style>
<tr-ui-b-table id="table">
</tr-ui-b-table>
</template>
</dom-module>
<script>
'use strict';
Polymer({
is: 'tr-ui-a-single-event-sub-view',
behaviors: [tr.ui.analysis.AnalysisSubView],
properties: {
isFlow: {
type: Boolean,
value: false
}
},
ready: function() {
this.currentSelection_ = undefined;
this.$.table.tableColumns = [
{
title: 'Label',
value: function(row) { return row.name; },
width: '150px'
},
{
title: 'Value',
width: '100%',
value: function(row) { return row.value; }
}
];
this.$.table.showHeader = false;
},
get selection() {
return this.currentSelection_;
},
set selection(selection) {
if (selection.length !== 1)
throw new Error('Only supports single slices');
this.setSelectionWithoutErrorChecks(selection);
},
setSelectionWithoutErrorChecks: function(selection) {
this.currentSelection_ = selection;
this.updateContents_();
},
getFlowEventRows_: function(event) {
// TODO(nduca): Figure out if there is a cleaner way to do this.
var rows = this.getEventRowsHelper_(event);
// var rows = this.__proto__.__proto__.getEventRows_(event);
// Put the ID up top.
rows.splice(0, 0, {
name: 'ID',
value: event.id
});
function createLinkTo(slice) {
var linkEl = document.createElement('tr-ui-a-analysis-link');
linkEl.setSelectionAndContent(function() {
return new tr.model.EventSet(slice);
});
Polymer.dom(linkEl).textContent = slice.userFriendlyName;
return linkEl;
}
rows.push({
name: 'From',
value: createLinkTo(event.startSlice)
});
rows.push({
name: 'To',
value: createLinkTo(event.endSlice)
});
return rows;
},
getEventRowsHelper_: function(event) {
var rows = [];
if (event.error)
rows.push({ name: 'Error', value: event.error });
if (event.title)
rows.push({ name: 'Title', value: event.title });
if (event.category)
rows.push({ name: 'Category', value: event.category });
if (event.model !== undefined) {
var ufc = event.model.getUserFriendlyCategoryFromEvent(event);
if (ufc !== undefined)
rows.push({ name: 'User Friendly Category', value: ufc });
}
if (event.name)
rows.push({ name: 'Name', value: event.name });
rows.push({
name: 'Start',
value: tr.v.ui.createScalarSpan(event.start, {
unit: tr.b.Unit.byName.timeStampInMs
})
});
if (event.duration) {
rows.push({
name: 'Wall Duration',
value: tr.v.ui.createScalarSpan(event.duration, {
unit: tr.b.Unit.byName.timeDurationInMs
})
});
}
if (event.cpuDuration) {
rows.push({
name: 'CPU Duration',
value: tr.v.ui.createScalarSpan(event.cpuDuration, {
unit: tr.b.Unit.byName.timeDurationInMs
})
});
}
if (event.subSlices !== undefined && event.subSlices.length !== 0) {
if (event.selfTime) {
rows.push({
name: 'Self Time',
value: tr.v.ui.createScalarSpan(event.selfTime, {
unit: tr.b.Unit.byName.timeDurationInMs
})
});
}
if (event.cpuSelfTime) {
var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, {
unit: tr.b.Unit.byName.timeDurationInMs
});
if (event.cpuSelfTime > event.selfTime) {
cpuSelfTimeEl.warning =
' Note that CPU Self Time is larger than Self Time. ' +
'This is a known limitation of this system, which occurs ' +
'due to several subslices, rounding issues, and imprecise ' +
'time at which we get cpu- and real-time.';
}
rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl });
}
}
if (event.durationInUserTime) {
rows.push({
name: 'Duration (U)',
value: tr.v.ui.createScalarSpan(event.durationInUserTime, {
unit: tr.b.Unit.byName.timeDurationInMs
})
});
}
function createStackFrameEl(sf) {
var sfEl = document.createElement('tr-ui-a-stack-frame');
sfEl.stackFrame = sf;
return sfEl;
}
if (event.startStackFrame && event.endStackFrame) {
if (event.startStackFrame === event.endStackFrame) {
rows.push({name: 'Start+End Stack Trace',
value: createStackFrameEl(event.startStackFrame)});
} else {
rows.push({ name: 'Start Stack Trace',
value: createStackFrameEl(event.startStackFrame)});
rows.push({ name: 'End Stack Trace',
value: createStackFrameEl(event.endStackFrame)});
}
} else if (event.startStackFrame) {
rows.push({ name: 'Start Stack Trace',
value: createStackFrameEl(event.startStackFrame)});
} else if (event.endStackFrame) {
rows.push({ name: 'End Stack Trace',
value: createStackFrameEl(event.endStackFrame)});
}
if (event.info) {
var descriptionEl = tr.ui.b.createDiv({
textContent: event.info.description,
maxWidth: '300px'
});
rows.push({
name: 'Description',
value: descriptionEl
});
if (event.info.docLinks) {
event.info.docLinks.forEach(function(linkObject) {
var linkEl = document.createElement('a');
linkEl.target = '_blank';
linkEl.href = linkObject.href;
Polymer.dom(linkEl).textContent = Polymer.dom(linkObject).textContent;
rows.push({
name: linkObject.label,
value: linkEl
});
});
}
}
if (event.associatedAlerts.length) {
var alertSubRows = [];
event.associatedAlerts.forEach(function(alert) {
var linkEl = document.createElement('tr-ui-a-analysis-link');
linkEl.setSelectionAndContent(function() {
return new tr.model.EventSet(alert);
}, alert.info.description);
alertSubRows.push({
name: alert.title,
value: linkEl
});
});
rows.push({
name: 'Alerts', value: '',
isExpanded: true, subRows: alertSubRows
});
}
return rows;
},
getEventRows_: function(event) {
if (this.isFlow)
return this.getFlowEventRows_(event);
return this.getEventRowsHelper_(event);
},
addArgsToRows_: function(rows, args) {
var n = 0;
for (var argName in args) {
n += 1;
}
if (n > 0) {
var subRows = [];
for (var argName in args) {
n += 1;
}
if (n > 0) {
var subRows = [];
for (var argName in args) {
var argView =
document.createElement('tr-ui-a-generic-object-view');
argView.object = args[argName];
subRows.push({name: argName, value: argView});
}
rows.push({
name: 'Args',
value: '',
isExpanded: true,
subRows: subRows
});
}
}
},
addContextsToRows_: function(rows, contexts) {
if (contexts.length) {
var subRows = contexts.map(function(context) {
var contextView =
document.createElement('tr-ui-a-generic-object-view');
contextView.object = context;
return {name: 'Context', value: contextView};
});
rows.push({
name: 'Contexts',
value: '',
isExpanded: true,
subRows: subRows
});
}
},
updateContents_: function() {
if (this.currentSelection_ === undefined) {
this.$.table.rows = [];
this.$.table.rebuild();
return;
}
var event = tr.b.getOnlyElement(this.currentSelection_);
var rows = this.getEventRows_(event);
if (event.argsStripped)
rows.push({ name: 'Args', value: 'Stripped' });
else
this.addArgsToRows_(rows, event.args);
this.addContextsToRows_(rows, event.contexts);
var customizeRowsEvent = new tr.b.Event('customize-rows');
customizeRowsEvent.rows = rows;
this.dispatchEvent(customizeRowsEvent);
this.$.table.tableRows = rows;
this.$.table.rebuild();
}
});
</script>