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

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

Issue 10911297: Modify AsyncResourceHandler to use a single shared memory buffer (in ring (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 3 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 | Annotate | Revision Log
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/renderer_host/async_resource_handler.h" 5 #include "content/browser/renderer_host/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/debug/alias.h" 11 #include "base/debug/alias.h"
11 #include "base/hash_tables.h" 12 #include "base/hash_tables.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
14 #include "base/shared_memory.h" 15 #include "base/shared_memory.h"
16 #include "base/string_number_conversions.h"
15 #include "content/browser/debugger/devtools_netlog_observer.h" 17 #include "content/browser/debugger/devtools_netlog_observer.h"
16 #include "content/browser/host_zoom_map_impl.h" 18 #include "content/browser/host_zoom_map_impl.h"
19 #include "content/browser/renderer_host/resource_buffer.h"
17 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" 20 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
18 #include "content/browser/renderer_host/resource_message_filter.h" 21 #include "content/browser/renderer_host/resource_message_filter.h"
19 #include "content/browser/renderer_host/resource_request_info_impl.h" 22 #include "content/browser/renderer_host/resource_request_info_impl.h"
20 #include "content/browser/resource_context_impl.h" 23 #include "content/browser/resource_context_impl.h"
21 #include "content/common/resource_messages.h" 24 #include "content/common/resource_messages.h"
22 #include "content/common/view_messages.h" 25 #include "content/common/view_messages.h"
23 #include "content/public/browser/global_request_id.h" 26 #include "content/public/browser/global_request_id.h"
24 #include "content/public/browser/resource_dispatcher_host_delegate.h" 27 #include "content/public/browser/resource_dispatcher_host_delegate.h"
25 #include "content/public/common/resource_response.h" 28 #include "content/public/common/resource_response.h"
26 #include "net/base/io_buffer.h" 29 #include "net/base/io_buffer.h"
27 #include "net/base/load_flags.h" 30 #include "net/base/load_flags.h"
28 #include "net/base/net_log.h" 31 #include "net/base/net_log.h"
29 #include "webkit/glue/resource_loader_bridge.h" 32 #include "webkit/glue/resource_loader_bridge.h"
30 33
31 using base::TimeTicks; 34 using base::TimeTicks;
32 35
33 namespace content { 36 namespace content {
34 namespace { 37 namespace {
35 38
36 // When reading, we don't know if we are going to get EOF (0 bytes read), so 39 static int kBufferSize = 1024 * 512;
37 // we typically have a buffer that we allocated but did not use. We keep 40 static int kMinAllocationSize = 1024 * 4;
38 // this buffer around for the next read as a small optimization. 41 static int kMaxAllocationSize = 1024 * 32;
39 SharedIOBuffer* g_spare_read_buffer = NULL;
40 42
41 // The initial size of the shared memory buffer. (32 kilobytes). 43 void GetNumericArg(const std::string& name, int* result) {
42 const int kInitialReadBufSize = 32768; 44 const std::string& value =
45 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
46 if (!value.empty())
47 base::StringToInt(value, result);
48 }
43 49
44 // The maximum size of the shared memory buffer. (512 kilobytes). 50 void InitializeResourceBufferConstants() {
brettw 2012/09/18 04:44:54 This seems to be never called. Maybe you want to c
45 const int kMaxReadBufSize = 524288; 51 static bool did_init = false;
52 if (did_init)
53 return;
54 did_init = true;
46 55
47 // Maximum number of pending data messages sent to the renderer at any 56 GetNumericArg("resource-buffer-size", &kBufferSize);
48 // given time for a given request. 57 GetNumericArg("resource-buffer-min-allocation-size", &kMinAllocationSize);
49 const int kMaxPendingDataMessages = 20; 58 GetNumericArg("resource-buffer-max-allocation-size", &kMaxAllocationSize);
59 }
50 60
51 int CalcUsedPercentage(int bytes_read, int buffer_size) { 61 int CalcUsedPercentage(int bytes_read, int buffer_size) {
52 double ratio = static_cast<double>(bytes_read) / buffer_size; 62 double ratio = static_cast<double>(bytes_read) / buffer_size;
53 return static_cast<int>(ratio * 100.0 + 0.5); // Round to nearest integer. 63 return static_cast<int>(ratio * 100.0 + 0.5); // Round to nearest integer.
54 } 64 }
55 65
56 } // namespace 66 } // namespace
57 67
58 // Our version of IOBuffer that uses shared memory. 68 class DependentIOBuffer : public net::WrappedIOBuffer {
59 class SharedIOBuffer : public net::IOBuffer {
60 public: 69 public:
61 explicit SharedIOBuffer(int buffer_size) 70 DependentIOBuffer(ResourceBuffer* backing, char* memory)
62 : net::IOBuffer(), 71 : net::WrappedIOBuffer(memory),
63 ok_(false), 72 backing_(backing) {
64 buffer_size_(buffer_size) {}
65
66 bool Init() {
67 if (shared_memory_.CreateAndMapAnonymous(buffer_size_)) {
68 data_ = reinterpret_cast<char*>(shared_memory_.memory());
69 DCHECK(data_);
70 ok_ = true;
71 }
72 return ok_;
73 } 73 }
74
75 base::SharedMemory* shared_memory() { return &shared_memory_; }
76 bool ok() { return ok_; }
77 int buffer_size() { return buffer_size_; }
78
79 private: 74 private:
80 ~SharedIOBuffer() { 75 ~DependentIOBuffer() {}
81 DCHECK(g_spare_read_buffer != this); 76 scoped_refptr<ResourceBuffer> backing_;
82 data_ = NULL;
83 }
84
85 base::SharedMemory shared_memory_;
86 bool ok_;
87 int buffer_size_;
88 }; 77 };
89 78
90 AsyncResourceHandler::AsyncResourceHandler( 79 AsyncResourceHandler::AsyncResourceHandler(
91 ResourceMessageFilter* filter, 80 ResourceMessageFilter* filter,
92 int routing_id, 81 int routing_id,
93 net::URLRequest* request, 82 net::URLRequest* request,
94 ResourceDispatcherHostImpl* rdh) 83 ResourceDispatcherHostImpl* rdh)
95 : filter_(filter), 84 : filter_(filter),
96 routing_id_(routing_id), 85 routing_id_(routing_id),
97 request_(request), 86 request_(request),
98 rdh_(rdh), 87 rdh_(rdh),
99 next_buffer_size_(kInitialReadBufSize),
100 pending_data_count_(0), 88 pending_data_count_(0),
89 allocation_size_(0),
101 did_defer_(false), 90 did_defer_(false),
102 sent_received_response_msg_(false) { 91 sent_received_response_msg_(false),
92 sent_first_data_msg_(false) {
103 // Set a back-pointer from ResourceRequestInfoImpl to |this|, so that the 93 // Set a back-pointer from ResourceRequestInfoImpl to |this|, so that the
104 // ResourceDispatcherHostImpl can send us IPC messages. 94 // ResourceDispatcherHostImpl can send us IPC messages.
105 // TODO(darin): Implement an IPC message filter instead? 95 // TODO(darin): Implement an IPC message filter instead?
106 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(this); 96 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(this);
107 } 97 }
108 98
109 AsyncResourceHandler::~AsyncResourceHandler() { 99 AsyncResourceHandler::~AsyncResourceHandler() {
110 // Cleanup back-pointer stored on the request info. 100 // Cleanup back-pointer stored on the request info.
111 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(NULL); 101 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(NULL);
112 } 102 }
113 103
114 void AsyncResourceHandler::OnFollowRedirect( 104 void AsyncResourceHandler::OnFollowRedirect(
115 bool has_new_first_party_for_cookies, 105 bool has_new_first_party_for_cookies,
116 const GURL& new_first_party_for_cookies) { 106 const GURL& new_first_party_for_cookies) {
117 if (!request_->status().is_success()) { 107 if (!request_->status().is_success()) {
118 DVLOG(1) << "OnFollowRedirect for invalid request"; 108 DVLOG(1) << "OnFollowRedirect for invalid request";
119 return; 109 return;
120 } 110 }
121 111
122 if (has_new_first_party_for_cookies) 112 if (has_new_first_party_for_cookies)
123 request_->set_first_party_for_cookies(new_first_party_for_cookies); 113 request_->set_first_party_for_cookies(new_first_party_for_cookies);
124 114
125 ResumeIfDeferred(); 115 ResumeIfDeferred();
126 } 116 }
127 117
128 void AsyncResourceHandler::OnDataReceivedACK() { 118 void AsyncResourceHandler::OnDataReceivedACK() {
129 if (pending_data_count_-- == kMaxPendingDataMessages) 119 --pending_data_count_;
120
121 buffer_->RecycleLeastRecentlyAllocated();
122 if (buffer_->CanAllocate())
130 ResumeIfDeferred(); 123 ResumeIfDeferred();
131 } 124 }
132 125
133 bool AsyncResourceHandler::OnUploadProgress(int request_id, 126 bool AsyncResourceHandler::OnUploadProgress(int request_id,
134 uint64 position, 127 uint64 position,
135 uint64 size) { 128 uint64 size) {
136 return filter_->Send(new ResourceMsg_UploadProgress(routing_id_, request_id, 129 return filter_->Send(new ResourceMsg_UploadProgress(routing_id_, request_id,
137 position, size)); 130 position, size));
138 } 131 }
139 132
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 bool AsyncResourceHandler::OnWillStart(int request_id, 198 bool AsyncResourceHandler::OnWillStart(int request_id,
206 const GURL& url, 199 const GURL& url,
207 bool* defer) { 200 bool* defer) {
208 return true; 201 return true;
209 } 202 }
210 203
211 bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf, 204 bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
212 int* buf_size, int min_size) { 205 int* buf_size, int min_size) {
213 DCHECK_EQ(-1, min_size); 206 DCHECK_EQ(-1, min_size);
214 207
215 if (g_spare_read_buffer) { 208 if (!EnsureResourceBufferIsInitialized())
216 DCHECK(!read_buffer_); 209 return false;
217 read_buffer_.swap(&g_spare_read_buffer);
218 DCHECK(read_buffer_->data());
219 210
220 *buf = read_buffer_.get(); 211 DCHECK(buffer_->CanAllocate());
221 *buf_size = read_buffer_->buffer_size(); 212 char* memory = buffer_->Allocate(&allocation_size_);
222 } else { 213 CHECK(memory);
223 read_buffer_ = new SharedIOBuffer(next_buffer_size_);
224 if (!read_buffer_->Init()) {
225 DLOG(ERROR) << "Couldn't allocate shared io buffer";
226 read_buffer_ = NULL;
227 return false;
228 }
229 DCHECK(read_buffer_->data());
230 *buf = read_buffer_.get();
231 *buf_size = next_buffer_size_;
232 214
233 UMA_HISTOGRAM_CUSTOM_COUNTS( 215 *buf = new DependentIOBuffer(buffer_, memory);
234 "Net.AsyncResourceHandler_SharedIOBuffer_Alloc", 216 *buf_size = allocation_size_;
235 next_buffer_size_, kInitialReadBufSize, kMaxReadBufSize, 16);
236 }
237 217
218 UMA_HISTOGRAM_CUSTOM_COUNTS(
219 "Net.AsyncResourceHandler_SharedIOBuffer_Alloc",
220 *buf_size, 0, kMaxAllocationSize, 100);
238 return true; 221 return true;
239 } 222 }
240 223
241 bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read, 224 bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read,
242 bool* defer) { 225 bool* defer) {
243 if (!bytes_read) 226 if (!bytes_read)
244 return true; 227 return true;
245 DCHECK(read_buffer_.get()); 228
229 buffer_->ShrinkLastAllocation(bytes_read);
246 230
247 UMA_HISTOGRAM_CUSTOM_COUNTS( 231 UMA_HISTOGRAM_CUSTOM_COUNTS(
248 "Net.AsyncResourceHandler_SharedIOBuffer_Used", 232 "Net.AsyncResourceHandler_SharedIOBuffer_Used",
249 bytes_read, 0, kMaxReadBufSize, 100); 233 bytes_read, 0, kMaxAllocationSize, 100);
250 UMA_HISTOGRAM_PERCENTAGE( 234 UMA_HISTOGRAM_PERCENTAGE(
251 "Net.AsyncResourceHandler_SharedIOBuffer_UsedPercentage", 235 "Net.AsyncResourceHandler_SharedIOBuffer_UsedPercentage",
252 CalcUsedPercentage(bytes_read, read_buffer_->buffer_size())); 236 CalcUsedPercentage(bytes_read, allocation_size_));
253 237
254 if (read_buffer_->buffer_size() == bytes_read) { 238 if (!sent_first_data_msg_) {
255 // The network layer has saturated our buffer. Next time, we should give it 239 base::SharedMemoryHandle handle;
256 // a bigger buffer for it to fill, to minimize the number of round trips we 240 int size;
257 // do with the renderer process. 241 if (!buffer_->ShareToProcess(filter_->peer_handle(), &handle, &size))
258 next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize); 242 return false;
243 filter_->Send(
244 new ResourceMsg_SetDataBuffer(routing_id_, request_id, handle, size));
245 sent_first_data_msg_ = true;
259 } 246 }
260 247
261 WillSendData(defer); 248 int data_offset = buffer_->GetLastAllocationOffset();
262
263 base::SharedMemoryHandle handle;
264 if (!read_buffer_->shared_memory()->GiveToProcess(
265 filter_->peer_handle(), &handle)) {
266 // We wrongfully incremented the pending data count. Fake an ACK message
267 // to fix this. We can't move this call above the WillSendData because
268 // it's killing our read_buffer_, and we don't want that when we pause
269 // the request.
270 OnDataReceivedACK();
271
272 // We just unmapped the memory.
273 read_buffer_ = NULL;
274 return false;
275 }
276 // We just unmapped the memory.
277 read_buffer_ = NULL;
278
279 int encoded_data_length = 249 int encoded_data_length =
280 DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_); 250 DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_);
281 filter_->Send(new ResourceMsg_DataReceived( 251
282 routing_id_, request_id, handle, bytes_read, encoded_data_length)); 252 filter_->Send(
253 new ResourceMsg_DataReceived(routing_id_, request_id, data_offset,
254 bytes_read, encoded_data_length));
255 ++pending_data_count_;
256 UMA_HISTOGRAM_CUSTOM_COUNTS(
257 "Net.AsyncResourceHandler_PendingDataCount",
258 pending_data_count_, 0, 100, 100);
259
260 if (!buffer_->CanAllocate()) {
261 UMA_HISTOGRAM_CUSTOM_COUNTS(
262 "Net.AsyncResourceHandler_PendingDataCount_WhenFull",
263 pending_data_count_, 0, 100, 100);
264 *defer = did_defer_ = true;
265 }
283 266
284 return true; 267 return true;
285 } 268 }
286 269
287 void AsyncResourceHandler::OnDataDownloaded( 270 void AsyncResourceHandler::OnDataDownloaded(
288 int request_id, int bytes_downloaded) { 271 int request_id, int bytes_downloaded) {
289 filter_->Send(new ResourceMsg_DataDownloaded( 272 filter_->Send(new ResourceMsg_DataDownloaded(
290 routing_id_, request_id, bytes_downloaded)); 273 routing_id_, request_id, bytes_downloaded));
291 } 274 }
292 275
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 error_code == net::OK) { 312 error_code == net::OK) {
330 error_code = net::ERR_FAILED; 313 error_code = net::ERR_FAILED;
331 } 314 }
332 315
333 filter_->Send(new ResourceMsg_RequestComplete(routing_id_, 316 filter_->Send(new ResourceMsg_RequestComplete(routing_id_,
334 request_id, 317 request_id,
335 error_code, 318 error_code,
336 was_ignored_by_handler, 319 was_ignored_by_handler,
337 security_info, 320 security_info,
338 completion_time)); 321 completion_time));
339
340 // If we still have a read buffer, then see about caching it for later...
341 // Note that we have to make sure the buffer is not still being used, so we
342 // have to perform an explicit check on the status code.
343 if (g_spare_read_buffer ||
344 net::URLRequestStatus::SUCCESS != status.status()) {
345 read_buffer_ = NULL;
346 } else if (read_buffer_.get()) {
347 DCHECK(read_buffer_->data());
348 read_buffer_.swap(&g_spare_read_buffer);
349 }
350 return true; 322 return true;
351 } 323 }
352 324
353 // static 325 bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() {
354 void AsyncResourceHandler::GlobalCleanup() { 326 if (buffer_ && buffer_->IsInitialized())
355 if (g_spare_read_buffer) { 327 return true;
356 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer().
357 SharedIOBuffer* tmp = g_spare_read_buffer;
358 g_spare_read_buffer = NULL;
359 tmp->Release();
360 }
361 }
362 328
363 void AsyncResourceHandler::WillSendData(bool* defer) { 329 buffer_ = new ResourceBuffer();
364 if (++pending_data_count_ >= kMaxPendingDataMessages) { 330 return buffer_->Initialize(kBufferSize,
365 // We reached the max number of data messages that can be sent to 331 kMinAllocationSize,
366 // the renderer for a given request. Pause the request and wait for 332 kMaxAllocationSize);
367 // the renderer to start processing them before resuming it.
368 *defer = did_defer_ = true;
369 }
370
371 UMA_HISTOGRAM_CUSTOM_COUNTS(
372 "Net.AsyncResourceHandler_PendingDataCount",
373 pending_data_count_, 0, kMaxPendingDataMessages, kMaxPendingDataMessages);
374 } 333 }
375 334
376 void AsyncResourceHandler::ResumeIfDeferred() { 335 void AsyncResourceHandler::ResumeIfDeferred() {
377 if (did_defer_) { 336 if (did_defer_) {
378 did_defer_ = false; 337 did_defer_ = false;
379 controller()->Resume(); 338 controller()->Resume();
380 } 339 }
381 } 340 }
382 341
383 } // namespace content 342 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698