OLD | NEW |
---|---|
(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 // A predicted renderer size. These values come from the median of appropriate | |
16 // UMA stats. | |
17 #if defined(OS_ANDROID) || defined(OS_IOS) | |
18 const int kDefaultPredictedRendererSizeMB = 40; | |
19 #elif defined(OS_WIN) | |
20 const int kDefaultPredictedRendererSizeMB = 70; | |
21 #else | |
22 const int kDefaultPredictedRendererSizeMB = 120; | |
haraken
2016/10/14 01:27:59
Not related to this CL, do you know why the median
bashi
2016/10/14 03:03:00
Unfortunately no. The UMA comes from WorkingSetKBy
| |
23 #endif | |
24 | |
25 // Default values for parameters to determine the global state. | |
26 const int kDefaultNewRenderersUntilThrottled = 4; | |
27 const int kDefaultNewRenderersUntilSuspended = 2; | |
28 const int kDefaultNewRenderersBackToNormal = 5; | |
29 const int kDefaultNewRenderersBackToThrottled = 3; | |
30 const int kDefaultMinimumTransitionPeriodSeconds = 30; | |
31 const int kDefaultMonitoringIntervalSeconds = 5; | |
32 | |
33 mojom::MemoryState ToMojomMemoryState(base::MemoryState state) { | |
34 switch (state) { | |
35 case base::MemoryState::UNKNOWN: | |
36 return mojom::MemoryState::UNKNOWN; | |
37 case base::MemoryState::NORMAL: | |
38 return mojom::MemoryState::NORMAL; | |
39 case base::MemoryState::THROTTLED: | |
40 return mojom::MemoryState::THROTTLED; | |
41 case base::MemoryState::SUSPENDED: | |
42 return mojom::MemoryState::SUSPENDED; | |
43 default: | |
44 NOTREACHED(); | |
45 return mojom::MemoryState::UNKNOWN; | |
46 } | |
47 } | |
48 | |
49 } // namespace | |
50 | |
51 // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl | |
52 // as an actual instance. | |
53 struct MemoryCoordinatorSingletonTraits | |
54 : public base::LeakySingletonTraits<MemoryCoordinator> { | |
55 static MemoryCoordinator* New() { | |
56 return new MemoryCoordinatorImpl(base::ThreadTaskRunnerHandle::Get(), | |
57 CreateMemoryMonitor()); | |
58 } | |
59 }; | |
60 | |
61 // static | |
62 MemoryCoordinator* MemoryCoordinator::GetInstance() { | |
63 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator)) | |
64 return nullptr; | |
65 return base::Singleton<MemoryCoordinator, | |
66 MemoryCoordinatorSingletonTraits>::get(); | |
67 } | |
68 | |
69 MemoryCoordinatorImpl::MemoryCoordinatorImpl( | |
70 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
71 std::unique_ptr<MemoryMonitor> memory_monitor) | |
72 : task_runner_(task_runner), | |
73 memory_monitor_(std::move(memory_monitor)), | |
74 weak_ptr_factory_(this) { | |
75 DCHECK(memory_monitor_.get()); | |
76 update_state_callback_ = base::Bind(&MemoryCoordinatorImpl::UpdateState, | |
77 weak_ptr_factory_.GetWeakPtr()); | |
78 | |
79 // Set initial parameters for calculating the global state. | |
80 predicted_renderer_size_ = kDefaultPredictedRendererSizeMB; | |
81 new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled; | |
82 new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended; | |
83 new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal; | |
84 new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled; | |
85 minimum_transition_period_ = | |
86 base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds); | |
87 monitoring_interval_ = | |
88 base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); | |
89 } | |
90 | |
91 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} | |
92 | |
93 void MemoryCoordinatorImpl::Start() { | |
94 DCHECK(CalledOnValidThread()); | |
95 DCHECK(last_state_change_.is_null()); | |
96 DCHECK(ValidateParameters()); | |
97 ScheduleUpdateState(base::TimeDelta()); | |
98 } | |
99 | |
100 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { | |
101 // Populate the global state as an initial state of a newly created process. | |
102 SetMemoryState(render_process_id, ToMojomMemoryState(current_state_)); | |
103 } | |
104 | |
105 base::MemoryState MemoryCoordinatorImpl::CalculateNextState() { | |
106 using MemoryState = base::MemoryState; | |
107 | |
108 int available = memory_monitor_->GetFreeMemoryUntilCriticalMB(); | |
109 if (available <= 0) | |
110 return MemoryState::SUSPENDED; | |
111 | |
112 int expected_renderer_count = available / predicted_renderer_size_; | |
113 | |
114 switch (current_state_) { | |
115 case MemoryState::NORMAL: | |
116 if (expected_renderer_count <= new_renderers_until_suspended_) | |
117 return MemoryState::SUSPENDED; | |
118 if (expected_renderer_count <= new_renderers_until_throttled_) | |
119 return MemoryState::THROTTLED; | |
120 return MemoryState::NORMAL; | |
121 case MemoryState::THROTTLED: | |
122 if (expected_renderer_count <= new_renderers_until_suspended_) | |
123 return MemoryState::SUSPENDED; | |
124 if (expected_renderer_count >= new_renderers_back_to_normal_) | |
125 return MemoryState::NORMAL; | |
126 return MemoryState::THROTTLED; | |
127 case MemoryState::SUSPENDED: | |
128 if (expected_renderer_count >= new_renderers_back_to_normal_) | |
129 return MemoryState::NORMAL; | |
130 if (expected_renderer_count >= new_renderers_back_to_throttled_) | |
131 return MemoryState::THROTTLED; | |
132 return MemoryState::SUSPENDED; | |
133 case MemoryState::UNKNOWN: | |
134 // Fall through | |
135 default: | |
136 NOTREACHED(); | |
137 return MemoryState::UNKNOWN; | |
138 } | |
139 } | |
140 | |
141 void MemoryCoordinatorImpl::UpdateState() { | |
142 base::TimeTicks now = base::TimeTicks::Now(); | |
143 MemoryState prev_state = current_state_; | |
144 MemoryState next_state = CalculateNextState(); | |
145 | |
146 if (last_state_change_.is_null() || current_state_ != next_state) { | |
147 current_state_ = next_state; | |
148 last_state_change_ = now; | |
149 } | |
150 | |
151 if (next_state != prev_state) { | |
152 NotifyStateToClients(); | |
153 NotifyStateToChildren(); | |
154 ScheduleUpdateState(minimum_transition_period_); | |
155 } else { | |
156 ScheduleUpdateState(monitoring_interval_); | |
157 } | |
158 } | |
159 | |
160 void MemoryCoordinatorImpl::NotifyStateToClients() { | |
161 // SUSPENDED state may not make sense to the browser process. Use THROTTLED | |
162 // instead when the global state is SUSPENDED. | |
163 // TODO(bashi): Maybe worth considering another state for the browser. | |
164 auto state = current_state_ == MemoryState::SUSPENDED ? MemoryState::THROTTLED | |
165 : current_state_; | |
166 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); | |
167 } | |
168 | |
169 void MemoryCoordinatorImpl::NotifyStateToChildren() { | |
170 auto mojo_state = ToMojomMemoryState(current_state_); | |
171 // It's OK to call SetMemoryState() unconditionally because it checks whether | |
172 // this state transition is valid. | |
173 // TODO(bashi): In SUSPENDED state, we should update children's state | |
174 // accordingly when the foreground tab is changed (e.g. resume a renderer | |
175 // which becomes foreground and suspend a renderer which goes to background). | |
176 for (auto& iter : children()) | |
177 SetMemoryState(iter.first, mojo_state); | |
178 } | |
179 | |
180 void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) { | |
181 task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta); | |
182 } | |
183 | |
184 bool MemoryCoordinatorImpl::ValidateParameters() { | |
185 return (new_renderers_until_throttled_ > new_renderers_until_suspended_) && | |
186 (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) && | |
187 (new_renderers_back_to_normal_ > new_renderers_until_throttled_) && | |
188 (new_renderers_back_to_throttled_ > new_renderers_until_suspended_); | |
189 } | |
190 | |
191 } // namespace content | |
OLD | NEW |