| Index: tracing/tracing/metrics/system_health/cpu_time_metric.html
|
| diff --git a/tracing/tracing/metrics/system_health/cpu_time_metric.html b/tracing/tracing/metrics/system_health/cpu_time_metric.html
|
| index abfc457fb58f8e6a795688a8e3ffb317100d9bcd..ba0487938b9ead75959df8540d71b63c78622c45 100644
|
| --- a/tracing/tracing/metrics/system_health/cpu_time_metric.html
|
| +++ b/tracing/tracing/metrics/system_health/cpu_time_metric.html
|
| @@ -9,21 +9,124 @@ found in the LICENSE file.
|
| <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html">
|
| <link rel="import" href="/tracing/model/helpers/chrome_renderer_helper.html">
|
| <link rel="import" href="/tracing/value/histogram.html">
|
| +<link rel="import" href="/tracing/extras/chrome/cpu_time.html">
|
| +
|
| +<!-- Experimental -->
|
| +<link rel="import" href="/tracing/base/multi_dimensional_view.html">
|
|
|
| <script>
|
| +// TODO: (Do this before landing) Cleanup imports once you're done
|
| 'use strict';
|
|
|
| tr.exportTo('tr.metrics.sh', function() {
|
| - // Use a lower bound of 0.01 for the metric boundaries (when no CPU time
|
| - // is consumed) and an upper bound of 50 (fifty cores are all active
|
| - // for the entire time). We can't use zero exactly for the lower bound with an
|
| - // exponential histogram.
|
| - const CPU_TIME_PERCENTAGE_BOUNDARIES =
|
| - tr.v.HistogramBinBoundaries.createExponential(0.01, 50, 200);
|
| + const CPU_TIME_UNIT = tr.b.Unit.byName.normalizedPercentage_smallerIsBetter;
|
| + const CPU_TIME_TOTAL_UNIT = tr.b.Unit.byName.timeDurationInMs_smallerIsBetter;
|
| +
|
| + const cpuTime = tr.e.chrome.cpuTime;
|
| +
|
| + /**
|
| + * Translates a multidimensional tree view path to process type, thread type,
|
| + * rail stage, and initiator type.
|
| + */
|
| + function translatePath_(path) {
|
| + return {
|
| + processType: path[0][0],
|
| + threadType: path[1][0],
|
| + railStage: path[2][0],
|
| + initiatorType: path[2][1]
|
| + };
|
| + }
|
| +
|
| + function createNewHistogramAndAddSample_(
|
| + histograms, histogramName, value, unit) {
|
| + const histogram = new tr.v.Histogram(histogramName, unit);
|
| + histogram.customizeSummaryOptions({
|
| + avg: false,
|
| + count: false,
|
| + max: false,
|
| + min: false,
|
| + std: false,
|
| + sum: true
|
| + });
|
| + histogram.addSample(value);
|
| + histograms.addHistogram(histogram);
|
| + }
|
| +
|
| + function getCanonicalHistogramName_(
|
| + histogramPrefix, processType, threadType, railStage, initiatorType) {
|
| + return `${histogramPrefix}:${processType}:${threadType}:` +
|
| + `${railStage}:${initiatorType}`;
|
| + }
|
| +
|
| + function maybeAddDataToHistograms_(histograms, path, node) {
|
| + const translatedPath = translatePath_(path);
|
| + const processType = translatedPath.processType || 'all_processes';
|
| + const threadType = translatedPath.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 (!translatedPath.railStage || !translatedPath.initiatorType) return;
|
| + const {railStage, initiatorType} = translatedPath;
|
| +
|
| + const cpuUsageValue = node.values[0].total;
|
| + const cpuTotalValue = node.values[1].total;
|
| +
|
| + createNewHistogramAndAddSample_(
|
| + histograms,
|
| + getCanonicalHistogramName_(
|
| + 'cpuUsage', processType, threadType, railStage, initiatorType),
|
| + cpuUsageValue, CPU_TIME_UNIT);
|
| +
|
| + createNewHistogramAndAddSample_(
|
| + histograms,
|
| + getCanonicalHistogramName_(
|
| + 'cpuTotal', processType, threadType, railStage, initiatorType),
|
| + cpuTotalValue, CPU_TIME_TOTAL_UNIT);
|
| + }
|
|
|
| /**
|
| - * This metric measures total CPU time for Chrome processes, per second of
|
| - * clock time.
|
| + * Returns a string representing which cpu time metric this node represents.
|
| + * This is not quite the histogram name, but a unique key for the node to
|
| + * keep track of whether it has been visited.
|
| + */
|
| + function getCanonicalTitleFromPath_(path) {
|
| + const translatedPath = translatePath_(path);
|
| + const titleComponents =
|
| + ['processType', 'threadType', 'railStage', 'initiatorType'];
|
| + return titleComponents.map(key => translatedPath[key]).join(':');
|
| + }
|
| +
|
| + function clonePath_(previousPath) {
|
| + return previousPath.map(subPath => subPath.map(x => x));
|
| + }
|
| +
|
| + /**
|
| + * Traverses all the path of a multidimensional tree view starting from
|
| + * |node|, creates necessary histograms and adds samples to them.
|
| + *
|
| + * TODO: DO BEFORE LANDING: Add param descriptions to this jsdoc.
|
| + */
|
| + function reportDataFromTree_(histograms, node, currentPath, visitedSet) {
|
| + const canonicalTitle = getCanonicalTitleFromPath_(currentPath);
|
| + if (visitedSet.has(canonicalTitle)) return;
|
| + visitedSet.add(canonicalTitle);
|
| + maybeAddDataToHistograms_(histograms, currentPath, node);
|
| +
|
| + for (let dimension = 0; dimension < node.children.length; dimension++) {
|
| + const children = node.children[dimension];
|
| + for (const [name, node] of children) {
|
| + const newPath = clonePath_(currentPath);
|
| + newPath[dimension].push(name);
|
| + reportDataFromTree_(histograms, node, newPath, visitedSet);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * This metric measures total cpuTime utilization per second of wall clock
|
| + * time.
|
| + *
|
| * This metric requires only the 'toplevel' tracing category.
|
| *
|
| * @param {!tr.v.HistogramSet} histograms
|
| @@ -31,79 +134,16 @@ tr.exportTo('tr.metrics.sh', function() {
|
| * @param {!Object=} opt_options
|
| */
|
| function cpuTimeMetric(histograms, model, opt_options) {
|
| - let rangeOfInterest = model.bounds;
|
| -
|
| + var rangeOfInterest = model.bounds;
|
| if (opt_options && opt_options.rangeOfInterest) {
|
| rangeOfInterest = opt_options.rangeOfInterest;
|
| - } else {
|
| - // If no range of interest is provided, limit the relevant range to
|
| - // Chrome processes. This prevents us from normalizing against non-Chrome
|
| - // related slices in the trace.
|
| - const chromeHelper = model.getOrCreateHelper(
|
| - tr.model.helpers.ChromeModelHelper);
|
| - if (chromeHelper) {
|
| - const chromeBounds = chromeHelper.chromeBounds;
|
| - if (chromeBounds) {
|
| - rangeOfInterest = chromeBounds;
|
| - }
|
| - }
|
| }
|
|
|
| - let allProcessCpuTime = 0;
|
| -
|
| - for (const pid in model.processes) {
|
| - const process = model.processes[pid];
|
| - if (tr.model.helpers.ChromeRendererHelper.isTracingProcess(process)) {
|
| - continue;
|
| - }
|
| -
|
| - let processCpuTime = 0;
|
| - for (const tid in process.threads) {
|
| - const thread = process.threads[tid];
|
| - let threadCpuTime = 0;
|
| - thread.sliceGroup.topLevelSlices.forEach(function(slice) {
|
| - if (slice.duration === 0) return;
|
| - if (!slice.cpuDuration) return;
|
| - const sliceRange = tr.b.math.Range.fromExplicitRange(
|
| - slice.start, slice.end);
|
| - const intersection = rangeOfInterest.findIntersection(sliceRange);
|
| - const fractionOfSliceInsideRangeOfInterest =
|
| - intersection.duration / slice.duration;
|
| -
|
| - // We assume that if a slice doesn't lie entirely inside the range of
|
| - // interest, then the CPU time is evenly distributed inside of the
|
| - // slice.
|
| - threadCpuTime +=
|
| - slice.cpuDuration * fractionOfSliceInsideRangeOfInterest;
|
| - });
|
| - processCpuTime += threadCpuTime;
|
| - }
|
| - allProcessCpuTime += processCpuTime;
|
| - }
|
| -
|
| - // Normalize cpu time by clock time.
|
| - let normalizedAllProcessCpuTime = 0;
|
| - if (rangeOfInterest.duration > 0) {
|
| - normalizedAllProcessCpuTime =
|
| - allProcessCpuTime / rangeOfInterest.duration;
|
| - }
|
| -
|
| - const unit = tr.b.Unit.byName.normalizedPercentage_smallerIsBetter;
|
| - const cpuTimeHist = new tr.v.Histogram(
|
| - 'cpu_time_percentage', unit, CPU_TIME_PERCENTAGE_BOUNDARIES);
|
| - cpuTimeHist.description =
|
| - 'Percent CPU utilization, normalized against a single core. Can be ' +
|
| - 'greater than 100% if machine has multiple cores.';
|
| - cpuTimeHist.customizeSummaryOptions({
|
| - avg: true,
|
| - count: false,
|
| - max: false,
|
| - min: false,
|
| - std: false,
|
| - sum: false
|
| - });
|
| - cpuTimeHist.addSample(normalizedAllProcessCpuTime);
|
| - histograms.addHistogram(cpuTimeHist);
|
| + const treeRoot =
|
| + cpuTime.constructMultiDimensionalView(model, rangeOfInterest);
|
| + const rootPath = [[], [], []];
|
| + const visitedSet = new Set();
|
| + reportDataFromTree_(histograms, treeRoot, rootPath, visitedSet);
|
| }
|
|
|
| tr.metrics.MetricRegistry.register(cpuTimeMetric, {
|
|
|