1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/url_info.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <math.h>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/format_macros.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/histogram.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeTicks;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chrome_browser_net {
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool detailed_logging_enabled = false;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use command line switch to enable detailed logging.
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid EnablePredictorDetailedLog(bool enable) {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  detailed_logging_enabled = enable;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint UrlInfo::sequence_counter = 1;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickUrlInfo::UrlInfo()
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    : state_(PENDING),
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      old_prequeue_state_(state_),
36731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      resolve_duration_(kNullDuration),
37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      queue_duration_(kNullDuration),
38731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      sequence_number_(0),
39731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      motivation_(NO_PREFETCH_MOTIVATION),
40731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      was_linked_(false) {
41731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
42731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
43731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickUrlInfo::~UrlInfo() {}
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UrlInfo::NeedsDnsUpdate() {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (state_) {
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PENDING:  // Just now created info.
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case QUEUED:  // In queue.
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case ASSIGNED:  // It's being resolved.
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case ASSIGNED_BUT_MARKED:  // It's being resolved.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;  // We're already working on it
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NO_SUCH_NAME:  // Lookup failed.
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case FOUND:  // Lookup succeeded.
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return !IsStillCached();  // See if DNS cache expired.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NOTREACHED();
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst TimeDelta UrlInfo::kNullDuration(TimeDelta::FromMilliseconds(-1));
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Common low end TTL for sites is 5 minutes.  However, DNS servers give us
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the remaining time, not the original 5 minutes.  Hence it doesn't much matter
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// whether we found something in the local cache, or an ISP cache, it will
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// on average be 2.5 minutes before it expires.  We could try to model this with
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 180 seconds, but simpler is just to do the lookups all the time (wasting
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// OS calls(?)), and let that OS cache decide what to do (with TTL in hand).
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We use a small time to help get some duplicate suppression, in case a page
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// has a TON of copies of the same domain name, so that we don't thrash the OS
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// to death.  Hopefully it is small enough that we're not hurting our cache hit
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// rate (i.e., we could always ask the OS).
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTimeDelta UrlInfo::cache_expiration_duration_(TimeDelta::FromSeconds(5));
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst TimeDelta UrlInfo::kMaxNonNetworkDnsLookupDuration(
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeDelta::FromMilliseconds(15));
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Used by test ONLY.  The value is otherwise constant.
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::set_cache_expiration(TimeDelta time) {
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  cache_expiration_duration_ = time;
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickTimeDelta UrlInfo::get_cache_expiration() {
903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return cache_expiration_duration_;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetQueuedState(ResolutionMotivation motivation) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(PENDING == state_ || FOUND == state_ || NO_SUCH_NAME == state_);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  old_prequeue_state_ = state_;
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = QUEUED;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  queue_duration_ = resolve_duration_ = kNullDuration;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetMotivation(motivation);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetDuration();  // Set time_
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DLogResultsStats("DNS Prefetch in queue");
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetAssignedState() {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(QUEUED == state_);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = ASSIGNED;
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  queue_duration_ = GetDuration();
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DLogResultsStats("DNS Prefetch assigned");
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("DNS.PrefetchQueue", queue_duration_);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::RemoveFromQueue() {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ASSIGNED == state_);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = old_prequeue_state_;
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DLogResultsStats("DNS Prefetch reset to prequeue");
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const TimeDelta kBoundary = TimeDelta::FromSeconds(2);
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (queue_duration_ > kBoundary) {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_MEDIUM_TIMES("DNS.QueueRecycledDeltaOver2",
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               queue_duration_ - kBoundary);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make a custom linear histogram for the region from 0 to boundary.
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const size_t kBucketCount = 52;
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  static base::Histogram* histogram(NULL);
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!histogram)
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    histogram = base::LinearHistogram::FactoryTimeGet(
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        "DNS.QueueRecycledUnder2", TimeDelta(), kBoundary, kBucketCount,
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        base::Histogram::kUmaTargetedHistogramFlag);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  histogram->AddTime(queue_duration_);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetPendingDeleteState() {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ASSIGNED == state_  || ASSIGNED_BUT_MARKED == state_);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = ASSIGNED_BUT_MARKED;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetFoundState() {
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ASSIGNED == state_);
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = FOUND;
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resolve_duration_ = GetDuration();
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (kMaxNonNetworkDnsLookupDuration <= resolve_duration_) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UMA_HISTOGRAM_CUSTOM_TIMES("DNS.PrefetchResolution", resolve_duration_,
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kMaxNonNetworkDnsLookupDuration, TimeDelta::FromMinutes(15), 100);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sequence_number_ = sequence_counter++;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DLogResultsStats("DNS PrefetchFound");
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetNoSuchNameState() {
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ASSIGNED == state_);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = NO_SUCH_NAME;
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resolve_duration_ = GetDuration();
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (kMaxNonNetworkDnsLookupDuration <= resolve_duration_) {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DHISTOGRAM_TIMES("DNS.PrefetchNotFoundName", resolve_duration_);
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sequence_number_ = sequence_counter++;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DLogResultsStats("DNS PrefetchNotFound");
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetUrl(const GURL& url) {
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (url_.is_empty())  // Not yet initialized.
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_ = url;
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_EQ(url_, url);
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// IsStillCached() guesses if the DNS cache still has IP data,
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// or at least remembers results about "not finding host."
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UrlInfo::IsStillCached() const {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(FOUND == state_ || NO_SUCH_NAME == state_);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Default MS OS does not cache failures. Hence we could return false almost
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // all the time for that case.  However, we'd never try again to prefetch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the value if we returned false that way.  Hence we'll just let the lookup
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // time out the same way as FOUND case.
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (sequence_counter - sequence_number_ > kMaxGuaranteedDnsCacheSize)
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeDelta time_since_resolution = TimeTicks::Now() - time_;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return time_since_resolution < cache_expiration_duration_;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::DLogResultsStats(const char* message) const {
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!detailed_logging_enabled)
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DVLOG(1) << "\t" << message << "\tq=" << queue_duration().InMilliseconds()
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           << "ms,\tr=" << resolve_duration().InMilliseconds()
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           << "ms,\tp=" << sequence_number_ << "\t" << url_.spec();
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This last section supports HTML output, such as seen in about:dns.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Preclude any possibility of Java Script or markup in the text, by only
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// allowing alphanumerics, '.', '-', ':', and whitespace.
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string RemoveJs(const std::string& text) {
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string output(text);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t length = output.length();
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < length; i++) {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    char next = output[i];
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (isalnum(next) || isspace(next) || strchr(".-:/", next) != NULL)
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      continue;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    output[i] = '?';
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return output;
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass MinMaxAverage {
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MinMaxAverage()
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : sum_(0), square_sum_(0), count_(0),
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      minimum_(kint64max), maximum_(kint64min) {
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Return values for use in printf formatted as "%d"
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int sample(int64 value) {
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sum_ += value;
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    square_sum_ += value * value;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    count_++;
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    minimum_ = std::min(minimum_, value);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    maximum_ = std::max(maximum_, value);
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return static_cast<int>(value);
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int minimum() const { return static_cast<int>(minimum_);    }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int maximum() const { return static_cast<int>(maximum_);    }
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int average() const { return static_cast<int>(sum_/count_); }
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int     sum() const { return static_cast<int>(sum_);        }
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int standard_deviation() const {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double average = static_cast<float>(sum_) / count_;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double variance = static_cast<float>(square_sum_)/count_
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      - average * average;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return static_cast<int>(floor(sqrt(variance) + .5));
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 sum_;
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 square_sum_;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int count_;
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 minimum_;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int64 maximum_;
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DISALLOW_COPY_AND_ASSIGN(MinMaxAverage);
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic std::string HoursMinutesSeconds(int seconds) {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string result;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int print_seconds = seconds % 60;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int minutes = seconds / 60;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int print_minutes = minutes % 60;
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int print_hours = minutes/60;
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (print_hours)
2554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::StringAppendF(&result, "%.2d:",  print_hours);
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (print_hours || print_minutes)
2574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::StringAppendF(&result, "%2.2d:",  print_minutes);
2584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::StringAppendF(&result, "%2.2d",  print_seconds);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid UrlInfo::GetHtmlTable(const UrlInfoTable& host_infos,
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           const char* description,
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           bool brief,
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           std::string* output) {
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (0 == host_infos.size())
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->append(description);
2704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::StringAppendF(output, "%" PRIuS " %s", host_infos.size(),
2714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                      (1 == host_infos.size()) ? "hostname" : "hostnames");
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (brief) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    output->append("<br><br>");
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  output->append("<br><table border=1>"
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "<tr><th>Host name</th>"
2803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "<th>How long ago<br>(HH:MM:SS)</th>"
2813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "<th>Motivation</th>"
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "</tr>");
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const char* row_format = "<tr align=right><td>%s</td>"  // Host name.
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                           "<td>%s</td>"                  // How long ago.
2863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                           "<td>%s</td>"                  // Motivation.
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                           "</tr>";
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Print bulk of table, and gather stats at same time.
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  MinMaxAverage queue, when;
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TimeTicks current_time = TimeTicks::Now();
2923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (UrlInfoTable::const_iterator it(host_infos.begin());
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != host_infos.end(); it++) {
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    queue.sample((it->queue_duration_.InMilliseconds()));
2954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    base::StringAppendF(
2964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        output,
2974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        row_format,
2984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        RemoveJs(it->url_.spec()).c_str(),
2994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                 HoursMinutesSeconds(when.sample(
3004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                     (current_time - it->time_).InSeconds())).c_str(),
3014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        it->GetAsciiMotivation().c_str());
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->append("</table>");
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#ifndef NDEBUG
3064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  base::StringAppendF(
3074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      output,
3084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      "Prefetch Queue Durations: min=%d, avg=%d, max=%d<br><br>",
3094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      queue.minimum(), queue.average(), queue.maximum());
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->append("<br>");
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UrlInfo::SetMotivation(ResolutionMotivation motivation) {
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  motivation_ = motivation;
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (motivation < LINKED_MAX_MOTIVATED)
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    was_linked_ = true;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string UrlInfo::GetAsciiMotivation() const {
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (motivation_) {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case MOUSE_OVER_MOTIVATED:
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "[mouse-over]";
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case PAGE_SCAN_MOTIVATED:
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "[page scan]";
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case OMNIBOX_MOTIVATED:
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "[omnibox]";
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case STARTUP_LIST_MOTIVATED:
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "[startup list]";
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case NO_PREFETCH_MOTIVATION:
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "n/a";
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case STATIC_REFERAL_MOTIVATED:
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return RemoveJs(referring_url_.spec()) + "*";
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case LEARNED_REFERAL_MOTIVATED:
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return RemoveJs(referring_url_.spec());
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return "";
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace chrome_browser_net
350