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 |