Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: content/browser/memory/memory_coordinator_impl.cc

Issue 2479673002: Expose MemoryCoordinator's global budget information. (Closed)
Patch Set: Small cleanup. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "content/browser/memory/memory_coordinator_impl.h" 5 #include "content/browser/memory/memory_coordinator_impl.h"
6 6
7 #include "base/threading/thread_task_runner_handle.h" 7 #include "base/threading/thread_task_runner_handle.h"
8 #include "base/trace_event/trace_event.h" 8 #include "base/trace_event/trace_event.h"
9 #include "content/browser/memory/memory_monitor.h" 9 #include "content/browser/memory/memory_monitor.h"
10 #include "content/public/browser/notification_service.h" 10 #include "content/public/browser/notification_service.h"
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 return nullptr; 69 return nullptr;
70 return base::Singleton<MemoryCoordinator, 70 return base::Singleton<MemoryCoordinator,
71 MemoryCoordinatorSingletonTraits>::get(); 71 MemoryCoordinatorSingletonTraits>::get();
72 } 72 }
73 73
74 MemoryCoordinatorImpl::MemoryCoordinatorImpl( 74 MemoryCoordinatorImpl::MemoryCoordinatorImpl(
75 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 75 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
76 std::unique_ptr<MemoryMonitor> memory_monitor) 76 std::unique_ptr<MemoryMonitor> memory_monitor)
77 : task_runner_(task_runner), 77 : task_runner_(task_runner),
78 memory_monitor_(std::move(memory_monitor)), 78 memory_monitor_(std::move(memory_monitor)),
79 remaining_global_budget_mb_(0),
79 weak_ptr_factory_(this) { 80 weak_ptr_factory_(this) {
80 DCHECK(memory_monitor_.get()); 81 DCHECK(memory_monitor_.get());
81 update_state_callback_ = base::Bind(&MemoryCoordinatorImpl::UpdateState, 82 update_state_callback_ = base::Bind(&MemoryCoordinatorImpl::UpdateState,
82 weak_ptr_factory_.GetWeakPtr()); 83 weak_ptr_factory_.GetWeakPtr());
83 84
84 // Set initial parameters for calculating the global state. 85 // Set initial parameters for calculating the global state.
85 expected_renderer_size_ = kDefaultExpectedRendererSizeMB; 86 expected_renderer_size_ = kDefaultExpectedRendererSizeMB;
Hannes Payer (out of office) 2016/11/11 12:55:19 Unrelated to this CL: How did you come up with kDe
bashi 2016/11/12 01:30:53 From UMA (median of average). This is just an esti
86 new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled; 87 new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled;
87 new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended; 88 new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended;
88 new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal; 89 new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal;
89 new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled; 90 new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled;
90 minimum_transition_period_ = 91 minimum_transition_period_ =
91 base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds); 92 base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds);
92 monitoring_interval_ = 93 monitoring_interval_ =
93 base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); 94 base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds);
94 } 95 }
95 96
(...skipping 29 matching lines...) Expand all
125 // updated later by the task posted at ScheduleUpdateState. 126 // updated later by the task posted at ScheduleUpdateState.
126 DCHECK(memory_state != MemoryState::UNKNOWN); 127 DCHECK(memory_state != MemoryState::UNKNOWN);
127 base::MemoryState prev_state = current_state_; 128 base::MemoryState prev_state = current_state_;
128 current_state_ = memory_state; 129 current_state_ = memory_state;
129 if (prev_state != current_state_) { 130 if (prev_state != current_state_) {
130 NotifyStateToClients(); 131 NotifyStateToClients();
131 NotifyStateToChildren(); 132 NotifyStateToChildren();
132 } 133 }
133 } 134 }
134 135
136 int64_t MemoryCoordinatorImpl::GetRemainingGlobalBudget() const {
137 return remaining_global_budget_mb_;
138 }
139
135 void MemoryCoordinatorImpl::Observe(int type, 140 void MemoryCoordinatorImpl::Observe(int type,
136 const NotificationSource& source, 141 const NotificationSource& source,
137 const NotificationDetails& details) { 142 const NotificationDetails& details) {
138 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); 143 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED);
139 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); 144 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr();
140 RenderProcessHost* process = render_widget_host->GetProcess(); 145 RenderProcessHost* process = render_widget_host->GetProcess();
141 if (!process) 146 if (!process)
142 return; 147 return;
143 auto iter = children().find(process->GetID()); 148 auto iter = children().find(process->GetID());
144 if (iter == children().end()) 149 if (iter == children().end())
145 return; 150 return;
146 bool is_visible = *Details<bool>(details).ptr(); 151 bool is_visible = *Details<bool>(details).ptr();
147 // We don't throttle/suspend a visible renderer for now. 152 // We don't throttle/suspend a visible renderer for now.
148 auto new_state = is_visible ? mojom::MemoryState::NORMAL 153 auto new_state = is_visible ? mojom::MemoryState::NORMAL
149 : ToMojomMemoryState(current_state_); 154 : ToMojomMemoryState(current_state_);
150 SetMemoryState(iter->first, new_state); 155 SetMemoryState(iter->first, new_state);
151 } 156 }
152 157
153 base::MemoryState MemoryCoordinatorImpl::CalculateNextState() { 158 base::MemoryState MemoryCoordinatorImpl::CalculateNextState(
159 int free_memory_until_critical_mb) {
154 using MemoryState = base::MemoryState; 160 using MemoryState = base::MemoryState;
155 161
156 int available = memory_monitor_->GetFreeMemoryUntilCriticalMB(); 162 // If memory is already critical then immediately go to the most aggressive
157 if (available <= 0) 163 // state.
164 if (free_memory_until_critical_mb <= 0)
158 return MemoryState::SUSPENDED; 165 return MemoryState::SUSPENDED;
159 166
160 int expected_renderer_count = available / expected_renderer_size_; 167 // Determine the next state.
161 168 int expected_renderer_count =
169 free_memory_until_critical_mb / expected_renderer_size_;
162 switch (current_state_) { 170 switch (current_state_) {
163 case MemoryState::NORMAL: 171 case MemoryState::NORMAL:
164 if (expected_renderer_count <= new_renderers_until_suspended_) 172 if (expected_renderer_count <= new_renderers_until_suspended_)
165 return MemoryState::SUSPENDED; 173 return MemoryState::SUSPENDED;
166 if (expected_renderer_count <= new_renderers_until_throttled_) 174 if (expected_renderer_count <= new_renderers_until_throttled_)
167 return MemoryState::THROTTLED; 175 return MemoryState::THROTTLED;
168 return MemoryState::NORMAL; 176 return MemoryState::NORMAL;
169 case MemoryState::THROTTLED: 177 case MemoryState::THROTTLED:
170 if (expected_renderer_count <= new_renderers_until_suspended_) 178 if (expected_renderer_count <= new_renderers_until_suspended_)
171 return MemoryState::SUSPENDED; 179 return MemoryState::SUSPENDED;
172 if (expected_renderer_count >= new_renderers_back_to_normal_) 180 if (expected_renderer_count >= new_renderers_back_to_normal_)
173 return MemoryState::NORMAL; 181 return MemoryState::NORMAL;
174 return MemoryState::THROTTLED; 182 return MemoryState::THROTTLED;
175 case MemoryState::SUSPENDED: 183 case MemoryState::SUSPENDED:
176 if (expected_renderer_count >= new_renderers_back_to_normal_) 184 if (expected_renderer_count >= new_renderers_back_to_normal_)
177 return MemoryState::NORMAL; 185 return MemoryState::NORMAL;
178 if (expected_renderer_count >= new_renderers_back_to_throttled_) 186 if (expected_renderer_count >= new_renderers_back_to_throttled_)
179 return MemoryState::THROTTLED; 187 return MemoryState::THROTTLED;
180 return MemoryState::SUSPENDED; 188 return MemoryState::SUSPENDED;
181 case MemoryState::UNKNOWN: 189 case MemoryState::UNKNOWN:
182 // Fall through 190 // Fall through.
183 default: 191 default:
184 NOTREACHED(); 192 NOTREACHED();
185 return MemoryState::UNKNOWN; 193 return MemoryState::UNKNOWN;
186 } 194 }
187 } 195 }
188 196
197 int64_t MemoryCoordinatorImpl::CalculateRemainingGlobalBudget(
198 int free_memory_until_critical_mb) {
199 int renderer_count = new_renderers_until_throttled_;
Hannes Payer (out of office) 2016/11/11 12:55:19 I do not understand why you use kDefaultNewRendere
bashi 2016/11/12 01:30:53 Because we don't know what an appropriate value fo
200 if (current_state_ != MemoryState::NORMAL)
201 renderer_count = new_renderers_back_to_normal_;
haraken 2016/11/05 12:52:21 Shouldn't new_renderers_back_to_normal_ be always
bashi 2016/11/07 00:16:37 We have different parameters for # of renderers to
chrisha 2016/11/07 19:33:41 Yeah, this enables a "dead band" to prevent thrash
202
203 return free_memory_until_critical_mb -
204 renderer_count * expected_renderer_size_;
205 }
206
189 void MemoryCoordinatorImpl::UpdateState() { 207 void MemoryCoordinatorImpl::UpdateState() {
190 base::TimeTicks now = base::TimeTicks::Now(); 208 base::TimeTicks now = base::TimeTicks::Now();
209
210 int available = memory_monitor_->GetFreeMemoryUntilCriticalMB();
211
191 MemoryState prev_state = current_state_; 212 MemoryState prev_state = current_state_;
192 MemoryState next_state = CalculateNextState(); 213 MemoryState next_state = CalculateNextState(available);
193 214
194 if (last_state_change_.is_null() || current_state_ != next_state) { 215 if (last_state_change_.is_null() || current_state_ != next_state) {
195 current_state_ = next_state; 216 current_state_ = next_state;
196 last_state_change_ = now; 217 last_state_change_ = now;
197 } 218 }
198 219
199 if (next_state != prev_state) { 220 if (next_state != prev_state) {
200 TRACE_EVENT2("memory-infra", "MemoryCoordinatorImpl::UpdateState", 221 TRACE_EVENT2("memory-infra", "MemoryCoordinatorImpl::UpdateState",
201 "prev", MemoryStateToString(prev_state), 222 "prev", MemoryStateToString(prev_state),
202 "next", MemoryStateToString(next_state)); 223 "next", MemoryStateToString(next_state));
203 224
204 NotifyStateToClients(); 225 NotifyStateToClients();
205 NotifyStateToChildren(); 226 NotifyStateToChildren();
206 ScheduleUpdateState(minimum_transition_period_); 227 ScheduleUpdateState(minimum_transition_period_);
207 } else { 228 } else {
208 ScheduleUpdateState(monitoring_interval_); 229 ScheduleUpdateState(monitoring_interval_);
209 } 230 }
231
232 // Update the global budget. This is used by some passive clients of the
233 // memory coordinator to smoothly scale their own resource consumption in
234 // sync with the memory coordinator.
235 int64_t prev_remaining = remaining_global_budget_mb_;
236 int64_t next_remaining = CalculateRemainingGlobalBudget(available);
237 if (prev_remaining != next_remaining) {
bashi 2016/11/07 00:16:37 How likely does this condition become true? |free_
chrisha 2016/11/07 19:33:41 Very unlikely to remain true, but this is a cheap
bashi 2016/11/07 23:17:08 Acknowledged.
chrisha 2016/12/15 21:10:24 (This is a moot point with a "pull" model.)
238 remaining_global_budget_mb_ = next_remaining;
239 NotifyRemainingGlobalBudgetToChildren();
haraken 2016/11/05 12:52:21 How frequently will this IPC be called?
bashi 2016/11/07 00:16:37 My guess is that it's almost the same as how frequ
chrisha 2016/11/07 19:33:41 Yup. Although we should likely still continue to c
bashi 2016/11/07 23:17:08 Yeah, as haraken@ said, async API may not be usefu
Hannes Payer (out of office) 2016/11/11 12:55:19 Currently, I am only planning to take advantage of
chrisha 2016/12/15 21:10:24 Moved to a "pull" model.
240 }
210 } 241 }
211 242
212 void MemoryCoordinatorImpl::NotifyStateToClients() { 243 void MemoryCoordinatorImpl::NotifyStateToClients() {
213 auto state = GetCurrentMemoryState(); 244 auto state = GetCurrentMemoryState();
214 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); 245 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state);
215 } 246 }
216 247
217 void MemoryCoordinatorImpl::NotifyStateToChildren() { 248 void MemoryCoordinatorImpl::NotifyStateToChildren() {
218 auto mojo_state = ToMojomMemoryState(current_state_); 249 auto mojo_state = ToMojomMemoryState(current_state_);
219 // It's OK to call SetMemoryState() unconditionally because it checks whether 250 // It's OK to call SetMemoryState() unconditionally because it checks whether
220 // this state transition is valid. 251 // this state transition is valid.
221 for (auto& iter : children()) 252 for (auto& iter : children())
222 SetMemoryState(iter.first, mojo_state); 253 SetMemoryState(iter.first, mojo_state);
223 } 254 }
224 255
256 void MemoryCoordinatorImpl::NotifyRemainingGlobalBudgetToChildren() {
257 for (auto& iter : children())
258 SetRemainingGlobalBudget(iter.first, remaining_global_budget_mb_);
259 }
260
225 void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) { 261 void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) {
226 task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta); 262 task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta);
227 } 263 }
228 264
229 bool MemoryCoordinatorImpl::ValidateParameters() { 265 bool MemoryCoordinatorImpl::ValidateParameters() {
230 return (new_renderers_until_throttled_ > new_renderers_until_suspended_) && 266 return (new_renderers_until_throttled_ > new_renderers_until_suspended_) &&
231 (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) && 267 (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) &&
232 (new_renderers_back_to_normal_ > new_renderers_until_throttled_) && 268 (new_renderers_back_to_normal_ > new_renderers_until_throttled_) &&
233 (new_renderers_back_to_throttled_ > new_renderers_until_suspended_); 269 (new_renderers_back_to_throttled_ > new_renderers_until_suspended_);
234 } 270 }
235 271
236 } // namespace content 272 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698