| <!DOCTYPE html> |
| <!-- |
| Copyright 2017 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/value/histogram.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.v', function() { |
| /* |
| * HistogramGrouping objects are registered named functions that map from |
| * Histogram objects to strings. |
| * |
| * They are used to group Histograms by |
| * tr.v.HistogramSet.groupHistogramsRecursively() |
| * |
| * The tr-ui-b-grouping-table-groupby-picker module within the |
| * tr-v-ui-histogram-set-controls module allows users to select and reorder |
| * groupings. |
| */ |
| class HistogramGrouping { |
| /** |
| * @param {string} key |
| * @param {!function(!tr.v.Histogram):string} callback |
| */ |
| constructor(key, callback) { |
| this.key_ = key; |
| this.callback_ = callback; |
| |
| HistogramGrouping.BY_KEY.set(key, this); |
| } |
| |
| get key() { |
| return this.key_; |
| } |
| |
| get callback() { |
| return this.callback_; |
| } |
| |
| get label() { |
| return this.key; |
| } |
| |
| /** |
| * @param {!Set.<string>} tags |
| * @param {string} diagnosticName |
| * @return {!Array.<!HistogramGrouping>} |
| */ |
| static buildFromTags(tags, diagnosticName) { |
| const booleanTags = new Set(); |
| const keyValueTags = new Set(); |
| for (const tag of tags) { |
| if (tag.includes(':')) { |
| const key = tag.split(':')[0]; |
| if (booleanTags.has(key)) { |
| throw new Error( |
| `Tag "${key}" cannot be both boolean and key-value`); |
| } |
| keyValueTags.add(key); |
| } else { |
| if (keyValueTags.has(tag)) { |
| throw new Error( |
| `Tag "${tag}" cannot be both boolean and key-value`); |
| } |
| booleanTags.add(tag); |
| } |
| } |
| |
| const groupings = []; |
| for (const tag of booleanTags) { |
| groupings.push(HistogramGrouping.buildBooleanTagGrouping_( |
| tag, diagnosticName)); |
| } |
| for (const tag of keyValueTags) { |
| groupings.push(HistogramGrouping.buildKeyValueTagGrouping_( |
| tag, diagnosticName)); |
| } |
| return groupings; |
| } |
| |
| static buildBooleanTagGrouping_(tag, diagnosticName) { |
| return new HistogramGrouping(`${tag}Tag`, h => { |
| const tags = h.diagnostics.get(diagnosticName); |
| if (tags === undefined || !tags.has(tag)) return `~${tag}`; |
| return tag; |
| }); |
| } |
| |
| static buildKeyValueTagGrouping_(tag, diagnosticName) { |
| return new HistogramGrouping(`${tag}Tag`, h => { |
| const tags = h.diagnostics.get(diagnosticName); |
| if (tags === undefined) return `~${tag}`; |
| const values = new Set(); |
| for (const value of tags) { |
| const kvp = value.split(':'); |
| if (kvp.length < 2 || kvp[0] !== tag) continue; |
| values.add(kvp[1]); |
| } |
| if (values.size === 0) return `~${tag}`; |
| const sortedValues = Array.from(values); |
| sortedValues.sort(); |
| return sortedValues.join(','); |
| }, `${tag} tag`); |
| } |
| } |
| |
| HistogramGrouping.BY_KEY = new Map(); |
| |
| HistogramGrouping.HISTOGRAM_NAME = new HistogramGrouping('name', h => h.name); |
| |
| HistogramGrouping.DISPLAY_LABEL = new HistogramGrouping( |
| 'displayLabel', hist => { |
| const labels = hist.diagnostics.get(tr.v.d.RESERVED_NAMES.LABELS); |
| if (labels !== undefined && labels.size > 0) { |
| return Array.from(labels).join(','); |
| } |
| |
| const benchmarks = hist.diagnostics.get( |
| tr.v.d.RESERVED_NAMES.BENCHMARKS); |
| const start = hist.diagnostics.get( |
| tr.v.d.RESERVED_NAMES.BENCHMARK_START); |
| if (benchmarks === undefined) { |
| if (start === undefined) return 'Value'; |
| |
| return start.toString(); |
| } |
| const benchmarksStr = Array.from(benchmarks).join('\n'); |
| |
| if (start === undefined) return benchmarksStr; |
| |
| return benchmarksStr + '\n' + start.toString(); |
| }); |
| |
| class GenericSetGrouping extends HistogramGrouping { |
| constructor(name) { |
| super(name, undefined); |
| this.callback_ = this.compute_.bind(this); |
| } |
| |
| compute_(hist) { |
| const diag = hist.diagnostics.get(this.key); |
| if (diag === undefined) return ''; |
| const parts = Array.from(diag); |
| parts.sort(); |
| return parts.join(','); |
| } |
| } |
| |
| GenericSetGrouping.NAMES = [ |
| tr.v.d.RESERVED_NAMES.ARCHITECTURES, |
| tr.v.d.RESERVED_NAMES.BENCHMARKS, |
| tr.v.d.RESERVED_NAMES.BOTS, |
| tr.v.d.RESERVED_NAMES.BUILDS, |
| tr.v.d.RESERVED_NAMES.DEVICE_IDS, |
| tr.v.d.RESERVED_NAMES.MASTERS, |
| tr.v.d.RESERVED_NAMES.MEMORY_AMOUNTS, |
| tr.v.d.RESERVED_NAMES.OS_NAMES, |
| tr.v.d.RESERVED_NAMES.OS_VERSIONS, |
| tr.v.d.RESERVED_NAMES.PRODUCT_VERSIONS, |
| tr.v.d.RESERVED_NAMES.STORIES, |
| tr.v.d.RESERVED_NAMES.STORYSET_REPEATS, |
| tr.v.d.RESERVED_NAMES.STORY_TAGS, |
| tr.v.d.RESERVED_NAMES.TEST_PATH, |
| ]; |
| |
| for (const name of GenericSetGrouping.NAMES) { |
| // Instantiating a HistogramGrouping adds it to BY_KEY. |
| new GenericSetGrouping(name); |
| } |
| |
| class DateRangeGrouping extends HistogramGrouping { |
| constructor(name) { |
| super(name, undefined); |
| this.callback_ = this.compute_.bind(this); |
| } |
| |
| compute_(hist) { |
| const diag = hist.diagnostics.get(this.key); |
| if (diag === undefined) return ''; |
| return diag.toString(); |
| } |
| } |
| |
| DateRangeGrouping.NAMES = [ |
| tr.v.d.RESERVED_NAMES.BENCHMARK_START, |
| tr.v.d.RESERVED_NAMES.TRACE_START, |
| ]; |
| |
| for (const name of DateRangeGrouping.NAMES) { |
| new DateRangeGrouping(name); |
| } |
| |
| return { |
| HistogramGrouping, |
| GenericSetGrouping, |
| DateRangeGrouping, |
| }; |
| }); |
| </script> |