OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/scheduler/renderer/budget_pool.h" | 5 #include "platform/scheduler/renderer/cpu_time_budget_pool.h" |
6 | 6 |
7 #include <cstdint> | 7 #include <cstdint> |
8 | 8 |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
12 #include "base/optional.h" | 12 #include "base/optional.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "platform/WebFrameScheduler.h" | |
15 #include "platform/scheduler/base/real_time_domain.h" | |
16 #include "platform/scheduler/child/scheduler_tqm_delegate.h" | |
17 #include "platform/scheduler/renderer/renderer_scheduler_impl.h" | |
18 #include "platform/scheduler/renderer/task_queue_throttler.h" | 14 #include "platform/scheduler/renderer/task_queue_throttler.h" |
19 #include "platform/scheduler/renderer/throttled_time_domain.h" | |
20 #include "platform/scheduler/renderer/web_frame_scheduler_impl.h" | |
21 | 15 |
22 namespace blink { | 16 namespace blink { |
23 namespace scheduler { | 17 namespace scheduler { |
24 | 18 |
25 namespace { | 19 namespace { |
26 | 20 |
27 std::string PointerToId(void* pointer) { | 21 std::string PointerToId(void* pointer) { |
28 return base::StringPrintf( | 22 return base::StringPrintf( |
29 "0x%" PRIx64, | 23 "0x%" PRIx64, |
30 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); | 24 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pointer))); |
31 } | 25 } |
32 | 26 |
33 } // namespace | 27 } // namespace |
34 | 28 |
35 BudgetPool::BudgetPool(const char* name, | |
36 BudgetPoolController* budget_pool_controller) | |
37 : name_(name), | |
38 budget_pool_controller_(budget_pool_controller), | |
39 is_enabled_(true) {} | |
40 | |
41 BudgetPool::~BudgetPool() {} | |
42 | |
43 const char* BudgetPool::Name() const { | |
44 return name_; | |
45 } | |
46 | |
47 void BudgetPool::AddQueue(base::TimeTicks now, TaskQueue* queue) { | |
48 budget_pool_controller_->AddQueueToBudgetPool(queue, this); | |
49 associated_task_queues_.insert(queue); | |
50 | |
51 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) | |
52 return; | |
53 | |
54 budget_pool_controller_->BlockQueue(now, queue); | |
55 } | |
56 | |
57 void BudgetPool::RemoveQueue(base::TimeTicks now, TaskQueue* queue) { | |
58 budget_pool_controller_->RemoveQueueFromBudgetPool(queue, this); | |
59 associated_task_queues_.erase(queue); | |
60 | |
61 if (!is_enabled_ || !budget_pool_controller_->IsThrottled(queue)) | |
62 return; | |
63 | |
64 budget_pool_controller_->UnblockQueue(now, queue); | |
65 } | |
66 | |
67 void BudgetPool::EnableThrottling(LazyNow* lazy_now) { | |
68 if (is_enabled_) | |
69 return; | |
70 is_enabled_ = true; | |
71 | |
72 TRACE_EVENT0("renderer.scheduler", "BudgetPool_EnableThrottling"); | |
73 | |
74 BlockThrottledQueues(lazy_now->Now()); | |
75 } | |
76 | |
77 void BudgetPool::DisableThrottling(LazyNow* lazy_now) { | |
78 if (!is_enabled_) | |
79 return; | |
80 is_enabled_ = false; | |
81 | |
82 TRACE_EVENT0("renderer.scheduler", "BudgetPool_DisableThrottling"); | |
83 | |
84 for (TaskQueue* queue : associated_task_queues_) { | |
85 if (!budget_pool_controller_->IsThrottled(queue)) | |
86 continue; | |
87 | |
88 budget_pool_controller_->UnblockQueue(lazy_now->Now(), queue); | |
89 } | |
90 | |
91 // TODO(altimin): We need to disable TimeBudgetQueues here or they will | |
92 // regenerate extra time budget when they are disabled. | |
93 } | |
94 | |
95 bool BudgetPool::IsThrottlingEnabled() const { | |
96 return is_enabled_; | |
97 } | |
98 | |
99 void BudgetPool::Close() { | |
100 DCHECK_EQ(0u, associated_task_queues_.size()); | |
101 | |
102 budget_pool_controller_->UnregisterBudgetPool(this); | |
103 } | |
104 | |
105 void BudgetPool::BlockThrottledQueues(base::TimeTicks now) { | |
106 for (TaskQueue* queue : associated_task_queues_) | |
107 budget_pool_controller_->BlockQueue(now, queue); | |
108 } | |
109 | |
110 CPUTimeBudgetPool::CPUTimeBudgetPool( | 29 CPUTimeBudgetPool::CPUTimeBudgetPool( |
111 const char* name, | 30 const char* name, |
112 BudgetPoolController* budget_pool_controller, | 31 BudgetPoolController* budget_pool_controller, |
113 base::TimeTicks now) | 32 base::TimeTicks now) |
114 : BudgetPool(name, budget_pool_controller), | 33 : BudgetPool(name, budget_pool_controller), |
115 last_checkpoint_(now), | 34 last_checkpoint_(now), |
116 cpu_percentage_(1) {} | 35 cpu_percentage_(1) {} |
117 | 36 |
118 CPUTimeBudgetPool::~CPUTimeBudgetPool() {} | 37 CPUTimeBudgetPool::~CPUTimeBudgetPool() {} |
119 | 38 |
39 QueueBlockType CPUTimeBudgetPool::GetBlockType() const { | |
40 return QueueBlockType::kAllTasks; | |
41 } | |
42 | |
120 void CPUTimeBudgetPool::SetMaxBudgetLevel( | 43 void CPUTimeBudgetPool::SetMaxBudgetLevel( |
121 base::TimeTicks now, | 44 base::TimeTicks now, |
122 base::Optional<base::TimeDelta> max_budget_level) { | 45 base::Optional<base::TimeDelta> max_budget_level) { |
123 Advance(now); | 46 Advance(now); |
124 max_budget_level_ = max_budget_level; | 47 max_budget_level_ = max_budget_level; |
125 EnforceBudgetLevelRestrictions(); | 48 EnforceBudgetLevelRestrictions(); |
126 } | 49 } |
127 | 50 |
128 void CPUTimeBudgetPool::SetMaxThrottlingDelay( | 51 void CPUTimeBudgetPool::SetMaxThrottlingDelay( |
129 base::TimeTicks now, | 52 base::TimeTicks now, |
(...skipping 22 matching lines...) Expand all Loading... | |
152 Advance(now); | 75 Advance(now); |
153 current_budget_level_ += budget_level; | 76 current_budget_level_ += budget_level; |
154 EnforceBudgetLevelRestrictions(); | 77 EnforceBudgetLevelRestrictions(); |
155 } | 78 } |
156 | 79 |
157 void CPUTimeBudgetPool::SetReportingCallback( | 80 void CPUTimeBudgetPool::SetReportingCallback( |
158 base::Callback<void(base::TimeDelta)> reporting_callback) { | 81 base::Callback<void(base::TimeDelta)> reporting_callback) { |
159 reporting_callback_ = reporting_callback; | 82 reporting_callback_ = reporting_callback; |
160 } | 83 } |
161 | 84 |
162 bool CPUTimeBudgetPool::HasEnoughBudgetToRun(base::TimeTicks now) { | 85 bool CPUTimeBudgetPool::CanRunTasksAt(base::TimeTicks now, |
163 return now >= GetNextAllowedRunTime(); | 86 bool is_wake_up) const { |
87 return now >= GetNextAllowedRunTime(now); | |
164 } | 88 } |
165 | 89 |
166 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime() { | 90 bool CPUTimeBudgetPool::CanRunTasksUntil(base::TimeTicks now, |
91 base::TimeTicks moment) const { | |
92 return CanRunTasksAt(now, false); | |
Sami
2017/04/29 17:43:02
I think this is slightly misleading: I would expec
altimin
2017/05/02 18:16:58
Scrapped CanRunTasksUntil completely.
| |
93 } | |
94 | |
95 base::TimeTicks CPUTimeBudgetPool::GetNextAllowedRunTime( | |
96 base::TimeTicks desired_run_time) const { | |
167 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { | 97 if (!is_enabled_ || current_budget_level_.InMicroseconds() >= 0) { |
168 return last_checkpoint_; | 98 return last_checkpoint_; |
169 } else { | 99 } else { |
170 // Subtract because current_budget is negative. | 100 // Subtract because current_budget is negative. |
171 return last_checkpoint_ + | 101 return last_checkpoint_ + |
172 (-current_budget_level_ + min_budget_level_to_run_) / | 102 (-current_budget_level_ + min_budget_level_to_run_) / |
173 cpu_percentage_; | 103 cpu_percentage_; |
174 } | 104 } |
175 } | 105 } |
176 | 106 |
177 void CPUTimeBudgetPool::RecordTaskRunTime(base::TimeTicks start_time, | 107 void CPUTimeBudgetPool::RecordTaskRunTime(TaskQueue* queue, |
108 base::TimeTicks start_time, | |
178 base::TimeTicks end_time) { | 109 base::TimeTicks end_time) { |
179 DCHECK_LE(start_time, end_time); | 110 DCHECK_LE(start_time, end_time); |
180 Advance(end_time); | 111 Advance(end_time); |
181 if (is_enabled_) { | 112 if (is_enabled_) { |
182 base::TimeDelta old_budget_level = current_budget_level_; | 113 base::TimeDelta old_budget_level = current_budget_level_; |
183 current_budget_level_ -= (end_time - start_time); | 114 current_budget_level_ -= (end_time - start_time); |
184 EnforceBudgetLevelRestrictions(); | 115 EnforceBudgetLevelRestrictions(); |
185 | 116 |
186 if (!reporting_callback_.is_null() && old_budget_level.InSecondsF() > 0 && | 117 if (!reporting_callback_.is_null() && old_budget_level.InSecondsF() > 0 && |
187 current_budget_level_.InSecondsF() < 0) { | 118 current_budget_level_.InSecondsF() < 0) { |
188 reporting_callback_.Run(-current_budget_level_ / cpu_percentage_); | 119 reporting_callback_.Run(-current_budget_level_ / cpu_percentage_); |
189 } | 120 } |
190 } | 121 } |
122 | |
123 if (current_budget_level_.InSecondsF() < 0) | |
124 BlockThrottledQueues(end_time); | |
191 } | 125 } |
192 | 126 |
127 void CPUTimeBudgetPool::OnQueueNextWakeUpChanged( | |
128 TaskQueue* queue, | |
129 base::TimeTicks now, | |
130 base::TimeTicks desired_run_time) { | |
131 budget_pool_controller_->UpdateQueueThrottlingState(now, queue); | |
132 } | |
133 | |
134 void CPUTimeBudgetPool::OnWakeUp(base::TimeTicks now) {} | |
135 | |
193 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state, | 136 void CPUTimeBudgetPool::AsValueInto(base::trace_event::TracedValue* state, |
194 base::TimeTicks now) const { | 137 base::TimeTicks now) const { |
195 state->BeginDictionary(name_); | 138 state->BeginDictionary(name_); |
196 | 139 |
197 state->SetString("name", name_); | 140 state->SetString("name", name_); |
198 state->SetDouble("time_budget", cpu_percentage_); | 141 state->SetDouble("time_budget", cpu_percentage_); |
199 state->SetDouble("time_budget_level_in_seconds", | 142 state->SetDouble("time_budget_level_in_seconds", |
200 current_budget_level_.InSecondsF()); | 143 current_budget_level_.InSecondsF()); |
201 state->SetDouble("last_checkpoint_seconds_ago", | 144 state->SetDouble("last_checkpoint_seconds_ago", |
202 (now - last_checkpoint_).InSecondsF()); | 145 (now - last_checkpoint_).InSecondsF()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 if (max_throttling_delay_) { | 183 if (max_throttling_delay_) { |
241 // Current budget level may be negative. | 184 // Current budget level may be negative. |
242 current_budget_level_ = | 185 current_budget_level_ = |
243 std::max(current_budget_level_, | 186 std::max(current_budget_level_, |
244 -max_throttling_delay_.value() * cpu_percentage_); | 187 -max_throttling_delay_.value() * cpu_percentage_); |
245 } | 188 } |
246 } | 189 } |
247 | 190 |
248 } // namespace scheduler | 191 } // namespace scheduler |
249 } // namespace blink | 192 } // namespace blink |
OLD | NEW |