6e9993a169964ae63d62060796255b4680484489
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / analysis / analysis_results.js
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 tvcm.requireStylesheet('tracing.analysis.analysis_results');
8
9 tvcm.require('tracing.analysis.util');
10 tvcm.require('tracing.analysis.analysis_link');
11 tvcm.require('tracing.analysis.generic_object_view');
12 tvcm.require('tvcm.ui');
13
14 tvcm.exportTo('tracing.analysis', function() {
15   var AnalysisResults = tvcm.ui.define('div');
16
17   AnalysisResults.prototype = {
18     __proto__: HTMLDivElement.prototype,
19
20     decorate: function() {
21       this.className = 'analysis-results';
22     },
23
24     get requiresTallView() {
25       return false;
26     },
27
28     clear: function() {
29       this.textContent = '';
30     },
31
32     createSelectionChangingLink: function(text, selectionGenerator,
33                                           opt_tooltip) {
34       var el = this.ownerDocument.createElement('a');
35       tracing.analysis.AnalysisLink.decorate(el);
36       el.textContent = text;
37       el.selectionGenerator = selectionGenerator;
38       if (opt_tooltip)
39         el.title = opt_tooltip;
40       return el;
41     },
42
43     appendElement_: function(parent, tagName, opt_text) {
44       var n = parent.ownerDocument.createElement(tagName);
45       parent.appendChild(n);
46       if (opt_text != undefined)
47         n.textContent = opt_text;
48       return n;
49     },
50
51     appendText_: function(parent, text) {
52       var textElement = parent.ownerDocument.createTextNode(text);
53       parent.appendChild(textNode);
54       return textNode;
55     },
56
57     appendTableCell_: function(table, row, cellnum, text, opt_warning) {
58       var td = this.appendElement_(row, 'td', text);
59       td.className = table.className + '-col-' + cellnum;
60       if (opt_warning) {
61         var span = document.createElement('span');
62         span.textContent = ' ' + String.fromCharCode(9888);
63         span.title = opt_warning;
64         td.appendChild(span);
65       }
66       return td;
67     },
68
69     /**
70      * Creates and append a table cell at the end of the given row.
71      */
72     appendTableCell: function(table, row, text) {
73       return this.appendTableCell_(table, row, row.children.length, text);
74     },
75
76     appendTableCellWithTooltip_: function(table, row, cellnum, text, tooltip) {
77       if (tooltip) {
78         var td = this.appendElement_(row, 'td');
79         td.className = table.className + '-col-' + cellnum;
80         var span = this.appendElement_(td, 'span', text);
81         span.className = 'tooltip';
82         span.title = tooltip;
83         return td;
84       } else {
85         this.appendTableCell_(table, row, cellnum, text);
86       }
87     },
88
89     /**
90      * Creates and appends a section header element.
91      */
92     appendHeader: function(label) {
93       var header = this.appendElement_(this, 'span', label);
94       header.className = 'analysis-header';
95       return header;
96     },
97
98     /**
99      * Creates and appends a info element of the format "<b>label</b>value".
100      */
101     appendInfo: function(label, value) {
102       var div = this.appendElement_(this, 'div');
103       div.label = this.appendElement_(div, 'b', label);
104       div.value = this.appendElement_(div, 'span', value);
105       return div;
106     },
107
108     /**
109      * Adds a table with the given className.
110      *
111      * @return {HTMLTableElement} The newly created table.
112      */
113     appendTable: function(className, numColumns) {
114       var table = this.appendElement_(this, 'table');
115       table.className = className + ' analysis-table';
116       table.numColumns = numColumns;
117       return table;
118     },
119
120     /**
121      * Creates and appends a |tr| in |thead|, if |thead| does not exist, create
122      * it as well.
123      */
124     appendHeadRow: function(table) {
125       if (table.headerRow)
126         throw new Error('Only one header row allowed.');
127       if (table.tbody || table.tfoot)
128         throw new Error(
129             'Cannot add a header row after data rows have been added.');
130       table.headerRow = this.appendElement_(
131                                   this.appendElement_(table, 'thead'), 'tr');
132       table.headerRow.className = 'analysis-table-header';
133       return table.headerRow;
134     },
135
136     /**
137      * Creates and appends a |tr| in |tbody|, if |tbody| does not exist, create
138      * it as well.
139      */
140     appendBodyRow: function(table) {
141       if (table.tfoot)
142         throw new Error(
143             'Cannot add a tbody row after footer rows have been added.');
144       if (!table.tbody)
145         table.tbody = this.appendElement_(table, 'tbody');
146       var row = this.appendElement_(table.tbody, 'tr');
147       if (table.headerRow)
148         row.className = 'analysis-table-row';
149       else
150         row.className = 'analysis-table-row-inverted';
151       return row;
152     },
153
154     /**
155      * Creates and appends a |tr| in |tfoot|, if |tfoot| does not exist, create
156      * it as well.
157      */
158     appendFootRow: function(table) {
159       if (!table.tfoot) {
160         table.tfoot = this.appendElement_(table, 'tfoot');
161         table.tfoot.rowsClassName = (
162             (table.headerRow ? 1 : 0) +
163             (table.tbody ? table.tbody.rows.length : 0)) % 2 ?
164                 'analysis-table-row' : 'analysis-table-row-inverted';
165       }
166
167       var row = this.appendElement_(table.tfoot, 'tr');
168       row.className = table.tfoot.rowsClassName;
169       return row;
170     },
171
172     /**
173      * Adds a spacing row to spread out results.
174      */
175     appendSpacingRow: function(table, opt_inFoot) {
176       if (table.tfoot || opt_inFoot)
177         var row = this.appendFootRow(table);
178       else
179         var row = this.appendBodyRow(table);
180       for (var i = 0; i < table.numColumns; i++)
181         this.appendTableCell_(table, row, i, ' ');
182     },
183
184     /**
185      * Creates and appends a row to |table| with a left-aligned |label] in the
186      * first column and an optional |opt_value| in the second column.
187      */
188     appendInfoRow: function(table, label, opt_value, opt_inFoot) {
189       if (table.tfoot || opt_inFoot)
190         var row = this.appendFootRow(table);
191       else
192         var row = this.appendBodyRow(table);
193       this.appendTableCell_(table, row, 0, label);
194       if (opt_value !== undefined) {
195         var objectView = new tracing.analysis.GenericObjectView();
196         objectView.object = opt_value;
197         objectView.classList.add('analysis-table-col-1');
198         objectView.style.display = 'table-cell';
199         row.appendChild(objectView);
200       } else {
201         this.appendTableCell_(table, row, 1, '');
202       }
203       for (var i = 2; i < table.numColumns; i++)
204         this.appendTableCell_(table, row, i, '');
205     },
206
207     /**
208      * Creates and appends a row to |table| with a left-aligned |label] in the
209      * first column and a millisecond |time| value in the second column.
210      */
211     appendInfoRowTime: function(table, label, time, opt_inFoot, opt_warning) {
212       if (table.tfoot || opt_inFoot)
213         var row = this.appendFootRow(table);
214       else
215         var row = this.appendBodyRow(table);
216       this.appendTableCell_(table, row, 0, label);
217       this.appendTableCell_(
218           table, row, 1, tracing.analysis.tsRound(time) + ' ms', opt_warning);
219     },
220
221     /**
222      * Creates and appends a row to |table| that summarizes a single slice or a
223      * single counter. The row has a left-aligned |start| in the first column,
224      * the |duration| of the data in the second, the number of |occurrences| in
225      * the third.
226      *
227      * @param {object=} opt_statistics May be undefined, or an object which
228      *          contains calculated staistics containing min/max/avg for slices,
229      *          or min/max/avg/start/end for counters.
230      */
231     appendDetailsRow: function(table, start, duration, selfTime, args,
232         opt_selectionGenerator, opt_cpuDuration) {
233       var row = this.appendBodyRow(table);
234
235       if (opt_selectionGenerator) {
236         var labelEl = this.appendTableCell(table, row,
237                                            tracing.analysis.tsRound(start));
238         labelEl.textContent = '';
239         labelEl.appendChild(this.createSelectionChangingLink(
240                                     tracing.analysis.tsRound(start),
241                                     opt_selectionGenerator, ''));
242       } else {
243         this.appendTableCell(table, row, tracing.analysis.tsRound(start));
244       }
245
246       if (duration !== null)
247         this.appendTableCell(table, row, tracing.analysis.tsRound(duration));
248
249       if (opt_cpuDuration)
250         this.appendTableCell(table, row,
251                              opt_cpuDuration != '' ?
252                              tracing.analysis.tsRound(opt_cpuDuration) :
253                              '');
254
255       if (selfTime !== null)
256         this.appendTableCell(table, row, tracing.analysis.tsRound(selfTime));
257
258       var argsCell = this.appendTableCell(table, row, '');
259       var n = 0;
260       for (var argName in args) {
261         n += 1;
262       }
263
264       if (n > 0) {
265         for (var argName in args) {
266           var argVal = args[argName];
267           var objectView = new tracing.analysis.GenericObjectView();
268           objectView.object = argVal;
269           var argsRow = this.appendElement_(
270               this.appendElement_(argsCell, 'table'), 'tr');
271           this.appendElement_(argsRow, 'td', argName + ':');
272           this.appendElement_(argsRow, 'td').appendChild(objectView);
273         }
274       }
275     },
276
277     /**
278      * Creates and appends a row to |table| that summarizes one or more slices,
279      * or one or more counters. The row has a left-aligned |label| in the first
280      * column, the |duration| of the data in the second, the number of
281      * |occurrences| in the third.
282      *
283      * @param {object=} opt_statistics May be undefined, or an object which
284      *          contains calculated staistics containing min/max/avg for slices,
285      *          or min/max/avg/start/end for counters.
286      */
287     appendDataRow: function(table, label, opt_duration, opt_cpuDuration,
288                             opt_selfTime, opt_cpuSelfTime, opt_occurences,
289                             opt_percentage, opt_statistics,
290                             opt_selectionGenerator, opt_inFoot) {
291
292       var tooltip = undefined;
293       if (opt_statistics) {
294         tooltip = 'Min Duration:\u0009' +
295                   tracing.analysis.tsRound(opt_statistics.min) +
296                   ' ms \u000DMax Duration:\u0009' +
297                   tracing.analysis.tsRound(opt_statistics.max) +
298                   ' ms \u000DAvg Duration:\u0009' +
299                   tracing.analysis.tsRound(opt_statistics.avg) +
300                   ' ms (\u03C3 = ' +
301                   tracing.analysis.tsRound(opt_statistics.avg_stddev) + ')';
302
303         if (opt_statistics.start) {
304           tooltip += '\u000DStart Time:\u0009' +
305               tracing.analysis.tsRound(opt_statistics.start) + ' ms';
306         }
307         if (opt_statistics.end) {
308           tooltip += '\u000DEnd Time:\u0009' +
309               tracing.analysis.tsRound(opt_statistics.end) + ' ms';
310         }
311         if (opt_statistics.frequency && opt_statistics.frequency_stddev) {
312           tooltip += '\u000DFrequency:\u0009' +
313               tracing.analysis.tsRound(opt_statistics.frequency) +
314               ' occurrences/s (\u03C3 = ' +
315               tracing.analysis.tsRound(opt_statistics.frequency_stddev) + ')';
316         }
317       }
318
319       if (table.tfoot || opt_inFoot)
320         var row = this.appendFootRow(table);
321       else
322         var row = this.appendBodyRow(table);
323
324       var cellNum = 0;
325       if (!opt_selectionGenerator) {
326         this.appendTableCellWithTooltip_(table, row, cellNum, label, tooltip);
327       } else {
328         var labelEl = this.appendTableCellWithTooltip_(
329             table, row, cellNum, label, tooltip);
330         if (labelEl) {
331           labelEl.textContent = '';
332           labelEl.appendChild(
333               this.createSelectionChangingLink(label, opt_selectionGenerator,
334                                                tooltip));
335         }
336       }
337       cellNum++;
338
339       if (opt_duration !== null) {
340         if (opt_duration) {
341           if (opt_duration instanceof Array) {
342             this.appendTableCellWithTooltip_(table, row, cellNum,
343                 '[' + opt_duration.join(', ') + ']', tooltip);
344           } else {
345             this.appendTableCellWithTooltip_(table, row, cellNum,
346                 tracing.analysis.tsRound(opt_duration), tooltip);
347           }
348         } else {
349           this.appendTableCell_(table, row, cellNum, '');
350         }
351         cellNum++;
352       }
353
354       if (opt_cpuDuration !== null) {
355         if (opt_cpuDuration != '') {
356           this.appendTableCellWithTooltip_(table, row, cellNum,
357               tracing.analysis.tsRound(opt_cpuDuration), tooltip);
358         } else {
359           this.appendTableCell_(table, row, cellNum, '');
360         }
361         cellNum++;
362       }
363
364       if (opt_selfTime !== null) {
365         if (opt_selfTime) {
366           this.appendTableCellWithTooltip_(table, row, cellNum,
367               tracing.analysis.tsRound(opt_selfTime), tooltip);
368         } else {
369           this.appendTableCell_(table, row, cellNum, '');
370         }
371         cellNum++;
372       }
373
374       if (opt_cpuSelfTime !== null) {
375         if (opt_cpuSelfTime) {
376           this.appendTableCellWithTooltip_(table, row, cellNum,
377               tracing.analysis.tsRound(opt_cpuSelfTime), tooltip);
378         } else {
379           this.appendTableCell_(table, row, cellNum, '');
380         }
381         cellNum++;
382       }
383
384       if (opt_percentage !== null) {
385         if (opt_percentage) {
386           this.appendTableCellWithTooltip_(table, row, cellNum,
387                                            opt_percentage, tooltip);
388         } else {
389           this.appendTableCell_(table, row, cellNum, '');
390         }
391         cellNum++;
392       }
393
394       if (opt_occurences) {
395         this.appendTableCellWithTooltip_(table, row, cellNum,
396             String(opt_occurences), tooltip);
397       } else {
398         this.appendTableCell_(table, row, cellNum, '');
399       }
400       cellNum++;
401     }
402   };
403   return {
404     AnalysisResults: AnalysisResults
405   };
406 });