| <!DOCTYPE html> |
| <!-- |
| Copyright 2016 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/extras/chrome/chrome_user_friendly_category_driver.html"> |
| <link rel="import" href="/tracing/metrics/metric_registry.html"> |
| <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> |
| <link rel="import" href="/tracing/value/histogram.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('tr.metrics.sh', function() { |
| var LONG_TASK_MS = 50; |
| |
| // Anything longer than this should be so rare that its length beyond this is |
| // uninteresting. |
| var LONGEST_TASK_MS = 1000; |
| |
| /** |
| * This helper function calls |cb| for each of the top-level tasks on the |
| * given thread in the given range whose duration is longer than LONG_TASK_MS. |
| * |
| * @param {tr.model.Thread} thread |
| * @param {tr.b.Range=} opt_range |
| * @param {function()} cb |
| * @param {Object=} opt_this |
| */ |
| function iterateLongTopLevelTasksOnThreadInRange( |
| thread, opt_range, cb, opt_this) { |
| thread.sliceGroup.topLevelSlices.forEach(function(slice) { |
| if (opt_range && |
| !opt_range.intersectsExplicitRangeInclusive(slice.start, slice.end)) |
| return; |
| |
| if (slice.duration < LONG_TASK_MS) |
| return; |
| |
| cb.call(opt_this, slice); |
| }); |
| } |
| |
| /** |
| * This helper function calls |cb| for each of the main renderer threads in |
| * the model. |
| * |
| * @param {tr.model.Model} model The model. |
| * @param {function()} cb Callback. |
| * @param {Object=} opt_this Context object. |
| */ |
| function iterateRendererMainThreads(model, cb, opt_this) { |
| var modelHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper); |
| tr.b.dictionaryValues(modelHelper.rendererHelpers).forEach( |
| function(rendererHelper) { |
| if (!rendererHelper.mainThread) |
| return; |
| cb.call(opt_this, rendererHelper.mainThread); |
| }); |
| } |
| |
| /** |
| * This metric directly measures long tasks on renderer main threads. |
| * This metric requires only the 'toplevel' tracing category. |
| * |
| * @param {!tr.v.ValueSet} values |
| * @param {!tr.model.Model} model |
| * @param {!Object=} opt_options |
| */ |
| function longTasksMetric(values, model, opt_options) { |
| var rangeOfInterest = opt_options ? opt_options.rangeOfInterest : undefined; |
| var longTaskNumeric = new tr.v.Histogram('long tasks', |
| tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, |
| tr.v.HistogramBinBoundaries.createLinear( |
| LONG_TASK_MS, LONGEST_TASK_MS, 40)); |
| longTaskNumeric.description = 'durations of long tasks'; |
| var slices = new tr.model.EventSet(); |
| iterateRendererMainThreads(model, function(thread) { |
| iterateLongTopLevelTasksOnThreadInRange( |
| thread, rangeOfInterest, function(task) { |
| longTaskNumeric.addSample(task.duration, |
| {relatedEvents: new tr.v.d.RelatedEventSet([task])}); |
| slices.push(task); |
| slices.addEventSet(task.descendentSlices); |
| }); |
| }); |
| values.addHistogram(longTaskNumeric); |
| |
| var sampleForEvent = undefined; |
| var composition = tr.v.d.Composition.buildFromEvents( |
| values, 'long tasks ', slices, |
| e => (model.getUserFriendlyCategoryFromEvent(e) || 'unknown'), |
| tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, sampleForEvent, |
| tr.v.HistogramBinBoundaries.createExponential(1, LONGEST_TASK_MS, 40)); |
| composition.colorScheme = |
| tr.v.d.COLOR_SCHEME_CHROME_USER_FRIENDLY_CATEGORY_DRIVER; |
| longTaskValue.diagnostics.set('category', composition); |
| } |
| |
| tr.metrics.MetricRegistry.register(longTasksMetric, { |
| supportsRangeOfInterest: true |
| }); |
| |
| return { |
| longTasksMetric: longTasksMetric, |
| iterateLongTopLevelTasksOnThreadInRange: |
| iterateLongTopLevelTasksOnThreadInRange, |
| iterateRendererMainThreads: iterateRendererMainThreads, |
| LONG_TASK_MS: LONG_TASK_MS, |
| LONGEST_TASK_MS: LONGEST_TASK_MS |
| }; |
| }); |
| </script> |