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

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

Powered by Google App Engine
This is Rietveld 408576698