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

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

Issue 146333004: Introduce an intra-priority level sorting value - Chromium Side (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes from review. Created 6 years, 10 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 <set>
6
5 #include "content/browser/loader/resource_scheduler.h" 7 #include "content/browser/loader/resource_scheduler.h"
6 8
7 #include "base/stl_util.h" 9 #include "base/stl_util.h"
8 #include "content/common/resource_messages.h" 10 #include "content/common/resource_messages.h"
9 #include "content/browser/loader/resource_message_delegate.h" 11 #include "content/browser/loader/resource_message_delegate.h"
10 #include "content/public/browser/resource_controller.h" 12 #include "content/public/browser/resource_controller.h"
11 #include "content/public/browser/resource_request_info.h" 13 #include "content/public/browser/resource_request_info.h"
12 #include "content/public/browser/resource_throttle.h" 14 #include "content/public/browser/resource_throttle.h"
13 #include "ipc/ipc_message_macros.h" 15 #include "ipc/ipc_message_macros.h"
14 #include "net/base/host_port_pair.h" 16 #include "net/base/host_port_pair.h"
15 #include "net/base/load_flags.h" 17 #include "net/base/load_flags.h"
16 #include "net/base/request_priority.h" 18 #include "net/base/request_priority.h"
17 #include "net/http/http_server_properties.h" 19 #include "net/http/http_server_properties.h"
18 #include "net/url_request/url_request.h" 20 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h" 21 #include "net/url_request/url_request_context.h"
20 22
21 namespace content { 23 namespace content {
22 24
23 static const size_t kMaxNumDelayableRequestsPerClient = 10; 25 static const size_t kMaxNumDelayableRequestsPerClient = 10;
24 static const size_t kMaxNumDelayableRequestsPerHost = 6; 26 static const size_t kMaxNumDelayableRequestsPerHost = 6;
25 27
26 // A thin wrapper around net::PriorityQueue that deals with 28
27 // ScheduledResourceRequests instead of PriorityQueue::Pointers.
28 class ResourceScheduler::RequestQueue { 29 class ResourceScheduler::RequestQueue {
29 private: 30 public:
30 typedef net::PriorityQueue<ScheduledResourceRequest*> NetQueue; 31 typedef std::multiset<ScheduledResourceRequest*, ScheduledResourceSorter>
32 NetQueue;
31 33
32 public: 34 RequestQueue() : fifo_ordering_ids_(0) {}
33 class Iterator {
34 public:
35 Iterator(NetQueue* queue) : queue_(queue) {
36 DCHECK(queue != NULL);
37 current_pointer_ = queue_->FirstMax();
38 }
39
40 Iterator& operator++() {
41 current_pointer_ = queue_->GetNextTowardsLastMin(current_pointer_);
42 return *this;
43 }
44
45 Iterator operator++(int) {
46 Iterator result(*this);
47 ++(*this);
48 return result;
49 }
50
51 ScheduledResourceRequest* value() {
52 return current_pointer_.value();
53 }
54
55 bool is_null() {
56 return current_pointer_.is_null();
57 }
58
59 private:
60 NetQueue* queue_;
61 NetQueue::Pointer current_pointer_;
62 };
63
64 RequestQueue() : queue_(net::NUM_PRIORITIES) {}
65 ~RequestQueue() {} 35 ~RequestQueue() {}
66 36
67 // Adds |request| to the queue with given |priority|. 37 // Adds |request| to the queue with given |priority|.
68 void Insert(ScheduledResourceRequest* request, 38 void Insert(ScheduledResourceRequest* request);
69 net::RequestPriority priority, int value) {
70 DCHECK(!ContainsKey(pointers_, request));
71 int calculated_priority = (priority << 16) | (0xFFFF & value);
72 NetQueue::Pointer pointer = queue_.Insert(request, calculated_priority);
73 pointers_[request] = pointer;
74 }
75 39
76 // Removes |request| from the queue. 40 // Removes |request| from the queue.
77 void Erase(ScheduledResourceRequest* request) { 41 void Erase(ScheduledResourceRequest* request) {
78 PointerMap::iterator it = pointers_.find(request); 42 PointerMap::iterator it = pointers_.find(request);
79 DCHECK(it != pointers_.end()); 43 DCHECK(it != pointers_.end());
80 if (it == pointers_.end()) 44 if (it == pointers_.end())
81 return; 45 return;
82 queue_.Erase(it->second); 46 queue_.erase(it->second);
83 pointers_.erase(it); 47 pointers_.erase(it);
84 } 48 }
85 49
86 // Returns the highest priority request that's queued, or NULL if none are. 50 NetQueue::iterator GetNextHighestIterator() {
87 ScheduledResourceRequest* FirstMax() { 51 return queue_.begin();
88 return queue_.FirstMax().value();
89 } 52 }
90 53
91 Iterator GetNextHighestIterator() { 54 NetQueue::iterator End() {
92 return Iterator(&queue_); 55 return queue_.end();
93 } 56 }
94 57
95 // Returns true if |request| is queued. 58 // Returns true if |request| is queued.
96 bool IsQueued(ScheduledResourceRequest* request) const { 59 bool IsQueued(ScheduledResourceRequest* request) const {
97 return ContainsKey(pointers_, request); 60 return ContainsKey(pointers_, request);
98 } 61 }
99 62
100 // Returns true if no requests are queued. 63 // Returns true if no requests are queued.
101 bool IsEmpty() const { return queue_.size() == 0; } 64 bool IsEmpty() const { return queue_.size() == 0; }
102 65
103 private: 66 private:
104 typedef std::map<ScheduledResourceRequest*, NetQueue::Pointer> PointerMap; 67 typedef std::map<ScheduledResourceRequest*, NetQueue::iterator> PointerMap;
68
69 uint32 MakeFifoOrderingId() {
70 fifo_ordering_ids_ += 1;
71 return fifo_ordering_ids_;
72 }
73
74 // Used to create an ordering ID for scheduled resources so that resources
75 // with same priority/intra_priority stay in fifo order.
76 uint32 fifo_ordering_ids_;
105 77
106 NetQueue queue_; 78 NetQueue queue_;
107 PointerMap pointers_; 79 PointerMap pointers_;
108 }; 80 };
109 81
110 // This is the handle we return to the ResourceDispatcherHostImpl so it can 82 // This is the handle we return to the ResourceDispatcherHostImpl so it can
111 // interact with the request. 83 // interact with the request.
112 class ResourceScheduler::ScheduledResourceRequest 84 class ResourceScheduler::ScheduledResourceRequest
113 : public ResourceMessageDelegate, 85 : public ResourceMessageDelegate,
114 public ResourceThrottle { 86 public ResourceThrottle {
115 public: 87 public:
116 ScheduledResourceRequest(const ClientId& client_id, 88 ScheduledResourceRequest(const ClientId& client_id,
117 net::URLRequest* request, 89 net::URLRequest* request,
118 ResourceScheduler* scheduler) 90 ResourceScheduler* scheduler)
119 : ResourceMessageDelegate(request), 91 : ResourceMessageDelegate(request),
120 client_id_(client_id), 92 client_id_(client_id),
121 request_(request), 93 request_(request),
122 ready_(false), 94 ready_(false),
123 deferred_(false), 95 deferred_(false),
124 scheduler_(scheduler), 96 scheduler_(scheduler),
125 priorityValue_(0) { 97 intra_priority_value_(0),
98 fifo_ordering_(0) {
126 TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_, 99 TRACE_EVENT_ASYNC_BEGIN1("net", "URLRequest", request_,
127 "url", request->url().spec()); 100 "url", request->url().spec());
128 } 101 }
129 102
130 virtual ~ScheduledResourceRequest() { 103 virtual ~ScheduledResourceRequest() {
131 scheduler_->RemoveRequest(this); 104 scheduler_->RemoveRequest(this);
132 } 105 }
133 106
134 void Start() { 107 void Start() {
135 TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued"); 108 TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request_, "Queued");
136 ready_ = true; 109 ready_ = true;
137 if (deferred_ && request_->status().is_success()) { 110 if (deferred_ && request_->status().is_success()) {
138 deferred_ = false; 111 deferred_ = false;
139 controller()->Resume(); 112 controller()->Resume();
140 } 113 }
141 } 114 }
142 115
143 const ClientId& client_id() const { return client_id_; } 116 const ClientId& client_id() const { return client_id_; }
144 net::URLRequest* url_request() { return request_; } 117 net::URLRequest* url_request() { return request_; }
145 const net::URLRequest* url_request() const { return request_; } 118 const net::URLRequest* url_request() const { return request_; }
146 int priorityValue() const { return priorityValue_; } 119 net::RequestPriority priority() const { return request_->priority(); }
147 void setPriorityValue(int priorityValue) { priorityValue_ = priorityValue; } 120 int intra_priority_value() const { return intra_priority_value_; }
121 void set_intra_priority_value(int intra_priority_value) {
122 intra_priority_value_ = intra_priority_value;
123 }
124 uint32 fifo_ordering() const { return fifo_ordering_; }
125 void set_fifo_ordering(uint32 fifo_ordering) {
126 fifo_ordering_ = fifo_ordering;
127 }
148 128
149 private: 129 private:
150 // ResourceMessageDelegate interface: 130 // ResourceMessageDelegate interface:
151 virtual bool OnMessageReceived(const IPC::Message& message, 131 virtual bool OnMessageReceived(const IPC::Message& message,
152 bool* message_was_ok) OVERRIDE { 132 bool* message_was_ok) OVERRIDE {
153 bool handled = true; 133 bool handled = true;
154 IPC_BEGIN_MESSAGE_MAP_EX(ScheduledResourceRequest, message, *message_was_ok) 134 IPC_BEGIN_MESSAGE_MAP_EX(ScheduledResourceRequest, message, *message_was_ok)
155 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) 135 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority)
156 IPC_MESSAGE_UNHANDLED(handled = false) 136 IPC_MESSAGE_UNHANDLED(handled = false)
157 IPC_END_MESSAGE_MAP_EX() 137 IPC_END_MESSAGE_MAP_EX()
158 return handled; 138 return handled;
159 } 139 }
160 140
161 // ResourceThrottle interface: 141 // ResourceThrottle interface:
162 virtual void WillStartRequest(bool* defer) OVERRIDE { 142 virtual void WillStartRequest(bool* defer) OVERRIDE {
163 deferred_ = *defer = !ready_; 143 deferred_ = *defer = !ready_;
164 } 144 }
165 145
166 virtual const char* GetNameForLogging() const OVERRIDE { 146 virtual const char* GetNameForLogging() const OVERRIDE {
167 return "ResourceScheduler"; 147 return "ResourceScheduler";
168 } 148 }
169 149
170 void DidChangePriority(int request_id, net::RequestPriority new_priority, int value) { 150 void DidChangePriority(int request_id, net::RequestPriority new_priority,
171 scheduler_->ReprioritizeRequest(this, new_priority, value); 151 int intra_priority_value) {
152 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value);
172 } 153 }
173 154
174 ClientId client_id_; 155 ClientId client_id_;
175 net::URLRequest* request_; 156 net::URLRequest* request_;
176 bool ready_; 157 bool ready_;
177 bool deferred_; 158 bool deferred_;
178 ResourceScheduler* scheduler_; 159 ResourceScheduler* scheduler_;
179 int priorityValue_; 160 int intra_priority_value_;
161 uint32 fifo_ordering_;
180 162
181 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 163 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
182 }; 164 };
183 165
166 bool ResourceScheduler::ScheduledResourceSorter::operator()(
167 const ScheduledResourceRequest* a,
168 const ScheduledResourceRequest* b) const {
169 // Want the set to be ordered first by decreasing priority, then by
170 // decreasing intra_priority.
171 // ie. with (priority, intra_priority)
172 // [(1, 0), (1, 0), (0, 100), (0, 0)]
173 if (a->priority() != b->priority())
darin (slow to review) 2014/02/28 05:14:12 it seems like you want to treat priority as a tupl
shatch 2014/03/03 18:57:15 Done.
174 return a->priority() > b->priority();
175
176 if (a->intra_priority_value() != b->intra_priority_value())
177 return a->intra_priority_value() > b->intra_priority_value();
178
179 // If priority/intra_priority is the same, fall back to fifo ordering.
180 // std::multiset doesn't guarantee this until c++11.
181 return a->fifo_ordering() < b->fifo_ordering();
182 }
183
184 void ResourceScheduler::RequestQueue::Insert(
185 ScheduledResourceRequest* request) {
186 DCHECK(!ContainsKey(pointers_, request));
187 request->set_fifo_ordering(MakeFifoOrderingId());
188 pointers_[request] = queue_.insert(request);
189 }
190
184 // Each client represents a tab. 191 // Each client represents a tab.
185 struct ResourceScheduler::Client { 192 struct ResourceScheduler::Client {
186 Client() : has_body(false), using_spdy_proxy(false) {} 193 Client() : has_body(false), using_spdy_proxy(false) {}
187 ~Client() {} 194 ~Client() {}
188 195
189 bool has_body; 196 bool has_body;
190 bool using_spdy_proxy; 197 bool using_spdy_proxy;
191 RequestQueue pending_requests; 198 RequestQueue pending_requests;
192 RequestSet in_flight_requests; 199 RequestSet in_flight_requests;
193 }; 200 };
(...skipping 23 matching lines...) Expand all
217 // 3. The tab is closed while a RequestResource IPC is in flight. 224 // 3. The tab is closed while a RequestResource IPC is in flight.
218 unowned_requests_.insert(request.get()); 225 unowned_requests_.insert(request.get());
219 request->Start(); 226 request->Start();
220 return request.PassAs<ResourceThrottle>(); 227 return request.PassAs<ResourceThrottle>();
221 } 228 }
222 229
223 Client* client = it->second; 230 Client* client = it->second;
224 if (ShouldStartRequest(request.get(), client) == START_REQUEST) { 231 if (ShouldStartRequest(request.get(), client) == START_REQUEST) {
225 StartRequest(request.get(), client); 232 StartRequest(request.get(), client);
226 } else { 233 } else {
227 client->pending_requests.Insert(request.get(), url_request->priority(), requ est->priorityValue()); 234 client->pending_requests.Insert(request.get());
228 } 235 }
229 return request.PassAs<ResourceThrottle>(); 236 return request.PassAs<ResourceThrottle>();
230 } 237 }
231 238
232 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) { 239 void ResourceScheduler::RemoveRequest(ScheduledResourceRequest* request) {
233 DCHECK(CalledOnValidThread()); 240 DCHECK(CalledOnValidThread());
234 if (ContainsKey(unowned_requests_, request)) { 241 if (ContainsKey(unowned_requests_, request)) {
235 unowned_requests_.erase(request); 242 unowned_requests_.erase(request);
236 return; 243 return;
237 } 244 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 } 341 }
335 } 342 }
336 343
337 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request, 344 void ResourceScheduler::StartRequest(ScheduledResourceRequest* request,
338 Client* client) { 345 Client* client) {
339 client->in_flight_requests.insert(request); 346 client->in_flight_requests.insert(request);
340 request->Start(); 347 request->Start();
341 } 348 }
342 349
343 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request, 350 void ResourceScheduler::ReprioritizeRequest(ScheduledResourceRequest* request,
344 net::RequestPriority new_priority, i nt value) { 351 net::RequestPriority new_priority,
352 int new_intra_priority_value) {
345 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) { 353 if (request->url_request()->load_flags() & net::LOAD_IGNORE_LIMITS) {
346 // We should not be re-prioritizing requests with the 354 // We should not be re-prioritizing requests with the
347 // IGNORE_LIMITS flag. 355 // IGNORE_LIMITS flag.
348 NOTREACHED(); 356 NOTREACHED();
349 return; 357 return;
350 } 358 }
351 net::RequestPriority old_priority = request->url_request()->priority(); 359 net::RequestPriority old_priority = request->url_request()->priority();
352 DCHECK_NE(new_priority, old_priority); 360 int old_intra_priority = request->intra_priority_value();
361 DCHECK((new_priority != old_priority) ||
362 (old_intra_priority != new_intra_priority_value));
353 request->url_request()->SetPriority(new_priority); 363 request->url_request()->SetPriority(new_priority);
354 request->setPriorityValue(value); 364 request->set_intra_priority_value(new_intra_priority_value);
355 ClientMap::iterator client_it = client_map_.find(request->client_id()); 365 ClientMap::iterator client_it = client_map_.find(request->client_id());
356 if (client_it == client_map_.end()) { 366 if (client_it == client_map_.end()) {
357 // The client was likely deleted shortly before we received this IPC. 367 // The client was likely deleted shortly before we received this IPC.
358 return; 368 return;
359 } 369 }
360 370
371 if ((new_priority == old_priority) &&
372 (new_intra_priority_value == old_intra_priority))
373 return;
374
361 Client *client = client_it->second; 375 Client *client = client_it->second;
362 if (!client->pending_requests.IsQueued(request)) { 376 if (!client->pending_requests.IsQueued(request)) {
363 DCHECK(ContainsKey(client->in_flight_requests, request)); 377 DCHECK(ContainsKey(client->in_flight_requests, request));
364 // Request has already started. 378 // Request has already started.
365 return; 379 return;
366 } 380 }
367 381
368 client->pending_requests.Erase(request); 382 client->pending_requests.Erase(request);
369 client->pending_requests.Insert(request, 383 client->pending_requests.Insert(request);
370 request->url_request()->priority(), value);
371 384
372 if (new_priority > old_priority) { 385 if (new_priority > old_priority) {
373 // Check if this request is now able to load at its new priority. 386 // Check if this request is now able to load at its new priority.
374 LoadAnyStartablePendingRequests(client); 387 LoadAnyStartablePendingRequests(client);
375 } 388 }
376 } 389 }
377 390
378 void ResourceScheduler::LoadAnyStartablePendingRequests(Client* client) { 391 void ResourceScheduler::LoadAnyStartablePendingRequests(Client* client) {
379 // We iterate through all the pending requests, starting with the highest 392 // We iterate through all the pending requests, starting with the highest
380 // priority one. For each entry, one of three things can happen: 393 // priority one. For each entry, one of three things can happen:
381 // 1) We start the request, remove it from the list, and keep checking. 394 // 1) We start the request, remove it from the list, and keep checking.
382 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 395 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
383 // there may be room for other requests, so we keep checking and leave 396 // there may be room for other requests, so we keep checking and leave
384 // the previous request still in the list. 397 // the previous request still in the list.
385 // 3) We do not start the request, same as above, but StartRequest() tells 398 // 3) We do not start the request, same as above, but StartRequest() tells
386 // us there's no point in checking any further requests. 399 // us there's no point in checking any further requests.
387 400 RequestQueue::NetQueue::iterator request_iter =
388 RequestQueue::Iterator request_iter =
389 client->pending_requests.GetNextHighestIterator(); 401 client->pending_requests.GetNextHighestIterator();
390 402 while (request_iter != client->pending_requests.End()) {
391 while (!request_iter.is_null()) { 403 ScheduledResourceRequest* request = *request_iter;
392 ScheduledResourceRequest* request = request_iter.value();
393 ShouldStartReqResult query_result = ShouldStartRequest(request, client); 404 ShouldStartReqResult query_result = ShouldStartRequest(request, client);
394 405
395 if (query_result == START_REQUEST) { 406 if (query_result == START_REQUEST) {
396 client->pending_requests.Erase(request); 407 client->pending_requests.Erase(request);
397 StartRequest(request, client); 408 StartRequest(request, client);
398 409
399 // StartRequest can modify the pending list, so we (re)start evaluation 410 // StartRequest can modify the pending list, so we (re)start evaluation
400 // from the currently highest priority request. Avoid copying a singular 411 // from the currently highest priority request. Avoid copying a singular
401 // iterator, which would trigger undefined behavior. 412 // iterator, which would trigger undefined behavior.
402 if (client->pending_requests.GetNextHighestIterator().is_null()) 413 if (client->pending_requests.GetNextHighestIterator() ==
414 client->pending_requests.End())
403 break; 415 break;
404 request_iter = client->pending_requests.GetNextHighestIterator(); 416 request_iter = client->pending_requests.GetNextHighestIterator();
405 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) { 417 } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
406 ++request_iter; 418 ++request_iter;
407 continue; 419 continue;
408 } else { 420 } else {
409 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 421 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
410 break; 422 break;
411 } 423 }
412 } 424 }
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
520 532
521 return START_REQUEST; 533 return START_REQUEST;
522 } 534 }
523 535
524 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 536 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
525 int child_id, int route_id) { 537 int child_id, int route_id) {
526 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 538 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
527 } 539 }
528 540
529 } // namespace content 541 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698