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

Unified Diff: net/http/http_cache_transaction.cc

Issue 10808047: Add HttpCache histograms focussed on blocking and transaction type. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: ... how about a fix that compiles. Created 8 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/http/http_cache_transaction.h ('k') | net/http/mock_http_cache.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/http_cache_transaction.cc
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 7dd8ecfae9c9d5b631216946d9906127124d134c..a52309b69552081b74a8300b3c045d9b86b1bd53 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -40,6 +40,16 @@ using base::Time;
using base::TimeDelta;
using base::TimeTicks;
+namespace {
+
+// The cutoff for tagging small transactions in histograms; this size was chosen
+// to cover resources likely to be received in a single TCP window. With an
+// initial CWND of 10, and an MTU of 1500 bytes, with TCP and HTTP framing
+// overhead this is a size relatively likely to take only one RTT.
+const int kSmallResourceMaxBytes = 14 * 1024;
+
+} // namespace
+
namespace net {
struct HeaderNameAndValue {
@@ -130,6 +140,9 @@ HttpCache::Transaction::Transaction(
ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
base::Bind(&Transaction::OnIOComplete,
weak_factory_.GetWeakPtr()))),
+ transaction_pattern_(PATTERN_UNDEFINED),
+ bytes_read_from_cache_(0),
+ bytes_read_from_network_(0),
transaction_delegate_(transaction_delegate) {
COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
arraysize(kValidationHeaders),
@@ -326,6 +339,7 @@ int HttpCache::Transaction::Read(IOBuffer* buf, int buf_len,
// user wishes to read the network response (the error page). If there is a
// previous response in the cache then we should leave it intact.
if (auth_response_.headers && mode_ != NONE) {
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
DCHECK(mode_ & WRITE);
DoneWritingToEntry(mode_ == READ_WRITE);
mode_ = NONE;
@@ -724,6 +738,8 @@ int HttpCache::Transaction::DoSendRequest() {
DCHECK(mode_ & WRITE || mode_ == NONE);
DCHECK(!network_trans_.get());
+ send_request_since_ = TimeTicks::Now();
+
// Create a network transaction.
int rv = cache_->network_layer_->CreateTransaction(&network_trans_, NULL);
if (rv != OK)
@@ -743,6 +759,8 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) {
return OK;
}
+ // Do not record requests that have network errors or restarts.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
if (IsCertificateError(result)) {
const HttpResponseInfo* response = network_trans_->GetResponseInfo();
// If we get a certificate error, then there is a certificate in ssl_info,
@@ -773,24 +791,29 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// If we have an authentication response, we are exposed to weird things
// hapenning if the user cancels the authentication before we receive
// the new response.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
response_ = HttpResponseInfo();
network_trans_.reset();
new_response_ = NULL;
next_state_ = STATE_SEND_REQUEST;
return OK;
}
+ bytes_read_from_network_ += new_response_->headers->raw_headers().size();
if (handling_206_ && mode_ == READ_WRITE && !truncated_ && !is_sparse_) {
// We have stored the full entry, but it changed and the server is
// sending a range. We have to delete the old entry.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
DoneWritingToEntry(false);
}
-
if (new_response_->headers->response_code() == 416) {
DCHECK_EQ(NONE, mode_);
response_ = *new_response_;
return OK;
}
+ if (mode_ == WRITE)
+ UpdateTransactionPattern(PATTERN_ENTRY_NOT_CACHED);
+
if (mode_ == WRITE &&
(request_->method == "PUT" || request_->method == "DELETE")) {
if (new_response->headers->response_code() == 200) {
@@ -803,9 +826,11 @@ int HttpCache::Transaction::DoSuccessfulSendRequest() {
// Are we expecting a response to a conditional query?
if (mode_ == READ_WRITE || mode_ == UPDATE) {
if (new_response->headers->response_code() == 304 || handling_206_) {
+ UpdateTransactionPattern(PATTERN_ENTRY_VALIDATED);
next_state_ = STATE_UPDATE_CACHED_RESPONSE;
return OK;
}
+ UpdateTransactionPattern(PATTERN_ENTRY_UPDATED);
mode_ = WRITE;
}
@@ -824,6 +849,9 @@ int HttpCache::Transaction::DoNetworkReadComplete(int result) {
if (!cache_)
return ERR_UNEXPECTED;
+ if (result > 0)
+ bytes_read_from_network_ += result;
+
// If there is an error or we aren't saving the data, we are done; just wait
// until the destructor runs to see if we can keep the data.
if (mode_ == NONE || result < 0)
@@ -853,6 +881,7 @@ int HttpCache::Transaction::DoOpenEntry() {
next_state_ = STATE_OPEN_ENTRY_COMPLETE;
cache_pending_ = true;
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
+ first_cache_access_since_ = TimeTicks::Now();
ReportCacheActionStart();
return cache_->OpenEntry(cache_key_, &new_entry_, this);
}
@@ -941,6 +970,8 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) {
int HttpCache::Transaction::DoDoomEntry() {
next_state_ = STATE_DOOM_ENTRY_COMPLETE;
cache_pending_ = true;
+ if (first_cache_access_since_.is_null())
+ first_cache_access_since_ = TimeTicks::Now();
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY);
ReportCacheActionStart();
return cache_->DoomEntry(cache_key_, this);
@@ -953,7 +984,6 @@ int HttpCache::Transaction::DoDoomEntryComplete(int result) {
cache_pending_ = false;
if (result == ERR_CACHE_RACE)
next_state_ = STATE_INIT_ENTRY;
-
return OK;
}
@@ -1239,6 +1269,7 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
&response_, &truncated_)) {
return OnCacheReadError(result, true);
}
+ bytes_read_from_cache_ += result;
// Some resources may have slipped in as truncated when they're not.
int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
@@ -1260,6 +1291,7 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
//
switch (mode_) {
case READ:
+ UpdateTransactionPattern(PATTERN_ENTRY_USED);
result = BeginCacheRead();
break;
case READ_WRITE:
@@ -1333,7 +1365,6 @@ int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
if (result != response_.metadata->size())
return OnCacheReadError(result, false);
-
return OK;
}
@@ -1378,12 +1409,18 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
if (!cache_)
return ERR_UNEXPECTED;
- if (partial_.get())
+ if (partial_.get()) {
+ // Partial requests are confusing to report in histograms because they may
+ // have multiple underlying requests.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
return DoPartialCacheReadCompleted(result);
+ }
if (result > 0) {
read_offset_ += result;
+ bytes_read_from_cache_ += result;
} else if (result == 0) { // End of file.
+ RecordHistograms();
cache_->DoneReadingFromEntry(entry_, this);
entry_ = NULL;
} else {
@@ -1537,6 +1574,7 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log,
}
if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) {
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
partial_.reset(new PartialData);
if (request_->method == "GET" && partial_->Init(request_->extra_headers)) {
// We will be modifying the actual range requested to the server, so
@@ -1608,8 +1646,12 @@ int HttpCache::Transaction::BeginCacheValidation() {
bool skip_validation = effective_load_flags_ & LOAD_PREFERRING_CACHE ||
!RequiresValidation();
- if (truncated_)
+ if (truncated_) {
+ // Truncated entries can cause partial gets, so we shouldn't record this
+ // load in histograms.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
skip_validation = !partial_->initial_validation();
+ }
if (partial_.get() && (is_sparse_ || truncated_) &&
(!partial_->IsCurrentRangeCached() || invalid_range_)) {
@@ -1620,6 +1662,7 @@ int HttpCache::Transaction::BeginCacheValidation() {
}
if (skip_validation) {
+ UpdateTransactionPattern(PATTERN_ENTRY_USED);
if (partial_.get()) {
if (truncated_ || is_sparse_ || !invalid_range_) {
// We are going to return the saved response headers to the caller, so
@@ -1641,6 +1684,7 @@ int HttpCache::Transaction::BeginCacheValidation() {
// Our mode remains READ_WRITE for a conditional request. We'll switch to
// either READ or WRITE mode once we hear back from the server.
if (!ConditionalizeRequest()) {
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
if (partial_.get())
return DoRestartPartialRequest();
@@ -1659,6 +1703,8 @@ int HttpCache::Transaction::BeginPartialCacheValidation() {
!truncated_)
return BeginCacheValidation();
+ // Partial requests should not be recorded in histograms.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
if (range_requested_) {
next_state_ = STATE_CACHE_QUERY_DATA;
return OK;
@@ -1713,6 +1759,7 @@ int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
validator.empty() || validator != external_validation_.values[i]) {
// The externally conditionalized request is not a validation request
// for our existing cache entry. Proceed with caching disabled.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
DoneWritingToEntry(true);
}
}
@@ -1946,6 +1993,7 @@ bool HttpCache::Transaction::ValidatePartialResponse() {
if (failure) {
// We cannot truncate this entry, it has to be deleted.
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
DoomPartialEntry(false);
mode_ = NONE;
if (!reading_ && !partial_->IsLastRange()) {
@@ -1970,6 +2018,7 @@ void HttpCache::Transaction::IgnoreRangeRequest() {
// returned the headers), but we'll just pretend that this request is not
// using the cache and see what happens. Most likely this is the first
// response from the server (it's not changing its mind midway, right?).
+ UpdateTransactionPattern(PATTERN_NOT_COVERED);
if (mode_ & WRITE) {
DoneWritingToEntry(mode_ != WRITE);
} else if (mode_ & READ && entry_) {
@@ -2068,9 +2117,7 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) {
if (!entry_)
return;
- if (cache_->mode() == RECORD)
- DVLOG(1) << "Recorded: " << request_->method << request_->url
- << " status: " << response_.headers->response_code();
+ RecordHistograms();
cache_->DoneWritingToEntry(entry_, success);
entry_ = NULL;
@@ -2185,4 +2232,127 @@ void HttpCache::Transaction::ReportCacheActionFinish() {
transaction_delegate_->OnCacheActionFinish();
}
+void HttpCache::Transaction::UpdateTransactionPattern(
+ TransactionPattern new_transaction_pattern) {
+ if (transaction_pattern_ == PATTERN_NOT_COVERED)
+ return;
+ DCHECK(transaction_pattern_ == PATTERN_UNDEFINED ||
+ new_transaction_pattern == PATTERN_NOT_COVERED);
+ transaction_pattern_ = new_transaction_pattern;
+}
+
+void HttpCache::Transaction::RecordHistograms() {
+ DCHECK_NE(PATTERN_UNDEFINED, transaction_pattern_);
+ if (!cache_ || !cache_->GetCurrentBackend() ||
+ cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE ||
+ cache_->mode() != NORMAL || request_->method != "GET") {
+ return;
+ }
+ UMA_HISTOGRAM_BOOLEAN("HttpCache.HasPattern",
+ transaction_pattern_ != PATTERN_NOT_COVERED);
+ if (transaction_pattern_ == PATTERN_NOT_COVERED)
+ return;
+ DCHECK(!range_requested_);
+ DCHECK(!first_cache_access_since_.is_null());
+
+ TimeDelta total_time = base::TimeTicks::Now() - first_cache_access_since_;
+
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone", total_time);
+
+ bool did_send_request = !send_request_since_.is_null();
+ DCHECK(
+ (did_send_request && (transaction_pattern_ == PATTERN_ENTRY_NOT_CACHED ||
+ transaction_pattern_ == PATTERN_ENTRY_VALIDATED ||
+ transaction_pattern_ == PATTERN_ENTRY_UPDATED)) ||
+ (!did_send_request && transaction_pattern_ == PATTERN_ENTRY_USED));
+
+ int resource_size;
+ if (transaction_pattern_ == PATTERN_ENTRY_NOT_CACHED ||
+ transaction_pattern_ == PATTERN_ENTRY_UPDATED) {
+ resource_size = bytes_read_from_network_;
+ } else {
+ DCHECK(transaction_pattern_ == PATTERN_ENTRY_VALIDATED ||
+ transaction_pattern_ == PATTERN_ENTRY_USED);
+ resource_size = bytes_read_from_cache_;
+ }
+
+ bool is_small_resource = resource_size < kSmallResourceMaxBytes;
+ if (is_small_resource)
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SmallResource", total_time);
+
+ if (!did_send_request) {
+ DCHECK(transaction_pattern_ == PATTERN_ENTRY_USED);
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time);
+ if (is_small_resource) {
+ UMA_HISTOGRAM_TIMES(
+ "HttpCache.AccessToDone.Used.SmallResource", total_time);
+ }
+ return;
+ }
+
+ TimeDelta before_send_time = send_request_since_ - first_cache_access_since_;
+ int before_send_percent =
+ total_time.ToInternalValue() == 0 ? 0
+ : before_send_time * 100 / total_time;
+ DCHECK_LE(0, before_send_percent);
+ DCHECK_GE(100, before_send_percent);
+
+ UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SentRequest", total_time);
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend", before_send_percent);
+ if (is_small_resource) {
+ UMA_HISTOGRAM_TIMES(
+ "HttpCache.AccessToDone.SentRequest.SmallResource", total_time);
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.SmallResource", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.SmallResource", before_send_percent);
+ }
+
+ // TODO(gavinp): Remove or minimize these histograms, particularly the ones
+ // below this comment after we have received initial data.
+ switch (transaction_pattern_) {
+ case PATTERN_ENTRY_NOT_CACHED: {
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.NotCached", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.NotCached", before_send_percent);
+ if (is_small_resource) {
+ UMA_HISTOGRAM_TIMES(
+ "HttpCache.BeforeSend.NotCached.SmallResource", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.NotCached.SmallResource",
+ before_send_percent);
+ }
+ break;
+ }
+ case PATTERN_ENTRY_VALIDATED: {
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Validated", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.Validated", before_send_percent);
+ if (is_small_resource) {
+ UMA_HISTOGRAM_TIMES(
+ "HttpCache.BeforeSend.Validated.SmallResource", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.Validated.SmallResource",
+ before_send_percent);
+ }
+ break;
+ }
+ case PATTERN_ENTRY_UPDATED: {
+ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Updated", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.Updated", before_send_percent);
+ if (is_small_resource) {
+ UMA_HISTOGRAM_TIMES(
+ "HttpCache.BeforeSend.Updated.SmallResource", before_send_time);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "HttpCache.PercentBeforeSend.Updated.SmallResource",
+ before_send_percent);
+ }
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
} // namespace net
« no previous file with comments | « net/http/http_cache_transaction.h ('k') | net/http/mock_http_cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698