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

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

Issue 146095: change backing store cache to be memory-based rather than count (Closed)
Patch Set: added better MemorySize() and comments Created 11 years, 6 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
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 namespace { 14 namespace {
14 15
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
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
20 // items will tend to be visible more of the time.
15 typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache; 21 typedef OwningMRUCache<RenderWidgetHost*, BackingStore*> BackingStoreCache;
16 static BackingStoreCache* cache = NULL; 22 static BackingStoreCache* large_cache = NULL;
23 static BackingStoreCache* small_cache = NULL;
17 24
18 // Returns the size of the backing store cache. 25 // Threshold is based on a large-monitor width toolstrip.
19 static size_t GetBackingStoreCacheSize() { 26 // TODO(erikkay) 32bpp assumption isn't great.
20 // This uses a similar approach to GetMaxRendererProcessCount. The goal 27 const size_t kSmallThreshold = 4 * 32 * 1920;
21 // is to reduce memory pressure and swapping on low-resource machines.
22 static const size_t kMaxDibCountByRamTier[] = {
23 2, // less than 256MB
24 3, // 256MB
25 4, // 512MB
26 5 // 768MB and above
27 };
28 28
29 static size_t max_size = kMaxDibCountByRamTier[ 29 // Previously, the backing store cache was based on a set number of backing
30 std::min(base::SysInfo::AmountOfPhysicalMemoryMB() / 256, 30 // stores, regardless of their size. The numbers were chosen based on a user
31 static_cast<int>(arraysize(kMaxDibCountByRamTier)) - 1)]; 31 // with a maximized browser on a large monitor. Now that the cache is based on
32 return max_size; 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
36 // 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.
38 // TODO(erikkay) 32bpp assumption isn't great.
39 const size_t kMemoryMultiplier = 4 * 1920 * 1200; // ~9MB
40
41 static size_t GetBackingStoreCacheMemorySize() {
42 // 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.
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;
33 } 50 }
34 51
35 // Expires the given backing store from the cache. 52 // Expires the given |backing_store| from |cache|.
36 void ExpireBackingStoreAt(BackingStoreCache::iterator backing_store) { 53 void ExpireBackingStoreAt(BackingStoreCache* cache,
54 BackingStoreCache::iterator backing_store) {
37 RenderWidgetHost* rwh = backing_store->second->render_widget_host(); 55 RenderWidgetHost* rwh = backing_store->second->render_widget_host();
38 if (rwh->painting_observer()) { 56 if (rwh->painting_observer()) {
39 rwh->painting_observer()->WidgetWillDestroyBackingStore( 57 rwh->painting_observer()->WidgetWillDestroyBackingStore(
40 backing_store->first, 58 backing_store->first,
41 backing_store->second); 59 backing_store->second);
42 } 60 }
43 cache->Erase(backing_store); 61 cache->Erase(backing_store);
44 } 62 }
45 63
64 void CreateCacheSpace(size_t size) {
65 // 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
67 // don't have enough.
68 while (size > 0 && (large_cache->size() > 1 || small_cache->size() > 1)) {
69 BackingStoreCache* cache =
70 (large_cache->size() > 1) ? large_cache : small_cache;
71 while (size > 0 && cache->size() > 1) {
72 // Crazy C++ alert: rbegin.base() is a forward iterator pointing to end(),
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)
78 size -= entry_size;
79 else
80 size = 0;
81 }
82 }
83 DCHECK(size == 0);
84 }
85
46 // Creates the backing store for the host based on the dimensions passed in. 86 // Creates the backing store for the host based on the dimensions passed in.
47 // Removes the existing backing store if there is one. 87 // Removes the existing backing store if there is one.
48 BackingStore* CreateBackingStore(RenderWidgetHost* host, 88 BackingStore* CreateBackingStore(RenderWidgetHost* host,
49 const gfx::Size& backing_store_size) { 89 const gfx::Size& backing_store_size) {
50 // Remove any existing backing store in case we're replacing it. 90 // Remove any existing backing store in case we're replacing it.
51 BackingStoreManager::RemoveBackingStore(host); 91 BackingStoreManager::RemoveBackingStore(host);
52 92
53 size_t max_cache_size = GetBackingStoreCacheSize(); 93 if (!large_cache) {
54 if (max_cache_size > 0 && !cache) 94 large_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
55 cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT); 95 small_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
96 }
56 97
57 if (cache->size() >= max_cache_size) { 98 // TODO(erikkay) 32bpp is not always accurate
58 // Need to remove an old backing store to make room for the new one. We 99 size_t new_mem = backing_store_size.GetArea() * 4;
100 size_t current_mem = BackingStoreManager::MemorySize();
101 size_t max_mem = GetBackingStoreCacheMemorySize();
102 DCHECK(new_mem < max_mem);
103 if (current_mem + new_mem > max_mem) {
104 // Need to remove old backing stores to make room for the new one. We
59 // don't want to do this when the backing store is being replace by a new 105 // don't want to do this when the backing store is being replace by a new
60 // one for the same tab, but this case won't get called then: we'll have 106 // one for the same tab, but this case won't get called then: we'll have
61 // removed the onld one in the RemoveBackingStore above, and the cache 107 // removed the onld one in the RemoveBackingStore above, and the cache
62 // won't be over-sized. 108 // won't be over-sized.
63 // 109 CreateCacheSpace((current_mem + new_mem) - max_mem);
64 // Crazy C++ alert: rbegin.base() is a forward iterator pointing to end(),
65 // so we need to do -- to move one back to the actual last item.
66 ExpireBackingStoreAt(--cache->rbegin().base());
67 } 110 }
111 DCHECK((BackingStoreManager::MemorySize() + new_mem) < max_mem);
68 112
69 BackingStore* backing_store = host->AllocBackingStore(backing_store_size); 113 BackingStore* backing_store = host->AllocBackingStore(backing_store_size);
70 if (max_cache_size > 0) 114 if (new_mem > kSmallThreshold)
71 cache->Put(host, backing_store); 115 large_cache->Put(host, backing_store);
116 else
117 small_cache->Put(host, backing_store);
72 return backing_store; 118 return backing_store;
73 } 119 }
74 120
75 } // namespace 121 } // namespace
76 122
77 // BackingStoreManager --------------------------------------------------------- 123 // BackingStoreManager ---------------------------------------------------------
78 124
79 // static 125 // static
80 BackingStore* BackingStoreManager::GetBackingStore( 126 BackingStore* BackingStoreManager::GetBackingStore(
81 RenderWidgetHost* host, 127 RenderWidgetHost* host,
(...skipping 30 matching lines...) Expand all
112 backing_store = CreateBackingStore(host, backing_store_size); 158 backing_store = CreateBackingStore(host, backing_store_size);
113 } 159 }
114 160
115 DCHECK(backing_store != NULL); 161 DCHECK(backing_store != NULL);
116 backing_store->PaintRect(process_handle, bitmap, bitmap_rect); 162 backing_store->PaintRect(process_handle, bitmap, bitmap_rect);
117 return backing_store; 163 return backing_store;
118 } 164 }
119 165
120 // static 166 // static
121 BackingStore* BackingStoreManager::Lookup(RenderWidgetHost* host) { 167 BackingStore* BackingStoreManager::Lookup(RenderWidgetHost* host) {
122 if (cache) { 168 if (large_cache) {
123 BackingStoreCache::iterator it = cache->Peek(host); 169 BackingStoreCache::iterator it = large_cache->Get(host);
124 if (it != cache->end()) 170 if (it != large_cache->end())
171 return it->second;
172
173 // This moves host to the front of the MRU.
174 it = small_cache->Get(host);
175 if (it != small_cache->end())
125 return it->second; 176 return it->second;
126 } 177 }
127 return NULL; 178 return NULL;
128 } 179 }
129 180
130 // static 181 // static
131 void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) { 182 void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) {
132 if (!cache) 183 if (!large_cache)
133 return; 184 return;
134 185
186 BackingStoreCache* cache = large_cache;
135 BackingStoreCache::iterator it = cache->Peek(host); 187 BackingStoreCache::iterator it = cache->Peek(host);
136 if (it == cache->end()) 188 if (it == cache->end()) {
137 return; 189 cache = small_cache;
190 it = cache->Peek(host);
191 if (it == cache->end())
192 return;
193 }
138 cache->Erase(it); 194 cache->Erase(it);
139
140 if (cache->empty()) {
141 delete cache;
142 cache = NULL;
143 }
144 } 195 }
145 196
146 // static 197 // static
147 bool BackingStoreManager::ExpireBackingStoreForTest(RenderWidgetHost* host) { 198 bool BackingStoreManager::ExpireBackingStoreForTest(RenderWidgetHost* host) {
199 BackingStoreCache* cache = large_cache;
200
148 BackingStoreCache::iterator it = cache->Peek(host); 201 BackingStoreCache::iterator it = cache->Peek(host);
149 if (it == cache->end()) 202 if (it == cache->end()) {
150 return false; 203 cache = small_cache;
151 ExpireBackingStoreAt(it); 204 it = cache->Peek(host);
205 if (it == cache->end())
206 return false;
207 }
208 ExpireBackingStoreAt(cache, it);
152 return true; 209 return true;
153 } 210 }
211
212 // static
213 size_t BackingStoreManager::MemorySize() {
214 if (!large_cache)
215 return 0;
216
217 size_t mem = 0;
218 BackingStoreCache::iterator it;
219 for (it = large_cache->begin(); it != large_cache->end(); ++it)
220 mem += it->second->MemorySize();
221
222 for (it = small_cache->begin(); it != small_cache->end(); ++it)
223 mem += it->second->MemorySize();
224
225 return mem;
226 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698