| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/predictors/resource_prefetch_common.h" |
| |
| #include <stdlib.h> |
| |
| #include "base/command_line.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/strings/string_split.h" |
| #include "chrome/browser/net/prediction_options.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| |
| using base::FieldTrialList; |
| using std::string; |
| using std::vector; |
| |
| namespace predictors { |
| |
| const char kSpeculativePrefetchingTrialName[] = |
| "SpeculativeResourcePrefetching"; |
| |
| /* |
| * SpeculativeResourcePrefetching is a field trial, and its value must have the |
| * following format: key1=value1:key2=value2:key3=value3 |
| * e.g. "Prefetching=Enabled:Predictor=Url:Confidence=High" |
| * The function below extracts the value corresponding to a key provided from |
| * the SpeculativeResourcePrefetching field trial. |
| */ |
| string GetFiledTrialSpecValue(string key) { |
| vector<string> elements; |
| base::SplitString( |
| FieldTrialList::FindFullName(kSpeculativePrefetchingTrialName), |
| ':', |
| &elements); |
| for (int i = 0; i < static_cast<int>(elements.size()); i++) { |
| vector<string> key_value; |
| base::SplitString(elements[i], '=', &key_value); |
| if (key_value.size() == 2 && key_value[0] == key) |
| return key_value[1]; |
| } |
| return string(); |
| } |
| |
| bool IsSpeculativeResourcePrefetchingEnabled( |
| Profile* profile, |
| ResourcePrefetchPredictorConfig* config) { |
| DCHECK(config); |
| |
| // Off the record - disabled. |
| if (!profile || profile->IsOffTheRecord()) |
| return false; |
| |
| // Enabled by command line switch. The config has the default params already |
| // set. The command line with just enable them with the default params. |
| if (CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kSpeculativeResourcePrefetching)) { |
| const std::string value = |
| CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kSpeculativeResourcePrefetching); |
| |
| if (value == switches::kSpeculativeResourcePrefetchingDisabled) { |
| return false; |
| } else if (value == switches::kSpeculativeResourcePrefetchingLearning) { |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| return true; |
| } else if (value == switches::kSpeculativeResourcePrefetchingEnabled) { |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING; |
| return true; |
| } |
| } |
| |
| // Disable if no field trial is specified. |
| std::string trial = base::FieldTrialList::FindFullName( |
| kSpeculativePrefetchingTrialName); |
| if (trial.empty()) |
| return false; |
| |
| // Enabled by field trial. |
| std::string spec_prefetching = GetFiledTrialSpecValue("Prefetching"); |
| std::string spec_predictor = GetFiledTrialSpecValue("Predictor"); |
| std::string spec_confidence = GetFiledTrialSpecValue("Confidence"); |
| std::string spec_more_resources = GetFiledTrialSpecValue("MoreResources"); |
| std::string spec_small_db = GetFiledTrialSpecValue("SmallDB"); |
| |
| if (spec_prefetching == "Learning") { |
| if (spec_predictor == "Url") { |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| } else if (spec_predictor == "Host") { |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| } else { |
| // Default: both Url and Host |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| } |
| } else if (spec_prefetching == "Enabled") { |
| if (spec_predictor == "Url") { |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING; |
| } else if (spec_predictor == "Host") { |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING; |
| } else { |
| // Default: both Url and Host |
| config->mode |= ResourcePrefetchPredictorConfig::URL_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_LEARNING; |
| config->mode |= ResourcePrefetchPredictorConfig::URL_PREFETCHING; |
| config->mode |= ResourcePrefetchPredictorConfig::HOST_PRFETCHING; |
| } |
| } else { |
| // Default: spec_prefetching == "Disabled" |
| return false; |
| } |
| |
| if (spec_confidence == "Low") { |
| config->min_url_visit_count = 1; |
| config->min_resource_confidence_to_trigger_prefetch = 0.5f; |
| config->min_resource_hits_to_trigger_prefetch = 1; |
| } else if (spec_confidence == "High") { |
| config->min_url_visit_count = 3; |
| config->min_resource_confidence_to_trigger_prefetch = 0.9f; |
| config->min_resource_hits_to_trigger_prefetch = 3; |
| } else { |
| // default |
| config->min_url_visit_count = 2; |
| config->min_resource_confidence_to_trigger_prefetch = 0.7f; |
| config->min_resource_hits_to_trigger_prefetch = 2; |
| } |
| |
| if (spec_more_resources == "Enabled") { |
| config->max_resources_per_entry = 100; |
| } |
| |
| if (spec_small_db == "Enabled") { |
| config->max_urls_to_track = 200; |
| config->max_hosts_to_track = 100; |
| } |
| |
| return true; |
| } |
| |
| NavigationID::NavigationID() |
| : render_process_id(-1), |
| render_frame_id(-1) { |
| } |
| |
| NavigationID::NavigationID(const NavigationID& other) |
| : render_process_id(other.render_process_id), |
| render_frame_id(other.render_frame_id), |
| main_frame_url(other.main_frame_url), |
| creation_time(other.creation_time) { |
| } |
| |
| NavigationID::NavigationID(content::WebContents* web_contents) |
| : render_process_id(web_contents->GetRenderProcessHost()->GetID()), |
| render_frame_id(web_contents->GetMainFrame()->GetRoutingID()), |
| main_frame_url(web_contents->GetURL()) { |
| } |
| |
| bool NavigationID::is_valid() const { |
| return render_process_id != -1 && render_frame_id != -1 && |
| !main_frame_url.is_empty(); |
| } |
| |
| bool NavigationID::operator<(const NavigationID& rhs) const { |
| DCHECK(is_valid() && rhs.is_valid()); |
| if (render_process_id != rhs.render_process_id) |
| return render_process_id < rhs.render_process_id; |
| else if (render_frame_id != rhs.render_frame_id) |
| return render_frame_id < rhs.render_frame_id; |
| else |
| return main_frame_url < rhs.main_frame_url; |
| } |
| |
| bool NavigationID::operator==(const NavigationID& rhs) const { |
| DCHECK(is_valid() && rhs.is_valid()); |
| return IsSameRenderer(rhs) && main_frame_url == rhs.main_frame_url; |
| } |
| |
| bool NavigationID::IsSameRenderer(const NavigationID& other) const { |
| DCHECK(is_valid() && other.is_valid()); |
| return render_process_id == other.render_process_id && |
| render_frame_id == other.render_frame_id; |
| } |
| |
| ResourcePrefetchPredictorConfig::ResourcePrefetchPredictorConfig() |
| : mode(0), |
| max_navigation_lifetime_seconds(60), |
| max_urls_to_track(500), |
| max_hosts_to_track(200), |
| min_url_visit_count(2), |
| max_resources_per_entry(50), |
| max_consecutive_misses(3), |
| min_resource_confidence_to_trigger_prefetch(0.7f), |
| min_resource_hits_to_trigger_prefetch(2), |
| max_prefetches_inflight_per_navigation(24), |
| max_prefetches_inflight_per_host_per_navigation(3) { |
| } |
| |
| ResourcePrefetchPredictorConfig::~ResourcePrefetchPredictorConfig() { |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsLearningEnabled() const { |
| return IsURLLearningEnabled() || IsHostLearningEnabled(); |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsPrefetchingEnabled( |
| Profile* profile) const { |
| return IsURLPrefetchingEnabled(profile) || IsHostPrefetchingEnabled(profile); |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsURLLearningEnabled() const { |
| return (mode & URL_LEARNING) > 0; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsHostLearningEnabled() const { |
| return (mode & HOST_LEARNING) > 0; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsURLPrefetchingEnabled( |
| Profile* profile) const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| if (!profile || !profile->GetPrefs() || |
| !chrome_browser_net::CanPrefetchAndPrerenderUI(profile->GetPrefs())) { |
| return false; |
| } |
| return (mode & URL_PREFETCHING) > 0; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsHostPrefetchingEnabled( |
| Profile* profile) const { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| if (!profile || !profile->GetPrefs() || |
| !chrome_browser_net::CanPrefetchAndPrerenderUI(profile->GetPrefs())) { |
| return false; |
| } |
| return (mode & HOST_PRFETCHING) > 0; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsLowConfidenceForTest() const { |
| return min_url_visit_count == 1 && |
| std::abs(min_resource_confidence_to_trigger_prefetch - 0.5f) < 1e-6 && |
| min_resource_hits_to_trigger_prefetch == 1; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsHighConfidenceForTest() const { |
| return min_url_visit_count == 3 && |
| std::abs(min_resource_confidence_to_trigger_prefetch - 0.9f) < 1e-6 && |
| min_resource_hits_to_trigger_prefetch == 3; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsMoreResourcesEnabledForTest() const { |
| return max_resources_per_entry == 100; |
| } |
| |
| bool ResourcePrefetchPredictorConfig::IsSmallDBEnabledForTest() const { |
| return max_urls_to_track == 200 && max_hosts_to_track == 100; |
| } |
| |
| } // namespace predictors |