Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: tracing/tracing/value/ui/value_set_table.html

Issue 2424933003: Rename ValueSet* to HistogramSet*. (Closed)
Patch Set: fix Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 <!DOCTYPE html>
2 <!--
3 Copyright 2016 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
6 -->
7
8 <link rel="import" href="/tracing/base/raf.html">
9 <link rel="import" href="/tracing/base/unit.html">
10 <link rel="import" href="/tracing/ui/base/grouping_table_groupby_picker.html">
11 <link rel="import" href="/tracing/ui/base/table.html">
12 <link rel="import" href="/tracing/value/ui/diagnostic_span.html">
13 <link rel="import" href="/tracing/value/ui/histogram_span.html">
14 <link rel="import" href="/tracing/value/ui/scalar_span.html">
15 <link rel="import" href="/tracing/value/value_set.html">
16
17 <dom-module id="tr-v-ui-value-set-table-cell">
18 <template>
19 <style>
20 :host {
21 display: flex;
22 flex-direction: row;
23 }
24
25 #missing, #empty, #unmergeable, #scalar {
26 flex-grow: 1;
27 }
28
29 svg {
30 height: 1em;
31 }
32
33 #open_histogram {
34 margin-left: 4px;
35 stroke-width: 0;
36 stroke: blue;
37 fill: blue;
38 }
39 :host(:hover) #open_histogram {
40 background: blue;
41 stroke: white;
42 fill: white;
43 }
44
45 #scalar {
46 flex-grow: 1;
47 white-space: nowrap;
48 }
49
50 #histogram {
51 flex-grow: 1;
52 }
53
54 #close_histogram line {
55 stroke-width: 18;
56 stroke: black;
57 }
58 #close_histogram:hover {
59 background: black;
60 }
61 #close_histogram:hover line {
62 stroke: white;
63 }
64 </style>
65
66 <span id="missing">(missing)</span>
67 <span id="empty">(empty)</span>
68 <span id="unmergeable">(unmergeable)</span>
69
70 <tr-v-ui-scalar-span id="scalar" on-click="openHistogram_"></tr-v-ui-scalar- span>
71
72 <svg viewbox="0 0 128 128" id="open_histogram" on-click="openHistogram_">
73 <rect x="16" y="24" width="32" height="16"/>
74 <rect x="16" y="56" width="96" height="16"/>
75 <rect x="16" y="88" width="64" height="16"/>
76 </svg>
77
78 <span id="histogram"></span>
79
80 <svg viewbox="0 0 128 128" id="close_histogram" on-click="closeHistogram_">
81 <line x1="28" y1="28" x2="100" y2="100"/>
82 <line x1="28" y1="100" x2="100" y2="28"/>
83 </svg>
84 </template>
85 </dom-module>
86
87 <dom-module id="tr-v-ui-value-set-table">
88 <template>
89 <style>
90 :host {
91 display: block;
92 }
93
94 #container {
95 flex-direction: column;
96 display: none;
97 }
98
99 table-container {
100 margin-top: 5px;
101 display: flex;
102 min-height: 0px;
103 overflow-y: auto;
104 }
105
106 #histogram {
107 display: none;
108 }
109
110 #zero {
111 color: red;
112 /* value-set-table is used by both metrics-side-panel and results2.html.
113 * This font-size rule has no effect in results2.html, but improves
114 * legibility in the metrics-side-panel, which sets font-size in order to
115 * make this table denser.
116 */
117 font-size: initial;
118 }
119
120 #search {
121 max-width: 20em;
122 margin-right: 20px;
123 }
124
125 #controls {
126 white-space: nowrap;
127 }
128
129 #reference_column_container * {
130 margin-right: 20px;
131 }
132 </style>
133
134 <div id="zero">zero values</div>
135
136 <div id="container">
137 <div id="controls">
138 <input id="search" placeholder="Find Histogram name" on-keyup="onSearch_ ">
139
140 <span id="reference_column_container"></span>
141
142 <input type="checkbox" id="show_all" on-change="onShowAllChange_" title= "When unchecked, less important histograms are hidden.">
143 <label for="show_all" title="When unchecked, less important histograms a re hidden.">Show all</label>
144 </div>
145
146 <tr-ui-b-grouping-table-groupby-picker id="picker">
147 </tr-ui-b-grouping-table-groupby-picker>
148
149 <table-container>
150 <tr-ui-b-table id="table"/>
151 </table-container>
152 </div>
153 </template>
154 </dom-module>
155
156 <script>
157 'use strict';
158 tr.exportTo('tr.ui', function() {
159 /**
160 * Returns a closure that gets a story grouping key label from a Histogram.
161 *
162 * @param {string} storyGroupingKey
163 * @return {!function(tr.v.Histogram):string}
164 */
165 function makeStoryGroupingKeyLabelGetter(storyGroupingKey) {
166 return v => tr.v.d.IterationInfo.getStoryGroupingKeyLabel(
167 v, storyGroupingKey);
168 }
169
170 var getDisplayLabel = tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL.callback;
171
172 var DEFAULT_POSSIBLE_GROUPS = [];
173 DEFAULT_POSSIBLE_GROUPS.push(new tr.v.HistogramGrouping(
174 tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key,
175 h => h.shortName || h.name));
176
177 tr.b.iterItems(tr.v.ValueSet.GROUPINGS, function(name, group) {
178 // DISPLAY_LABEL is used to define the columns, so don't allow grouping
179 // rows by it.
180 // Override HISTOGRAM_NAME so that we can display shortName.
181 if (group !== tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL &&
182 group !== tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME)
183 DEFAULT_POSSIBLE_GROUPS.push(group);
184 });
185
186 var SHOW_ALL_SETTINGS_KEY = 'tr-v-ui-value-set-table-show-all';
187
188 var UNMERGEABLE = '(unmergeable)';
189
190 Polymer({
191 is: 'tr-v-ui-value-set-table-cell',
192
193 created: function() {
194 this.histogram_ = undefined;
195 this.referenceHistogram_ = undefined;
196 this.histogramSpan_ = undefined;
197 },
198
199 ready: function() {
200 this.addEventListener('click', this.onClick_.bind(this));
201 },
202
203 onClick_: function(event) {
204 // Since the value-set-table's table doesn't support any kind of
205 // selection, clicking anywhere within a row that has subRows will
206 // expand/collapse that row, which can relayout the table and move things
207 // around. Prevent table relayout by preventing the tr-ui-b-table from
208 // receiving the click event.
209 event.stopPropagation();
210 },
211
212 get histogram() {
213 return this.histogram_;
214 },
215
216 /**
217 * @param {undefined|string|!tr.v.Histogram} h
218 */
219 set histogram(h) {
220 this.histogram_ = h;
221 this.updateContents_();
222 },
223
224 /**
225 * @param {undefined|string|!tr.v.Histogram} rh
226 */
227 set referenceHistogram(rh) {
228 this.referenceHistogram_ = rh;
229 this.updateContents_();
230 },
231
232 get referenceHistogram() {
233 return this.referenceHistogram_;
234 },
235
236 get isHistogramOpen() {
237 return this.histogramSpan_ &&
238 (this.$.histogram.style.display === 'block');
239 },
240
241 set isHistogramOpen(open) {
242 if (!this.histogram ||
243 this.histogram === UNMERGEABLE ||
244 !(this.histogram instanceof tr.v.Histogram) ||
245 (this.histogram.numValues === 0)) {
246 return;
247 }
248
249 // Unfortunately, we can't use a css attribute for this since this stuff
250 // is tied up in all the possible states of this.histogram. See
251 // updateContents_().
252
253 this.$.scalar.style.display = open ? 'none' : 'block';
254 this.$.open_histogram.style.display = open ? 'none' : 'block';
255
256 this.$.close_histogram.style.display = open ? 'block' : 'none';
257 this.$.histogram.style.display = open ? 'block' : 'none';
258
259 // Wait to create the histogram-span until the user wants to display it
260 // in order to speed up creating lots of value-set-table-cells when
261 // building the table.
262 // Wait to pass the Histogram to the histogram-span until it's displayed
263 // so that it can size its BarChart appropriately.
264 if (open && this.histogramSpan_ === undefined) {
265 this.histogramSpan_ = document.createElement('tr-v-ui-histogram-span');
266 this.$.histogram.appendChild(this.histogramSpan_);
267 this.histogramSpan_.referenceHistogram = this.referenceHistogram;
268 this.histogramSpan_.histogram = this.histogram;
269 }
270 },
271
272 openHistogram_: function() {
273 this.isHistogramOpen = true;
274 },
275
276 closeHistogram_: function() {
277 this.isHistogramOpen = false;
278 },
279
280 updateContents_: function() {
281 this.$.empty.style.display = 'none';
282 this.$.unmergeable.style.display = 'none';
283 this.$.scalar.style.display = 'none';
284 this.$.histogram.style.display = 'none';
285 this.$.close_histogram.style.display = 'none';
286 this.$.open_histogram.style.visibility = 'hidden';
287
288 if (!this.histogram) {
289 this.$.missing.style.display = 'block';
290 return;
291 }
292
293 this.$.missing.style.display = 'none';
294
295 if (this.histogram === UNMERGEABLE) {
296 this.$.unmergeable.style.display = 'block';
297 return;
298 }
299
300 if (!(this.histogram instanceof tr.v.Histogram)) {
301 throw new Error('Invalid Histogram: ' + this.histogram);
302 }
303
304 if (this.histogram.numValues === 0) {
305 this.$.empty.style.display = 'block';
306 return;
307 }
308
309 this.$.open_histogram.style.display = 'block';
310 this.$.open_histogram.style.visibility = 'visible';
311 this.$.scalar.style.display = 'block';
312
313 if ((this.referenceHistogram instanceof tr.v.Histogram) &&
314 (this.histogram.unit === this.referenceHistogram.unit) &&
315 (this.referenceHistogram.numValues > 0)) {
316 this.$.scalar.setValueAndUnit(
317 this.histogram.average - this.referenceHistogram.average,
318 this.histogram.unit.correspondingDeltaUnit);
319 this.$.scalar.significance = this.histogram.getDifferenceSignificance(
320 this.referenceHistogram);
321 } else {
322 this.$.scalar.setValueAndUnit(
323 this.histogram.average, this.histogram.unit);
324 }
325 }
326 });
327
328 Polymer({
329 is: 'tr-v-ui-value-set-table',
330
331 /**
332 * This can optionally depend on the ValueSet.
333 *
334 * @return {string}
335 */
336 get tabLabel() {
337 return 'Table';
338 },
339
340 created: function() {
341 /** @type {undefined|!tr.v.ValueSet} */
342 this.values_ = undefined;
343
344 /** @type {undefined|!tr.v.ValueSet} */
345 this.sourceValues_ = undefined;
346
347 this.rows_ = undefined;
348 this.columns_ = undefined;
349
350 this.updatingContents_ = false;
351 this.displayLabels_ = undefined;
352 this.referenceDisplayLabel_ = undefined;
353 },
354
355 ready: function() {
356 this.$.table.zebra = true;
357 this.addEventListener('requestSelectionChange',
358 this.onRelatedValueSelected_.bind(this));
359 this.$.show_all.checked = tr.b.Settings.get(SHOW_ALL_SETTINGS_KEY, false);
360 this.$.picker.settingsKey = 'tr-v-ui-value-set-table-groupby-picker';
361
362 this.$.picker.possibleGroups = DEFAULT_POSSIBLE_GROUPS.slice();
363 this.$.picker.defaultGroupKeys = [
364 tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key,
365 tr.v.ValueSet.GROUPINGS.STORY_NAME.key];
366 this.$.picker.addEventListener('current-groups-changed',
367 this.currentGroupsChanged_.bind(this));
368 },
369
370 set groupingKeys(keys) {
371 this.$.picker.currentGroupKeys = keys;
372 },
373
374 get groupingKeys() {
375 return this.$.picker.currentGroupKeys;
376 },
377
378 get possibleGroupingKeys() {
379 return this.$.picker.possibleGroups.map(g => g.key);
380 },
381
382 currentGroupsChanged_: function() {
383 if (this.updatingContents_)
384 return;
385
386 if (this.$.picker.currentGroups.length === 0 &&
387 this.possibleGroupingKeys.length > 0) {
388 this.$.picker.currentGroupKeys = [this.$.picker.possibleGroups[0].key];
389 }
390 var expansionStates = undefined;
391 if (this.rows_)
392 expansionStates = this.getExpansionStates_();
393 this.updateContents_();
394 if (expansionStates)
395 this.setExpansionStates_(expansionStates);
396 },
397
398 onShowAllChange_: function() {
399 if (this.updatingContents_)
400 return;
401
402 tr.b.Settings.set(SHOW_ALL_SETTINGS_KEY, this.$.show_all.checked);
403 var expansionStates = this.getExpansionStates_();
404 this.updateContents_();
405 this.setExpansionStates_(expansionStates);
406 },
407
408 getExpansionStates_: function() {
409 var table = this.$.table;
410 function recurse(row) {
411 var rowStates = {
412 expanded: table.getExpandedForTableRow(row),
413 cells: new Map(),
414 subRows: new Map()
415 };
416
417 tr.b.iterItems(row.cells, function(displayLabel, cell) {
418 if (cell.isHistogramOpen) {
419 rowStates.cells.set(displayLabel, true);
420 }
421 });
422
423 if (rowStates.expanded) {
424 for (var i = 0; i < row.subRows.length; ++i) {
425 rowStates.subRows.set(i, recurse(row.subRows[i]));
426 }
427 }
428 return rowStates;
429 }
430
431 var states = new Map();
432 for (var i = 0; i < this.rows_.length; ++i) {
433 states.set(i, recurse(this.rows_[i]));
434 }
435 return states;
436 },
437
438 setExpansionStates_: function(states) {
439 var table = this.$.table;
440 function recurse(row, rowStates) {
441 if (rowStates.expanded) {
442 table.setExpandedForTableRow(row, true);
443 }
444
445 for (var [displayLabel, value] of rowStates.cells) {
446 var cell = row.cells[displayLabel];
447 if (cell) {
448 cell.isHistogramOpen = value;
449 }
450 }
451 for (var [key, value] of rowStates.subRows) {
452 var subRow = row.subRows[key];
453 recurse(subRow, value);
454 }
455 }
456
457 for (var i = 0; i < this.rows_.length; ++i) {
458 var rowStates = states.get(i);
459 if (rowStates === undefined) {
460 continue;
461 }
462 var row = this.rows_[i];
463 recurse(row, rowStates);
464 }
465 },
466
467 onSearch_: function() {
468 this.updateContents_();
469 },
470
471 rowMatchesSearch_: function(row) {
472 return row.name.indexOf(this.$.search.value) >= 0;
473 },
474
475 onRelatedValueSelected_: function(event) {
476 var value = event.selection;
477 if (!(value instanceof tr.v.Histogram))
478 return;
479
480 event.stopPropagation();
481
482 var displayLabel = getDisplayLabel(value);
483 var columnIndex = -1;
484 for (var i = 0; i < this.columns_.length; ++i) {
485 if (this.columns_[i].title === displayLabel) {
486 columnIndex = i;
487 break;
488 }
489 }
490 if (columnIndex < 0)
491 return;
492
493 var hierarchy = [];
494 var found = false;
495 function search(row) {
496 if (row.columns[displayLabel] === value) {
497 for (var hirow in hierarchy) {
498 this.$.table.setExpandedForTableRow(hirow, true);
499 }
500 found = true;
501 row.cells[displayLabel].isHistogramOpen = true;
502 return;
503 }
504 if (!row.subRows)
505 return;
506 hierarchy.push(row);
507 row.subRows.forEach(search, this);
508 hierarchy.pop(row);
509 }
510 this.rows_.forEach(search, this);
511
512 if (found || this.$.show_all.checked)
513 return;
514
515 // Search hidden values for |value|.
516 for (var test of this.values) {
517 if (test === value) {
518 found = true;
519 this.$.show_all.checked = true;
520 this.onShowAllChange_();
521 this.onRelatedValueSelected_(event);
522 break;
523 }
524 }
525 },
526
527 get values() {
528 return this.values_;
529 },
530
531 /**
532 * @param {!tr.v.ValueSet} values
533 */
534 set values(values) {
535 this.values_ = values;
536 this.sourceValues_ = values ? values.sourceValues : new tr.v.ValueSet();
537 this.displayLabels_ = undefined;
538 this.referenceDisplayLabel_ = undefined;
539 this.maybeDisableShowAll_();
540 this.updateContents_();
541 },
542
543 get referenceDisplayLabel() {
544 return this.referenceDisplayLabel_;
545 },
546
547 set referenceDisplayLabel(reference) {
548 this.referenceDisplayLabel_ = reference;
549
550 if (this.updatingContents_)
551 return;
552
553 this.$.table.selectedTableColumnIndex = this.referenceDisplayLabel ?
554 1 + this.displayLabels.indexOf(this.referenceDisplayLabel) : undefined;
555
556 // Force the table to rebuild the cell values without forgetting which
557 // rows were expanded.
558 var expansionStates = this.getExpansionStates_();
559 this.$.table.tableRows = this.rows_;
560 this.setExpansionStates_(expansionStates);
561 },
562
563 updateReferenceColumnSelector_: function() {
564 Polymer.dom(this.$.reference_column_container).textContent = '';
565
566 if (this.displayLabels.length < 2)
567 return;
568
569 var options = [{value: '', label: 'Select a reference column'}];
570 for (var displayLabel of this.displayLabels)
571 options.push({value: displayLabel, label: displayLabel});
572
573 var settingsKey =
574 'tr-v-ui-value-set-table-reference-display-label';
575 Polymer.dom(this.$.reference_column_container).appendChild(
576 tr.ui.b.createSelector(
577 this, 'referenceDisplayLabel', settingsKey, '', options));
578 },
579
580 updateGroups_: function() {
581 var groups = DEFAULT_POSSIBLE_GROUPS.filter(function(group) {
582 // Remove groups for which there is only one value, except
583 // HISTOGRAM_NAME.
584 if (group.key === tr.v.ValueSet.GROUPINGS.HISTOGRAM_NAME.key)
585 return true;
586
587 var values = new Set();
588 for (var value of this.values_) {
589 value = group.callback(value);
590 if (!value)
591 continue;
592
593 values.add(value);
594 if (values.size > 1)
595 return true;
596 }
597 return false; // Prune this grouping.
598 }, this);
599
600 // Add all storyGroupingKey groups for the current values.
601 for (var storyGroupingKey of this.storyGroupingKeys) {
602 groups.push(new tr.v.HistogramGrouping(
603 'storyGroupingKey_' + storyGroupingKey,
604 makeStoryGroupingKeyLabelGetter(storyGroupingKey),
605 storyGroupingKey));
606 }
607
608 // Save and restore current grouping keys in order to let
609 // |set groupingKeys| filter out the keys that are no longer in
610 // possibleGroups.
611 var groupingKeys = this.groupingKeys;
612 if (groupingKeys.length === 0 &&
613 groups.length > 0) {
614 // This can happen if the settings key contains an empty Array,
615 // which *should* never happen, but somehow sometimes does.
616 // When |groupingKeys| is empty, then the entire table will be
617 // mysteriously empty, so recover by ensuring that |groupingKeys| is
618 // never empty.
619 groupingKeys = [groups[0].key];
620 }
621 this.$.picker.possibleGroups = groups;
622 this.$.picker.currentGroupKeys = groupingKeys;
623
624 this.$.picker.style.display = (groups.length === 1) ? 'none' : '';
625 },
626
627 updateContents_: function() {
628 if (this.updatingContents_)
629 return;
630
631 if (!this.values_ || (this.values_.length === 0)) {
632 this.$.container.style.display = '';
633 this.$.zero.style.display = '';
634 return;
635 }
636
637 this.updatingContents_ = true;
638
639 this.$.zero.style.display = 'none';
640 this.$.container.style.display = 'block';
641 this.$.table.style.display = '';
642
643 this.updateReferenceColumnSelector_();
644 this.updateGroups_();
645 this.buildRows_();
646 this.buildColumns_();
647 this.$.table.tableColumns = this.columns_;
648 this.$.table.tableRows = this.rows_;
649 this.$.table.sortColumnIndex = 0;
650 this.$.table.rebuild();
651
652 this.$.table.selectedTableColumnIndex = this.referenceDisplayLabel ?
653 1 + this.displayLabels.indexOf(this.referenceDisplayLabel) : undefined;
654
655 this.updatingContents_ = false;
656 },
657
658 maybeDisableShowAll_: function() {
659 var allValuesAreSource = !this.values ||
660 (this.values.length === this.sourceValues_.length);
661
662 // Disable show_all if all values are sourceValues.
663 // Re-enable show_all if this changes.
664 this.$.show_all.disabled = allValuesAreSource;
665
666 // Check show_all if it is disabled.
667 // Do not automatically uncheck show_all.
668 if (this.$.show_all.disabled) {
669 this.$.show_all.checked = true;
670 }
671 },
672
673 /**
674 * Build table rows recursively from organized Values. The recursion stack
675 * of subRows is maintained in |hierarchy|.
676 *
677 * @param {!Object} organizedValues
678 * @param {!Array.<!Object>} hierarchy
679 */
680 buildRow_: function(organizedValues, hierarchy) {
681 for (var [name, values] of organizedValues) {
682 if (values instanceof Array) {
683 // This recursion base case corresponds to the recursion base case of
684 // groupHistogramsRecursively(). The last groupingCallback is always
685 // getDisplayLabel, which defines the columns of the table and is
686 // unskippable.
687 for (var value of values) {
688 // Merge Values up the grouping hierarchy.
689 for (var row of hierarchy) {
690 if (!row.description) {
691 row.description = value.description;
692 }
693
694 if (row.columns[name] === undefined) {
695 row.columns[name] = value;
696 continue;
697 }
698 if (row.columns[name] === UNMERGEABLE) {
699 continue;
700 }
701 if (!row.columns[name].canAddHistogram(value)) {
702 row.columns[name] = UNMERGEABLE;
703 continue;
704 }
705
706 // Create a new Histogram with a new uuid instead of cloning
707 // either |value| or |row.columns[name]| so that we don't clone
708 // either Histogram's diagnostics.
709 // |value.name| might not necessarily equal |row.columns[name]|,
710 // but that shouldn't matter for this dom-module.
711 var merged = row.columns[name];
712 if (!merged.diagnostics.has(tr.v.MERGED_FROM_DIAGNOSTIC_KEY)) {
713 merged = merged.cloneEmpty();
714 merged.addHistogram(row.columns[name]);
715 }
716 merged.addHistogram(value);
717 row.columns[name] = merged;
718 }
719 }
720 } else if (values instanceof Map) {
721 // |values| is actually a nested organizedValues.
722 var row = {name: name, subRows: [], columns: {}, cells: {}};
723 hierarchy.push(row);
724 this.buildRow_(values, hierarchy);
725 hierarchy.pop();
726
727 if (hierarchy.length === 0)
728 this.rows_.push(row);
729 else
730 hierarchy[hierarchy.length - 1].subRows.push(row);
731 }
732 }
733 },
734
735 get storyGroupingKeys() {
736 var keys = new Set();
737 for (var value of this.values) {
738 var iteration = tr.v.d.IterationInfo.getFromValue(value);
739 if (!(iteration instanceof tr.v.d.IterationInfo) ||
740 !iteration.storyGroupingKeys)
741 continue;
742
743 for (var key in iteration.storyGroupingKeys)
744 keys.add(key);
745 }
746 return [...keys.values()].sort();
747 },
748
749 /**
750 * A ValueSet is a flat set of Values. Value-set-table must present a
751 * hierarchical view. This method recursively groups this.values as an
752 * intermediate step towards building tableRows in buildRow_().
753 * {
754 * valueA: {
755 * benchmarkA: {
756 * storyA: {
757 * startA: {
758 * storysetRepeatCounterA: {
759 * storyRepeatCounterA: {
760 * displayLabelA: Value,
761 * displayLabelB: Value
762 * }
763 * }
764 * }
765 * }
766 * }
767 * }
768 * }
769 * @return {!Object}
770 */
771 get organizedValues_() {
772 var showingValueSet = this.$.show_all.checked ?
773 this.values : this.sourceValues_;
774
775 var groupings = this.$.picker.currentGroups.slice();
776 groupings.push(tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL);
777
778 function canSkipGrouping(grouping, groupedHistograms) {
779 // Never skip meaningful groupings.
780 if (groupedHistograms.size > 1)
781 return false;
782
783 // Never skip the zero-th grouping.
784 if (grouping.key === groupings[0].key)
785 return false;
786
787 // Never skip the grouping that defines the table columns.
788 if (grouping.key === tr.v.ValueSet.GROUPINGS.DISPLAY_LABEL.key)
789 return false;
790
791 // Skip meaningless groupings.
792 return true;
793 }
794
795 return showingValueSet.groupHistogramsRecursively(
796 groupings, canSkipGrouping);
797 },
798
799 /* this.rows_ will look something like
800 * [
801 * {
802 * name: 'value name',
803 * columns: {
804 * displayLabelA: Value,
805 * displayLabelB: Value,
806 * },
807 * subRows: [
808 * {
809 * name: 'benchmark name if multiple',
810 * columns: {
811 * displayLabelA: Value,
812 * displayLabelB: Value,
813 * },
814 * subRows: [
815 * {
816 * name: 'story name if multiple',
817 * columns: {
818 * displayLabelA: Value,
819 * displayLabelB: Value,
820 * },
821 * subRows: [
822 * {
823 * name: 'benchmark start if multiple',
824 * columns: {
825 * displayLabelA: Value,
826 * displayLabelB: Value,
827 * },
828 * subRows: [
829 * {
830 * name: 'storyset repeat counter if multiple',
831 * columns: {
832 * displayLabelA: Value,
833 * displayLabelB: Value,
834 * },
835 * subRows: [
836 * {
837 * name: 'story repeat counter if multiple',
838 * columns: {
839 * displayLabelA: Value,
840 * displayLabelB: Value,
841 * }
842 * }
843 * ]
844 * }
845 * ]
846 * }
847 * ]
848 * }
849 * ]
850 * }
851 * ]
852 * }
853 * ]
854 *
855 * Any of those layers may be missing except 'value name'.
856 */
857 buildRows_: function() {
858 this.rows_ = [];
859 var hierarchy = [];
860 var organizedValues = this.organizedValues_;
861 this.buildRow_(organizedValues, hierarchy);
862 this.rows_ = this.rows_.filter(this.rowMatchesSearch_.bind(this));
863 },
864
865 get startTimesForDisplayLabels() {
866 var startTimesForDisplayLabels = {};
867 for (var value of this.values) {
868 var displayLabel = getDisplayLabel(value);
869 startTimesForDisplayLabels[displayLabel] = Math.min(
870 startTimesForDisplayLabels[displayLabel] || 0,
871 tr.v.d.IterationInfo.getField(
872 value, 'benchmarkStart', new Date(0)).getTime());
873 }
874 return startTimesForDisplayLabels;
875 },
876
877 get displayLabels() {
878 if (this.displayLabels_ === undefined) {
879 var startTimesForDisplayLabels = this.startTimesForDisplayLabels;
880 this.displayLabels_ = Object.keys(startTimesForDisplayLabels);
881 this.displayLabels_.sort(function(a, b) {
882 return startTimesForDisplayLabels[a] - startTimesForDisplayLabels[b];
883 });
884 }
885 return this.displayLabels_;
886 },
887
888 buildColumn_: function(displayLabel) {
889 return {
890 title: displayLabel,
891 align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT,
892
893 value: row => {
894 var cell = document.createElement('tr-v-ui-value-set-table-cell');
895 cell.histogram = row.columns[displayLabel];
896 if (this.referenceDisplayLabel &&
897 this.referenceDisplayLabel !== displayLabel) {
898 cell.referenceHistogram = row.columns[this.referenceDisplayLabel];
899 }
900 row.cells[displayLabel] = cell;
901 return cell;
902 },
903
904 cmp: (rowA, rowB) => {
905 var cellA = rowA.columns[displayLabel];
906 var cellB = rowB.columns[displayLabel];
907 if (!(cellA instanceof tr.v.Histogram) ||
908 !(cellB instanceof tr.v.Histogram)) {
909 return undefined;
910 }
911
912 var valueA = cellA.average;
913 var valueB = cellB.average;
914
915 // If a reference column is selected, compare the absolute deltas
916 // between the two cells and their references.
917 if (this.referenceDisplayLabel &&
918 this.referenceDisplayLabel !== displayLabel) {
919 var referenceCellA = rowA.columns[this.referenceDisplayLabel];
920 var referenceCellB = rowB.columns[this.referenceDisplayLabel];
921 if (referenceCellA instanceof tr.v.Histogram &&
922 referenceCellB instanceof tr.v.Histogram &&
923 cellA.unit === referenceCellA.unit &&
924 cellB.unit === referenceCellB.unit) {
925 valueA -= referenceCellA.average;
926 valueB -= referenceCellB.average;
927 }
928 }
929
930 return valueA - valueB;
931 }
932 };
933 },
934
935 buildColumns_: function() {
936 this.columns_ = [
937 {
938 title: 'Name',
939
940 value: function(row) {
941 var nameEl = document.createElement('span');
942 Polymer.dom(nameEl).textContent = row.name;
943 if (row.description) {
944 nameEl.title = row.description;
945 }
946 nameEl.style.whiteSpace = 'nowrap';
947 return nameEl;
948 },
949
950 cmp: (a, b) => a.name.localeCompare(b.name)
951 }
952 ];
953
954 for (var displayLabel of this.displayLabels) {
955 this.columns_.push(this.buildColumn_(displayLabel));
956 }
957 }
958 });
959
960 return {};
961 });
962 </script>
OLDNEW
« no previous file with comments | « tracing/tracing/value/ui/histogram_set_view_test.html ('k') | tracing/tracing/value/ui/value_set_table_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698