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

Side by Side Diff: chrome/browser/renderer_host/backing_store_manager.cc

Issue 165538: cap the number of tabs in the backing store cache (Closed)
Patch Set: fix git weird upload Created 11 years, 4 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
« no previous file with comments | « chrome/browser/memory_details.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/backing_store_manager.h" 5 #include "chrome/browser/renderer_host/backing_store_manager.h"
6 6
7 #include "base/sys_info.h" 7 #include "base/sys_info.h"
8 #include "chrome/browser/renderer_host/backing_store.h" 8 #include "chrome/browser/renderer_host/backing_store.h"
9 #include "chrome/browser/renderer_host/render_widget_host.h" 9 #include "chrome/browser/renderer_host/render_widget_host.h"
10 #include "chrome/browser/renderer_host/render_widget_host_painting_observer.h" 10 #include "chrome/browser/renderer_host/render_widget_host_painting_observer.h"
11 #include "chrome/common/chrome_constants.h" 11 #include "chrome/common/chrome_constants.h"
12 12
13 13
14 namespace { 14 namespace {
15 15
16 // There are two separate caches, |large_cache| and |small_cache|. large_cache 16 // There are two separate caches, |large_cache| and |small_cache|. large_cache
17 // is meant for large items (tabs, popup windows), while small_cache is meant 17 // is meant for large items (tabs, popup windows), while small_cache is meant
18 // for small items (extension toolstrips and buttons, etc.). The idea is that 18 // for small items (extension toolstrips and buttons, etc.). The idea is that
19 // we'll almost always try to evict from large_cache first since small_cache 19 // we'll almost always try to evict from large_cache first since small_cache
20 // items will tend to be visible more of the time. 20 // items will tend to be visible more of the time.
21 typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache; 21 typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache;
22 static BackingStoreCache* large_cache = NULL; 22 static BackingStoreCache* large_cache = NULL;
23 static BackingStoreCache* small_cache = NULL; 23 static BackingStoreCache* small_cache = NULL;
24 24
25 // Threshold is based on a large-monitor width toolstrip. 25 // Threshold is based on a single large-monitor-width toolstrip.
26 // (32bpp, 32 pixels high, 1920 pixels wide)
26 // TODO(erikkay) 32bpp assumption isn't great. 27 // TODO(erikkay) 32bpp assumption isn't great.
27 const size_t kSmallThreshold = 4 * 32 * 1920; 28 const size_t kSmallThreshold = 4 * 32 * 1920;
28 29
29 // Previously, the backing store cache was based on a set number of backing 30 // Pick a large monitor size to use as a multiplier. This is multiplied by the
30 // stores, regardless of their size. The numbers were chosen based on a user 31 // max number of large backing stores (usually tabs) to pick a ceiling on the
31 // with a maximized browser on a large monitor. Now that the cache is based on 32 // max memory to use.
32 // total memory size of the backing stores, we'll keep an approximation of the
33 // numbers from the previous algorithm by choosing a large monitor backing store
34 // size as our multiplier.
35 // TODO(erikkay) Perhaps we should actually use monitor size? That way we 33 // TODO(erikkay) Perhaps we should actually use monitor size? That way we
36 // could make an assertion like "worse case, there are two tabs in the cache". 34 // could make an assertion like "worse case, there are two tabs in the cache".
37 // However, the small_cache might mess up these calculations a bit. 35 // However, the small_cache might mess up these calculations a bit.
38 // TODO(erikkay) 32bpp assumption isn't great. 36 // TODO(erikkay) 32bpp assumption isn't great.
39 const size_t kMemoryMultiplier = 4 * 1920 * 1200; // ~9MB 37 const size_t kMemoryMultiplier = 4 * 1920 * 1200; // ~9MB
40 38
41 static size_t GetBackingStoreCacheMemorySize() { 39 // The maximum number of large BackingStoreCache objects (tabs) to use.
40 // Use a minimum of 2, and add one for each 256MB of physical memory you have.
41 // Cap at 5, the thinking being that even if you have a gigantic amount of
42 // RAM, there's a limit to how much caching helps beyond a certain number
43 // of tabs.
44 static size_t MaxNumberOfBackingStores() {
45 return std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
46 }
47
48 // The maximum about of memory to use for all BackingStoreCache object combined.
49 // We use this
50 static size_t MaxBackingStoreMemory() {
42 // Compute in terms of the number of large monitor's worth of backing-store. 51 // Compute in terms of the number of large monitor's worth of backing-store.
43 // Use a minimum of 2, and add one for each 256MB of physical memory you have. 52 return MaxNumberOfBackingStores() * kMemoryMultiplier;
44 // Cap at 5, the thinking being that even if you have a gigantic amount of
45 // RAM, there's a limit to how much caching helps beyond a certain number
46 // of tabs.
47 size_t mem_tier = std::min(5,
48 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
49 return mem_tier * kMemoryMultiplier;
50 } 53 }
51 54
52 // Expires the given |backing_store| from |cache|. 55 // Expires the given |backing_store| from |cache|.
53 void ExpireBackingStoreAt(BackingStoreCache* cache, 56 void ExpireBackingStoreAt(BackingStoreCache* cache,
54 BackingStoreCache::iterator backing_store) { 57 BackingStoreCache::iterator backing_store) {
55 RenderWidgetHost* rwh = backing_store->second->render_widget_host(); 58 RenderWidgetHost* rwh = backing_store->second->render_widget_host();
56 if (rwh->painting_observer()) { 59 if (rwh->painting_observer()) {
57 rwh->painting_observer()->WidgetWillDestroyBackingStore( 60 rwh->painting_observer()->WidgetWillDestroyBackingStore(
58 backing_store->first, 61 backing_store->first,
59 backing_store->second); 62 backing_store->second);
60 } 63 }
61 cache->Erase(backing_store); 64 cache->Erase(backing_store);
62 } 65 }
63 66
67 size_t ExpireLastBackingStore(BackingStoreCache* cache) {
68 if (cache->size() < 1)
69 return 0;
70
71 // Crazy C++ alert: rbegin.base() is a forward iterator pointing to end(),
72 // so we need to do -- to move one back to the actual last item.
73 BackingStoreCache::iterator entry = --cache->rbegin().base();
74 size_t entry_size = entry->second->MemorySize();
75 ExpireBackingStoreAt(cache, entry);
76 return entry_size;
77 }
78
64 void CreateCacheSpace(size_t size) { 79 void CreateCacheSpace(size_t size) {
65 // Given a request for |size|, first free from the large cache (until there's 80 // Given a request for |size|, first free from the large cache (until there's
66 // only one item left) and then do the same from the small cache if we still 81 // only one item left) and then do the same from the small cache if we still
67 // don't have enough. 82 // don't have enough.
68 while (size > 0 && (large_cache->size() > 1 || small_cache->size() > 1)) { 83 while (size > 0 && (large_cache->size() > 1 || small_cache->size() > 1)) {
69 BackingStoreCache* cache = 84 BackingStoreCache* cache =
70 (large_cache->size() > 1) ? large_cache : small_cache; 85 (large_cache->size() > 1) ? large_cache : small_cache;
71 while (size > 0 && cache->size() > 1) { 86 while (size > 0 && cache->size() > 1) {
72 // Crazy C++ alert: rbegin.base() is a forward iterator pointing to end(), 87 size_t entry_size = ExpireLastBackingStore(cache);
73 // so we need to do -- to move one back to the actual last item.
74 BackingStoreCache::iterator entry = --cache->rbegin().base();
75 size_t entry_size = entry->second->MemorySize();
76 ExpireBackingStoreAt(cache, entry);
77 if (size > entry_size) 88 if (size > entry_size)
78 size -= entry_size; 89 size -= entry_size;
79 else 90 else
80 size = 0; 91 size = 0;
81 } 92 }
82 } 93 }
83 DCHECK(size == 0); 94 DCHECK(size == 0);
84 } 95 }
85 96
86 // Creates the backing store for the host based on the dimensions passed in. 97 // Creates the backing store for the host based on the dimensions passed in.
87 // Removes the existing backing store if there is one. 98 // Removes the existing backing store if there is one.
88 BackingStore* CreateBackingStore(RenderWidgetHost* host, 99 BackingStore* CreateBackingStore(RenderWidgetHost* host,
89 const gfx::Size& backing_store_size) { 100 const gfx::Size& backing_store_size) {
90 // Remove any existing backing store in case we're replacing it. 101 // Remove any existing backing store in case we're replacing it.
91 BackingStoreManager::RemoveBackingStore(host); 102 BackingStoreManager::RemoveBackingStore(host);
92 103
93 if (!large_cache) { 104 if (!large_cache) {
94 large_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT); 105 large_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
95 small_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT); 106 small_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
96 } 107 }
97 108
98 // TODO(erikkay) 32bpp is not always accurate 109 // TODO(erikkay) 32bpp is not always accurate
99 size_t new_mem = backing_store_size.GetArea() * 4; 110 size_t new_mem = backing_store_size.GetArea() * 4;
100 size_t current_mem = BackingStoreManager::MemorySize(); 111 size_t current_mem = BackingStoreManager::MemorySize();
101 size_t max_mem = GetBackingStoreCacheMemorySize(); 112 size_t max_mem = MaxBackingStoreMemory();
102 DCHECK(new_mem < max_mem); 113 DCHECK(new_mem < max_mem);
103 if (current_mem + new_mem > max_mem) { 114 if (current_mem + new_mem > max_mem) {
104 // Need to remove old backing stores to make room for the new one. We 115 // Need to remove old backing stores to make room for the new one. We
105 // don't want to do this when the backing store is being replace by a new 116 // don't want to do this when the backing store is being replace by a new
106 // one for the same tab, but this case won't get called then: we'll have 117 // one for the same tab, but this case won't get called then: we'll have
107 // removed the onld one in the RemoveBackingStore above, and the cache 118 // removed the old one in the RemoveBackingStore above, and the cache
108 // won't be over-sized. 119 // won't be over-sized.
109 CreateCacheSpace((current_mem + new_mem) - max_mem); 120 CreateCacheSpace((current_mem + new_mem) - max_mem);
110 } 121 }
111 DCHECK((BackingStoreManager::MemorySize() + new_mem) < max_mem); 122 DCHECK((BackingStoreManager::MemorySize() + new_mem) < max_mem);
112 123
124 BackingStoreCache* cache;
125 if (new_mem > kSmallThreshold) {
126 // Limit the number of large backing stores (tabs) to the memory tier number
127 // (between 2-5). While we allow a larger amount of memory for people who
128 // have large windows, this means that those who use small browser windows
129 // won't ever cache more than 5 tabs, so they pay a smaller memory cost.
130 if (large_cache->size() >= MaxNumberOfBackingStores())
131 ExpireLastBackingStore(large_cache);
132 cache = large_cache;
133 } else {
134 cache = small_cache;
135 }
113 BackingStore* backing_store = host->AllocBackingStore(backing_store_size); 136 BackingStore* backing_store = host->AllocBackingStore(backing_store_size);
114 if (new_mem > kSmallThreshold) 137 cache->Put(host, backing_store);
115 large_cache->Put(host, backing_store);
116 else
117 small_cache->Put(host, backing_store);
118 return backing_store; 138 return backing_store;
119 } 139 }
120 140
121 } // namespace 141 } // namespace
122 142
123 // BackingStoreManager --------------------------------------------------------- 143 // BackingStoreManager ---------------------------------------------------------
124 144
125 // static 145 // static
126 BackingStore* BackingStoreManager::GetBackingStore( 146 BackingStore* BackingStoreManager::GetBackingStore(
127 RenderWidgetHost* host, 147 RenderWidgetHost* host,
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 size_t mem = 0; 237 size_t mem = 0;
218 BackingStoreCache::iterator it; 238 BackingStoreCache::iterator it;
219 for (it = large_cache->begin(); it != large_cache->end(); ++it) 239 for (it = large_cache->begin(); it != large_cache->end(); ++it)
220 mem += it->second->MemorySize(); 240 mem += it->second->MemorySize();
221 241
222 for (it = small_cache->begin(); it != small_cache->end(); ++it) 242 for (it = small_cache->begin(); it != small_cache->end(); ++it)
223 mem += it->second->MemorySize(); 243 mem += it->second->MemorySize();
224 244
225 return mem; 245 return mem;
226 } 246 }
OLDNEW
« no previous file with comments | « chrome/browser/memory_details.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698