Chromium Code Reviews| Index: net/http/http_cache_transaction.cc |
| diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc |
| index 652a3b26b6d136d0a7fa3d8926deb9841f940582..80b5a8b3d099c7074576672dd4c7450bd493005d 100644 |
| --- a/net/http/http_cache_transaction.cc |
| +++ b/net/http/http_cache_transaction.cc |
| @@ -41,6 +41,19 @@ using base::TimeTicks; |
| namespace net { |
| +namespace { |
|
rvargas (doing something else)
2012/07/21 02:24:21
Move this outside of net
gavinp
2012/07/25 01:07:01
Done. You didn't say why: is it because it doesn't
rvargas (doing something else)
2012/07/25 19:41:04
In part because it's the common pattern everywhere
|
| + |
| +// 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; |
| + |
| +// Requests faster than this do not report as many performance histograms. |
| +const int kFastRequestCutoffMs = 5; |
| + |
| +} |
| + |
| struct HeaderNameAndValue { |
| const char* name; |
| const char* value; |
| @@ -126,7 +139,8 @@ HttpCache::Transaction::Transaction(HttpCache* cache) |
| ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), |
| ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_( |
| base::Bind(&Transaction::OnIOComplete, |
| - weak_factory_.GetWeakPtr()))) { |
| + weak_factory_.GetWeakPtr()))), |
| + disposition_(DISPOSITION_UNDEFINED) { |
| COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders == |
| arraysize(kValidationHeaders), |
| Invalid_number_of_validation_headers); |
| @@ -670,6 +684,8 @@ int HttpCache::Transaction::DoGetBackendComplete(int result) { |
| if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) { |
| mode_ = READ; |
| } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) { |
| + // Don't record a load that isn't really testing the cache. |
|
rvargas (doing something else)
2012/07/21 02:24:21
This goes through the cache.
gavinp
2012/07/25 01:07:01
Good point. Comment fixed. Srsly fixed.
|
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| mode_ = WRITE; |
| } else { |
| mode_ = READ_WRITE; |
| @@ -718,6 +734,8 @@ int HttpCache::Transaction::DoSendRequest() { |
| DCHECK(mode_ & WRITE || mode_ == NONE); |
| DCHECK(!network_trans_.get()); |
| + started_reading_since_ = TimeTicks::Now(); |
|
rvargas (doing something else)
2012/07/21 02:24:21
The name is weird for what it is measuring.
gavinp
2012/07/25 01:07:01
Yup. Do you like the new name and use?
|
| + |
| // Create a network transaction. |
| int rv = cache_->network_layer_->CreateTransaction(&network_trans_); |
| if (rv != OK) |
| @@ -737,6 +755,8 @@ int HttpCache::Transaction::DoSendRequestComplete(int result) { |
| return OK; |
| } |
| + // Do not record requests that have network errors or restarts. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| if (IsCertificateError(result)) { |
| const HttpResponseInfo* response = network_trans_->GetResponseInfo(); |
| // If we get a certificate error, then there is a certificate in ssl_info, |
| @@ -767,6 +787,7 @@ 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. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| response_ = HttpResponseInfo(); |
| network_trans_.reset(); |
| new_response_ = NULL; |
| @@ -797,9 +818,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_) { |
| + MaybeUpdateDisposition(DISPOSITION_ENTRY_VALIDATED_304); |
|
rvargas (doing something else)
2012/07/21 02:24:21
This is more than just 304. Why not drop the 304 p
gavinp
2012/07/25 01:07:01
Done, the new more consistant names are good. Than
rvargas (doing something else)
2012/07/25 19:41:04
No other case, but to know that 206 doesn't matter
|
| next_state_ = STATE_UPDATE_CACHED_RESPONSE; |
| return OK; |
| } |
| + MaybeUpdateDisposition(DISPOSITION_ENTRY_VALIDATED_200); |
|
rvargas (doing something else)
2012/07/21 02:24:21
What about names that match the histogram? used, v
gavinp
2012/07/25 01:07:01
Done.
|
| mode_ = WRITE; |
| } |
| @@ -847,6 +870,7 @@ int HttpCache::Transaction::DoOpenEntry() { |
| next_state_ = STATE_OPEN_ENTRY_COMPLETE; |
| cache_pending_ = true; |
| net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY); |
| + open_entry_since_ = TimeTicks::Now(); |
| return cache_->OpenEntry(cache_key_, &new_entry_, this); |
| } |
| @@ -866,6 +890,7 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
| return OK; |
| } |
| + MaybeUpdateDisposition(DISPOSITION_NO_ENTRY); |
| if (request_->method == "PUT" || request_->method == "DELETE") { |
| DCHECK(mode_ == READ_WRITE || mode_ == WRITE); |
| mode_ = NONE; |
| @@ -1239,6 +1264,8 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { |
| // |
| switch (mode_) { |
| case READ: |
| + MaybeUpdateDisposition(DISPOSITION_ENTRY_UNCONDITIONALLY_USED); |
| + started_reading_since_ = TimeTicks::Now(); |
|
rvargas (doing something else)
2012/07/21 02:24:21
Now I'm confused about what do you want to measure
gavinp
2012/07/25 01:07:01
You're right, it was too confusing. I came into th
|
| result = BeginCacheRead(); |
| break; |
| case READ_WRITE: |
| @@ -1346,12 +1373,17 @@ 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. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| return DoPartialCacheReadCompleted(result); |
| + } |
| if (result > 0) { |
| read_offset_ += result; |
| } else if (result == 0) { // End of file. |
| + RecordHistograms(read_offset_); |
| cache_->DoneReadingFromEntry(entry_, this); |
| entry_ = NULL; |
| } else { |
| @@ -1499,6 +1531,7 @@ void HttpCache::Transaction::SetRequest(const BoundNetLog& net_log, |
| } |
| if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) { |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| 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 |
| @@ -1570,13 +1603,19 @@ 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. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| skip_validation = !partial_->initial_validation(); |
| + } |
| if ((partial_.get() && !partial_->IsCurrentRangeCached()) || invalid_range_) |
| skip_validation = false; |
| if (skip_validation) { |
| + MaybeUpdateDisposition(DISPOSITION_ENTRY_UNCONDITIONALLY_USED); |
| + started_reading_since_ = TimeTicks::Now(); |
| if (partial_.get()) { |
| // We are going to return the saved response headers to the caller, so |
| // we may need to adjust them first. |
| @@ -1594,6 +1633,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()) { |
| + MaybeUpdateDisposition(DISPOSITION_ENTRY_UNCONDITIONALLY_USED); |
| DCHECK(!partial_.get()); |
| DCHECK_NE(206, response_.headers->response_code()); |
| mode_ = WRITE; |
| @@ -1610,6 +1650,8 @@ int HttpCache::Transaction::BeginPartialCacheValidation() { |
| !truncated_) |
| return BeginCacheValidation(); |
| + // Partial requests should not be recorded in histograms. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| if (range_requested_) { |
| next_state_ = STATE_CACHE_QUERY_DATA; |
| return OK; |
| @@ -1670,6 +1712,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. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| DoneWritingToEntry(true); |
| } |
| } |
| @@ -1893,6 +1936,7 @@ bool HttpCache::Transaction::ValidatePartialResponse() { |
| if (failure) { |
| // We cannot truncate this entry, it has to be deleted. |
| + MaybeUpdateDisposition(DISPOSITION_DO_NOT_RECORD); |
| DoomPartialEntry(false); |
| mode_ = NONE; |
| if (!reading_ && !partial_->IsLastRange()) { |
| @@ -2015,9 +2059,11 @@ void HttpCache::Transaction::DoneWritingToEntry(bool success) { |
| if (!entry_) |
| return; |
| - if (cache_->mode() == RECORD) |
| + RecordHistograms(entry_->disk_entry->GetDataSize(kResponseContentIndex)); |
| + if (cache_->mode() == RECORD) { |
| DVLOG(1) << "Recorded: " << request_->method << request_->url |
|
rvargas (doing something else)
2012/07/21 02:24:21
unrelated: we should just delete this log.
gavinp
2012/07/25 01:07:01
Done.
|
| << " status: " << response_.headers->response_code(); |
| + } |
| cache_->DoneWritingToEntry(entry_, success); |
| entry_ = NULL; |
| @@ -2112,4 +2158,113 @@ void HttpCache::Transaction::OnIOComplete(int result) { |
| DoLoop(result); |
| } |
| +void HttpCache::Transaction::MaybeUpdateDisposition( |
|
rvargas (doing something else)
2012/07/21 02:24:21
Remove the "maybe" part from the name.
gavinp
2012/07/25 01:07:01
Done.
|
| + const Disposition disposition) { |
|
rvargas (doing something else)
2012/07/21 02:24:21
Drop the const
gavinp
2012/07/25 01:07:01
Done.
|
| + // Once a transaction has been found to have a complicated disposition, it |
| + // can't change to any other simpler disposition. |
| + if (disposition_ == DISPOSITION_DO_NOT_RECORD) |
|
rvargas (doing something else)
2012/07/21 02:24:21
is this really worth the extra work?. We could jus
gavinp
2012/07/25 01:07:01
Done. Having both and the DCHECK was very good for
gavinp
2012/07/25 14:00:27
I should have updated this comment before uploadin
|
| + return; |
| + DCHECK(disposition_ == DISPOSITION_UNDEFINED || |
| + disposition == DISPOSITION_DO_NOT_RECORD); |
|
rvargas (doing something else)
2012/07/21 02:24:21
cannot reach do_not_record
gavinp
2012/07/25 01:07:01
Hrm, you are wrong. Does this mean I'm naming my p
rvargas (doing something else)
2012/07/25 19:41:04
Why am I wrong? the previous line returns if p_not
gavinp
2012/07/28 01:36:06
The previous line compares the member variable |di
|
| + disposition_ = disposition; |
| +} |
| + |
| +void HttpCache::Transaction::RecordHistograms(const int resource_size) { |
|
rvargas (doing something else)
2012/07/21 02:24:21
Drop the const
gavinp
2012/07/25 01:07:01
Done.
|
| + if (cache_->mode() != NORMAL || request_->method != "GET") |
| + return; |
| + |
| + UMA_HISTOGRAM_BOOLEAN( |
| + "HttpCache.DoNotRecord", disposition_ == DISPOSITION_DO_NOT_RECORD); |
| + if (disposition_ == DISPOSITION_DO_NOT_RECORD) |
| + return; |
| + DCHECK(!range_requested_); |
| + DCHECK_NE(DISPOSITION_UNDEFINED, disposition_); |
|
gavinp
2012/07/20 17:19:24
Should these DCHECKs be changed into early returns
rvargas (doing something else)
2012/07/21 02:24:21
DCHECKS seem file to me.
gavinp
2012/07/25 01:07:01
What I found very interesting was how many differe
|
| + DCHECK(!open_entry_since_.is_null()); |
| + DCHECK(!started_reading_since_.is_null()); |
| + |
| + const TimeDelta before_reading_time = |
|
rvargas (doing something else)
2012/07/21 02:24:21
I also think we should drop the const on these var
gavinp
2012/07/25 01:07:01
Done.
|
| + started_reading_since_ - open_entry_since_; |
| + const TimeDelta reading_time = TimeTicks::Now() - started_reading_since_; |
| + const TimeDelta total_time = before_reading_time + reading_time; |
| + |
| + UMA_HISTOGRAM_TIMES("HttpCache.TimeBlocked", before_reading_time); |
|
rvargas (doing something else)
2012/07/21 02:24:21
This puts together all cache types under the same
|
| + UMA_HISTOGRAM_TIMES("HttpCache.TimeReading", reading_time); |
| + |
| + const bool is_small_resource = resource_size < kSmallResourceMaxBytes; |
|
rvargas (doing something else)
2012/07/21 02:24:21
This is not what the caller is passing... I mean,
gavinp
2012/07/25 01:07:01
Good point. It's also undefined since I don't real
|
| + if (is_small_resource) { |
| + UMA_HISTOGRAM_TIMES( |
| + "HttpCache.TimeBlocked.SmallResource", before_reading_time); |
|
rvargas (doing something else)
2012/07/21 02:24:21
nit: TimeBlocked?
|
| + UMA_HISTOGRAM_TIMES("HttpCache.TimeReading.SmallResource", reading_time); |
| + } |
| + |
| + // The more detailed histograms are only interesting for requests that are not |
|
rvargas (doing something else)
2012/07/21 02:24:21
why?
gavinp
2012/07/25 01:07:01
Good point I had no reason whatsoever to actually
|
| + // fast. |
| + if (total_time.InMilliseconds() < kFastRequestCutoffMs) |
| + return; |
| + |
| + const int before_reading_percent = before_reading_time * 100 / total_time; |
| + DCHECK_LE(0, before_reading_percent); |
| + DCHECK_GE(100, before_reading_percent); |
| + |
| + UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBlocked", before_reading_percent); |
|
rvargas (doing something else)
2012/07/21 02:24:21
nit: Not really blocked
gavinp
2012/07/25 01:07:01
Now named how long before send. The request isn't
|
| + if (is_small_resource) |
| + UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBlocked.SmallResource", |
| + before_reading_percent); |
| + |
| + // TODO(gavinp): Remove or minimize these histograms, particularly the ones |
| + // below this comment after we have received initial data. |
| + switch (disposition_) { |
|
rvargas (doing something else)
2012/07/21 02:24:21
nit: I'm not really happy with the term "dispositi
gavinp
2012/07/25 01:07:01
Now that you point it out, I hate the name too.
T
|
| + case DISPOSITION_NO_ENTRY: { |
| + UMA_HISTOGRAM_TIMES( |
| + "HttpCache.TimeBlocked.NotCached", before_reading_time); |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.NotCached", before_reading_percent); |
|
rvargas (doing something else)
2012/07/21 02:24:21
Id suggest just dropping the absolute times.
gavinp
2012/07/25 01:07:01
You might be right. I'd like to wait for results.
|
| + if (is_small_resource) { |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.NotCached.SmallResource", |
| + before_reading_percent); |
| + } |
| + break; |
| + } |
| + case DISPOSITION_ENTRY_UNCONDITIONALLY_USED: { |
| + UMA_HISTOGRAM_TIMES( |
| + "HttpCache.TimeBlocked.Used", before_reading_time); |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.Used", before_reading_percent); |
| + if (is_small_resource) { |
| + UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBlocked.Used.SmallResource", |
| + before_reading_percent); |
| + } |
| + break; |
| + } |
| + case DISPOSITION_ENTRY_VALIDATED_304: { |
| + UMA_HISTOGRAM_TIMES( |
| + "HttpCache.TimeBlocked.Validated", before_reading_time); |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.Validated", before_reading_percent); |
| + if (is_small_resource) { |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.Validated.SmallResource", |
| + before_reading_percent); |
| + } |
| + break; |
| + } |
| + case DISPOSITION_ENTRY_VALIDATED_200: { |
| + UMA_HISTOGRAM_TIMES( |
| + "HttpCache.TimeBlocked.Updated", before_reading_time); |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.Updated", before_reading_percent); |
| + if (is_small_resource) { |
| + UMA_HISTOGRAM_PERCENTAGE( |
| + "HttpCache.PercentBlocked.Updated.SmallResource", |
| + before_reading_percent); |
| + } |
| + break; |
| + } |
| + case DISPOSITION_UNDEFINED: |
| + default: |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| } // namespace net |