| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/prerender/prerender_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 struct PrerenderManager::PrerenderContentsData { | 54 struct PrerenderManager::PrerenderContentsData { |
| 55 PrerenderContents* contents_; | 55 PrerenderContents* contents_; |
| 56 base::Time start_time_; | 56 base::Time start_time_; |
| 57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
| 58 : contents_(contents), | 58 : contents_(contents), |
| 59 start_time_(start_time) { | 59 start_time_(start_time) { |
| 60 } | 60 } |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 PrerenderManager::PrerenderManager(Profile* profile) | 63 PrerenderManager::PrerenderManager(Profile* profile) |
| 64 : profile_(profile), | 64 : rate_limit_enabled_(true), |
| 65 profile_(profile), |
| 65 max_prerender_age_(base::TimeDelta::FromSeconds( | 66 max_prerender_age_(base::TimeDelta::FromSeconds( |
| 66 kDefaultMaxPrerenderAgeSeconds)), | 67 kDefaultMaxPrerenderAgeSeconds)), |
| 67 max_elements_(kDefaultMaxPrerenderElements), | 68 max_elements_(kDefaultMaxPrerenderElements), |
| 68 prerender_contents_factory_(PrerenderContents::CreateFactory()) { | 69 prerender_contents_factory_(PrerenderContents::CreateFactory()), |
| 70 last_prerender_start_time_(GetCurrentTimeTicks() - |
| 71 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)) { |
| 69 } | 72 } |
| 70 | 73 |
| 71 PrerenderManager::~PrerenderManager() { | 74 PrerenderManager::~PrerenderManager() { |
| 72 while (!prerender_list_.empty()) { | 75 while (!prerender_list_.empty()) { |
| 73 PrerenderContentsData data = prerender_list_.front(); | 76 PrerenderContentsData data = prerender_list_.front(); |
| 74 prerender_list_.pop_front(); | 77 prerender_list_.pop_front(); |
| 75 data.contents_->set_final_status(FINAL_STATUS_MANAGER_SHUTDOWN); | 78 data.contents_->set_final_status(FINAL_STATUS_MANAGER_SHUTDOWN); |
| 76 delete data.contents_; | 79 delete data.contents_; |
| 77 } | 80 } |
| 78 } | 81 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 94 // a shared process, so that we can always reliably lower the CPU | 97 // a shared process, so that we can always reliably lower the CPU |
| 95 // priority for prerendering. | 98 // priority for prerendering. |
| 96 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | 99 // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
| 97 // case, when a new tab is added to a process used for prerendering. | 100 // case, when a new tab is added to a process used for prerendering. |
| 98 if (RenderProcessHost::ShouldTryToUseExistingProcessHost()) { | 101 if (RenderProcessHost::ShouldTryToUseExistingProcessHost()) { |
| 99 // Only record the status if we are not in the control group. | 102 // Only record the status if we are not in the control group. |
| 100 if (!IsControlGroup()) | 103 if (!IsControlGroup()) |
| 101 RecordFinalStatus(FINAL_STATUS_TOO_MANY_PROCESSES); | 104 RecordFinalStatus(FINAL_STATUS_TOO_MANY_PROCESSES); |
| 102 return false; | 105 return false; |
| 103 } | 106 } |
| 107 |
| 108 // Check if enough time has passed since the last prerender. |
| 109 if (!DoesRateLimitAllowPrerender()) { |
| 110 // Cancel the prerender. We could add it to the pending prerender list but |
| 111 // this doesn't make sense as the next prerender request will be triggered |
| 112 // by a navigation and is unlikely to be the same site. |
| 113 RecordFinalStatus(FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| 114 return false; |
| 115 } |
| 116 |
| 104 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | 117 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| 105 PrerenderContentsData data(CreatePrerenderContents(url, alias_urls, referrer), | 118 PrerenderContentsData data(CreatePrerenderContents(url, alias_urls, referrer), |
| 106 GetCurrentTime()); | 119 GetCurrentTime()); |
| 107 prerender_list_.push_back(data); | 120 prerender_list_.push_back(data); |
| 108 if (!IsControlGroup()) | 121 if (!IsControlGroup()) { |
| 122 last_prerender_start_time_ = GetCurrentTimeTicks(); |
| 109 data.contents_->StartPrerendering(); | 123 data.contents_->StartPrerendering(); |
| 124 } |
| 110 while (prerender_list_.size() > max_elements_) { | 125 while (prerender_list_.size() > max_elements_) { |
| 111 data = prerender_list_.front(); | 126 data = prerender_list_.front(); |
| 112 prerender_list_.pop_front(); | 127 prerender_list_.pop_front(); |
| 113 data.contents_->set_final_status(FINAL_STATUS_EVICTED); | 128 data.contents_->set_final_status(FINAL_STATUS_EVICTED); |
| 114 delete data.contents_; | 129 delete data.contents_; |
| 115 } | 130 } |
| 116 StartSchedulingPeriodicCleanups(); | 131 StartSchedulingPeriodicCleanups(); |
| 117 return true; | 132 return true; |
| 118 } | 133 } |
| 119 | 134 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 | 169 |
| 155 // If we are just in the control group (which can be detected by noticing | 170 // If we are just in the control group (which can be detected by noticing |
| 156 // that prerendering hasn't even started yet), record that this TC now would | 171 // that prerendering hasn't even started yet), record that this TC now would |
| 157 // be showing a prerendered contents, but otherwise, don't do anything. | 172 // be showing a prerendered contents, but otherwise, don't do anything. |
| 158 if (!pc->prerendering_has_started()) { | 173 if (!pc->prerendering_has_started()) { |
| 159 MarkTabContentsAsWouldBePrerendered(tc); | 174 MarkTabContentsAsWouldBePrerendered(tc); |
| 160 return false; | 175 return false; |
| 161 } | 176 } |
| 162 | 177 |
| 163 if (!pc->load_start_time().is_null()) | 178 if (!pc->load_start_time().is_null()) |
| 164 RecordTimeUntilUsed(base::TimeTicks::Now() - pc->load_start_time()); | 179 RecordTimeUntilUsed(GetCurrentTimeTicks() - pc->load_start_time()); |
| 165 pc->set_final_status(FINAL_STATUS_USED); | 180 pc->set_final_status(FINAL_STATUS_USED); |
| 166 | 181 |
| 167 RenderViewHost* rvh = pc->render_view_host(); | 182 RenderViewHost* rvh = pc->render_view_host(); |
| 168 // RenderViewHosts in PrerenderContents start out hidden. | 183 // RenderViewHosts in PrerenderContents start out hidden. |
| 169 // Since we are actually using it now, restore it. | 184 // Since we are actually using it now, restore it. |
| 170 rvh->WasRestored(); | 185 rvh->WasRestored(); |
| 171 pc->set_render_view_host(NULL); | 186 pc->set_render_view_host(NULL); |
| 172 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); | 187 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); |
| 173 tc->SwapInRenderViewHost(rvh); | 188 tc->SwapInRenderViewHost(rvh); |
| 174 MarkTabContentsAsPrerendered(tc); | 189 MarkTabContentsAsPrerendered(tc); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 201 break; | 216 break; |
| 202 } | 217 } |
| 203 } | 218 } |
| 204 DeleteOldEntries(); | 219 DeleteOldEntries(); |
| 205 } | 220 } |
| 206 | 221 |
| 207 base::Time PrerenderManager::GetCurrentTime() const { | 222 base::Time PrerenderManager::GetCurrentTime() const { |
| 208 return base::Time::Now(); | 223 return base::Time::Now(); |
| 209 } | 224 } |
| 210 | 225 |
| 226 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { |
| 227 return base::TimeTicks::Now(); |
| 228 } |
| 229 |
| 211 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | 230 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { |
| 212 base::Time now = GetCurrentTime(); | 231 base::Time now = GetCurrentTime(); |
| 213 return (now - start < max_prerender_age_); | 232 return (now - start < max_prerender_age_); |
| 214 } | 233 } |
| 215 | 234 |
| 216 PrerenderContents* PrerenderManager::CreatePrerenderContents( | 235 PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| 217 const GURL& url, | 236 const GURL& url, |
| 218 const std::vector<GURL>& alias_urls, | 237 const std::vector<GURL>& alias_urls, |
| 219 const GURL& referrer) { | 238 const GURL& referrer) { |
| 220 return prerender_contents_factory_->CreatePrerenderContents( | 239 return prerender_contents_factory_->CreatePrerenderContents( |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 // static | 328 // static |
| 310 bool PrerenderManager::ShouldRecordWindowedPPLT() { | 329 bool PrerenderManager::ShouldRecordWindowedPPLT() { |
| 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 312 if (last_prefetch_seen_time_.is_null()) | 331 if (last_prefetch_seen_time_.is_null()) |
| 313 return false; | 332 return false; |
| 314 base::TimeDelta elapsed_time = | 333 base::TimeDelta elapsed_time = |
| 315 base::TimeTicks::Now() - last_prefetch_seen_time_; | 334 base::TimeTicks::Now() - last_prefetch_seen_time_; |
| 316 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); | 335 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); |
| 317 } | 336 } |
| 318 | 337 |
| 338 bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
| 339 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 340 base::TimeDelta elapsed_time = |
| 341 GetCurrentTimeTicks() - last_prerender_start_time_; |
| 342 UMA_HISTOGRAM_TIMES("Prerender.TimeBetweenPrerenderRequests", |
| 343 elapsed_time); |
| 344 if (!rate_limit_enabled_) |
| 345 return true; |
| 346 return elapsed_time > |
| 347 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); |
| 348 } |
| 349 |
| 319 void PrerenderManager::StartSchedulingPeriodicCleanups() { | 350 void PrerenderManager::StartSchedulingPeriodicCleanups() { |
| 320 if (repeating_timer_.IsRunning()) | 351 if (repeating_timer_.IsRunning()) |
| 321 return; | 352 return; |
| 322 repeating_timer_.Start( | 353 repeating_timer_.Start( |
| 323 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), | 354 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), |
| 324 this, | 355 this, |
| 325 &PrerenderManager::PeriodicCleanup); | 356 &PrerenderManager::PeriodicCleanup); |
| 326 } | 357 } |
| 327 | 358 |
| 328 void PrerenderManager::StopSchedulingPeriodicCleanups() { | 359 void PrerenderManager::StopSchedulingPeriodicCleanups() { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 | 393 |
| 363 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { | 394 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { |
| 364 return prerendered_tc_set_.count(tc) > 0; | 395 return prerendered_tc_set_.count(tc) > 0; |
| 365 } | 396 } |
| 366 | 397 |
| 367 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { | 398 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { |
| 368 return would_be_prerendered_tc_set_.count(tc) > 0; | 399 return would_be_prerendered_tc_set_.count(tc) > 0; |
| 369 } | 400 } |
| 370 | 401 |
| 371 } // namespace prerender | 402 } // namespace prerender |
| OLD | NEW |