| <!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.metrics.sh', function() { |
| const CPU_PERCENTAGE_UNIT = |
| tr.b.Unit.byName.normalizedPercentage_smallerIsBetter; |
| const CPU_TIME_UNIT = tr.b.Unit.byName.timeDurationInMs_smallerIsBetter; |
| |
| /** |
| * Returns a deep clone of CPU time multidimensional view path object. |
| * |
| * @param {!Array.<!Array.<string>>} previousPath |
| * @returns {!Array.<!Array.<string>>} |
| */ |
| function clonePath_(previousPath) { |
| return previousPath.map(subPath => subPath.map(x => x)); |
| } |
| |
| |
| /** |
| * Returns an object containing the processType, threadType, railStage, and |
| * initiatorType encoded in the provided CPU time multidimensional view path |
| * object. Decoding the path into this object can make code easier to |
| * understand than indexing directly into the path array. |
| * |
| * @param {!Array.<!Array.<string>>} path - A path in a CPU time |
| * multidimensional tree view. |
| * @returns {Object.<string, string>} |
| */ |
| function decodePath_(path) { |
| return { |
| processType: path[0][0], |
| threadType: path[1][0], |
| railStage: path[2][0], |
| initiatorType: path[2][1] |
| }; |
| } |
| |
| /** |
| * Returns a unique string representation of |path|. |
| * |
| * Paths are of the following form in CPU time multidimensional trees: |
| * [[processType], [threadType], [railStage, initiatorType]] |
| * |
| * The returned string is of the form |
| * "$processtype:$threadType:$railStage:$initiatorType". |
| * |
| * @param {Array.<!Array.<string>>} path |
| * @returns {string} |
| */ |
| function stringifyPathName_(path) { |
| const decodedPath = decodePath_(path); |
| return [ |
| decodedPath.processType, |
| decodedPath.threadType, |
| decodedPath.railStage, |
| decodedPath.initiatorType |
| ].join(':'); |
| } |
| |
| /** |
| * This class is used to traverse a multidimensional tree view and report CPU |
| * percentage and CPU time from the tree as histograms. |
| */ |
| class CpuTimeTreeDataReporter { |
| constructor() { |
| this.visitedSet_ = new Set(); |
| } |
| |
| /** |
| * Extracts CPU percentage and CPU time values from |node| located at |path| |
| * and adds values as histograms to |this.histogramSet_|. Each value is |
| * added as a single sample histogram. |
| * |
| * @param {!tr.b.MultiDimensionalViewNode} node |
| * @param {!Array.<!Array.<string>>} path |
| */ |
| reportValuesFromNode_(node, path) { |
| const decodedPath = decodePath_(path); |
| const processType = decodedPath.processType || 'all_processes'; |
| const threadType = decodedPath.threadType || 'all_threads'; |
| |
| // We need some RAIL stage and some initiator type to process a node. |
| // All RAIL stages and all initiator types are handled by the special |
| // 'all_stages' and 'all_initiators' nodes respectively. |
| if (!decodedPath.railStage || !decodedPath.initiatorType) return; |
| const {railStage, initiatorType} = decodedPath; |
| |
| const serializedPathName = |
| [processType, threadType, railStage, initiatorType].join(':'); |
| |
| // node.values is a two element array. The first element holds |
| // cpuPercentage data and the second holds cpuTime data. The final |
| // '.total' (as opposed to '.self') signifies we're including all the data |
| // from children nodes. This is an artifact of how the multidimensional |
| // view data structure works and is not very relevant - we exclusively use |
| // '.total' for CPU time. |
| const cpuPercentageValue = node.values[0].total; |
| const cpuTimeValue = node.values[1].total; |
| |
| this.histogramSet_.createHistogram(`cpuPercentage:${serializedPathName}`, |
| CPU_PERCENTAGE_UNIT, cpuPercentageValue); |
| this.histogramSet_.createHistogram(`cpuTime:${serializedPathName}`, |
| CPU_TIME_UNIT, cpuTimeValue); |
| } |
| |
| |
| /** |
| * Traverses all the paths of a multidimensional view subtree and reports |
| * node data to |this.histogramSet_|. |
| * |
| * @param {!tr.b.MultiDimensionalViewNode} root - Root of the subtree. |
| * @param {!Array.<!Array.<string>>} rootPath - Path of the subtree root |
| * node with respect to |this.rootNode_|. |
| */ |
| reportDataFromTree_(root, rootPath) { |
| const rootPathString = stringifyPathName_(rootPath); |
| if (this.visitedSet_.has(rootPathString)) return; |
| this.visitedSet_.add(rootPathString); |
| |
| this.reportValuesFromNode_(root, rootPath); |
| |
| for (let dimension = 0; dimension < root.children.length; dimension++) { |
| const children = root.children[dimension]; |
| for (const [name, node] of children) { |
| const childPath = clonePath_(rootPath); |
| childPath[dimension].push(name); |
| this.reportDataFromTree_(node, childPath); |
| } |
| } |
| } |
| |
| /** |
| * Adds values from the multidimensional tree view rooted at |rootNode| as |
| * single value histograms in |histogramSet|. |
| * |
| * @param {!tr.b.MultiDimensionalViewNode} rootNode |
| * @param {!tr.v.HistogramSet} histogramSet |
| */ |
| addTreeValuesToHistogramSet(rootNode, histogramSet) { |
| const rootPath = [[], [], []]; |
| this.rootNode_ = rootNode; |
| this.histogramSet_ = histogramSet; |
| this.reportDataFromTree_(this.rootNode_, rootPath); |
| } |
| |
| /** |
| * Reports values from the multidimensional tree view rooted at |rootNode| |
| * as single value histograms in |histogramSet|. |
| * |
| * The histograms are dynamically generated from the tree. The histogram |
| * names are of the form |
| * "${cpuTime|cpuPercentage}:${processType}:${threadType}:" + |
| * "${railStage}:${railStageInitiator}" |
| * |
| * cpuTime histograms contain total consumed cpu time, while cpuPercentage |
| * histograms contain cpu time as a percentage of wall time. In multicore |
| * situations, this percentage can be larger than 100. |
| * |
| * @param {!tr.b.MultiDimensionalViewNode} rootNode |
| * @param {!tr.v.HistogramSet} histogramSet |
| */ |
| static reportToHistogramSet(rootNode, histogramSet) { |
| const reporter = new CpuTimeTreeDataReporter(); |
| reporter.addTreeValuesToHistogramSet(rootNode, histogramSet); |
| } |
| } |
| |
| return { |
| CpuTimeTreeDataReporter, |
| }; |
| }); |
| </script> |