[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / latency_ukm_reporter.cc
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/metrics/latency_ukm_reporter.h"
6
7 #include <climits>
8 #include <memory>
9
10 #include "base/rand_util.h"
11 #include "cc/trees/ukm_manager.h"
12
13 namespace cc {
14
15 // We use a Poisson process with an exponential decay multiplier. The goal is to
16 // get many randomly distributed samples early during page load and initial
17 // interaction, then samples at an exponentially decreasing rate to effectively
18 // cap the number of samples. The particular parameters chosen here give roughly
19 // 5-10 samples in the first 100 frames, decaying to several hours between
20 // samples by the 40th sample. The multiplier value should be tuned to achieve a
21 // total sample count that avoids throttling by the UKM system.
22 class LatencyUkmReporter::SamplingController {
23  public:
24   SamplingController() = default;
25   ~SamplingController() = default;
26
27   // When a new UKM event is issued, this function should be called (once and
28   // only once) by the client to determine whether that event should be recorded
29   // or ignored, according to the sampling parameters. The sampling state will
30   // be updated to be ready for the next UKM event.
31   bool ShouldRecordNextEvent() {
32     bool should_record = false;
33     if (!frames_to_next_event_) {
34       should_record = true;
35       frames_to_next_event_ = SampleFramesToNextEvent();
36     }
37     DCHECK_GT(frames_to_next_event_, 0);
38     --frames_to_next_event_;
39     return should_record;
40   }
41
42  private:
43   // The |kSampleRateMultiplier| and |kSampleDecayRate| have been set to meet
44   // UKM goals for data volume.
45   const double kSampleDecayRate = 1.0;
46   const double kSampleRateMultiplier = 2.0;
47
48   int SampleFramesToNextEvent() {
49     // Sample from an exponential distribution to give a Poisson distribution
50     // of samples per time unit, then weigh it with an exponential multiplier
51     // to give a few samples in rapid succession (for frames early in the
52     // page's life) then exponentially fewer as the page lives longer.
53     // RandDouble() returns [0,1), but we need (0,1]. If RandDouble() is
54     // uniformly random, so is 1-RandDouble(), so use it to adjust the range.
55     // When RandDouble() returns 0.0, as it could, we will get a float_sample
56     // of 0, causing underflow. So rejection sample until we get a positive
57     // count.
58     double float_sample = 0.0;
59     do {
60       float_sample = -(kSampleRateMultiplier *
61                        std::exp(samples_so_far_ * kSampleDecayRate) *
62                        std::log(1.0 - base::RandDouble()));
63     } while (float_sample == 0.0);
64     // float_sample is positive, so we don't need to worry about underflow.
65     // After around 30 samples we will end up with a super high sample. That's
66     // OK because it just means we'll stop reporting metrics for that session,
67     // but we do need to be careful about overflow and NaN.
68     samples_so_far_++;
69     int integer_sample =
70         std::isnan(float_sample)
71             ? INT_MAX
72             : base::saturated_cast<int>(std::ceil(float_sample));
73     return integer_sample;
74   }
75
76   int samples_so_far_ = 0;
77   int frames_to_next_event_ = 0;
78 };
79
80 LatencyUkmReporter::LatencyUkmReporter()
81     : compositor_latency_sampling_controller_(
82           std::make_unique<SamplingController>()),
83       event_latency_sampling_controller_(
84           std::make_unique<SamplingController>()) {}
85
86 LatencyUkmReporter::~LatencyUkmReporter() = default;
87
88 void LatencyUkmReporter::ReportCompositorLatencyUkm(
89     const CompositorFrameReporter::FrameReportTypes& report_types,
90     const std::vector<CompositorFrameReporter::StageData>& stage_history,
91     const ActiveTrackers& active_trackers,
92     const CompositorFrameReporter::ProcessedBlinkBreakdown&
93         processed_blink_breakdown,
94     const CompositorFrameReporter::ProcessedVizBreakdown&
95         processed_viz_breakdown) {
96   if (ukm_manager_ &&
97       compositor_latency_sampling_controller_->ShouldRecordNextEvent()) {
98     ukm_manager_->RecordCompositorLatencyUKM(
99         report_types, stage_history, active_trackers, processed_blink_breakdown,
100         processed_viz_breakdown);
101   }
102 }
103
104 void LatencyUkmReporter::ReportEventLatencyUkm(
105     const EventMetrics::List& events_metrics,
106     const std::vector<CompositorFrameReporter::StageData>& stage_history,
107     const CompositorFrameReporter::ProcessedBlinkBreakdown&
108         processed_blink_breakdown,
109     const CompositorFrameReporter::ProcessedVizBreakdown&
110         processed_viz_breakdown) {
111   if (ukm_manager_ &&
112       event_latency_sampling_controller_->ShouldRecordNextEvent()) {
113     ukm_manager_->RecordEventLatencyUKM(events_metrics, stage_history,
114                                         processed_blink_breakdown,
115                                         processed_viz_breakdown);
116   }
117 }
118
119 }  // namespace cc