summaryrefslogtreecommitdiff
path: root/chromium/third_party/catapult/tracing/tracing/metrics/system_health/hazard_metric.html
blob: e8b6eeb2ba81ccfa693615e7ebdd9e0ab05bd405 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!DOCTYPE html>
<!--
Copyright (c) 2015 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/metrics/metric_registry.html">
<link rel="import" href="/tracing/metrics/system_health/long_tasks_metric.html">
<link rel="import" href="/tracing/value/numeric.html">

<script>
'use strict';

tr.exportTo('tr.metrics.sh', function() {
  // The following math is easier if the units are seconds rather than ms,
  // so durations will be converted from ms to s.
  var MS_PER_S = 1000;

  // https://www.desmos.com/calculator/ysabhcc42g
  var RESPONSE_RISK =
    tr.b.Statistics.LogNormalDistribution.fromMedianAndDiminishingReturns(
      100 / MS_PER_S, 50 / MS_PER_S);

  /**
   * This helper function computes the risk that a task of the given duration
   * would impact the responsiveness of a speculative input.
   *
   * @param {number} durationMs
   * @return {number} task hazard
   */
  function computeResponsivenessRisk(durationMs) {
    // Returns 0 when the risk of impacting responsiveness is minimal.
    // Returns 1 when it is maximal.
    // durationMs is the duration of a long task.
    // It is at least LONG_TASK_MS.
    // The FAST_RESPONSE_HISTOGRAM was designed to permit both a 50ms task
    // when a Scroll Response begins, plus 16ms latency between the task
    // and the first frame of the scroll, without impacting the responsiveness
    // score.
    // Add 16ms to durationMs to simulate the standard (maximum ideal) scroll
    // response latency, and use the FAST_RESPONSE_HISTOGRAM to punish every ms
    // that the long task exceeds LONG_TASK_MS.

    durationMs += 16;

    // This returns a normalized percentage that
    // represents the fraction of users that would be satisfied with a
    // Scroll Response that takes durationMs to respond.
    // The risk of impacting responsiveness is approximated as the long task's
    // impact on a hypothetical Scroll Response that starts when the long task
    // starts, and then takes the standard 16ms to respond after the long task
    // finishes.
    // We imagine a Scroll Response instead of a Load or another type of
    // Response because the Scroll Response carries the strictest expectation.
    // The risk of impacting responsiveness is framed as the fraction of users
    // that would be *un*satisifed with the responsiveness of that hypothetical
    // Scroll Response. The fraction of users who are unsatisfied with something
    // is equal to 1 - the fraction of users who are satisfied with it.
    return RESPONSE_RISK.computePercentile(durationMs / MS_PER_S);
  }

  /**
   * This weighting function is similar to tr.metrics.sh.perceptualBlend,
   * but this version is appropriate for SmallerIsBetter metrics, whereas
   * that version is for BiggerIsBetter metrics.
   * (This would not be necessary if hazard were reframed as a BiggerIsBetter
   * metric such as "input readiness".)
   * Also, that version assumes that the 'ary' will be UserExpectations, whereas
   * this version assumes that the 'ary' will be scores.
   *
   * @param {number} hazardScore
   * @return {number} weight
   */
  function perceptualBlendSmallerIsBetter(hazardScore) {
    return Math.exp(hazardScore);
  }

  /**
   * Compute and return the normalized score for the risk that a speculative
   * input's responsiveness would have been impacted by long tasks on the given
   * thread in the given range.
   *
   * @param {tr.model.Thread} thread
   * @param {tr.b.Range=} opt_range
   * @return {number} hazard
   */
  function computeHazardForLongTasksInRangeOnThread(thread, opt_range) {
    var taskHazardScores = [];
    tr.metrics.sh.iterateLongTopLevelTasksOnThreadInRange(
        thread, opt_range, function(task) {
      taskHazardScores.push(computeResponsivenessRisk(task.duration));
    });
    return tr.b.Statistics.weightedMean(
        taskHazardScores, perceptualBlendSmallerIsBetter);
  }

  /**
   * Compute and return the normalized score for the risk that a speculative
   * input's responsiveness would have been impacted by long tasks.
   *
   * @param {tr.model.Model} model The model.
   * @return {number} hazard
   */
  function computeHazardForLongTasks(model) {
    var threadHazardScores = [];
    tr.metrics.sh.iterateRendererMainThreads(model, function(thread) {
      threadHazardScores.push(computeHazardForLongTasksInRangeOnThread(
          thread));
    });
    return tr.b.Statistics.weightedMean(
        threadHazardScores, perceptualBlendSmallerIsBetter);
  }

  /**
   * This EXPERIMENTAL metric computes a scalar normalized score that
   * represents the risk that a speculative input's responsiveness would have
   * been impacted by long tasks.
   * This metric requires only the 'toplevel' tracing category.
   */
  function hazardMetric(values, model) {
    var overallHazard = computeHazardForLongTasks(model);
    if (overallHazard === undefined)
      overallHazard = 0;

    var hist = new tr.v.Histogram('hazard',
        tr.b.Unit.byName.normalizedPercentage_smallerIsBetter);
    hist.addSample(overallHazard);
    values.addHistogram(hist);
  }

  tr.metrics.MetricRegistry.register(hazardMetric);

  return {
    hazardMetric: hazardMetric,
    computeHazardForLongTasksInRangeOnThread:
      computeHazardForLongTasksInRangeOnThread,
    computeHazardForLongTasks: computeHazardForLongTasks,
    computeResponsivenessRisk: computeResponsivenessRisk
  };
});
</script>