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

Side by Side Diff: chrome/browser/predictors/resource_prefetch_predictor.cc

Issue 10416002: Seculative resource prefetching for URLs CL. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Addressing dominich's and willchan's comments. Created 8 years, 7 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
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/predictors/resource_prefetch_predictor.h"
6
7 #include <utility>
8
9 #include "base/command_line.h"
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/time.h"
13 #include "chrome/browser/history/history.h"
14 #include "chrome/browser/history/history_notifications.h"
15 #include "chrome/browser/history/in_memory_database.h"
16 #include "chrome/browser/history/url_database.h"
17 #include "chrome/browser/predictors/predictor_database.h"
18 #include "chrome/browser/predictors/predictor_database_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/browser/load_from_memory_cache_details.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/navigation_controller.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_source.h"
28 #include "content/public/browser/notification_types.h"
29 #include "content/public/browser/resource_request_info.h"
30 #include "content/public/browser/web_contents.h"
31 #include "net/base/mime_util.h"
32 #include "net/http/http_response_headers.h"
33 #include "net/url_request/url_request.h"
34 #include "net/url_request/url_request_context_getter.h"
35
36 using content::BrowserThread;
37
38 namespace {
39
40 // If a navigation hasn't seen a load complete event in this much time, it is
41 // considered abandoned.
42 static const int kMaxNavigationLifetimeSeconds = 60;
43
44 // Size of LRU caches for the Url data.
45 static const size_t kMaxNumUrlsToTrack = 500;
46
47 // The number of times, we should have seen visit to this Url in history
48 // to start tracking it. This is to ensure we dont bother with oneoff entries.
49 static const int kMinUrlVisitCount = 3;
50
51 // The maximum number of resources to store per entry. This is about double of
52 // the expected 25 we expect to prefetch.
53 static const int kMaxResourcesPerEntry = 50;
54
55 // Don't store subresources whose Urls are longer than this.
56 static const size_t kMaxSubresourceUrlLengthBytes = 1000;
57
58 // The number of consecutive misses after we stop tracking a resource Url.
59 static const int kMaxConsecutiveMisses = 3;
60
61 // The number of resources we should report accuracy stats on.
62 static const int kNumResourcesAssumedPrefetched = 25;
63
64 ResourceType::Type GetResourceTypeFromMimeType(const std::string& mime_type,
65 ResourceType::Type fallback) {
66 if (net::IsSupportedImageMimeType(mime_type.c_str()))
67 return ResourceType::IMAGE;
68 else if (net::IsSupportedJavascriptMimeType(mime_type.c_str()))
69 return ResourceType::SCRIPT;
70 else if (net::MatchesMimeType("text/css", mime_type))
71 return ResourceType::STYLESHEET;
72 else
73 return fallback;
74 }
75
76 } // namespace
77
78 namespace predictors {
79
80 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
81 : was_cached_(false) {
dominich 2012/05/24 16:07:53 initialize resource_type_ to something sensible?
Shishir 2012/05/30 01:07:51 Done.
82 }
83
84 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary(
85 const URLRequestSummary& other)
86 : navigation_id_(other.navigation_id_),
87 resource_url_(other.resource_url_),
88 resource_type_(other.resource_type_),
89 mime_type_(other.mime_type_),
90 was_cached_(other.was_cached_) {
91 }
92
93 ResourcePrefetchPredictor::URLRequestSummary::~URLRequestSummary() {
94 }
95
96 bool ResourcePrefetchPredictor::URLRequestSummary::InitFromURLRequest(
97 net::URLRequest* request,
98 bool is_response) {
99 const content::ResourceRequestInfo* info =
willchan no longer on Chromium 2012/05/24 22:28:52 OIC, this is all only for RDH requests? Then maybe
Shishir 2012/05/30 01:07:51 Done.
100 content::ResourceRequestInfo::ForRequest(request);
101 if (!info) {
102 LOG(ERROR) << "No ResourceRequestInfo in request";
103 return false;
104 }
105
106 int render_process_id, render_view_id;
107 if (!info->GetAssociatedRenderView(&render_process_id, &render_view_id)) {
108 LOG(ERROR) << "Could not get RenderViewId from request info.";
109 return false;
110 }
111
112 navigation_id_.render_process_id_ = render_process_id;
113 navigation_id_.render_view_id_ = render_view_id;
114 navigation_id_.main_frame_url_ = request->first_party_for_cookies();
115 navigation_id_.creation_time_ = request->creation_time();
116 resource_url_ = request->original_url();
117 resource_type_ = info->GetResourceType();
118 if (is_response) {
119 request->GetMimeType(&mime_type_);
120 was_cached_ = request->was_cached();
121 // We want to rely on the mime_type for the resource type.
122 resource_type_ = GetResourceTypeFromMimeType(mime_type_, resource_type_);
123 }
124
125 return true;
126 }
127
128 ResourcePrefetchPredictor::ResourcePrefetchPredictor(Profile* profile)
129 : profile_(profile),
130 initialized_(false),
131 tables_(PredictorDatabaseFactory::GetForProfile(
132 profile)->resource_prefetch_tables()),
133 notification_registrar_(new content::NotificationRegistrar()) {
134 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135
136 // Request the in-memory database from the history to force it to load so it's
137 // available as soon as possible.
138 HistoryService* history_service =
139 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
140 if (history_service)
141 history_service->InMemoryDatabase();
142
143 // Create local caches using the database as loaded.
144 std::vector<UrlTableRow>* url_rows = new std::vector<UrlTableRow>();
145 BrowserThread::PostTaskAndReply(
willchan no longer on Chromium 2012/05/24 22:28:52 How about PostTaskAndReplyWithResult()? http://cod
Shishir 2012/05/30 01:07:51 Delayed to first navigation seen. The PostTaskAndR
146 BrowserThread::DB, FROM_HERE,
147 base::Bind(&ResourcePrefetchPredictorTables::GetAllRows,
148 tables_, url_rows),
149 base::Bind(&ResourcePrefetchPredictor::CreateCaches, this,
150 base::Owned(url_rows)));
151 }
152
153 ResourcePrefetchPredictor::~ResourcePrefetchPredictor() {
154 }
155
156 // static
157 bool ResourcePrefetchPredictor::IsEnabled() {
158 CommandLine* command_line = CommandLine::ForCurrentProcess();
159 return command_line->HasSwitch(
160 switches::kEnableSpeculativeResourcePrefetching);
dominich 2012/05/24 16:07:53 to confirm - this is currently only enabled by exp
Shishir 2012/05/30 01:07:51 No field trial at the moment. Just the command lin
161 }
162
163 void ResourcePrefetchPredictor::CreateCaches(
164 std::vector<UrlTableRow>* url_rows) {
165 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166
167 DCHECK(!initialized_);
168 DCHECK(url_table_cache_.empty());
169 DCHECK(inflight_navigations_.empty());
170
171 // Copy the data to local caches.
172 for (UrlTableRowVector::iterator it = url_rows->begin();
173 it != url_rows->end(); ++it) {
174 url_table_cache_[it->main_frame_url_].rows_.push_back(*it);
175 }
176
177 // Score and sort the database caches.
dominich 2012/05/24 16:07:53 comment is inaccurate - scoring is updated in GetA
Shishir 2012/05/30 01:07:51 Done.
178 // TODO(shishir): The following would be much more efficient if we used
179 // pointers.
180 for (UrlTableCacheMap::iterator it = url_table_cache_.begin();
181 it != url_table_cache_.end(); ++it) {
182 std::sort(it->second.rows_.begin(),
183 it->second.rows_.end(),
184 ResourcePrefetchPredictorTables::UrlTableRowSorter());
185 }
186
187 // Add notifications for history loading if it is not ready.
188 if (!profile_->GetHistoryService(Profile::EXPLICIT_ACCESS)) {
189 notification_registrar_->Add(this, chrome::NOTIFICATION_HISTORY_LOADED,
190 content::Source<Profile>(profile_));
191 } else {
192 OnHistoryAndCacheLoaded();
193 }
194 }
195
196 // static
197 bool ResourcePrefetchPredictor::ShouldRecordRequest(net::URLRequest* request) {
willchan no longer on Chromium 2012/05/24 22:28:52 Can we use a const net::URLRequest*? Ditto for the
Shishir 2012/05/30 01:07:51 Done.
198 const content::ResourceRequestInfo* request_info =
199 content::ResourceRequestInfo::ForRequest(request);
200 if (!request_info)
201 return false;
202
203 return request_info->GetResourceType() == ResourceType::MAIN_FRAME &&
204 IsHandledMainPage(request);
205 }
206
207 // static
208 bool ResourcePrefetchPredictor::ShouldRecordResponse(
209 net::URLRequest* response) {
210 const content::ResourceRequestInfo* request_info =
211 content::ResourceRequestInfo::ForRequest(response);
212 if (!request_info)
213 return false;
214
215 return request_info->GetResourceType() == ResourceType::MAIN_FRAME ?
216 IsHandledMainPage(response) : IsHandledSubresource(response);
217 }
218
219 // static
220 bool ResourcePrefetchPredictor::ShouldRecordRedirect(
221 net::URLRequest* response) {
222 const content::ResourceRequestInfo* request_info =
223 content::ResourceRequestInfo::ForRequest(response);
224 if (!request_info)
225 return false;
226
227 return request_info->GetResourceType() == ResourceType::MAIN_FRAME &&
228 IsHandledMainPage(response);
229 }
230
231 // static
232 bool ResourcePrefetchPredictor::IsHandledMainPage(net::URLRequest* request) {
willchan no longer on Chromium 2012/05/24 22:28:52 const net::URLRequest&?
Shishir 2012/05/30 01:07:51 Same comment as above.
233 return request->original_url().scheme() == chrome::kHttpScheme;
234 }
235
236 // static
237 bool ResourcePrefetchPredictor::IsHandledSubresource(
238 net::URLRequest* response) {
239 if (response->first_party_for_cookies().scheme() != chrome::kHttpScheme)
240 return false;
241
242 if (response->original_url().scheme() != chrome::kHttpScheme)
243 return false;
244
245 std::string mime_type;
246 response->GetMimeType(&mime_type);
247 if (!mime_type.empty() &&
248 !net::IsSupportedImageMimeType(mime_type.c_str()) &&
249 !net::IsSupportedJavascriptMimeType(mime_type.c_str()) &&
250 !net::MatchesMimeType("text/css", mime_type)) {
251 return false;
252 }
253
254 if (response->method() != "GET")
255 return false;
256
257 if (response->original_url().spec().length() > kMaxSubresourceUrlLengthBytes)
258 return false;
259
260 bool is_cacheable = IsCacheable(response);
261 UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.IsCacheableResource",
262 is_cacheable);
263 return is_cacheable;
264 }
265
266 // static
267 bool ResourcePrefetchPredictor::IsCacheable(const net::URLRequest* response) {
willchan no longer on Chromium 2012/05/24 22:28:52 const net::URLRequest&?
Shishir 2012/05/30 01:07:51 Same as above.
268 if (response->was_cached())
269 return true;
270
271 // For non cached responses, we will ensure that the freshness lifetime is
272 // some sane value.
273 const net::HttpResponseInfo& response_info = response->response_info();
274 base::Time response_time(response_info.response_time);
275 response_time += base::TimeDelta::FromSeconds(1);
276 base::TimeDelta freshness = response_info.headers->GetFreshnessLifetime(
277 response_time);
278 return freshness > base::TimeDelta();
279 }
280
281 void ResourcePrefetchPredictor::RecordURLRequest(
282 const URLRequestSummary& request) {
283 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
284
285 CHECK_EQ(request.resource_type_, ResourceType::MAIN_FRAME);
286 OnMainFrameRequest(request);
287 }
288
289 void ResourcePrefetchPredictor::RecordUrlResponse(
290 const URLRequestSummary& response) {
291 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
292
293 if (response.resource_type_ == ResourceType::MAIN_FRAME)
294 OnMainFrameResponse(response);
295 else
296 OnSubresourceResponse(response);
297 }
298
299 void ResourcePrefetchPredictor::RecordUrlRedirect(
300 const URLRequestSummary& response) {
301 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
302
303 CHECK_EQ(response.resource_type_, ResourceType::MAIN_FRAME);
304 OnMainFrameRedirect(response);
305 }
306
307 void ResourcePrefetchPredictor::OnMainFrameRequest(
308 const URLRequestSummary& request) {
309 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
310 if (!initialized_)
311 return;
312
313 // TODO(shishir): Remove this code after verifying that the same navigation is
314 // not seen multiple times.
315 NavigationMap::const_iterator it =
316 inflight_navigations_.find(request.navigation_id_);
317 if (it != inflight_navigations_.end()) {
318 DCHECK(it->first.creation_time_ != request.navigation_id_.creation_time_);
319 }
320
321 // Cleanup older navigations.
322 CleanupAbandonedNavigations(request.navigation_id_);
323
324 // New empty navigation entry.
325 inflight_navigations_.insert(std::make_pair(
326 request.navigation_id_, std::vector<URLRequestSummary>()));
327 }
328
329 void ResourcePrefetchPredictor::OnMainFrameResponse(
330 const URLRequestSummary& response) {
331 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
332 if (!initialized_)
333 return;
334
335 // TODO(shishir): The prefreshing will be stopped here.
336 }
337
338 void ResourcePrefetchPredictor::OnMainFrameRedirect(
339 const URLRequestSummary& response) {
340 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
341 if (!initialized_)
342 return;
343
344 inflight_navigations_.erase(response.navigation_id_);
345 }
346
347 void ResourcePrefetchPredictor::OnSubresourceResponse(
348 const URLRequestSummary& response) {
349 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
350
351 if (inflight_navigations_.find(response.navigation_id_) ==
352 inflight_navigations_.end())
353 return;
354
355 inflight_navigations_[response.navigation_id_].push_back(response);
356 }
357
358 void ResourcePrefetchPredictor::OnSubresourceLoadedFromMemory(
359 const NavigationID& navigation_id,
360 const GURL& resource_url) {
361 if (inflight_navigations_.find(navigation_id) == inflight_navigations_.end())
362 return;
363
364 URLRequestSummary summary;
365 summary.navigation_id_ = navigation_id;
366 summary.resource_url_ = resource_url;
367 // The mime_type is currently not available in this notification.
368 // TODO(shishir): Set correct type when CL:10413064 is committed.
369 summary.resource_type_ = ResourceType::LAST_TYPE;
370 summary.was_cached_ = true;
371 inflight_navigations_[navigation_id].push_back(summary);
372 }
373
374 void ResourcePrefetchPredictor::CleanupAbandonedNavigations(
375 const NavigationID& navigation_id) {
376 static const base::TimeDelta max_navigation_age =
377 base::TimeDelta::FromSeconds(kMaxNavigationLifetimeSeconds);
378
379 base::TimeTicks time_now = base::TimeTicks::Now();
380 for (NavigationMap::iterator it = inflight_navigations_.begin();
381 it != inflight_navigations_.end();) {
382 if (it->first.IsSameRenderer(navigation_id) ||
383 (time_now - it->first.creation_time_ > max_navigation_age)) {
384 inflight_navigations_.erase(it++);
385 UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.DidNavigationComplete",
386 false);
387 } else {
388 ++it;
389 }
390 }
391 }
392
393 void ResourcePrefetchPredictor::ShutdownOnUIThread() {
394 notification_registrar_.reset(NULL);
395 }
396
397 void ResourcePrefetchPredictor::Observe(
398 int type,
399 const content::NotificationSource& source,
400 const content::NotificationDetails& details) {
401 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
402
403 switch (type) {
404 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
405 const content::WebContents* web_contents =
406 content::Source<content::WebContents>(source).ptr();
407 NavigationID navigation_id(*web_contents);
408 OnNavigationComplete(navigation_id);
409 break;
410 }
411
412 case content::NOTIFICATION_LOAD_FROM_MEMORY_CACHE: {
413 const LoadFromMemoryCacheDetails* load_details =
414 content::Details<LoadFromMemoryCacheDetails>(details).ptr();
415 const content::WebContents* web_contents =
416 content::Source<content::NavigationController>(
417 source).ptr()->GetWebContents();
418
419 NavigationID navigation_id(*web_contents);
420 OnSubresourceLoadedFromMemory(navigation_id, load_details->url());
421 break;
422 }
423
424 case chrome::NOTIFICATION_HISTORY_LOADED: {
425 DCHECK(!initialized_);
426 notification_registrar_->Remove(this,
427 chrome::NOTIFICATION_HISTORY_LOADED,
428 content::Source<Profile>(profile_));
429 OnHistoryAndCacheLoaded();
430 break;
431 }
432
433 default:
434 NOTREACHED() << "Unexpected notification observed.";
435 break;
436 }
437 }
438
439 void ResourcePrefetchPredictor::OnHistoryAndCacheLoaded() {
440 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441 CHECK(!initialized_);
442
443 // Update the data with last visit info from in memory history db.
444 HistoryService* history_service =
445 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
446 DCHECK(history_service);
447 history::URLDatabase* url_db = history_service->InMemoryDatabase();
448 if (url_db) {
449 std::vector<GURL> urls_to_delete;
450 for (UrlTableCacheMap::iterator it = url_table_cache_.begin();
451 it != url_table_cache_.end();) {
452 history::URLRow url_row;
453 if (url_db->GetRowForURL(it->first, &url_row) == 0) {
454 urls_to_delete.push_back(it->first);
455 url_table_cache_.erase(it++);
456 } else {
457 it->second.last_visit_ = url_row.last_visit();
458 ++it;
459 }
460 }
461 if (!urls_to_delete.empty())
462 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
463 base::Bind(&ResourcePrefetchPredictorTables::DeleteUrlRows,
464 tables_,
465 urls_to_delete));
466 }
467
468 notification_registrar_->Add(
469 this,
470 content::NOTIFICATION_LOAD_FROM_MEMORY_CACHE,
471 content::NotificationService::AllSources());
472
473 notification_registrar_->Add(
474 this,
475 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
476 content::NotificationService::AllSources());
477
478 // TODO(shishir): Maybe listen for notifications for navigation being
479 // abandoned and cleanup the inflight_navigations_.
480
481 initialized_ = true;
482 }
483
484 bool ResourcePrefetchPredictor::ShouldTrackUrl(const GURL& url) {
485 if (url_table_cache_.find(url) != url_table_cache_.end())
486 return true;
487
488 HistoryService* history_service =
489 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
490 DCHECK(history_service);
491 history::URLDatabase* url_db = history_service->InMemoryDatabase();
492 if (!url_db)
493 return false;
494
495 history::URLRow url_row;
496 return url_db->GetRowForURL(url, &url_row) != 0 &&
497 url_row.visit_count() >= kMinUrlVisitCount;
498 }
499
500 void ResourcePrefetchPredictor::OnNavigationComplete(
501 const NavigationID& navigation_id) {
502 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
503
504 UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.DidNavigationComplete",
505 true);
506
507 DCHECK(inflight_navigations_.find(navigation_id) !=
508 inflight_navigations_.end());
509
510 // Report any stats.
511 MaybeReportAccuracyStats(navigation_id);
512
513 // Update the URL table.
514 const GURL& main_frame_url = navigation_id.main_frame_url_;
515 if (ShouldTrackUrl(main_frame_url))
516 LearnUrlNavigation(main_frame_url, inflight_navigations_[navigation_id]);
517
518 // Remove the navigation.
519 inflight_navigations_.erase(navigation_id);
520 }
521
522 void ResourcePrefetchPredictor::LearnUrlNavigation(
523 const GURL& main_frame_url,
524 const std::vector<URLRequestSummary>& new_resources) {
525 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
526
527 if (url_table_cache_.find(main_frame_url) == url_table_cache_.end()) {
528 if (url_table_cache_.size() >= kMaxNumUrlsToTrack)
529 RemoveAnEntryFromUrlDB();
530
531 url_table_cache_[main_frame_url].last_visit_ = base::Time::Now();
532 int new_resources_size = static_cast<int>(new_resources.size());
533 for (int i = 0; i < new_resources_size; ++i) {
534 UrlTableRow row_to_add;
535 row_to_add.main_frame_url_ = main_frame_url;
536 row_to_add.resource_url_ = new_resources[i].resource_url_;
537 row_to_add.resource_type_ = new_resources[i].resource_type_;
538 row_to_add.number_of_hits_ = 1;
539 row_to_add.average_position_ = i + 1;
540 url_table_cache_[main_frame_url].rows_.push_back(row_to_add);
541 }
542 } else {
543 UrlTableRowVector& old_resources = url_table_cache_[main_frame_url].rows_;
dominich 2012/05/24 16:07:53 i'm really worried about how slow this will be. Pu
Shishir 2012/05/30 01:07:51 Will look at the profiler in more detail over this
544 url_table_cache_[main_frame_url].last_visit_ = base::Time::Now();
545
546 // Build indices over the data.
547 std::map<GURL, int> new_index, old_index;
548 int new_resources_size = static_cast<int>(new_resources.size());
549 for (int i = 0; i < new_resources_size; ++i) {
550 const URLRequestSummary& summary = new_resources[i];
551 // Take the first occurence of every url.
552 if (new_index.find(summary.resource_url_) == new_index.end())
553 new_index[summary.resource_url_] = i;
554 }
555 int old_resources_size = static_cast<int>(old_resources.size());
556 for (int i = 0; i < old_resources_size; ++i) {
557 const UrlTableRow& row = old_resources[i];
558 DCHECK(old_index.find(row.resource_url_) == old_index.end());
559 old_index[row.resource_url_] = i;
560 }
561
562 // Go through the old urls and update their hit/miss counts.
563 for (int i = 0; i < old_resources_size; ++i) {
564 UrlTableRow& old_row = old_resources[i];
565 if (new_index.find(old_row.resource_url_) == new_index.end()) {
566 ++old_row.number_of_misses_;
567 ++old_row.consecutive_misses_;
568 } else {
569 const URLRequestSummary& new_row =
570 new_resources[new_index[old_row.resource_url_]];
571
572 // Update the resource type since it could have changed.
573 if (new_row.resource_type_ != ResourceType::LAST_TYPE)
574 old_row.resource_type_ = new_row.resource_type_;
575
576 int position = new_index[old_row.resource_url_] + 1;
577 int total = old_row.number_of_hits_ + old_row.number_of_misses_;
578 old_row.average_position_ =
579 ((old_row.average_position_ * total) + position) / (total + 1);
580 ++old_row.number_of_hits_;
581 old_row.consecutive_misses_ = 0;
582 }
583 }
584
585 // Add the new ones that we have not seen before.
586 for (int i = 0; i < new_resources_size; ++i) {
587 const URLRequestSummary& summary = new_resources[i];
588 if (old_index.find(summary.resource_url_) != old_index.end())
589 continue;
590
591 // Only need to add new stuff.
592 UrlTableRow row_to_add;
593 row_to_add.main_frame_url_ = main_frame_url;
594 row_to_add.resource_url_ = summary.resource_url_;
595 row_to_add.resource_type_ = summary.resource_type_;
596 row_to_add.number_of_hits_ = 1;
597 row_to_add.average_position_ = i + 1;
598 old_resources.push_back(row_to_add);
599
600 // To ensure we dont add the same url twice.
601 old_index[summary.resource_url_] = 0;
602 }
603 }
604
605 // Trim and sort the rows after the update.
606 UrlTableRowVector& rows = url_table_cache_[main_frame_url].rows_;
607 for (UrlTableRowVector::iterator it = rows.begin(); it != rows.end();) {
608 it->UpdateScore();
609 if (it->consecutive_misses_ >= kMaxConsecutiveMisses)
610 it = rows.erase(it);
611 else
612 ++it;
613 }
614 std::sort(rows.begin(), rows.end(),
615 ResourcePrefetchPredictorTables::UrlTableRowSorter());
616
617 BrowserThread::PostTask(
618 BrowserThread::DB, FROM_HERE,
619 base::Bind(&ResourcePrefetchPredictorTables::UpdateRowsForUrl,
620 tables_,
621 main_frame_url,
622 rows));
623 }
624
625 void ResourcePrefetchPredictor::RemoveAnEntryFromUrlDB() {
626 if (url_table_cache_.empty())
627 return;
628
629 // TODO(shishir): Maybe use a heap to do this more efficiently.
630 base::Time oldest_time;
631 GURL url_to_erase;
632 for (UrlTableCacheMap::iterator it = url_table_cache_.begin();
633 it != url_table_cache_.end(); ++it) {
634 if (url_to_erase.is_empty() || it->second.last_visit_ < oldest_time) {
635 url_to_erase = it->first;
636 oldest_time = it->second.last_visit_;
637 }
638 }
639 url_table_cache_.erase(url_to_erase);
640
641 std::vector<GURL> urls_to_delete(1, url_to_erase);
642 BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
643 base::Bind(&ResourcePrefetchPredictorTables::DeleteUrlRows,
644 tables_,
645 urls_to_delete));
646 }
647
648 void ResourcePrefetchPredictor::MaybeReportAccuracyStats(
649 const NavigationID& navigation_id) {
650 const GURL& main_frame_url = navigation_id.main_frame_url_;
651 DCHECK(inflight_navigations_.find(navigation_id) !=
652 inflight_navigations_.end());
653
654 bool have_predictions_for_url =
655 url_table_cache_.find(main_frame_url) != url_table_cache_.end();
656 UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.HavePredictionsForUrl",
657 have_predictions_for_url);
658 if (!have_predictions_for_url)
659 return;
660
661 const std::vector<URLRequestSummary>& actual =
662 inflight_navigations_[navigation_id];
663 const UrlTableRowVector& predicted = url_table_cache_[main_frame_url].rows_;
664
665 std::map<GURL, bool> actual_resources;
666 for (std::vector<URLRequestSummary>::const_iterator it = actual.begin();
667 it != actual.end(); ++it) {
668 actual_resources[it->resource_url_] = it->was_cached_;
669 }
670
671 int prefetch_cached = 0, prefetch_network = 0, prefetch_missed = 0;
672 int num_assumed_prefetched = std::min(static_cast<int>(predicted.size()),
673 kNumResourcesAssumedPrefetched);
674 for (int i = 0; i < num_assumed_prefetched; ++i) {
675 const UrlTableRow& row = predicted[i];
676 if (actual_resources.find(row.resource_url_) == actual_resources.end()) {
677 ++prefetch_missed;
678 } else if (actual_resources[row.resource_url_]) {
679 ++prefetch_cached;
680 } else {
681 ++prefetch_network;
682 }
683 }
684
685 UMA_HISTOGRAM_PERCENTAGE(
dominich 2012/05/24 16:07:53 it might be more flexible to report the total coun
Shishir 2012/05/30 01:07:51 Will we be able to do that? We will only get aggre
686 "ResourcePrefetchPredictor.PredictedPrefetchMisses",
687 prefetch_missed * 100.0 / num_assumed_prefetched);
688 UMA_HISTOGRAM_PERCENTAGE(
689 "ResourcePrefetchPredictor.PredictedPrefetchFromCache",
690 prefetch_cached * 100.0 / num_assumed_prefetched);
691 UMA_HISTOGRAM_PERCENTAGE(
692 "ResourcePrefetchPredictor.PredictedPrefetchFromNetwork",
693 prefetch_network * 100.0 / num_assumed_prefetched);
694 }
695
696 } // namespace predictors
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698