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

Side by Side Diff: content/browser/loader/async_resource_handler.cc

Issue 2762953004: Remove inline small resource transfer experiment (Closed)
Patch Set: Created 3 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/loader/async_resource_handler.h" 5 #include "content/browser/loader/async_resource_handler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/containers/hash_tables.h" 11 #include "base/containers/hash_tables.h"
12 #include "base/debug/alias.h" 12 #include "base/debug/alias.h"
13 #include "base/feature_list.h"
14 #include "base/logging.h" 13 #include "base/logging.h"
15 #include "base/macros.h" 14 #include "base/macros.h"
16 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
17 #include "base/memory/shared_memory.h" 16 #include "base/memory/shared_memory.h"
18 #include "base/metrics/histogram_macros.h" 17 #include "base/metrics/histogram_macros.h"
19 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
20 #include "base/time/time.h" 19 #include "base/time/time.h"
21 #include "content/browser/loader/netlog_observer.h" 20 #include "content/browser/loader/netlog_observer.h"
22 #include "content/browser/loader/resource_buffer.h" 21 #include "content/browser/loader/resource_buffer.h"
23 #include "content/browser/loader/resource_controller.h" 22 #include "content/browser/loader/resource_controller.h"
24 #include "content/browser/loader/resource_dispatcher_host_impl.h" 23 #include "content/browser/loader/resource_dispatcher_host_impl.h"
25 #include "content/browser/loader/resource_message_filter.h" 24 #include "content/browser/loader/resource_message_filter.h"
26 #include "content/browser/loader/resource_request_info_impl.h" 25 #include "content/browser/loader/resource_request_info_impl.h"
27 #include "content/browser/loader/upload_progress_tracker.h" 26 #include "content/browser/loader/upload_progress_tracker.h"
28 #include "content/common/resource_messages.h" 27 #include "content/common/resource_messages.h"
29 #include "content/common/resource_request_completion_status.h" 28 #include "content/common/resource_request_completion_status.h"
30 #include "content/common/view_messages.h" 29 #include "content/common/view_messages.h"
31 #include "content/public/common/content_features.h"
32 #include "content/public/common/resource_response.h" 30 #include "content/public/common/resource_response.h"
33 #include "ipc/ipc_message_macros.h" 31 #include "ipc/ipc_message_macros.h"
34 #include "net/base/io_buffer.h" 32 #include "net/base/io_buffer.h"
35 #include "net/base/load_flags.h" 33 #include "net/base/load_flags.h"
36 #include "net/base/upload_progress.h" 34 #include "net/base/upload_progress.h"
37 #include "net/url_request/redirect_info.h" 35 #include "net/url_request/redirect_info.h"
38 36
39 using base::TimeDelta; 37 using base::TimeDelta;
40 using base::TimeTicks; 38 using base::TimeTicks;
41 39
42 namespace content { 40 namespace content {
43 namespace { 41 namespace {
44 42
45 static int kBufferSize = 1024 * 512; 43 static int kBufferSize = 1024 * 512;
46 static int kMinAllocationSize = 1024 * 4; 44 static int kMinAllocationSize = 1024 * 4;
47 static int kMaxAllocationSize = 1024 * 32; 45 static int kMaxAllocationSize = 1024 * 32;
48 46
49 // Used when kOptimizeLoadingIPCForSmallResources is enabled.
50 // Small resource typically issues two Read call: one for the content itself
51 // and another for getting zero response to detect EOF.
52 // Inline these two into the IPC message to avoid allocating an expensive
53 // SharedMemory for small resources.
54 const int kNumLeadingChunk = 2;
55 const int kInlinedLeadingChunkSize = 2048;
56
57 void GetNumericArg(const std::string& name, int* result) { 47 void GetNumericArg(const std::string& name, int* result) {
58 const std::string& value = 48 const std::string& value =
59 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name); 49 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
60 if (!value.empty()) 50 if (!value.empty())
61 base::StringToInt(value, result); 51 base::StringToInt(value, result);
62 } 52 }
63 53
64 void InitializeResourceBufferConstants() { 54 void InitializeResourceBufferConstants() {
65 static bool did_init = false; 55 static bool did_init = false;
66 if (did_init) 56 if (did_init)
(...skipping 11 matching lines...) Expand all
78 EQ_RESPONSE_BODY_GT_EQ_BUFFER_SIZE = 1, 68 EQ_RESPONSE_BODY_GT_EQ_BUFFER_SIZE = 1,
79 GT_EQ_BUFFER_SIZE = 2, 69 GT_EQ_BUFFER_SIZE = 2,
80 LT_RESPONSE_BODY = 3, 70 LT_RESPONSE_BODY = 3,
81 GT_RESPONSE_BODY = 4, 71 GT_RESPONSE_BODY = 4,
82 UNKNOWN = 5, 72 UNKNOWN = 5,
83 EXPECTED_CONTENT_MAX, 73 EXPECTED_CONTENT_MAX,
84 }; 74 };
85 75
86 } // namespace 76 } // namespace
87 77
88 // Used when kOptimizeLoadingIPCForSmallResources is enabled.
89 // The instance hooks the buffer allocation of AsyncResourceHandler, and
90 // determine if we should use SharedMemory or should inline the data into
91 // the IPC message.
92 class AsyncResourceHandler::InliningHelper {
93 public:
94
95 InliningHelper() {}
96 ~InliningHelper() {}
97
98 void OnResponseReceived(const ResourceResponse& response) {
99 InliningStatus status = IsInliningApplicable(response);
100 UMA_HISTOGRAM_ENUMERATION(
101 "Net.ResourceLoader.InliningStatus",
102 static_cast<int>(status),
103 static_cast<int>(InliningStatus::INLINING_STATUS_COUNT));
104 inlining_applicable_ = status == InliningStatus::APPLICABLE;
105 }
106
107 // Returns true if InliningHelper allocates the buffer for inlining.
108 bool PrepareInlineBufferIfApplicable(scoped_refptr<net::IOBuffer>* buf,
109 int* buf_size) {
110 ++num_allocation_;
111
112 // If the server sends the resource in multiple small chunks,
113 // |num_allocation_| may exceed |kNumLeadingChunk|. Disable inlining and
114 // fall back to the regular resource loading path in that case.
115 if (!inlining_applicable_ ||
116 num_allocation_ > kNumLeadingChunk ||
117 !base::FeatureList::IsEnabled(
118 features::kOptimizeLoadingIPCForSmallResources)) {
119 return false;
120 }
121
122 leading_chunk_buffer_ = new net::IOBuffer(kInlinedLeadingChunkSize);
123 *buf = leading_chunk_buffer_;
124 *buf_size = kInlinedLeadingChunkSize;
125 return true;
126 }
127
128 // Returns true if the received data is sent to the consumer.
129 bool SendInlinedDataIfApplicable(int bytes_read,
130 int encoded_data_length,
131 IPC::Sender* sender,
132 int request_id) {
133 DCHECK(sender);
134 if (!leading_chunk_buffer_)
135 return false;
136
137 std::vector<char> data(
138 leading_chunk_buffer_->data(),
139 leading_chunk_buffer_->data() + bytes_read);
140 leading_chunk_buffer_ = nullptr;
141
142 sender->Send(new ResourceMsg_InlinedDataChunkReceived(
143 request_id, data, encoded_data_length));
144 return true;
145 }
146
147 void RecordHistogram(int64_t elapsed_time) {
148 if (inlining_applicable_) {
149 UMA_HISTOGRAM_CUSTOM_COUNTS(
150 "Net.ResourceLoader.ResponseStartToEnd.InliningApplicable",
151 elapsed_time, 1, 100000, 100);
152 }
153 }
154
155 private:
156 enum class InliningStatus : int {
157 APPLICABLE = 0,
158 EARLY_ALLOCATION = 1,
159 UNKNOWN_CONTENT_LENGTH = 2,
160 LARGE_CONTENT = 3,
161 HAS_TRANSFER_ENCODING = 4,
162 HAS_CONTENT_ENCODING = 5,
163 INLINING_STATUS_COUNT,
164 };
165
166 InliningStatus IsInliningApplicable(const ResourceResponse& response) {
167 // Disable if the leading chunk is already arrived.
168 if (num_allocation_)
169 return InliningStatus::EARLY_ALLOCATION;
170
171 // Disable if the content is known to be large.
172 if (response.head.content_length > kInlinedLeadingChunkSize)
173 return InliningStatus::LARGE_CONTENT;
174
175 // Disable if the length of the content is unknown.
176 if (response.head.content_length < 0)
177 return InliningStatus::UNKNOWN_CONTENT_LENGTH;
178
179 if (response.head.headers) {
180 if (response.head.headers->HasHeader("Transfer-Encoding"))
181 return InliningStatus::HAS_TRANSFER_ENCODING;
182 if (response.head.headers->HasHeader("Content-Encoding"))
183 return InliningStatus::HAS_CONTENT_ENCODING;
184 }
185
186 return InliningStatus::APPLICABLE;
187 }
188
189 int num_allocation_ = 0;
190 bool inlining_applicable_ = false;
191 scoped_refptr<net::IOBuffer> leading_chunk_buffer_;
192 };
193
194 class DependentIOBuffer : public net::WrappedIOBuffer { 78 class DependentIOBuffer : public net::WrappedIOBuffer {
195 public: 79 public:
196 DependentIOBuffer(ResourceBuffer* backing, char* memory) 80 DependentIOBuffer(ResourceBuffer* backing, char* memory)
197 : net::WrappedIOBuffer(memory), 81 : net::WrappedIOBuffer(memory),
198 backing_(backing) { 82 backing_(backing) {
199 } 83 }
200 private: 84 private:
201 ~DependentIOBuffer() override {} 85 ~DependentIOBuffer() override {}
202 scoped_refptr<ResourceBuffer> backing_; 86 scoped_refptr<ResourceBuffer> backing_;
203 }; 87 };
204 88
205 AsyncResourceHandler::AsyncResourceHandler(net::URLRequest* request, 89 AsyncResourceHandler::AsyncResourceHandler(net::URLRequest* request,
206 ResourceDispatcherHostImpl* rdh) 90 ResourceDispatcherHostImpl* rdh)
207 : ResourceHandler(request), 91 : ResourceHandler(request),
208 ResourceMessageDelegate(request), 92 ResourceMessageDelegate(request),
209 rdh_(rdh), 93 rdh_(rdh),
210 pending_data_count_(0), 94 pending_data_count_(0),
211 allocation_size_(0), 95 allocation_size_(0),
212 total_read_body_bytes_(0), 96 total_read_body_bytes_(0),
213 has_checked_for_sufficient_resources_(false), 97 has_checked_for_sufficient_resources_(false),
214 sent_received_response_msg_(false), 98 sent_received_response_msg_(false),
215 sent_data_buffer_msg_(false), 99 sent_data_buffer_msg_(false),
216 inlining_helper_(new InliningHelper),
217 reported_transfer_size_(0) { 100 reported_transfer_size_(0) {
218 DCHECK(GetRequestInfo()->requester_info()->IsRenderer()); 101 DCHECK(GetRequestInfo()->requester_info()->IsRenderer());
219 InitializeResourceBufferConstants(); 102 InitializeResourceBufferConstants();
220 } 103 }
221 104
222 AsyncResourceHandler::~AsyncResourceHandler() { 105 AsyncResourceHandler::~AsyncResourceHandler() {
223 if (has_checked_for_sufficient_resources_) 106 if (has_checked_for_sufficient_resources_)
224 rdh_->FinishedWithResourcesForRequest(request()); 107 rdh_->FinishedWithResourcesForRequest(request());
225 } 108 }
226 109
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head)); 213 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head));
331 sent_received_response_msg_ = true; 214 sent_received_response_msg_ = true;
332 215
333 if (request()->response_info().metadata.get()) { 216 if (request()->response_info().metadata.get()) {
334 std::vector<char> copy(request()->response_info().metadata->data(), 217 std::vector<char> copy(request()->response_info().metadata->data(),
335 request()->response_info().metadata->data() + 218 request()->response_info().metadata->data() +
336 request()->response_info().metadata->size()); 219 request()->response_info().metadata->size());
337 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy)); 220 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy));
338 } 221 }
339 222
340 inlining_helper_->OnResponseReceived(*response);
341 controller->Resume(); 223 controller->Resume();
342 } 224 }
343 225
344 void AsyncResourceHandler::OnWillStart( 226 void AsyncResourceHandler::OnWillStart(
345 const GURL& url, 227 const GURL& url,
346 std::unique_ptr<ResourceController> controller) { 228 std::unique_ptr<ResourceController> controller) {
347 ResourceMessageFilter* filter = GetFilter(); 229 ResourceMessageFilter* filter = GetFilter();
348 if (!filter) { 230 if (!filter) {
349 controller->Cancel(); 231 controller->Cancel();
350 return; 232 return;
(...skipping 14 matching lines...) Expand all
365 scoped_refptr<net::IOBuffer>* buf, 247 scoped_refptr<net::IOBuffer>* buf,
366 int* buf_size, 248 int* buf_size,
367 std::unique_ptr<ResourceController> controller) { 249 std::unique_ptr<ResourceController> controller) {
368 DCHECK(!has_controller()); 250 DCHECK(!has_controller());
369 251
370 if (!CheckForSufficientResource()) { 252 if (!CheckForSufficientResource()) {
371 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); 253 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
372 return; 254 return;
373 } 255 }
374 256
375 // Return early if InliningHelper allocates the buffer, so that we should
376 // inline the data into the IPC message without allocating SharedMemory.
377 if (inlining_helper_->PrepareInlineBufferIfApplicable(buf, buf_size)) {
378 controller->Resume();
379 return;
380 }
381
382 if (!EnsureResourceBufferIsInitialized()) { 257 if (!EnsureResourceBufferIsInitialized()) {
383 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); 258 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES);
384 return; 259 return;
385 } 260 }
386 261
387 DCHECK(buffer_->CanAllocate()); 262 DCHECK(buffer_->CanAllocate());
388 char* memory = buffer_->Allocate(&allocation_size_); 263 char* memory = buffer_->Allocate(&allocation_size_);
389 CHECK(memory); 264 CHECK(memory);
390 265
391 *buf = new DependentIOBuffer(buffer_.get(), memory); 266 *buf = new DependentIOBuffer(buffer_.get(), memory);
(...skipping 18 matching lines...) Expand all
410 controller->Cancel(); 285 controller->Cancel();
411 return; 286 return;
412 } 287 }
413 288
414 int encoded_data_length = CalculateEncodedDataLengthToReport(); 289 int encoded_data_length = CalculateEncodedDataLengthToReport();
415 if (!first_chunk_read_) 290 if (!first_chunk_read_)
416 encoded_data_length -= request()->raw_header_size(); 291 encoded_data_length -= request()->raw_header_size();
417 292
418 first_chunk_read_ = true; 293 first_chunk_read_ = true;
419 294
420 // Return early if InliningHelper handled the received data.
421 if (inlining_helper_->SendInlinedDataIfApplicable(
422 bytes_read, encoded_data_length, filter, GetRequestID())) {
423 controller->Resume();
424 return;
425 }
426
427 buffer_->ShrinkLastAllocation(bytes_read); 295 buffer_->ShrinkLastAllocation(bytes_read);
428 296
429 total_read_body_bytes_ += bytes_read; 297 total_read_body_bytes_ += bytes_read;
430 298
431 if (!sent_data_buffer_msg_) { 299 if (!sent_data_buffer_msg_) {
432 base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle( 300 base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle(
433 buffer_->GetSharedMemory().handle()); 301 buffer_->GetSharedMemory().handle());
434 if (!base::SharedMemory::IsHandleValid(handle)) { 302 if (!base::SharedMemory::IsHandleValid(handle)) {
435 controller->Cancel(); 303 controller->Cancel();
436 return; 304 return;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 // The resource was smaller than single chunk. 448 // The resource was smaller than single chunk.
581 UMA_HISTOGRAM_CUSTOM_COUNTS( 449 UMA_HISTOGRAM_CUSTOM_COUNTS(
582 "Net.ResourceLoader.ResponseStartToEnd.LT_512kB", 450 "Net.ResourceLoader.ResponseStartToEnd.LT_512kB",
583 elapsed_time, 1, 100000, 100); 451 elapsed_time, 1, 100000, 100);
584 } else { 452 } else {
585 UMA_HISTOGRAM_CUSTOM_COUNTS( 453 UMA_HISTOGRAM_CUSTOM_COUNTS(
586 "Net.ResourceLoader.ResponseStartToEnd.Over_512kB", 454 "Net.ResourceLoader.ResponseStartToEnd.Over_512kB",
587 elapsed_time, 1, 100000, 100); 455 elapsed_time, 1, 100000, 100);
588 } 456 }
589 457
590 inlining_helper_->RecordHistogram(elapsed_time);
591
592 // Record if content size was known in advance. 458 // Record if content size was known in advance.
593 int64_t expected_content_size = request()->GetExpectedContentSize(); 459 int64_t expected_content_size = request()->GetExpectedContentSize();
594 ExpectedContentSizeResult expected_content_size_result = 460 ExpectedContentSizeResult expected_content_size_result =
595 ExpectedContentSizeResult::UNKNOWN; 461 ExpectedContentSizeResult::UNKNOWN;
596 if (expected_content_size >= 0) { 462 if (expected_content_size >= 0) {
597 // Compare response body size to expected content size. 463 // Compare response body size to expected content size.
598 if (expected_content_size == total_read_body_bytes_ && 464 if (expected_content_size == total_read_body_bytes_ &&
599 expected_content_size >= kBufferSize) { 465 expected_content_size >= kBufferSize) {
600 expected_content_size_result = 466 expected_content_size_result =
601 ExpectedContentSizeResult::EQ_RESPONSE_BODY_GT_EQ_BUFFER_SIZE; 467 ExpectedContentSizeResult::EQ_RESPONSE_BODY_GT_EQ_BUFFER_SIZE;
(...skipping 19 matching lines...) Expand all
621 void AsyncResourceHandler::SendUploadProgress( 487 void AsyncResourceHandler::SendUploadProgress(
622 const net::UploadProgress& progress) { 488 const net::UploadProgress& progress) {
623 ResourceMessageFilter* filter = GetFilter(); 489 ResourceMessageFilter* filter = GetFilter();
624 if (!filter) 490 if (!filter)
625 return; 491 return;
626 filter->Send(new ResourceMsg_UploadProgress( 492 filter->Send(new ResourceMsg_UploadProgress(
627 GetRequestID(), progress.position(), progress.size())); 493 GetRequestID(), progress.position(), progress.size()));
628 } 494 }
629 495
630 } // namespace content 496 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/async_resource_handler.h ('k') | content/browser/loader/async_resource_handler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698