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

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

Issue 2374343002: Add MemoryCoordinatorImpl (Closed)
Patch Set: Attempt to fix mac failure Created 4 years, 2 months 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/memory/memory_coordinator_impl.h"
6
7 #include "base/threading/thread_task_runner_handle.h"
8 #include "content/browser/memory/memory_monitor.h"
9 #include "content/public/common/content_features.h"
10
11 namespace content {
12
13 namespace {
14
15 #if defined(OS_ANDROID)
16 static const int kDefaultPredictedRendererSizeMB = 40;
chrisha 2016/10/10 23:53:01 Can you comment where these come from (ie, the XXt
bashi 2016/10/11 02:07:33 Done. I was thinking that that's kind of informati
17 #else
18 static const int kDefaultPredictedRendererSizeMB = 80;
19 #endif
20
21 mojom::MemoryState ToMojomMemoryState(base::MemoryState state) {
22 switch (state) {
23 case base::MemoryState::UNKNOWN:
24 return mojom::MemoryState::UNKNOWN;
25 case base::MemoryState::NORMAL:
26 return mojom::MemoryState::NORMAL;
27 case base::MemoryState::THROTTLED:
28 return mojom::MemoryState::THROTTLED;
29 case base::MemoryState::SUSPENDED:
30 return mojom::MemoryState::SUSPENDED;
31 default:
32 NOTREACHED();
33 return mojom::MemoryState::UNKNOWN;
34 }
35 }
36
37 } // namespace
38
39 // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl
40 // as an actual instance.
41 struct MemoryCoordinatorSingletonTraits
42 : public base::LeakySingletonTraits<MemoryCoordinator> {
43 static MemoryCoordinator* New() {
44 return new MemoryCoordinatorImpl(base::ThreadTaskRunnerHandle::Get(),
45 CreateMemoryMonitor());
46 }
47 };
48
49 // static
50 MemoryCoordinator* MemoryCoordinator::GetInstance() {
51 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator))
52 return nullptr;
53 return base::Singleton<MemoryCoordinator,
54 MemoryCoordinatorSingletonTraits>::get();
55 }
56
57 MemoryCoordinatorImpl::MemoryCoordinatorImpl(
58 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
59 std::unique_ptr<MemoryMonitor> memory_monitor)
60 : task_runner_(task_runner),
61 memory_monitor_(std::move(memory_monitor)),
62 weak_ptr_factory_(this) {
63 DCHECK(memory_monitor_.get());
64 update_state_callback_ = base::Bind(&MemoryCoordinatorImpl::UpdateState,
65 weak_ptr_factory_.GetWeakPtr());
66
67 // Set initial parameters for calculating the global state.
68 predicted_renderer_size_ = kDefaultPredictedRendererSizeMB;
69 new_renderers_until_throttled_ = 4;
70 new_renderers_until_suspended_ = 2;
71 new_renderers_back_to_normal_ = 5;
72 new_renderers_back_to_throttled_ = 3;
chrisha 2016/10/10 23:53:02 I'd prefer to have constants defined in an anonymo
bashi 2016/10/11 02:07:33 Done.
73 minimum_transition_period_ = base::TimeDelta::FromSeconds(30);
74 monitoring_interval_ = base::TimeDelta::FromSeconds(5);
chrisha 2016/10/10 23:53:02 Ditto.
bashi 2016/10/11 02:07:33 Done.
75 }
76
77 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {}
78
79 void MemoryCoordinatorImpl::Start() {
80 DCHECK(CalledOnValidThread());
81 DCHECK(last_state_change_.is_null());
82 DCHECK(ValidateParameters());
83 ScheduleUpdateState(base::TimeDelta());
84 }
85
86 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) {
87 // Populate the global state as an initial state of a newly created process.
88 SetMemoryState(render_process_id, ToMojomMemoryState(current_state_));
chrisha 2016/10/10 23:53:02 Either SetMemoryState needs to be defensive and on
bashi 2016/10/11 02:07:33 I've added checks in SetMemoryState() to prevent i
chrisha 2016/10/14 20:06:05 I'm not sure what the right answer is. Under extre
bashi 2016/10/16 23:51:22 I see. Added CanThrottleRenderer() which checks wh
89 }
90
91 base::MemoryState MemoryCoordinatorImpl::CalculateNextState() {
92 using MemoryState = base::MemoryState;
93
94 int available = memory_monitor_->GetFreeMemoryUntilCriticalMB();
95 if (available <= 0)
96 return MemoryState::SUSPENDED;
97
98 int new_renderers_until_critical = available / predicted_renderer_size_;
chrisha 2016/10/10 23:53:02 expected_renderer_size_ is a better name maybe? (
bashi 2016/10/11 02:07:33 Yeah, changed to expected_renderer_count.
99
100 switch (current_state_) {
101 case MemoryState::NORMAL:
102 if (new_renderers_until_critical <= new_renderers_until_suspended_)
103 return MemoryState::SUSPENDED;
104 if (new_renderers_until_critical <= new_renderers_until_throttled_)
105 return MemoryState::THROTTLED;
106 return MemoryState::NORMAL;
107 case MemoryState::THROTTLED:
108 if (new_renderers_until_critical <= new_renderers_until_suspended_)
109 return MemoryState::SUSPENDED;
110 if (new_renderers_until_critical >= new_renderers_back_to_normal_)
111 return MemoryState::NORMAL;
112 return MemoryState::THROTTLED;
113 case MemoryState::SUSPENDED:
114 if (new_renderers_until_critical >= new_renderers_back_to_normal_)
115 return MemoryState::NORMAL;
116 if (new_renderers_until_critical >= new_renderers_back_to_throttled_)
117 return MemoryState::THROTTLED;
118 return MemoryState::SUSPENDED;
119 case MemoryState::UNKNOWN:
120 // Fall through
121 default:
122 NOTREACHED();
123 return MemoryState::UNKNOWN;
124 }
125 }
126
127 void MemoryCoordinatorImpl::UpdateState() {
128 base::TimeTicks now = base::TimeTicks::Now();
129 MemoryState prev_state = current_state_;
130 MemoryState next_state = CalculateNextState();
131
132 if (last_state_change_.is_null() || current_state_ != next_state) {
133 current_state_ = next_state;
134 last_state_change_ = now;
135 }
136
137 if (next_state != prev_state) {
138 NotifyStateToClients();
139 NotifyStateToChildren();
140 ScheduleUpdateState(minimum_transition_period_);
141 } else {
142 ScheduleUpdateState(monitoring_interval_);
143 }
144 }
145
146 void MemoryCoordinatorImpl::NotifyStateToClients() {
147 // SUSPENDED state may not make sense to the browser process. Use THROTTLED
148 // instead when the global state is SUSPENDED.
149 // TODO(bashi): Maybe worth considering another state for the browser.
150 auto state = current_state_ == MemoryState::SUSPENDED ? MemoryState::THROTTLED
151 : current_state_;
152 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state);
153 }
154
155 void MemoryCoordinatorImpl::NotifyStateToChildren() {
156 // TODO(bashi): Don't send SUSPENDED state to the foreground renderer.
157 // TODO(bashi): Consider how to deal with background renderers which can't
158 // be suspended.
chrisha 2016/10/10 23:53:02 These TODOs need to happen before this can land, I
bashi 2016/10/11 02:07:33 Yes. I'll submit this after the delegate is landed
159 auto mojo_state = ToMojomMemoryState(current_state_);
160 for (auto& iter : children())
161 SetMemoryState(iter.first, mojo_state);
162 }
163
164 void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) {
165 task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta);
166 }
167
168 bool MemoryCoordinatorImpl::ValidateParameters() {
169 return (new_renderers_until_throttled_ > new_renderers_until_suspended_) &&
170 (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) &&
171 (new_renderers_back_to_normal_ > new_renderers_until_throttled_) &&
172 (new_renderers_back_to_throttled_ > new_renderers_until_suspended_);
173 }
174
175 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698