OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/common/gpu/gpu_memory_manager.h" | 5 #include "content/common/gpu/gpu_memory_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 | 28 |
29 const int kDelayedScheduleManageTimeoutMs = 67; | 29 const int kDelayedScheduleManageTimeoutMs = 67; |
30 | 30 |
31 const uint64 kBytesAllocatedUnmanagedStep = 16 * 1024 * 1024; | 31 const uint64 kBytesAllocatedUnmanagedStep = 16 * 1024 * 1024; |
32 | 32 |
33 void TrackValueChanged(uint64 old_size, uint64 new_size, uint64* total_size) { | 33 void TrackValueChanged(uint64 old_size, uint64 new_size, uint64* total_size) { |
34 DCHECK(new_size > old_size || *total_size >= (old_size - new_size)); | 34 DCHECK(new_size > old_size || *total_size >= (old_size - new_size)); |
35 *total_size += (new_size - old_size); | 35 *total_size += (new_size - old_size); |
36 } | 36 } |
37 | 37 |
| 38 template<typename T> |
| 39 T RoundUp(T n, T mul) { |
| 40 return ((n + mul - 1) / mul) * mul; |
| 41 } |
| 42 |
| 43 template<typename T> |
| 44 T RoundDown(T n, T mul) { |
| 45 return (n / mul) * mul; |
| 46 } |
| 47 |
38 } | 48 } |
39 | 49 |
40 GpuMemoryManager::GpuMemoryManager( | 50 GpuMemoryManager::GpuMemoryManager( |
41 GpuChannelManager* channel_manager, | 51 GpuChannelManager* channel_manager, |
42 uint64 max_surfaces_with_frontbuffer_soft_limit) | 52 uint64 max_surfaces_with_frontbuffer_soft_limit) |
43 : channel_manager_(channel_manager), | 53 : channel_manager_(channel_manager), |
44 manage_immediate_scheduled_(false), | 54 manage_immediate_scheduled_(false), |
45 disable_schedule_manage_(false), | |
46 max_surfaces_with_frontbuffer_soft_limit_( | 55 max_surfaces_with_frontbuffer_soft_limit_( |
47 max_surfaces_with_frontbuffer_soft_limit), | 56 max_surfaces_with_frontbuffer_soft_limit), |
48 client_hard_limit_bytes_(0), | 57 priority_cutoff_(MemoryAllocation::CUTOFF_ALLOW_EVERYTHING), |
| 58 bytes_available_gpu_memory_(0), |
| 59 bytes_available_gpu_memory_overridden_(false), |
| 60 bytes_minimum_per_client_(0), |
| 61 bytes_default_per_client_(0), |
49 bytes_allocated_managed_current_(0), | 62 bytes_allocated_managed_current_(0), |
50 bytes_allocated_unmanaged_current_(0), | 63 bytes_allocated_unmanaged_current_(0), |
51 bytes_allocated_historical_max_(0) | 64 bytes_allocated_historical_max_(0), |
52 { } | 65 bytes_allocated_unmanaged_high_(0), |
| 66 bytes_allocated_unmanaged_low_(0), |
| 67 bytes_unmanaged_limit_step_(kBytesAllocatedUnmanagedStep), |
| 68 disable_schedule_manage_(false) |
| 69 { |
| 70 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 71 |
| 72 // Use a more conservative memory allocation policy on Linux and Mac because |
| 73 // the platform is unstable when under memory pressure. |
| 74 // http://crbug.com/145600 (Linux) |
| 75 // http://crbug.com/141377 (Mac) |
| 76 #if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) |
| 77 priority_cutoff_ = MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; |
| 78 #endif |
| 79 |
| 80 #if defined(OS_ANDROID) |
| 81 bytes_default_per_client_ = 8 * 1024 * 1024; |
| 82 bytes_minimum_per_client_ = 8 * 1024 * 1024; |
| 83 #elif defined(OS_CHROMEOS) |
| 84 bytes_default_per_client_ = 64 * 1024 * 1024; |
| 85 bytes_minimum_per_client_ = 4 * 1024 * 1024; |
| 86 #elif defined(OS_MACOSX) |
| 87 bytes_default_per_client_ = 128 * 1024 * 1024; |
| 88 bytes_minimum_per_client_ = 128 * 1024 * 1024; |
| 89 #else |
| 90 bytes_default_per_client_ = 64 * 1024 * 1024; |
| 91 bytes_minimum_per_client_ = 64 * 1024 * 1024; |
| 92 #endif |
| 93 |
| 94 if (command_line->HasSwitch(switches::kForceGpuMemAvailableMb)) { |
| 95 base::StringToUint64( |
| 96 command_line->GetSwitchValueASCII(switches::kForceGpuMemAvailableMb), |
| 97 &bytes_available_gpu_memory_); |
| 98 bytes_available_gpu_memory_ *= 1024 * 1024; |
| 99 bytes_available_gpu_memory_overridden_ = true; |
| 100 } else |
| 101 bytes_available_gpu_memory_ = GetDefaultAvailableGpuMemory(); |
| 102 } |
53 | 103 |
54 GpuMemoryManager::~GpuMemoryManager() { | 104 GpuMemoryManager::~GpuMemoryManager() { |
55 DCHECK(tracking_groups_.empty()); | 105 DCHECK(tracking_groups_.empty()); |
56 DCHECK(clients_visible_mru_.empty()); | 106 DCHECK(clients_visible_mru_.empty()); |
57 DCHECK(clients_nonvisible_mru_.empty()); | 107 DCHECK(clients_nonvisible_mru_.empty()); |
58 DCHECK(clients_nonsurface_.empty()); | 108 DCHECK(clients_nonsurface_.empty()); |
59 DCHECK(!bytes_allocated_managed_current_); | 109 DCHECK(!bytes_allocated_managed_current_); |
60 DCHECK(!bytes_allocated_unmanaged_current_); | 110 DCHECK(!bytes_allocated_unmanaged_current_); |
61 } | 111 } |
62 | 112 |
| 113 uint64 GpuMemoryManager::GetAvailableGpuMemory() const { |
| 114 // Allow unmanaged allocations to over-subscribe by at most (high_ - low_) |
| 115 // before restricting managed (compositor) memory based on unmanaged usage. |
| 116 if (bytes_allocated_unmanaged_low_ > bytes_available_gpu_memory_) |
| 117 return 0; |
| 118 return bytes_available_gpu_memory_ - bytes_allocated_unmanaged_low_; |
| 119 } |
| 120 |
| 121 uint64 GpuMemoryManager::GetDefaultAvailableGpuMemory() const { |
| 122 #if defined(OS_ANDROID) |
| 123 return 16 * 1024 * 1024; |
| 124 #elif defined(OS_CHROMEOS) |
| 125 return 1024 * 1024 * 1024; |
| 126 #else |
| 127 return 256 * 1024 * 1024; |
| 128 #endif |
| 129 } |
| 130 |
| 131 uint64 GpuMemoryManager::GetMaximumTotalGpuMemory() const { |
| 132 #if defined(OS_ANDROID) |
| 133 return 256 * 1024 * 1024; |
| 134 #else |
| 135 return 1024 * 1024 * 1024; |
| 136 #endif |
| 137 } |
| 138 |
| 139 uint64 GpuMemoryManager::GetMaximumClientAllocation() const { |
| 140 #if defined(OS_ANDROID) || defined(OS_CHROMEOS) |
| 141 return bytes_available_gpu_memory_; |
| 142 #else |
| 143 // This is to avoid allowing a single page on to use a full 256MB of memory |
| 144 // (the current total limit). Long-scroll pages will hit this limit, |
| 145 // resulting in instability on some platforms (e.g, issue 141377). |
| 146 return bytes_available_gpu_memory_ / 2; |
| 147 #endif |
| 148 } |
| 149 |
| 150 uint64 GpuMemoryManager::CalcAvailableFromGpuTotal(uint64 total_gpu_memory) { |
| 151 #if defined(OS_ANDROID) |
| 152 // We don't need to reduce the total on Android, since |
| 153 // the total is an estimate to begin with. |
| 154 return total_gpu_memory; |
| 155 #else |
| 156 // Allow Chrome to use 75% of total GPU memory, or all-but-64MB of GPU |
| 157 // memory, whichever is less. |
| 158 return std::min(3 * total_gpu_memory / 4, total_gpu_memory - 64*1024*1024); |
| 159 #endif |
| 160 } |
| 161 |
63 void GpuMemoryManager::UpdateAvailableGpuMemory() { | 162 void GpuMemoryManager::UpdateAvailableGpuMemory() { |
64 // If the value was overridden on the command line, use the specified value. | 163 // If the amount of video memory to use was specified at the command |
65 static bool client_hard_limit_bytes_overridden = | 164 // line, never change it. |
66 CommandLine::ForCurrentProcess()->HasSwitch( | 165 if (bytes_available_gpu_memory_overridden_) |
67 switches::kForceGpuMemAvailableMb); | |
68 if (client_hard_limit_bytes_overridden) { | |
69 base::StringToUint64( | |
70 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
71 switches::kForceGpuMemAvailableMb), | |
72 &client_hard_limit_bytes_); | |
73 client_hard_limit_bytes_ *= 1024 * 1024; | |
74 return; | 166 return; |
75 } | |
76 | 167 |
77 // On non-Android, we use an operating system query when possible. | 168 // On non-Android, we use an operating system query when possible. |
78 // We do not have a reliable concept of multiple GPUs existing in | 169 // We do not have a reliable concept of multiple GPUs existing in |
79 // a system, so just be safe and go with the minimum encountered. | 170 // a system, so just be safe and go with the minimum encountered. |
80 uint64 bytes_min = 0; | 171 uint64 bytes_min = 0; |
81 | 172 |
82 // Only use the clients that are visible, because otherwise the set of clients | 173 // Only use the clients that are visible, because otherwise the set of clients |
83 // we are querying could become extremely large. | 174 // we are querying could become extremely large. |
84 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); | 175 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
85 it != clients_visible_mru_.end(); | 176 it != clients_visible_mru_.end(); |
86 ++it) { | 177 ++it) { |
87 const GpuMemoryManagerClientState* client_state = *it; | 178 const GpuMemoryManagerClientState* client_state = *it; |
88 if (!client_state->has_surface_) | 179 if (!client_state->has_surface_) |
89 continue; | 180 continue; |
90 if (!client_state->visible_) | 181 if (!client_state->visible_) |
91 continue; | 182 continue; |
92 | 183 |
93 uint64 bytes = 0; | 184 uint64 bytes = 0; |
94 if (client_state->client_->GetTotalGpuMemory(&bytes)) { | 185 if (client_state->client_->GetTotalGpuMemory(&bytes)) { |
95 if (!bytes_min || bytes < bytes_min) | 186 if (!bytes_min || bytes < bytes_min) |
96 bytes_min = bytes; | 187 bytes_min = bytes; |
97 } | 188 } |
98 } | 189 } |
99 | 190 |
100 if (!bytes_min) | 191 if (!bytes_min) |
101 return; | 192 return; |
102 | 193 |
103 client_hard_limit_bytes_ = bytes_min; | 194 bytes_available_gpu_memory_ = CalcAvailableFromGpuTotal(bytes_min); |
104 | 195 |
105 #if defined(OS_ANDROID) | 196 // Never go below the default allocation |
106 // Clamp the observed value to a specific range on Android. | 197 bytes_available_gpu_memory_ = std::max(bytes_available_gpu_memory_, |
107 client_hard_limit_bytes_ = std::max(client_hard_limit_bytes_, | 198 GetDefaultAvailableGpuMemory()); |
108 static_cast<uint64>(16 * 1024 * 1024)); | 199 |
109 client_hard_limit_bytes_ = std::min(client_hard_limit_bytes_, | 200 // Never go above the maximum. |
110 static_cast<uint64>(256 * 1024 * 1024)); | 201 bytes_available_gpu_memory_ = std::min(bytes_available_gpu_memory_, |
111 #else | 202 GetMaximumTotalGpuMemory()); |
112 // Ignore what the system said and give all clients the same maximum | 203 } |
113 // allocation on desktop platforms. | 204 |
114 client_hard_limit_bytes_ = 256 * 1024 * 1024; | 205 void GpuMemoryManager::UpdateUnmanagedMemoryLimits() { |
115 #endif | 206 // Set the limit to be [current_, current_ + step_ / 4), with the endpoints |
| 207 // of the intervals rounded down and up to the nearest step_, to avoid |
| 208 // thrashing the interval. |
| 209 bytes_allocated_unmanaged_high_ = RoundUp( |
| 210 bytes_allocated_unmanaged_current_ + bytes_unmanaged_limit_step_ / 4, |
| 211 bytes_unmanaged_limit_step_); |
| 212 bytes_allocated_unmanaged_low_ = RoundDown( |
| 213 bytes_allocated_unmanaged_current_, |
| 214 bytes_unmanaged_limit_step_); |
116 } | 215 } |
117 | 216 |
118 void GpuMemoryManager::ScheduleManage( | 217 void GpuMemoryManager::ScheduleManage( |
119 ScheduleManageTime schedule_manage_time) { | 218 ScheduleManageTime schedule_manage_time) { |
120 if (disable_schedule_manage_) | 219 if (disable_schedule_manage_) |
121 return; | 220 return; |
122 if (manage_immediate_scheduled_) | 221 if (manage_immediate_scheduled_) |
123 return; | 222 return; |
124 if (schedule_manage_time == kScheduleManageNow) { | 223 if (schedule_manage_time == kScheduleManageNow) { |
125 base::MessageLoop::current()->PostTask( | 224 base::MessageLoop::current()->PostTask( |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 default: | 256 default: |
158 NOTREACHED(); | 257 NOTREACHED(); |
159 break; | 258 break; |
160 } | 259 } |
161 if (new_size != old_size) { | 260 if (new_size != old_size) { |
162 TRACE_COUNTER1("gpu", | 261 TRACE_COUNTER1("gpu", |
163 "GpuMemoryUsage", | 262 "GpuMemoryUsage", |
164 GetCurrentUsage()); | 263 GetCurrentUsage()); |
165 } | 264 } |
166 | 265 |
167 if (GetCurrentUsage() > bytes_allocated_historical_max_ + | 266 // If we've gone past our current limit on unmanaged memory, schedule a |
168 kBytesAllocatedUnmanagedStep) { | 267 // re-manage to take int account the unmanaged memory. |
| 268 if (bytes_allocated_unmanaged_current_ >= bytes_allocated_unmanaged_high_) |
| 269 ScheduleManage(kScheduleManageNow); |
| 270 if (bytes_allocated_unmanaged_current_ < bytes_allocated_unmanaged_low_) |
| 271 ScheduleManage(kScheduleManageLater); |
| 272 |
| 273 if (GetCurrentUsage() > bytes_allocated_historical_max_) { |
169 bytes_allocated_historical_max_ = GetCurrentUsage(); | 274 bytes_allocated_historical_max_ = GetCurrentUsage(); |
170 // If we're blowing into new memory usage territory, spam the browser | 275 // If we're blowing into new memory usage territory, spam the browser |
171 // process with the most up-to-date information about our memory usage. | 276 // process with the most up-to-date information about our memory usage. |
172 SendUmaStatsToBrowser(); | 277 SendUmaStatsToBrowser(); |
173 } | 278 } |
174 } | 279 } |
175 | 280 |
176 bool GpuMemoryManager::EnsureGPUMemoryAvailable(uint64 /* size_needed */) { | 281 bool GpuMemoryManager::EnsureGPUMemoryAvailable(uint64 /* size_needed */) { |
177 // TODO: Check if there is enough space. Lose contexts until there is. | 282 // TODO: Check if there is enough space. Lose contexts until there is. |
178 return true; | 283 return true; |
(...skipping 28 matching lines...) Expand all Loading... |
207 return; | 312 return; |
208 | 313 |
209 RemoveClientFromList(client_state); | 314 RemoveClientFromList(client_state); |
210 client_state->visible_ = visible; | 315 client_state->visible_ = visible; |
211 AddClientToList(client_state); | 316 AddClientToList(client_state); |
212 ScheduleManage(visible ? kScheduleManageNow : kScheduleManageLater); | 317 ScheduleManage(visible ? kScheduleManageNow : kScheduleManageLater); |
213 } | 318 } |
214 | 319 |
215 void GpuMemoryManager::SetClientStateManagedMemoryStats( | 320 void GpuMemoryManager::SetClientStateManagedMemoryStats( |
216 GpuMemoryManagerClientState* client_state, | 321 GpuMemoryManagerClientState* client_state, |
217 const ManagedMemoryStats& stats) { | 322 const ManagedMemoryStats& stats) |
218 // TODO(ccameron): delete this from the full stack. | 323 { |
| 324 client_state->managed_memory_stats_ = stats; |
| 325 |
| 326 // If this is the first time that stats have been received for this |
| 327 // client, use them immediately. |
| 328 if (!client_state->managed_memory_stats_received_) { |
| 329 client_state->managed_memory_stats_received_ = true; |
| 330 ScheduleManage(kScheduleManageNow); |
| 331 return; |
| 332 } |
| 333 |
| 334 // If these statistics sit outside of the range that we used in our |
| 335 // computation of memory allocations then recompute the allocations. |
| 336 if (client_state->managed_memory_stats_.bytes_nice_to_have > |
| 337 client_state->bytes_nicetohave_limit_high_) { |
| 338 ScheduleManage(kScheduleManageNow); |
| 339 } else if (client_state->managed_memory_stats_.bytes_nice_to_have < |
| 340 client_state->bytes_nicetohave_limit_low_) { |
| 341 ScheduleManage(kScheduleManageLater); |
| 342 } |
219 } | 343 } |
220 | 344 |
221 uint64 GpuMemoryManager::GetClientMemoryUsage( | 345 uint64 GpuMemoryManager::GetClientMemoryUsage( |
222 const GpuMemoryManagerClient* client) const { | 346 const GpuMemoryManagerClient* client) const { |
223 TrackingGroupMap::const_iterator tracking_group_it = | 347 TrackingGroupMap::const_iterator tracking_group_it = |
224 tracking_groups_.find(client->GetMemoryTracker()); | 348 tracking_groups_.find(client->GetMemoryTracker()); |
225 DCHECK(tracking_group_it != tracking_groups_.end()); | 349 DCHECK(tracking_group_it != tracking_groups_.end()); |
226 return tracking_group_it->second->GetSize(); | 350 return tracking_group_it->second->GetSize(); |
227 } | 351 } |
228 | 352 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 bytes_allocated_historical_max_; | 388 bytes_allocated_historical_max_; |
265 } | 389 } |
266 | 390 |
267 void GpuMemoryManager::Manage() { | 391 void GpuMemoryManager::Manage() { |
268 manage_immediate_scheduled_ = false; | 392 manage_immediate_scheduled_ = false; |
269 delayed_manage_callback_.Cancel(); | 393 delayed_manage_callback_.Cancel(); |
270 | 394 |
271 // Update the amount of GPU memory available on the system. | 395 // Update the amount of GPU memory available on the system. |
272 UpdateAvailableGpuMemory(); | 396 UpdateAvailableGpuMemory(); |
273 | 397 |
| 398 // Update the limit on unmanaged memory. |
| 399 UpdateUnmanagedMemoryLimits(); |
| 400 |
274 // Determine which clients are "hibernated" (which determines the | 401 // Determine which clients are "hibernated" (which determines the |
275 // distribution of frontbuffers and memory among clients that don't have | 402 // distribution of frontbuffers and memory among clients that don't have |
276 // surfaces). | 403 // surfaces). |
277 SetClientsHibernatedState(); | 404 SetClientsHibernatedState(); |
278 | 405 |
279 // Assign memory allocations to clients that have surfaces. | 406 // Assign memory allocations to clients that have surfaces. |
280 AssignSurfacesAllocations(); | 407 AssignSurfacesAllocations(); |
281 | 408 |
282 // Assign memory allocations to clients that don't have surfaces. | 409 // Assign memory allocations to clients that don't have surfaces. |
283 AssignNonSurfacesAllocations(); | 410 AssignNonSurfacesAllocations(); |
284 | 411 |
285 SendUmaStatsToBrowser(); | 412 SendUmaStatsToBrowser(); |
286 } | 413 } |
287 | 414 |
| 415 // static |
| 416 uint64 GpuMemoryManager::ComputeCap( |
| 417 std::vector<uint64> bytes, uint64 bytes_sum_limit) |
| 418 { |
| 419 size_t bytes_size = bytes.size(); |
| 420 uint64 bytes_sum = 0; |
| 421 |
| 422 if (bytes_size == 0) |
| 423 return std::numeric_limits<uint64>::max(); |
| 424 |
| 425 // Sort and add up all entries |
| 426 std::sort(bytes.begin(), bytes.end()); |
| 427 for (size_t i = 0; i < bytes_size; ++i) |
| 428 bytes_sum += bytes[i]; |
| 429 |
| 430 // As we go through the below loop, let bytes_partial_sum be the |
| 431 // sum of bytes[0] + ... + bytes[bytes_size - i - 1] |
| 432 uint64 bytes_partial_sum = bytes_sum; |
| 433 |
| 434 // Try using each entry as a cap, and see where we get cut off. |
| 435 for (size_t i = 0; i < bytes_size; ++i) { |
| 436 // Try limiting cap to bytes[bytes_size - i - 1] |
| 437 uint64 test_cap = bytes[bytes_size - i - 1]; |
| 438 uint64 bytes_sum_with_test_cap = i * test_cap + bytes_partial_sum; |
| 439 |
| 440 // If that fits, raise test_cap to give an even distribution to the |
| 441 // last i entries. |
| 442 if (bytes_sum_with_test_cap <= bytes_sum_limit) { |
| 443 if (i == 0) |
| 444 return std::numeric_limits<uint64>::max(); |
| 445 else |
| 446 return test_cap + (bytes_sum_limit - bytes_sum_with_test_cap) / i; |
| 447 } else { |
| 448 bytes_partial_sum -= test_cap; |
| 449 } |
| 450 } |
| 451 |
| 452 // If we got here, then we can't fully accommodate any of the clients, |
| 453 // so distribute bytes_sum_limit evenly. |
| 454 return bytes_sum_limit / bytes_size; |
| 455 } |
| 456 |
| 457 uint64 GpuMemoryManager::ComputeClientAllocationWhenVisible( |
| 458 GpuMemoryManagerClientState* client_state, |
| 459 uint64 bytes_above_required_cap, |
| 460 uint64 bytes_above_minimum_cap, |
| 461 uint64 bytes_overall_cap) { |
| 462 ManagedMemoryStats* stats = &client_state->managed_memory_stats_; |
| 463 |
| 464 if (!client_state->managed_memory_stats_received_) |
| 465 return GetDefaultClientAllocation(); |
| 466 |
| 467 uint64 bytes_required = 9 * stats->bytes_required / 8; |
| 468 bytes_required = std::min(bytes_required, GetMaximumClientAllocation()); |
| 469 bytes_required = std::max(bytes_required, GetMinimumClientAllocation()); |
| 470 |
| 471 uint64 bytes_nicetohave = 4 * stats->bytes_nice_to_have / 3; |
| 472 bytes_nicetohave = std::min(bytes_nicetohave, GetMaximumClientAllocation()); |
| 473 bytes_nicetohave = std::max(bytes_nicetohave, GetMinimumClientAllocation()); |
| 474 bytes_nicetohave = std::max(bytes_nicetohave, bytes_required); |
| 475 |
| 476 uint64 allocation = GetMinimumClientAllocation(); |
| 477 allocation += std::min(bytes_required - GetMinimumClientAllocation(), |
| 478 bytes_above_minimum_cap); |
| 479 allocation += std::min(bytes_nicetohave - bytes_required, |
| 480 bytes_above_required_cap); |
| 481 allocation = std::min(allocation, |
| 482 bytes_overall_cap); |
| 483 return allocation; |
| 484 } |
| 485 |
| 486 void GpuMemoryManager::ComputeVisibleSurfacesAllocations() { |
| 487 uint64 bytes_available_total = GetAvailableGpuMemory(); |
| 488 uint64 bytes_above_required_cap = std::numeric_limits<uint64>::max(); |
| 489 uint64 bytes_above_minimum_cap = std::numeric_limits<uint64>::max(); |
| 490 uint64 bytes_overall_cap_visible = GetMaximumClientAllocation(); |
| 491 |
| 492 // Compute memory usage at three levels |
| 493 // - painting everything that is nicetohave for visible clients |
| 494 // - painting only what that is visible |
| 495 // - giving every client the minimum allocation |
| 496 uint64 bytes_nicetohave_visible = 0; |
| 497 uint64 bytes_required_visible = 0; |
| 498 uint64 bytes_minimum_visible = 0; |
| 499 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 500 it != clients_visible_mru_.end(); |
| 501 ++it) { |
| 502 GpuMemoryManagerClientState* client_state = *it; |
| 503 client_state->bytes_allocation_ideal_nicetohave_ = |
| 504 ComputeClientAllocationWhenVisible( |
| 505 client_state, |
| 506 bytes_above_required_cap, |
| 507 bytes_above_minimum_cap, |
| 508 bytes_overall_cap_visible); |
| 509 client_state->bytes_allocation_ideal_required_ = |
| 510 ComputeClientAllocationWhenVisible( |
| 511 client_state, |
| 512 0, |
| 513 bytes_above_minimum_cap, |
| 514 bytes_overall_cap_visible); |
| 515 client_state->bytes_allocation_ideal_minimum_ = |
| 516 ComputeClientAllocationWhenVisible( |
| 517 client_state, |
| 518 0, |
| 519 0, |
| 520 bytes_overall_cap_visible); |
| 521 |
| 522 bytes_nicetohave_visible += |
| 523 client_state->bytes_allocation_ideal_nicetohave_; |
| 524 bytes_required_visible += |
| 525 client_state->bytes_allocation_ideal_required_; |
| 526 bytes_minimum_visible += |
| 527 client_state->bytes_allocation_ideal_minimum_; |
| 528 } |
| 529 |
| 530 // Determine which of those three points we can satisfy, and limit |
| 531 // bytes_above_required_cap and bytes_above_minimum_cap to not go |
| 532 // over the limit. |
| 533 if (bytes_minimum_visible > bytes_available_total) { |
| 534 bytes_above_required_cap = 0; |
| 535 bytes_above_minimum_cap = 0; |
| 536 } else if (bytes_required_visible > bytes_available_total) { |
| 537 std::vector<uint64> bytes_to_fit; |
| 538 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 539 it != clients_visible_mru_.end(); |
| 540 ++it) { |
| 541 GpuMemoryManagerClientState* client_state = *it; |
| 542 bytes_to_fit.push_back(client_state->bytes_allocation_ideal_required_ - |
| 543 client_state->bytes_allocation_ideal_minimum_); |
| 544 } |
| 545 bytes_above_required_cap = 0; |
| 546 bytes_above_minimum_cap = ComputeCap( |
| 547 bytes_to_fit, bytes_available_total - bytes_minimum_visible); |
| 548 } else if (bytes_nicetohave_visible > bytes_available_total) { |
| 549 std::vector<uint64> bytes_to_fit; |
| 550 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 551 it != clients_visible_mru_.end(); |
| 552 ++it) { |
| 553 GpuMemoryManagerClientState* client_state = *it; |
| 554 bytes_to_fit.push_back(client_state->bytes_allocation_ideal_nicetohave_ - |
| 555 client_state->bytes_allocation_ideal_required_); |
| 556 } |
| 557 bytes_above_required_cap = ComputeCap( |
| 558 bytes_to_fit, bytes_available_total - bytes_required_visible); |
| 559 bytes_above_minimum_cap = std::numeric_limits<uint64>::max(); |
| 560 } |
| 561 |
| 562 // Given those computed limits, set the actual memory allocations for the |
| 563 // visible clients, tracking the largest allocation and the total allocation |
| 564 // for future use. |
| 565 uint64 bytes_allocated_visible = 0; |
| 566 uint64 bytes_allocated_max_client_allocation = 0; |
| 567 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 568 it != clients_visible_mru_.end(); |
| 569 ++it) { |
| 570 GpuMemoryManagerClientState* client_state = *it; |
| 571 client_state->bytes_allocation_when_visible_ = |
| 572 ComputeClientAllocationWhenVisible( |
| 573 client_state, |
| 574 bytes_above_required_cap, |
| 575 bytes_above_minimum_cap, |
| 576 bytes_overall_cap_visible); |
| 577 bytes_allocated_visible += client_state->bytes_allocation_when_visible_; |
| 578 bytes_allocated_max_client_allocation = std::max( |
| 579 bytes_allocated_max_client_allocation, |
| 580 client_state->bytes_allocation_when_visible_); |
| 581 } |
| 582 |
| 583 // Set the limit for nonvisible clients for when they become visible. |
| 584 // Use the same formula, with a lowered overall cap in case any of the |
| 585 // currently-nonvisible clients are much more resource-intensive than any |
| 586 // of the existing clients. |
| 587 uint64 bytes_overall_cap_nonvisible = bytes_allocated_max_client_allocation; |
| 588 if (bytes_available_total > bytes_allocated_visible) { |
| 589 bytes_overall_cap_nonvisible += |
| 590 bytes_available_total - bytes_allocated_visible; |
| 591 } |
| 592 bytes_overall_cap_nonvisible = std::min(bytes_overall_cap_nonvisible, |
| 593 GetMaximumClientAllocation()); |
| 594 for (ClientStateList::const_iterator it = clients_nonvisible_mru_.begin(); |
| 595 it != clients_nonvisible_mru_.end(); |
| 596 ++it) { |
| 597 GpuMemoryManagerClientState* client_state = *it; |
| 598 client_state->bytes_allocation_when_visible_ = |
| 599 ComputeClientAllocationWhenVisible( |
| 600 client_state, |
| 601 bytes_above_required_cap, |
| 602 bytes_above_minimum_cap, |
| 603 bytes_overall_cap_nonvisible); |
| 604 } |
| 605 } |
| 606 |
| 607 void GpuMemoryManager::DistributeRemainingMemoryToVisibleSurfaces() { |
| 608 uint64 bytes_available_total = GetAvailableGpuMemory(); |
| 609 uint64 bytes_allocated_total = 0; |
| 610 |
| 611 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 612 it != clients_visible_mru_.end(); |
| 613 ++it) { |
| 614 GpuMemoryManagerClientState* client_state = *it; |
| 615 bytes_allocated_total += client_state->bytes_allocation_when_visible_; |
| 616 } |
| 617 |
| 618 if (bytes_allocated_total >= bytes_available_total) |
| 619 return; |
| 620 |
| 621 std::vector<uint64> bytes_extra_requests; |
| 622 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 623 it != clients_visible_mru_.end(); |
| 624 ++it) { |
| 625 GpuMemoryManagerClientState* client_state = *it; |
| 626 CHECK(GetMaximumClientAllocation() >= |
| 627 client_state->bytes_allocation_when_visible_); |
| 628 uint64 bytes_extra = GetMaximumClientAllocation() - |
| 629 client_state->bytes_allocation_when_visible_; |
| 630 bytes_extra_requests.push_back(bytes_extra); |
| 631 } |
| 632 uint64 bytes_extra_cap = ComputeCap( |
| 633 bytes_extra_requests, bytes_available_total - bytes_allocated_total); |
| 634 for (ClientStateList::const_iterator it = clients_visible_mru_.begin(); |
| 635 it != clients_visible_mru_.end(); |
| 636 ++it) { |
| 637 GpuMemoryManagerClientState* client_state = *it; |
| 638 uint64 bytes_extra = GetMaximumClientAllocation() - |
| 639 client_state->bytes_allocation_when_visible_; |
| 640 client_state->bytes_allocation_when_visible_ += std::min( |
| 641 bytes_extra, bytes_extra_cap); |
| 642 } |
| 643 } |
| 644 |
288 void GpuMemoryManager::AssignSurfacesAllocations() { | 645 void GpuMemoryManager::AssignSurfacesAllocations() { |
| 646 // Compute allocation when for all clients. |
| 647 ComputeVisibleSurfacesAllocations(); |
| 648 |
| 649 // Distribute the remaining memory to visible clients. |
| 650 DistributeRemainingMemoryToVisibleSurfaces(); |
| 651 |
289 // Send that allocation to the clients. | 652 // Send that allocation to the clients. |
290 ClientStateList clients = clients_visible_mru_; | 653 ClientStateList clients = clients_visible_mru_; |
291 clients.insert(clients.end(), | 654 clients.insert(clients.end(), |
292 clients_nonvisible_mru_.begin(), | 655 clients_nonvisible_mru_.begin(), |
293 clients_nonvisible_mru_.end()); | 656 clients_nonvisible_mru_.end()); |
294 for (ClientStateList::const_iterator it = clients.begin(); | 657 for (ClientStateList::const_iterator it = clients.begin(); |
295 it != clients.end(); | 658 it != clients.end(); |
296 ++it) { | 659 ++it) { |
297 GpuMemoryManagerClientState* client_state = *it; | 660 GpuMemoryManagerClientState* client_state = *it; |
298 | 661 |
| 662 // Re-assign memory limits to this client when its "nice to have" bucket |
| 663 // grows or shrinks by 1/4. |
| 664 client_state->bytes_nicetohave_limit_high_ = |
| 665 5 * client_state->managed_memory_stats_.bytes_nice_to_have / 4; |
| 666 client_state->bytes_nicetohave_limit_low_ = |
| 667 3 * client_state->managed_memory_stats_.bytes_nice_to_have / 4; |
| 668 |
299 // Populate and send the allocation to the client | 669 // Populate and send the allocation to the client |
300 MemoryAllocation allocation; | 670 MemoryAllocation allocation; |
301 allocation.bytes_limit_when_visible = client_hard_limit_bytes_; | 671 |
302 #if defined(OS_ANDROID) | 672 allocation.bytes_limit_when_visible = |
303 // On Android, because there is only one visible tab at any time, allow | 673 client_state->bytes_allocation_when_visible_; |
304 // that renderer to cache as much as it can. | 674 allocation.priority_cutoff_when_visible = priority_cutoff_; |
305 allocation.priority_cutoff_when_visible = | |
306 MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; | |
307 #else | |
308 // On desktop platforms, instruct the renderers to cache only a smaller | |
309 // set, to play nice with other renderers and other applications. If this | |
310 // if not done, then the system can become unstable. | |
311 // http://crbug.com/145600 (Linux) | |
312 // http://crbug.com/141377 (Mac) | |
313 allocation.priority_cutoff_when_visible = | |
314 MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; | |
315 #endif | |
316 | 675 |
317 client_state->client_->SetMemoryAllocation(allocation); | 676 client_state->client_->SetMemoryAllocation(allocation); |
318 client_state->client_->SuggestHaveFrontBuffer(!client_state->hibernated_); | 677 client_state->client_->SuggestHaveFrontBuffer(!client_state->hibernated_); |
319 } | 678 } |
320 } | 679 } |
321 | 680 |
322 void GpuMemoryManager::AssignNonSurfacesAllocations() { | 681 void GpuMemoryManager::AssignNonSurfacesAllocations() { |
323 for (ClientStateList::const_iterator it = clients_nonsurface_.begin(); | 682 for (ClientStateList::const_iterator it = clients_nonsurface_.begin(); |
324 it != clients_nonsurface_.end(); | 683 it != clients_nonsurface_.end(); |
325 ++it) { | 684 ++it) { |
326 GpuMemoryManagerClientState* client_state = *it; | 685 GpuMemoryManagerClientState* client_state = *it; |
327 MemoryAllocation allocation; | 686 MemoryAllocation allocation; |
328 | 687 |
329 if (!client_state->hibernated_) { | 688 if (!client_state->hibernated_) { |
330 allocation.bytes_limit_when_visible = 1; | 689 allocation.bytes_limit_when_visible = |
| 690 GetMinimumClientAllocation(); |
331 allocation.priority_cutoff_when_visible = | 691 allocation.priority_cutoff_when_visible = |
332 MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; | 692 MemoryAllocation::CUTOFF_ALLOW_EVERYTHING; |
333 } | 693 } |
334 | 694 |
335 client_state->client_->SetMemoryAllocation(allocation); | 695 client_state->client_->SetMemoryAllocation(allocation); |
336 } | 696 } |
337 } | 697 } |
338 | 698 |
339 void GpuMemoryManager::SetClientsHibernatedState() const { | 699 void GpuMemoryManager::SetClientsHibernatedState() const { |
340 // Re-set all tracking groups as being hibernated. | 700 // Re-set all tracking groups as being hibernated. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 client_state->hibernated_ = client_state->tracking_group_->hibernated_; | 737 client_state->hibernated_ = client_state->tracking_group_->hibernated_; |
378 } | 738 } |
379 } | 739 } |
380 | 740 |
381 void GpuMemoryManager::SendUmaStatsToBrowser() { | 741 void GpuMemoryManager::SendUmaStatsToBrowser() { |
382 if (!channel_manager_) | 742 if (!channel_manager_) |
383 return; | 743 return; |
384 GPUMemoryUmaStats params; | 744 GPUMemoryUmaStats params; |
385 params.bytes_allocated_current = GetCurrentUsage(); | 745 params.bytes_allocated_current = GetCurrentUsage(); |
386 params.bytes_allocated_max = bytes_allocated_historical_max_; | 746 params.bytes_allocated_max = bytes_allocated_historical_max_; |
387 params.bytes_limit = client_hard_limit_bytes_; | 747 params.bytes_limit = bytes_available_gpu_memory_; |
388 params.client_count = clients_visible_mru_.size() + | 748 params.client_count = clients_visible_mru_.size() + |
389 clients_nonvisible_mru_.size() + | 749 clients_nonvisible_mru_.size() + |
390 clients_nonsurface_.size(); | 750 clients_nonsurface_.size(); |
391 params.context_group_count = tracking_groups_.size(); | 751 params.context_group_count = tracking_groups_.size(); |
392 channel_manager_->Send(new GpuHostMsg_GpuMemoryUmaStats(params)); | 752 channel_manager_->Send(new GpuHostMsg_GpuMemoryUmaStats(params)); |
393 } | 753 } |
394 | 754 |
395 GpuMemoryManager::ClientStateList* GpuMemoryManager::GetClientList( | 755 GpuMemoryManager::ClientStateList* GpuMemoryManager::GetClientList( |
396 GpuMemoryManagerClientState* client_state) { | 756 GpuMemoryManagerClientState* client_state) { |
397 if (client_state->has_surface_) { | 757 if (client_state->has_surface_) { |
(...skipping 16 matching lines...) Expand all Loading... |
414 | 774 |
415 void GpuMemoryManager::RemoveClientFromList( | 775 void GpuMemoryManager::RemoveClientFromList( |
416 GpuMemoryManagerClientState* client_state) { | 776 GpuMemoryManagerClientState* client_state) { |
417 DCHECK(client_state->list_iterator_valid_); | 777 DCHECK(client_state->list_iterator_valid_); |
418 ClientStateList* client_list = GetClientList(client_state); | 778 ClientStateList* client_list = GetClientList(client_state); |
419 client_list->erase(client_state->list_iterator_); | 779 client_list->erase(client_state->list_iterator_); |
420 client_state->list_iterator_valid_ = false; | 780 client_state->list_iterator_valid_ = false; |
421 } | 781 } |
422 | 782 |
423 } // namespace content | 783 } // namespace content |
OLD | NEW |