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

Side by Side Diff: chrome/browser/prerender/prerender_manager.cc

Issue 6625066: Add pending preloads indexed by routing id. Start preloading once we navigate. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 9 years, 9 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 | Annotate | Revision Log
OLDNEW
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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 56
57 struct PrerenderManager::PrerenderContentsData { 57 struct PrerenderManager::PrerenderContentsData {
58 PrerenderContents* contents_; 58 PrerenderContents* contents_;
59 base::Time start_time_; 59 base::Time start_time_;
60 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) 60 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
61 : contents_(contents), 61 : contents_(contents),
62 start_time_(start_time) { 62 start_time_(start_time) {
63 } 63 }
64 }; 64 };
65 65
66 struct PrerenderManager::PendingContentsData {
67 PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls,
68 const GURL& referrer)
69 : url_(url), alias_urls_(alias_urls), referrer_(referrer) { }
70 ~PendingContentsData() {}
71 GURL url_;
72 std::vector<GURL> alias_urls_;
73 GURL referrer_;
74 };
75
76
66 PrerenderManager::PrerenderManager(Profile* profile) 77 PrerenderManager::PrerenderManager(Profile* profile)
67 : rate_limit_enabled_(true), 78 : rate_limit_enabled_(true),
68 profile_(profile), 79 profile_(profile),
69 max_prerender_age_(base::TimeDelta::FromSeconds( 80 max_prerender_age_(base::TimeDelta::FromSeconds(
70 kDefaultMaxPrerenderAgeSeconds)), 81 kDefaultMaxPrerenderAgeSeconds)),
71 max_elements_(kDefaultMaxPrerenderElements), 82 max_elements_(kDefaultMaxPrerenderElements),
72 prerender_contents_factory_(PrerenderContents::CreateFactory()), 83 prerender_contents_factory_(PrerenderContents::CreateFactory()),
73 last_prerender_start_time_(GetCurrentTimeTicks() - 84 last_prerender_start_time_(GetCurrentTimeTicks() -
74 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)) { 85 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)) {
75 } 86 }
(...skipping 12 matching lines...) Expand all
88 prerender_contents_factory_.reset(prerender_contents_factory); 99 prerender_contents_factory_.reset(prerender_contents_factory);
89 } 100 }
90 101
91 bool PrerenderManager::AddPreload(const GURL& url, 102 bool PrerenderManager::AddPreload(const GURL& url,
92 const std::vector<GURL>& alias_urls, 103 const std::vector<GURL>& alias_urls,
93 const GURL& referrer) { 104 const GURL& referrer) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
95 DeleteOldEntries(); 106 DeleteOldEntries();
96 if (FindEntry(url)) 107 if (FindEntry(url))
97 return false; 108 return false;
109
98 // Do not prerender if there are too many render processes, and we would 110 // Do not prerender if there are too many render processes, and we would
99 // have to use an existing one. We do not want prerendering to happen in 111 // have to use an existing one. We do not want prerendering to happen in
100 // a shared process, so that we can always reliably lower the CPU 112 // a shared process, so that we can always reliably lower the CPU
101 // priority for prerendering. 113 // priority for prerendering.
102 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 114 // TODO(tburkard): Figure out how to cancel prerendering in the opposite
103 // case, when a new tab is added to a process used for prerendering. 115 // case, when a new tab is added to a process used for prerendering.
104 if (RenderProcessHost::ShouldTryToUseExistingProcessHost()) { 116 if (RenderProcessHost::ShouldTryToUseExistingProcessHost()) {
105 // Only record the status if we are not in the control group. 117 // Only record the status if we are not in the control group.
106 if (!IsControlGroup()) 118 if (!IsControlGroup())
107 RecordFinalStatus(FINAL_STATUS_TOO_MANY_PROCESSES); 119 RecordFinalStatus(FINAL_STATUS_TOO_MANY_PROCESSES);
108 return false; 120 return false;
109 } 121 }
110 122
111 // Check if enough time has passed since the last prerender. 123 // Check if enough time has passed since the last prerender.
112 if (!DoesRateLimitAllowPrerender()) { 124 if (!DoesRateLimitAllowPrerender()) {
113 // Cancel the prerender. We could add it to the pending prerender list but 125 // Cancel the prerender. We could add it to the pending prerender list but
114 // this doesn't make sense as the next prerender request will be triggered 126 // this doesn't make sense as the next prerender request will be triggered
115 // by a navigation and is unlikely to be the same site. 127 // by a navigation and is unlikely to be the same site.
116 RecordFinalStatus(FINAL_STATUS_RATE_LIMIT_EXCEEDED); 128 RecordFinalStatus(FINAL_STATUS_RATE_LIMIT_EXCEEDED);
129
117 return false; 130 return false;
118 } 131 }
119 132
120 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 133 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
121 PrerenderContentsData data(CreatePrerenderContents(url, alias_urls, referrer), 134 PrerenderContentsData data(CreatePrerenderContents(url, alias_urls, referrer),
122 GetCurrentTime()); 135 GetCurrentTime());
123 prerender_list_.push_back(data); 136 prerender_list_.push_back(data);
124 if (!IsControlGroup()) { 137 if (!IsControlGroup()) {
125 last_prerender_start_time_ = GetCurrentTimeTicks(); 138 last_prerender_start_time_ = GetCurrentTimeTicks();
126 data.contents_->StartPrerendering(); 139 data.contents_->StartPrerendering();
127 } 140 }
128 while (prerender_list_.size() > max_elements_) { 141 while (prerender_list_.size() > max_elements_) {
129 data = prerender_list_.front(); 142 data = prerender_list_.front();
130 prerender_list_.pop_front(); 143 prerender_list_.pop_front();
131 data.contents_->set_final_status(FINAL_STATUS_EVICTED); 144 data.contents_->set_final_status(FINAL_STATUS_EVICTED);
132 delete data.contents_; 145 delete data.contents_;
133 } 146 }
134 StartSchedulingPeriodicCleanups(); 147 StartSchedulingPeriodicCleanups();
135 return true; 148 return true;
136 } 149 }
137 150
151 void PrerenderManager::AddPendingPreload(
152 const std::pair<int,int>& child_route_id_pair,
153 const GURL& url,
154 const std::vector<GURL>& alias_urls,
155 const GURL& referrer) {
156 // Check if this is coming from a valid prerender rvh.
157 bool is_valid_prerender = false;
158 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
159 it != prerender_list_.end(); ++it) {
160 PrerenderContents* pc = it->contents_;
161
162 int child_id;
163 int route_id;
164 bool has_child_id = pc->GetChildId(&child_id);
165 bool has_route_id = has_child_id && pc->GetRouteId(&route_id);
166
167 if (has_child_id && has_route_id &&
168 child_id == child_route_id_pair.first &&
169 route_id == child_route_id_pair.second) {
170 is_valid_prerender = true;
171 break;
172 }
173 }
174
175 // If not, we could check to see if the RenderViewHost specified by the
176 // child_route_id_pair exists and if so just start prerendering, as this
177 // suggests that the link was clicked, though this might prerender something
178 // that the user has already navigated away from. For now, we'll be
179 // conservative and skip the prerender which will mean some prerender requests
180 // from prerendered pages will be missed if the user navigates quickly.
181 if (!is_valid_prerender) {
182 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED);
183 return;
184 }
185
186 PendingPrerenderList::iterator it =
187 pending_prerender_list_.find(child_route_id_pair);
188 if (it == pending_prerender_list_.end()) {
189 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair,
190 std::vector<PendingContentsData>());
191 it = pending_prerender_list_.insert(el).first;
192 }
193
194 it->second.push_back(PendingContentsData(url, alias_urls, referrer));
195 }
196
138 void PrerenderManager::DeleteOldEntries() { 197 void PrerenderManager::DeleteOldEntries() {
139 while (!prerender_list_.empty()) { 198 while (!prerender_list_.empty()) {
140 PrerenderContentsData data = prerender_list_.front(); 199 PrerenderContentsData data = prerender_list_.front();
141 if (IsPrerenderElementFresh(data.start_time_)) 200 if (IsPrerenderElementFresh(data.start_time_))
142 return; 201 return;
143 prerender_list_.pop_front(); 202 prerender_list_.pop_front();
144 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); 203 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT);
145 delete data.contents_; 204 delete data.contents_;
146 } 205 }
147 if (prerender_list_.empty()) 206 if (prerender_list_.empty())
(...skipping 30 matching lines...) Expand all
178 return false; 237 return false;
179 } 238 }
180 239
181 if (!pc->load_start_time().is_null()) 240 if (!pc->load_start_time().is_null())
182 RecordTimeUntilUsed(GetCurrentTimeTicks() - pc->load_start_time()); 241 RecordTimeUntilUsed(GetCurrentTimeTicks() - pc->load_start_time());
183 242
184 UMA_HISTOGRAM_COUNTS("Prerender.PrerendersPerSessionCount", 243 UMA_HISTOGRAM_COUNTS("Prerender.PrerendersPerSessionCount",
185 ++prerenders_per_session_count_); 244 ++prerenders_per_session_count_);
186 pc->set_final_status(FINAL_STATUS_USED); 245 pc->set_final_status(FINAL_STATUS_USED);
187 246
247 int child_id;
248 int route_id;
249 CHECK(pc->GetChildId(&child_id));
250 CHECK(pc->GetRouteId(&route_id));
251
188 RenderViewHost* rvh = pc->render_view_host(); 252 RenderViewHost* rvh = pc->render_view_host();
189 // RenderViewHosts in PrerenderContents start out hidden. 253 // RenderViewHosts in PrerenderContents start out hidden.
190 // Since we are actually using it now, restore it. 254 // Since we are actually using it now, restore it.
191 rvh->WasRestored(); 255 rvh->WasRestored();
192 pc->set_render_view_host(NULL); 256 pc->set_render_view_host(NULL);
193 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); 257 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id()));
194 tc->SwapInRenderViewHost(rvh); 258 tc->SwapInRenderViewHost(rvh);
195 MarkTabContentsAsPrerendered(tc); 259 MarkTabContentsAsPrerendered(tc);
196 260
261 // See if we have any pending prerender requests for this routing id and start
262 // the preload if we do.
263 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
264 PendingPrerenderList::iterator pending_it =
265 pending_prerender_list_.find(child_route_pair);
266 if (pending_it != pending_prerender_list_.end()) {
267 for (std::vector<PendingContentsData>::iterator content_it =
268 pending_it->second.begin();
269 content_it != pending_it->second.end(); ++content_it) {
270 AddPreload(content_it->url_, content_it->alias_urls_,
271 content_it->referrer_);
272 }
273 pending_prerender_list_.erase(pending_it);
274 }
275
197 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); 276 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params();
198 if (p != NULL) 277 if (p != NULL)
199 tc->DidNavigate(rvh, *p); 278 tc->DidNavigate(rvh, *p);
200 279
201 string16 title = pc->title(); 280 string16 title = pc->title();
202 if (!title.empty()) 281 if (!title.empty())
203 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); 282 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
204 283
205 GURL icon_url = pc->icon_url(); 284 GURL icon_url = pc->icon_url();
206 if (!icon_url.is_empty()) 285 if (!icon_url.is_empty())
207 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url); 286 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url);
208 287
209 if (pc->has_stopped_loading()) 288 if (pc->has_stopped_loading())
210 tc->DidStopLoading(); 289 tc->DidStopLoading();
211 290
212 return true; 291 return true;
213 } 292 }
214 293
215 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { 294 void PrerenderManager::RemoveEntry(PrerenderContents* entry) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
217 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 296 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
218 it != prerender_list_.end(); 297 it != prerender_list_.end();
219 ++it) { 298 ++it) {
220 if (it->contents_ == entry) { 299 if (it->contents_ == entry) {
300 RemovePendingPreload(entry);
221 prerender_list_.erase(it); 301 prerender_list_.erase(it);
222 break; 302 break;
223 } 303 }
224 } 304 }
225 DeleteOldEntries(); 305 DeleteOldEntries();
226 } 306 }
227 307
228 base::Time PrerenderManager::GetCurrentTime() const { 308 base::Time PrerenderManager::GetCurrentTime() const {
229 return base::Time::Now(); 309 return base::Time::Now();
230 } 310 }
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); 378 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
299 it != prerender_list_.end(); 379 it != prerender_list_.end();
300 ++it) { 380 ++it) {
301 if (it->contents_->MatchesURL(url)) 381 if (it->contents_->MatchesURL(url))
302 return it->contents_; 382 return it->contents_;
303 } 383 }
304 // Entry not found. 384 // Entry not found.
305 return NULL; 385 return NULL;
306 } 386 }
307 387
388 PrerenderManager::PendingContentsData*
389 PrerenderManager::FindPendingEntry(const GURL& url) {
390 for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin();
391 map_it != pending_prerender_list_.end();
392 ++map_it) {
393 for (std::vector<PendingContentsData>::iterator content_it =
394 map_it->second.begin();
395 content_it != map_it->second.end();
396 ++content_it) {
397 if (content_it->url_ == url) {
398 return &(*content_it);
399 }
400 }
401 }
402
403 return NULL;
404 }
405
308 // static 406 // static
309 void PrerenderManager::RecordPrefetchTagObserved() { 407 void PrerenderManager::RecordPrefetchTagObserved() {
310 // Ensure that we are in the UI thread, and post to the UI thread if 408 // Ensure that we are in the UI thread, and post to the UI thread if
311 // necessary. 409 // necessary.
312 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 410 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
313 BrowserThread::PostTask( 411 BrowserThread::PostTask(
314 BrowserThread::UI, 412 BrowserThread::UI,
315 FROM_HERE, 413 FROM_HERE,
316 NewRunnableFunction( 414 NewRunnableFunction(
317 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); 415 &PrerenderManager::RecordPrefetchTagObservedOnUIThread));
318 } else { 416 } else {
319 RecordPrefetchTagObservedOnUIThread(); 417 RecordPrefetchTagObservedOnUIThread();
320 } 418 }
321 } 419 }
322 420
323 // static 421 // static
324 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { 422 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() {
325 // Once we get here, we have to be on the UI thread. 423 // Once we get here, we have to be on the UI thread.
326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
327 425
328 // If we observe multiple tags within the 30 second window, we will still 426 // If we observe multiple tags within the 30 second window, we will still
329 // reset the window to begin at the most recent occurrence, so that we will 427 // reset the window to begin at the most recent occurrence, so that we will
330 // always be in a window in the 30 seconds from each occurrence. 428 // always be in a window in the 30 seconds from each occurrence.
331 last_prefetch_seen_time_ = base::TimeTicks::Now(); 429 last_prefetch_seen_time_ = base::TimeTicks::Now();
332 } 430 }
333 431
432 void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) {
433 int child_id;
434 int route_id;
435 bool has_child_id = entry->GetChildId(&child_id);
436 bool has_route_id = has_child_id && entry->GetRouteId(&route_id);
437
438 // If the entry doesn't have a RenderViewHost then it didn't start
439 // prerendering and there shouldn't be any pending preloads to remove.
440 if (has_child_id && has_route_id) {
441 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
442 pending_prerender_list_.erase(child_route_pair);
443 }
444 }
445
334 // static 446 // static
335 bool PrerenderManager::ShouldRecordWindowedPPLT() { 447 bool PrerenderManager::ShouldRecordWindowedPPLT() {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
337 if (last_prefetch_seen_time_.is_null()) 449 if (last_prefetch_seen_time_.is_null())
338 return false; 450 return false;
339 base::TimeDelta elapsed_time = 451 base::TimeDelta elapsed_time =
340 base::TimeTicks::Now() - last_prefetch_seen_time_; 452 base::TimeTicks::Now() - last_prefetch_seen_time_;
341 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); 453 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds);
342 } 454 }
343 455
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 511
400 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { 512 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const {
401 return prerendered_tc_set_.count(tc) > 0; 513 return prerendered_tc_set_.count(tc) > 0;
402 } 514 }
403 515
404 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { 516 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const {
405 return would_be_prerendered_tc_set_.count(tc) > 0; 517 return would_be_prerendered_tc_set_.count(tc) > 0;
406 } 518 }
407 519
408 } // namespace prerender 520 } // namespace prerender
OLDNEW
« no previous file with comments | « chrome/browser/prerender/prerender_manager.h ('k') | chrome/browser/prerender/prerender_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698