1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/base.html">
9<link rel="import" href="/tracing/model/event_set.html">
10<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
11<link rel="import" href="/tracing/ui/analysis/generic_object_view.html">
12<link rel="import" href="/tracing/ui/analysis/stack_frame.html">
13<link rel="import" href="/tracing/ui/base/table.html">
14<link rel="import" href="/tracing/ui/base/ui.html">
15<link rel="import" href="/tracing/value/ui/scalar_span.html">
16<link rel="import" href="/tracing/value/unit.html">
17
18<polymer-element name="tr-ui-a-single-event-sub-view"
19    extends="tr-ui-a-sub-view">
20  <template>
21    <style>
22    :host {
23      display: flex;
24      flex-direction: column;
25    }
26    #table {
27      flex: 1 1 auto;
28      align-self: stretch;
29    }
30    </style>
31    <tr-ui-b-table id="table">
32    </tr-ui-b-table>
33  </template>
34  <script>
35  'use strict';
36
37  Polymer({
38    ready: function() {
39      this.currentSelection_ = undefined;
40      this.$.table.tableColumns = [
41        {
42          title: 'Label',
43          value: function(row) { return row.name; },
44          width: '150px'
45        },
46        {
47          title: 'Value',
48          width: '100%',
49          value: function(row) { return row.value; }
50        }
51      ];
52      this.$.table.showHeader = false;
53    },
54
55    get selection() {
56      return this.currentSelection_;
57    },
58
59    set selection(selection) {
60      if (selection.length !== 1)
61        throw new Error('Only supports single slices');
62      this.setSelectionWithoutErrorChecks(selection);
63    },
64
65    setSelectionWithoutErrorChecks: function(selection) {
66      this.currentSelection_ = selection;
67      this.updateContents_();
68    },
69
70    getEventRows_: function(event) {
71      var rows = [];
72
73      if (event.error)
74        rows.push({ name: 'Error', value: event.error });
75
76      if (event.title)
77        rows.push({ name: 'Title', value: event.title });
78
79      if (event.category)
80        rows.push({ name: 'Category', value: event.category });
81
82      if (event.model !== undefined) {
83        var ufc = event.model.getUserFriendlyCategoryFromEvent(event);
84        if (ufc !== undefined)
85          rows.push({ name: 'User Friendly Category', value: ufc });
86      }
87
88      if (event.name)
89        rows.push({ name: 'Name', value: event.name });
90
91      rows.push({
92        name: 'Start',
93        value: tr.v.ui.createScalarSpan(event.start, {
94          unit: tr.v.Unit.byName.timeStampInMs
95        })
96      });
97
98      if (event.duration) {
99        rows.push({
100          name: 'Wall Duration',
101          value: tr.v.ui.createScalarSpan(event.duration, {
102            unit: tr.v.Unit.byName.timeDurationInMs
103          })
104        });
105      }
106
107      if (event.cpuDuration) {
108        rows.push({
109          name: 'CPU Duration',
110          value: tr.v.ui.createScalarSpan(event.cpuDuration, {
111            unit: tr.v.Unit.byName.timeDurationInMs
112          })
113        });
114      }
115
116      if (event.subSlices !== undefined && event.subSlices.length !== 0) {
117        if (event.selfTime) {
118          rows.push({
119            name: 'Self Time',
120            value: tr.v.ui.createScalarSpan(event.selfTime, {
121              unit: tr.v.Unit.byName.timeDurationInMs
122            })
123          });
124        }
125
126        if (event.cpuSelfTime) {
127          var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, {
128            unit: tr.v.Unit.byName.timeDurationInMs
129          });
130          if (event.cpuSelfTime > event.selfTime) {
131            cpuSelfTimeEl.warning =
132                ' Note that CPU Self Time is larger than Self Time. ' +
133                'This is a known limitation of this system, which occurs ' +
134                'due to several subslices, rounding issues, and imprecise ' +
135                'time at which we get cpu- and real-time.';
136          }
137          rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl });
138        }
139      }
140
141      if (event.durationInUserTime) {
142        rows.push({
143          name: 'Duration (U)',
144          value: tr.v.ui.createScalarSpan(event.durationInUserTime, {
145            unit: tr.v.Unit.byName.timeDurationInMs
146          })
147        });
148      }
149
150      function createStackFrameEl(sf) {
151        var sfEl = document.createElement('tr-ui-a-stack-frame');
152        sfEl.stackFrame = sf;
153        return sfEl;
154      }
155      if (event.startStackFrame && event.endStackFrame) {
156        if (event.startStackFrame === event.endStackFrame) {
157          rows.push({name: 'Start+End Stack Trace',
158              value: createStackFrameEl(event.startStackFrame)});
159
160        } else {
161          rows.push({ name: 'Start Stack Trace',
162              value: createStackFrameEl(event.startStackFrame)});
163          rows.push({ name: 'End Stack Trace',
164              value: createStackFrameEl(event.endStackFrame)});
165        }
166      } else if (event.startStackFrame) {
167        rows.push({ name: 'Start Stack Trace',
168            value: createStackFrameEl(event.startStackFrame)});
169
170      } else if (event.endStackFrame) {
171        rows.push({ name: 'End Stack Trace',
172            value: createStackFrameEl(event.endStackFrame)});
173      }
174
175      if (event.info) {
176        var descriptionEl = tr.ui.b.createDiv({
177            textContent: event.info.description,
178            maxWidth: '300px'
179        });
180        rows.push({
181          name: 'Description',
182          value: descriptionEl
183        });
184
185
186        if (event.info.docLinks) {
187          event.info.docLinks.forEach(function(linkObject) {
188            var linkEl = document.createElement('a');
189            linkEl.target = '_blank';
190            linkEl.href = linkObject.href;
191            linkEl.textContent = linkObject.textContent;
192            rows.push({
193              name: linkObject.label,
194              value: linkEl
195            });
196          });
197        }
198      }
199
200      if (event.associatedAlerts.length) {
201        var alertSubRows = [];
202        event.associatedAlerts.forEach(function(alert) {
203          var linkEl = document.createElement('tr-ui-a-analysis-link');
204          linkEl.setSelectionAndContent(function() {
205            return new tr.model.EventSet(alert);
206          }, alert.info.description);
207          alertSubRows.push({
208            name: alert.title,
209            value: linkEl
210          });
211        });
212
213        rows.push({
214          name: 'Alerts', value: '',
215          isExpanded: true, subRows: alertSubRows
216        });
217      }
218      return rows;
219    },
220
221    addArgsToRows_: function(rows, args) {
222      var n = 0;
223      for (var argName in args) {
224        n += 1;
225      }
226      if (n > 0) {
227        var subRows = [];
228        for (var argName in args) {
229          var argView =
230              document.createElement('tr-ui-a-generic-object-view');
231          argView.object = args[argName];
232          subRows.push({ name: argName,
233                      value: argView});
234        }
235        rows.push({
236          name: 'Args', value: '',
237          isExpanded: true, subRows: subRows
238        });
239      }
240      return rows;
241    },
242
243    updateContents_: function() {
244      if (this.currentSelection_ === undefined) {
245        this.$.table.rows = [];
246        this.$.table.rebuild();
247        return;
248      }
249
250      var event = this.currentSelection_[0];
251
252      var rows = this.getEventRows_(event);
253      if (event.argsStripped)
254        rows.push({ name: 'Args', value: 'Stripped' });
255      else
256        this.addArgsToRows_(rows, event.args);
257
258      var event = new tr.b.Event('customize-rows');
259      event.rows = rows;
260      this.dispatchEvent(event);
261
262      this.$.table.tableRows = rows;
263      this.$.table.rebuild();
264    }
265  });
266  </script>
267</polymer-element>
268