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

Unified Diff: tracing/tracing/value/histogram_set_hierarchy.html

Issue 2747453003: Refactor histogram-set-view to an MVC pattern. (Closed)
Patch Set: Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: tracing/tracing/value/histogram_set_hierarchy.html
diff --git a/tracing/tracing/value/histogram_set_hierarchy.html b/tracing/tracing/value/histogram_set_hierarchy.html
new file mode 100644
index 0000000000000000000000000000000000000000..3e5e451a7b9af969fad91d3b79c838daa5901834
--- /dev/null
+++ b/tracing/tracing/value/histogram_set_hierarchy.html
@@ -0,0 +1,317 @@
+<!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_set.html">
+
+<script>
+'use strict';
+tr.exportTo('tr.v', function() {
+ /*
+ * See also HistogramSet.groupHistogramsRecursively().
+ * See also tr.v.ui.HistogramSetTableRow.
+ */
+ class HistogramSetHierarchy {
+ /**
+ * @param {string} name
+ */
+ constructor(name) {
+ this.name = name;
+ this.description = '';
+ this.depth = 0;
+ this.subRows = [];
+ this.columns = new Map();
+ this.overviewDataRange_ = undefined;
+ this.mergeRelationshipsForColumn_ = new Map();
+ }
+
+ * walk() {
+ yield this;
+ for (const row of this.subRows) yield* row.walk();
+ }
+
+ static* walkAll(rootRows) {
+ for (const rootRow of rootRows) yield* rootRow.walk();
+ }
+
+ /**
+ * Build table rows recursively from grouped Histograms.
+ *
+ * @param {!(HistogramArray|HistogramArrayMap)}
+ * @returns {!Array.<!HistogramSetHierarchy>}
+ */
+ static build(histogramArrayMap) {
+ const rootRows = [];
+ HistogramSetHierarchy.buildInternal_(histogramArrayMap, [], rootRows);
+
+ const histograms = new tr.v.HistogramSet();
+
+ for (const row of HistogramSetHierarchy.walkAll(rootRows)) {
+ for (const hist of row.columns.values()) {
+ if (!(hist instanceof tr.v.Histogram)) continue;
+ histograms.addHistogram(hist);
+ }
+ }
+
+ histograms.deduplicateDiagnostics();
+
+ for (const row of HistogramSetHierarchy.walkAll(rootRows)) {
+ for (const [name, hist] of row.columns) {
+ if (!(hist instanceof tr.v.Histogram)) continue;
+ if (!row.mergeRelationshipsForColumn_.get(name)) continue;
+ hist.diagnostics.mergeRelationships(hist);
+ }
+ }
+
+ // Delete "merged to" diagnostics from the original Histograms, or else
+ // they'll accumulate as the user re-groups them, and slow down future
+ // mergeRelationships operations.
+ for (const row of HistogramSetHierarchy.walkAll(rootRows)) {
+ // Walk directly down to the leaves in order to avoid touching
+ // original Histograms more than once.
+ if (row.subRows.length) continue;
+
+ for (const hist of row.columns.values()) {
+ if (!(hist instanceof tr.v.Histogram)) continue;
+
+ const mergedFrom = hist.diagnostics.get(
+ tr.v.MERGED_FROM_DIAGNOSTIC_KEY);
+ if (mergedFrom !== undefined) {
+ for (const other of mergedFrom) {
+ other.diagnostics.delete(tr.v.MERGED_TO_DIAGNOSTIC_KEY);
+ }
+ }
+ }
+ }
+
+ for (const row of HistogramSetHierarchy.walkAll(rootRows)) {
+ row.maybeRebin_();
+ }
+
+ return rootRows;
+ }
+
+ maybeRebin_() {
+ // if all of |this| row's columns are single-bin, then re-bin all of them.
+ const dataRange = new tr.b.math.Range();
+ for (const hist of this.columns.values()) {
+ if (!(hist instanceof tr.v.Histogram)) continue;
+ if (hist.allBins.length > 1) return; // don't re-bin
+ if (hist.numValues === 0) continue; // ignore hist
+ dataRange.addValue(hist.min);
+ dataRange.addValue(hist.max);
+ }
+
+ dataRange.addValue(tr.b.math.lesserWholeNumber(dataRange.min));
+ dataRange.addValue(tr.b.math.greaterWholeNumber(dataRange.max));
+
+ if (dataRange.min === dataRange.max) return; // don't rebin
+
+ const boundaries = tr.v.HistogramBinBoundaries.createLinear(
+ dataRange.min, dataRange.max, tr.v.DEFAULT_REBINNED_COUNT);
+
+ for (const [name, hist] of this.columns) {
+ if (!(hist instanceof tr.v.Histogram)) continue;
+ this.columns.set(name, hist.rebin(boundaries));
+ }
+ }
+
+ static mergeHistogramDownHierarchy_(histogram, hierarchy, columnName) {
+ // Track the path down the grouping tree to each Histogram,
+ // but only start tracking the path at the grouping level that
+ // corresponds to the Histogram NAME Grouping. This groupingPath will be
+ // attached to Histograms in order to help mergeRelationships() figure out
+ // which merged Histograms should be related to which other merged
+ // Histograms.
+ let groupingPath = undefined;
+
+ for (const row of hierarchy) {
+ if (groupingPath !== undefined) {
+ groupingPath.push(row.name);
+ } else if (row.name === histogram.name) {
+ // Start tracking the path, but don't add histogram.name to the path,
+ // since related histograms won't have the same name.
+ groupingPath = [];
+ }
+
+ if (!row.description) {
+ row.description = histogram.description;
+ }
+
+ const existing = row.columns.get(columnName);
+
+ if (existing === undefined) {
+ const clone = histogram.clone();
+ if (groupingPath !== undefined) {
+ new tr.v.d.GroupingPath(groupingPath).addToHistogram(clone);
+ }
+ row.columns.set(columnName, clone);
+ row.mergeRelationshipsForColumn_.set(columnName, true);
+ continue;
+ }
+
+ if (existing instanceof tr.v.HistogramSet) {
+ // There have already been unmergeable histograms.
+ existing.addHistogram(histogram);
+ continue;
+ }
+
+ if (!existing.canAddHistogram(histogram)) {
+ // Remember all of the original unmergeable Histograms so that
+ // filter() can keep the rows that match the given HistogramSet even
+ // if the rows will only be able to display (unmergeable).
+ const unmergeableHistograms = new tr.v.HistogramSet([histogram]);
+ const mergedFrom = existing.diagnostics.get(
+ tr.v.d.MERGED_FROM_DIAGNOSTIC_KEY);
+ if (mergedFrom !== undefined) {
+ for (const origHist of mergedFrom) {
+ unmergeableHistograms.addHistogram(origHist);
+ }
+ }
+ row.columns.set(columnName, unmergeableHistograms);
+ continue;
+ }
+
+ if (existing.name !== histogram.name) {
+ // It won't make sense to merge relationships for this merged
+ // Histogram.
+ row.mergeRelationshipsForColumn_.set(name, false);
+ }
+
+ existing.addHistogram(histogram);
+ }
+ }
+
+ static buildInternal_(
+ histogramArrayMap, hierarchy, rootRows) {
+ for (const [name, histograms] of histogramArrayMap) {
+ if (histograms instanceof Array) {
+ // This recursion base case corresponds to the recursion base case of
+ // groupHistogramsRecursively(). The last groupingCallback is always
+ // getDisplayLabel, which defines the columns of the table and is
+ // unskippable.
+ for (const histogram of histograms) {
+ HistogramSetHierarchy.mergeHistogramDownHierarchy_(
+ histogram, hierarchy, name);
+ }
+ } else if (histograms instanceof Map) {
+ // |histograms| is actually a nested histogramArrayMap.
+ const row = new HistogramSetHierarchy(name);
+ row.depth = hierarchy.length;
+ hierarchy.push(row);
+ HistogramSetHierarchy.buildInternal_(histograms, hierarchy, rootRows);
+ hierarchy.pop();
+
+ if (hierarchy.length === 0) {
+ rootRows.push(row);
+ } else {
+ const parentRow = hierarchy[hierarchy.length - 1];
+ parentRow.subRows.push(row);
+ }
+ }
+ }
+ }
+
+ /**
+ * Clones and filters |rows| to contain only |histograms|.
+ *
+ * @param {!Array.<HistogramSetHierarchy>} rows
+ * @param {!tr.v.HistogramSet} histograms
+ * @returns {!Array.<HistogramSetHierarchy>}
+ */
+ static filter(rows, histograms) {
+ const results = [];
+ for (const row of rows) {
+ let filteredSubRows = [];
+ if (row.subRows.length > 0) {
+ // This is a branch row. Drop it if all of its subrows were dropped.
+ filteredSubRows = HistogramSetHierarchy.filter(
+ row.subRows, histograms);
+ if (filteredSubRows.length === 0) continue;
+ } else {
+ // This is a leaf row. Drop it if none of the Histograms in
+ // |row.columns| were merged from any in |histograms|.
+ let found = false;
+ for (const testHist of row.columns.values()) {
+ if (testHist instanceof tr.v.HistogramSet) {
+ // Keep this unmergeable cell if it was merged from any of
+ // |histograms|.
+ for (const origHist of testHist) {
+ if (histograms.lookupHistogram(origHist.guid) !== undefined) {
+ found = true;
+ break;
+ }
+ }
+ if (found) break;
+
+ continue;
+ }
+
+ if (!(testHist instanceof tr.v.Histogram)) {
+ throw new Error(
+ 'Cells can only contain Histogram or HistogramSet');
+ }
+
+ if (histograms.lookupHistogram(testHist.guid) !== undefined) {
+ found = true;
+ break;
+ }
+
+ const mergedFrom = testHist.diagnostics.get(
+ tr.v.d.MERGED_FROM_DIAGNOSTIC_KEY);
+ if (mergedFrom !== undefined) {
+ for (const origHist of mergedFrom) {
+ if (histograms.lookupHistogram(origHist.guid) !== undefined) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (found) break;
+ }
+ // If none of the Histograms in |row| were merged from any of
+ // |histograms|, then drop this row.
+ if (!found) continue;
+ }
+
+ const clone = new HistogramSetHierarchy(row.name);
+ clone.description = row.description;
+ clone.depth = row.depth;
+ clone.subRows = filteredSubRows;
+ // Don't need to clone Histograms.
+ clone.columns = row.columns;
+ clone.overviewDataRange_ = row.overviewDataRange_;
+ results.push(clone);
+ }
+ return results;
+ }
+
+ get overviewDataRange() {
+ if (this.overviewDataRange_ === undefined) {
+ this.overviewDataRange_ = new tr.b.math.Range();
+ for (const [displayLabel, hist] of this.columns) {
+ if (hist instanceof tr.v.Histogram &&
+ hist.average !== undefined) {
+ this.overviewDataRange_.addValue(hist.average);
+ }
+
+ for (const subRow of this.subRows) {
+ const subHist = subRow.columns.get(displayLabel);
+ if (!(subHist instanceof tr.v.Histogram)) continue;
+ if (subHist.average === undefined) continue;
+ this.overviewDataRange_.addValue(subHist.average);
+ }
+ }
+ }
+ return this.overviewDataRange_;
+ }
+ }
+
+ return {
+ HistogramSetHierarchy,
+ };
+});
+</script>
« no previous file with comments | « tracing/tracing/value/histogram_parameter_collector_test.html ('k') | tracing/tracing/value/ui/histogram-set-view.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698