This source file includes following definitions.
- MaxNonNetworkDnsLookupDuration
- EnablePredictorDetailedLog
- was_linked_
- NeedsDnsUpdate
- set_cache_expiration
- get_cache_expiration
- SetQueuedState
- SetAssignedState
- RemoveFromQueue
- SetPendingDeleteState
- SetFoundState
- SetNoSuchNameState
- SetUrl
- IsStillCached
- DLogResultsStats
- RemoveJs
- maximum_
- sample
- minimum
- maximum
- average
- sum
- standard_deviation
- HoursMinutesSeconds
- GetHtmlTable
- SetMotivation
- GetAsciiMotivation
#include "chrome/browser/net/url_info.h"
#include <ctype.h>
#include <math.h>
#include <algorithm>
#include <string>
#include "base/format_macros.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/strings/stringprintf.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
namespace chrome_browser_net {
namespace {
const int kMaxGuaranteedDnsCacheSize = 50;
const int kDefaultCacheExpirationDuration = 5;
TimeDelta MaxNonNetworkDnsLookupDuration() {
return TimeDelta::FromMilliseconds(15);
}
bool detailed_logging_enabled = false;
struct GlobalState {
GlobalState() {
cache_expiration_duration =
TimeDelta::FromSeconds(kDefaultCacheExpirationDuration);
}
TimeDelta cache_expiration_duration;
};
base::LazyInstance<GlobalState>::Leaky global_state;
}
void EnablePredictorDetailedLog(bool enable) {
detailed_logging_enabled = enable;
}
int UrlInfo::sequence_counter = 1;
UrlInfo::UrlInfo()
: state_(PENDING),
old_prequeue_state_(state_),
resolve_duration_(NullDuration()),
queue_duration_(NullDuration()),
sequence_number_(0),
motivation_(NO_PREFETCH_MOTIVATION),
was_linked_(false) {
}
UrlInfo::~UrlInfo() {}
bool UrlInfo::NeedsDnsUpdate() {
switch (state_) {
case PENDING:
return true;
case QUEUED:
case ASSIGNED:
case ASSIGNED_BUT_MARKED:
return false;
case NO_SUCH_NAME:
case FOUND:
return !IsStillCached();
default:
NOTREACHED();
return false;
}
}
void UrlInfo::set_cache_expiration(TimeDelta time) {
global_state.Pointer()->cache_expiration_duration = time;
}
TimeDelta UrlInfo::get_cache_expiration() {
return global_state.Get().cache_expiration_duration;
}
void UrlInfo::SetQueuedState(ResolutionMotivation motivation) {
DCHECK(PENDING == state_ || FOUND == state_ || NO_SUCH_NAME == state_);
old_prequeue_state_ = state_;
state_ = QUEUED;
queue_duration_ = resolve_duration_ = NullDuration();
SetMotivation(motivation);
GetDuration();
DLogResultsStats("DNS Prefetch in queue");
}
void UrlInfo::SetAssignedState() {
DCHECK(QUEUED == state_);
state_ = ASSIGNED;
queue_duration_ = GetDuration();
DLogResultsStats("DNS Prefetch assigned");
UMA_HISTOGRAM_TIMES("DNS.PrefetchQueue", queue_duration_);
}
void UrlInfo::RemoveFromQueue() {
DCHECK(ASSIGNED == state_);
state_ = old_prequeue_state_;
DLogResultsStats("DNS Prefetch reset to prequeue");
const TimeDelta kBoundary = TimeDelta::FromSeconds(2);
if (queue_duration_ > kBoundary) {
UMA_HISTOGRAM_MEDIUM_TIMES("DNS.QueueRecycledDeltaOver2",
queue_duration_ - kBoundary);
return;
}
static const size_t kBucketCount = 52;
static base::HistogramBase* histogram(NULL);
if (!histogram)
histogram = base::LinearHistogram::FactoryTimeGet(
"DNS.QueueRecycledUnder2", TimeDelta(), kBoundary, kBucketCount,
base::HistogramBase::kUmaTargetedHistogramFlag);
histogram->AddTime(queue_duration_);
}
void UrlInfo::SetPendingDeleteState() {
DCHECK(ASSIGNED == state_ || ASSIGNED_BUT_MARKED == state_);
state_ = ASSIGNED_BUT_MARKED;
}
void UrlInfo::SetFoundState() {
DCHECK(ASSIGNED == state_);
state_ = FOUND;
resolve_duration_ = GetDuration();
const TimeDelta max_duration = MaxNonNetworkDnsLookupDuration();
if (max_duration <= resolve_duration_) {
UMA_HISTOGRAM_CUSTOM_TIMES("DNS.PrefetchResolution", resolve_duration_,
max_duration, TimeDelta::FromMinutes(15), 100);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchFound");
}
void UrlInfo::SetNoSuchNameState() {
DCHECK(ASSIGNED == state_);
state_ = NO_SUCH_NAME;
resolve_duration_ = GetDuration();
if (MaxNonNetworkDnsLookupDuration() <= resolve_duration_) {
DHISTOGRAM_TIMES("DNS.PrefetchNotFoundName", resolve_duration_);
}
sequence_number_ = sequence_counter++;
DLogResultsStats("DNS PrefetchNotFound");
}
void UrlInfo::SetUrl(const GURL& url) {
if (url_.is_empty())
url_ = url;
else
DCHECK_EQ(url_, url);
}
bool UrlInfo::IsStillCached() const {
DCHECK(FOUND == state_ || NO_SUCH_NAME == state_);
if (sequence_counter - sequence_number_ > kMaxGuaranteedDnsCacheSize)
return false;
TimeDelta time_since_resolution = TimeTicks::Now() - time_;
return time_since_resolution < global_state.Get().cache_expiration_duration;
}
void UrlInfo::DLogResultsStats(const char* message) const {
if (!detailed_logging_enabled)
return;
DVLOG(1) << "\t" << message << "\tq=" << queue_duration().InMilliseconds()
<< "ms,\tr=" << resolve_duration().InMilliseconds()
<< "ms,\tp=" << sequence_number_ << "\t" << url_.spec();
}
static std::string RemoveJs(const std::string& text) {
std::string output(text);
size_t length = output.length();
for (size_t i = 0; i < length; i++) {
char next = output[i];
if (isalnum(next) || isspace(next) || strchr(".-:/", next) != NULL)
continue;
output[i] = '?';
}
return output;
}
class MinMaxAverage {
public:
MinMaxAverage()
: sum_(0), square_sum_(0), count_(0),
minimum_(kint64max), maximum_(kint64min) {
}
int sample(int64 value) {
sum_ += value;
square_sum_ += value * value;
count_++;
minimum_ = std::min(minimum_, value);
maximum_ = std::max(maximum_, value);
return static_cast<int>(value);
}
int minimum() const { return static_cast<int>(minimum_); }
int maximum() const { return static_cast<int>(maximum_); }
int average() const { return static_cast<int>(sum_/count_); }
int sum() const { return static_cast<int>(sum_); }
int standard_deviation() const {
double average = static_cast<float>(sum_) / count_;
double variance = static_cast<float>(square_sum_)/count_
- average * average;
return static_cast<int>(floor(sqrt(variance) + .5));
}
private:
int64 sum_;
int64 square_sum_;
int count_;
int64 minimum_;
int64 maximum_;
};
static std::string HoursMinutesSeconds(int seconds) {
std::string result;
int print_seconds = seconds % 60;
int minutes = seconds / 60;
int print_minutes = minutes % 60;
int print_hours = minutes/60;
if (print_hours)
base::StringAppendF(&result, "%.2d:", print_hours);
if (print_hours || print_minutes)
base::StringAppendF(&result, "%2.2d:", print_minutes);
base::StringAppendF(&result, "%2.2d", print_seconds);
return result;
}
void UrlInfo::GetHtmlTable(const UrlInfoTable& host_infos,
const char* description,
bool brief,
std::string* output) {
if (0 == host_infos.size())
return;
output->append(description);
base::StringAppendF(output, "%" PRIuS " %s", host_infos.size(),
(1 == host_infos.size()) ? "hostname" : "hostnames");
if (brief) {
output->append("<br><br>");
return;
}
output->append("<br><table border=1>"
"<tr><th>Host name</th>"
"<th>How long ago<br>(HH:MM:SS)</th>"
"<th>Motivation</th>"
"</tr>");
const char* row_format = "<tr align=right><td>%s</td>"
"<td>%s</td>"
"<td>%s</td>"
"</tr>";
MinMaxAverage queue, when;
TimeTicks current_time = TimeTicks::Now();
for (UrlInfoTable::const_iterator it(host_infos.begin());
it != host_infos.end(); it++) {
queue.sample((it->queue_duration_.InMilliseconds()));
base::StringAppendF(
output,
row_format,
RemoveJs(it->url_.spec()).c_str(),
HoursMinutesSeconds(when.sample(
(current_time - it->time_).InSeconds())).c_str(),
it->GetAsciiMotivation().c_str());
}
output->append("</table>");
#ifndef NDEBUG
base::StringAppendF(
output,
"Prefetch Queue Durations: min=%d, avg=%d, max=%d<br><br>",
queue.minimum(), queue.average(), queue.maximum());
#endif
output->append("<br>");
}
void UrlInfo::SetMotivation(ResolutionMotivation motivation) {
motivation_ = motivation;
if (motivation < LINKED_MAX_MOTIVATED)
was_linked_ = true;
}
std::string UrlInfo::GetAsciiMotivation() const {
switch (motivation_) {
case MOUSE_OVER_MOTIVATED:
return "[mouse-over]";
case PAGE_SCAN_MOTIVATED:
return "[page scan]";
case OMNIBOX_MOTIVATED:
return "[omnibox]";
case STARTUP_LIST_MOTIVATED:
return "[startup list]";
case NO_PREFETCH_MOTIVATION:
return "n/a";
case STATIC_REFERAL_MOTIVATED:
return RemoveJs(referring_url_.spec()) + "*";
case LEARNED_REFERAL_MOTIVATED:
return RemoveJs(referring_url_.spec());
default:
return std::string();
}
}
}