1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/renderer_host/web_cache_manager.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/singleton.h" 11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/sys_info.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h" 153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h" 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/render_messages.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time; 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta; 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing WebKit::WebCache; 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const unsigned int kReviseAllocationDelayMS = 200 /* milliseconds */; 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The default size limit of the in-memory cache is 8 MB 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kDefaultMemoryCacheSize = 8 * 1024 * 1024; 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint GetDefaultCacheSize() { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Start off with a modest default 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int default_cache_size = kDefaultMemoryCacheSize; 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check how much physical memory the OS has 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int mem_size_mb = base::SysInfo::AmountOfPhysicalMemoryMB(); 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (mem_size_mb >= 1000) // If we have a GB of memory, set a larger default. 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_cache_size *= 4; 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else if (mem_size_mb >= 512) // With 512 MB, set a slightly larger default. 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_cache_size *= 2; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.MaxCacheSizeMB", 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default_cache_size / 1024 / 1024); 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return default_cache_size; 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // anonymous namespace 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::RegisterPrefs(PrefService* prefs) { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch prefs->RegisterIntegerPref(prefs::kMemoryCacheSize, GetDefaultCacheSize()); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebCacheManager* WebCacheManager::GetInstance() { 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return Singleton<WebCacheManager>::get(); 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebCacheManager::WebCacheManager() 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : global_size_limit_(GetDefaultGlobalSizeLimit()), 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ALLOW_THIS_IN_INITIALIZER_LIST(revise_allocation_factory_(this)) { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebCacheManager::~WebCacheManager() { 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::Add(int renderer_id) { 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(inactive_renderers_.count(renderer_id) == 0); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // It is tempting to make the following DCHECK here, but it fails when a new 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tab is created as we observe activity from that tab because the 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // RenderProcessHost is recreated and adds itself. 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // DCHECK(active_renderers_.count(renderer_id) == 0); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // However, there doesn't seem to be much harm in receiving the calls in this 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // order. 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_renderers_.insert(renderer_id); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RendererInfo* stats = &(stats_[renderer_id]); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(stats, 0, sizeof(*stats)); 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->access = Time::Now(); 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Revise our allocation strategy to account for this new renderer. 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReviseAllocationStrategyLater(); 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::Remove(int renderer_id) { 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Erase all knowledge of this renderer 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_renderers_.erase(renderer_id); 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive_renderers_.erase(renderer_id); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats_.erase(renderer_id); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Reallocate the resources used by this renderer 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReviseAllocationStrategyLater(); 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::ObserveActivity(int renderer_id) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StatsMap::iterator item = stats_.find(renderer_id); 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (item == stats_.end()) 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // We might see stats for a renderer that has been destroyed. 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Record activity. 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_renderers_.insert(renderer_id); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch item->second.access = Time::Now(); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<int>::iterator elmt = inactive_renderers_.find(renderer_id); 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (elmt != inactive_renderers_.end()) { 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive_renderers_.erase(elmt); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // A renderer that was inactive, just became active. We should make sure 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // it is given a fair cache allocation, but we defer this for a bit in 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // order to make this function call cheap. 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReviseAllocationStrategyLater(); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::ObserveStats(int renderer_id, 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebCache::UsageStats& stats) { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StatsMap::iterator entry = stats_.find(renderer_id); 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (entry == stats_.end()) 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; // We might see stats for a renderer that has been destroyed. 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Record the updated stats. 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->second.capacity = stats.capacity; 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->second.deadSize = stats.deadSize; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->second.liveSize = stats.liveSize; 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->second.maxDeadCapacity = stats.maxDeadCapacity; 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch entry->second.minDeadCapacity = stats.minDeadCapacity; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // trigger notification 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebCache::UsageStats stats_details(stats); 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // &stats_details is only valid during the notification. 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // See notification_types.h. 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationService::current()->Notify( 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::WEB_CACHE_STATS_OBSERVED, 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<RenderProcessHost>(RenderProcessHost::FromID(renderer_id)), 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Details<WebCache::UsageStats>(&stats_details)); 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::SetGlobalSizeLimit(size_t bytes) { 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch global_size_limit_ = bytes; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ReviseAllocationStrategyLater(); 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid WebCacheManager::ClearCache() { 151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Tell each renderer process to clear the cache. 152731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ClearRendederCache(active_renderers_); 153731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ClearRendederCache(inactive_renderers_); 154731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 155731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t WebCacheManager::GetDefaultGlobalSizeLimit() { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PrefService* perf_service = g_browser_process->local_state(); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (perf_service) 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return perf_service->GetInteger(prefs::kMemoryCacheSize); 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return GetDefaultCacheSize(); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::GatherStats(const std::set<int>& renderers, 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebCache::UsageStats* stats) { 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(stats); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(stats, 0, sizeof(WebCache::UsageStats)); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<int>::const_iterator iter = renderers.begin(); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (iter != renderers.end()) { 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StatsMap::iterator elmt = stats_.find(*iter); 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (elmt != stats_.end()) { 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->minDeadCapacity += elmt->second.minDeadCapacity; 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->maxDeadCapacity += elmt->second.maxDeadCapacity; 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->capacity += elmt->second.capacity; 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->liveSize += elmt->second.liveSize; 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch stats->deadSize += elmt->second.deadSize; 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++iter; 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochsize_t WebCacheManager::GetSize(AllocationTactic tactic, 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebCache::UsageStats& stats) { 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (tactic) { 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case DIVIDE_EVENLY: 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We aren't going to reserve any space for existing objects. 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case KEEP_CURRENT_WITH_HEADROOM: 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need enough space for our current objects, plus some headroom. 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 3 * GetSize(KEEP_CURRENT, stats) / 2; 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case KEEP_CURRENT: 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need enough space to keep our current objects. 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return stats.liveSize + stats.deadSize; 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case KEEP_LIVE_WITH_HEADROOM: 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need enough space to keep out live resources, plus some headroom. 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 3 * GetSize(KEEP_LIVE, stats) / 2; 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case KEEP_LIVE: 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We need enough space to keep our live resources. 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return stats.liveSize; 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unknown cache allocation tactic"; 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebCacheManager::AttemptTactic( 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationTactic active_tactic, 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebCache::UsageStats& active_stats, 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationTactic inactive_tactic, 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const WebCache::UsageStats& inactive_stats, 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationStrategy* strategy) { 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(strategy); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t active_size = GetSize(active_tactic, active_stats); 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t inactive_size = GetSize(inactive_tactic, inactive_stats); 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Give up if we don't have enough space to use this tactic. 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (global_size_limit_ < active_size + inactive_size) 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute the unreserved space available. 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t total_extra = global_size_limit_ - (active_size + inactive_size); 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The plan for the extra space is to divide it evenly amoung the active 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // renderers. 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t shares = active_renderers_.size(); 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The inactive renderers get one share of the extra memory to be divided 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // among themselves. 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t inactive_extra = 0; 235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!inactive_renderers_.empty()) { 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++shares; 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive_extra = total_extra / shares; 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The remaining memory is allocated to the active renderers. 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t active_extra = total_extra - inactive_extra; 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Actually compute the allocations for each renderer. 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddToStrategy(active_renderers_, active_tactic, active_extra, strategy); 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddToStrategy(inactive_renderers_, inactive_tactic, inactive_extra, strategy); 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We succeeded in computing an allocation strategy. 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 251513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid WebCacheManager::AddToStrategy(const std::set<int>& renderers, 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationTactic tactic, 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t extra_bytes_to_allocate, 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationStrategy* strategy) { 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(strategy); 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Nothing to do if there are no renderers. It is common for there to be no 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // inactive renderers if there is a single active tab. 259dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (renderers.empty()) 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Divide the extra memory evenly among the renderers. 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t extra_each = extra_bytes_to_allocate / renderers.size(); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<int>::const_iterator iter = renderers.begin(); 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (iter != renderers.end()) { 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t cache_size = extra_each; 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Add in the space required to implement |tactic|. 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StatsMap::iterator elmt = stats_.find(*iter); 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (elmt != stats_.end()) 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cache_size += GetSize(tactic, elmt->second); 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Record the allocation in our strategy. 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch strategy->push_back(Allocation(*iter, cache_size)); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++iter; 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::EnactStrategy(const AllocationStrategy& strategy) { 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Inform each render process of its cache allocation. 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationStrategy::const_iterator allocation = strategy.begin(); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (allocation != strategy.end()) { 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch RenderProcessHost* host = RenderProcessHost::FromID(allocation->first); 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host) { 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // This is the capacity this renderer has been allocated. 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t capacity = allocation->second; 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We don't reserve any space for dead objects in the cache. Instead, we 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // prefer to keep live objects around. There is probably some performance 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // tuning to be done here. 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t min_dead_capacity = 0; 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We allow the dead objects to consume all of the cache, if the renderer 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // so desires. If we wanted this memory, we would have set the total 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // capacity lower. 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t max_dead_capacity = capacity; 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host->Send(new ViewMsg_SetCacheCapacities(min_dead_capacity, 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch max_dead_capacity, 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch capacity)); 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++allocation; 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 307513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid WebCacheManager::ClearRendederCache(const std::set<int>& renderers) { 308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::set<int>::const_iterator iter = renderers.begin(); 309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (; iter != renderers.end(); ++iter) { 310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick RenderProcessHost* host = RenderProcessHost::FromID(*iter); 311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (host) 312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick host->Send(new ViewMsg_ClearCache()); 313731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 315731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::ReviseAllocationStrategy() { 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(stats_.size() <= 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_renderers_.size() + inactive_renderers_.size()); 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Check if renderers have gone inactive. 321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FindInactiveRenderers(); 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Gather statistics 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebCache::UsageStats active; 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WebCache::UsageStats inactive; 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GatherStats(active_renderers_, &active); 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GatherStats(inactive_renderers_, &inactive); 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Cache.ActiveTabs", active_renderers_.size()); 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_COUNTS_100("Cache.InactiveTabs", inactive_renderers_.size()); 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveCapacityMB", 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active.capacity / 1024 / 1024); 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveDeadSizeMB", 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active.deadSize / 1024 / 1024); 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.ActiveLiveSizeMB", 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active.liveSize / 1024 / 1024); 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveCapacityMB", 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive.capacity / 1024 / 1024); 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveDeadSizeMB", 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive.deadSize / 1024 / 1024); 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch UMA_HISTOGRAM_MEMORY_MB("Cache.InactiveLiveSizeMB", 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive.liveSize / 1024 / 1024); 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute an allocation strategy. 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We attempt various tactics in order of preference. Our first preference 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // is not to evict any objects. If we don't have enough resources, we'll 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // first try to evict dead data only. If that fails, we'll just divide the 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // resources we have evenly. 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We always try to give the active renderers some head room in their 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // allocations so they can take memory away from an inactive renderer with 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // a large cache allocation. 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Notice the early exit will prevent attempting less desirable tactics once 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // we've found a workable strategy. 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AllocationStrategy strategy; 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if ( // Ideally, we'd like to give the active renderers some headroom and 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // keep all our current objects. 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active, 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KEEP_CURRENT, inactive, &strategy) || 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we can't have that, then we first try to evict the dead objects in 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the caches of inactive renderers. 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AttemptTactic(KEEP_CURRENT_WITH_HEADROOM, active, 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch KEEP_LIVE, inactive, &strategy) || 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Next, we try to keep the live objects in the active renders (with some 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // room for new objects) and give whatever is left to the inactive 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // renderers. 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AttemptTactic(KEEP_LIVE_WITH_HEADROOM, active, 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DIVIDE_EVENLY, inactive, &strategy) || 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we've gotten this far, then we are very tight on memory. Let's try 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to at least keep around the live objects for the active renderers. 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AttemptTactic(KEEP_LIVE, active, DIVIDE_EVENLY, inactive, &strategy) || 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We're basically out of memory. The best we can do is just divide up 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // what we have and soldier on. 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AttemptTactic(DIVIDE_EVENLY, active, DIVIDE_EVENLY, inactive, 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &strategy)) { 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Having found a workable strategy, we enact it. 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch EnactStrategy(strategy); 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // DIVIDE_EVENLY / DIVIDE_EVENLY should always succeed. 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unable to find a cache allocation"; 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::ReviseAllocationStrategyLater() { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Ask to be called back in a few milliseconds to actually recompute our 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // allocation. 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostDelayedTask(FROM_HERE, 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch revise_allocation_factory_.NewRunnableMethod( 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &WebCacheManager::ReviseAllocationStrategy), 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch kReviseAllocationDelayMS); 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebCacheManager::FindInactiveRenderers() { 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::set<int>::const_iterator iter = active_renderers_.begin(); 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (iter != active_renderers_.end()) { 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch StatsMap::iterator elmt = stats_.find(*iter); 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(elmt != stats_.end()); 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TimeDelta idle = Time::Now() - elmt->second.access; 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (idle >= TimeDelta::FromMinutes(kRendererInactiveThresholdMinutes)) { 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Moved to inactive status. This invalidates our iterator. 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inactive_renderers_.insert(*iter); 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch active_renderers_.erase(*iter); 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iter = active_renderers_.begin(); 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch continue; 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ++iter; 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 411