summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/scheduler/renderer/queueing_time_estimator.h
blob: b31312639d2f5805c06dec493e26ec1ccf14e615 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 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.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_

#include "base/macros.h"
#include "base/time/time.h"
#include "third_party/blink/public/common/page/launching_process_state.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/scheduler/renderer/main_thread_task_queue.h"
#include "third_party/blink/renderer/platform/scheduler/renderer/renderer_metrics_helper.h"

#include <array>
#include <vector>

namespace blink {
namespace scheduler {

// Records the expected queueing time for a high priority task occurring
// randomly during each interval of length equal to window's duration.
class PLATFORM_EXPORT QueueingTimeEstimator {
 public:
  class PLATFORM_EXPORT Client {
   public:
    virtual void OnQueueingTimeForWindowEstimated(base::TimeDelta queueing_time,
                                                  bool is_disjoint_window) = 0;
    virtual void OnReportFineGrainedExpectedQueueingTime(
        const char* split_description,
        base::TimeDelta queueing_time) = 0;
    Client() = default;
    virtual ~Client() = default;

   private:
    DISALLOW_COPY_AND_ASSIGN(Client);
  };

  class RunningAverage {
   public:
    explicit RunningAverage(int steps_per_window);
    int GetStepsPerWindow() const;
    void Add(base::TimeDelta bin_value);
    base::TimeDelta GetAverage() const;
    bool IndexIsZero() const;

   private:
    size_t index_;
    std::vector<base::TimeDelta> circular_buffer_;
    base::TimeDelta running_sum_;
  };

  class PLATFORM_EXPORT Calculator {
   public:
    explicit Calculator(int steps_per_window);
    static const char* GetReportingMessageFromQueueType(
        MainThreadTaskQueue::QueueType queue_type);
    static const char* GetReportingMessageFromFrameStatus(
        FrameStatus frame_status);

    void UpdateStatusFromTaskQueue(MainThreadTaskQueue* queue);
    void AddQueueingTime(base::TimeDelta queuing_time);
    void EndStep(Client* client);
    void ResetStep();

   private:
    // Variables to compute the total Expected Queueing Time.
    // |steps_per_window_| is the ratio of window duration to the sliding
    // window's step width. It is an integer since the window must be a integer
    // multiple of the step's width. This parameter is used for deciding the
    // sliding window's step width, and the number of bins of the circular
    // buffer.
    const int steps_per_window_;

    // |step_expected_queueing_time_| is the expected queuing time of a
    // smaller window of a step's width. By combining these step EQTs through a
    // running average, we can get window EQTs of a bigger window.
    //
    // ^ Instantaneous queuing time
    // |
    // |
    // |   |\                                           .
    // |   | \            |\             |\             .
    // |   |  \           | \       |\   | \            .
    // |   |   \    |\    |  \      | \  |  \           .
    // |   |    \   | \   |   \     |  \ |   \          .
    // ------------------------------------------------> Time
    //
    // |stepEQT|stepEQT|stepEQT|stepEQT|stepEQT|stepEQT|
    //
    // |------windowEQT_1------|
    //         |------windowEQT_2------|
    //                 |------windowEQT_3------|
    //
    // In this case:
    // |steps_per_window_| = 3, because each window is the length of 3 steps.
    base::TimeDelta step_expected_queueing_time_;
    RunningAverage step_queueing_times_;

    // Variables to split Expected Queueing Time by task queue type.
    std::array<base::TimeDelta,
               static_cast<int>(MainThreadTaskQueue::QueueType::kCount)>
        eqt_by_queue_type_;
    MainThreadTaskQueue::QueueType current_queue_type_ =
        MainThreadTaskQueue::QueueType::kOther;

    // Variables to split Expected Queueing Time by frame type.
    std::array<base::TimeDelta, static_cast<int>(FrameStatus::kCount)>
        eqt_by_frame_status_;
    FrameStatus current_frame_status_ = FrameStatus::kNone;
  };

  class State {
   public:
    explicit State(int steps_per_window);
    void OnTopLevelTaskStarted(Client* client,
                               base::TimeTicks task_start_time,
                               MainThreadTaskQueue* queue);
    void OnTopLevelTaskCompleted(Client* client, base::TimeTicks task_end_time);
    void OnBeginNestedRunLoop();
    void OnRendererStateChanged(Client* client,
                                bool backgrounded,
                                base::TimeTicks transition_time);

    base::TimeDelta window_step_width;
    base::TimeTicks step_start_time;
    base::TimeTicks current_task_start_time;
    // |renderer_backgrounded| is the renderer's current status.
    bool renderer_backgrounded = kLaunchingProcessIsBackgrounded;
    bool processing_task = false;
    Calculator calculator_;

   private:
    void AdvanceTime(Client* client, base::TimeTicks current_time);
    bool TimePastStepEnd(base::TimeTicks task_end_time);
    bool in_nested_message_loop_ = false;
  };

  QueueingTimeEstimator(Client* client,
                        base::TimeDelta window_duration,
                        int steps_per_window);
  explicit QueueingTimeEstimator(const State& state);

  void OnTopLevelTaskStarted(base::TimeTicks task_start_time,
                             MainThreadTaskQueue* queue);
  void OnTopLevelTaskCompleted(base::TimeTicks task_end_time);
  void OnBeginNestedRunLoop();
  void OnRendererStateChanged(bool backgrounded,
                              base::TimeTicks transition_time);

  // Returns all state except for the current |client_|.
  const State& GetState() const { return state_; }

  base::TimeDelta EstimateQueueingTimeIncludingCurrentTask(
      base::TimeTicks now) const;

 private:
  Client* client_;  // NOT OWNED.
  State state_;

  DISALLOW_ASSIGN(QueueingTimeEstimator);
};

}  // namespace scheduler
}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_QUEUEING_TIME_ESTIMATOR_H_