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

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

Issue 1230133005: Fix Resource Priorities and Scheduling (Chrome Side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 4 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/resource_scheduler.h"
6
7 #include <stdint.h>
5 #include <set> 8 #include <set>
6 9
7 #include "content/browser/loader/resource_scheduler.h"
8
9 #include "base/metrics/field_trial.h" 10 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h" 12 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h" 14 #include "base/strings/string_piece.h"
14 #include "base/supports_user_data.h" 15 #include "base/supports_user_data.h"
15 #include "base/time/time.h" 16 #include "base/time/time.h"
16 #include "content/common/resource_messages.h" 17 #include "content/common/resource_messages.h"
17 #include "content/public/browser/resource_controller.h" 18 #include "content/public/browser/resource_controller.h"
18 #include "content/public/browser/resource_request_info.h" 19 #include "content/public/browser/resource_request_info.h"
(...skipping 10 matching lines...) Expand all
29 namespace { 30 namespace {
30 31
31 // Field trial constants 32 // Field trial constants
32 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing"; 33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing";
33 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle"; 34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle";
34 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce"; 35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce";
35 36
36 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting"; 37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting";
37 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit"; 38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit";
38 39
40 const char kResourcePrioritiesFieldTrial[] = "ResourcePriorities";
41
42 // Flags identifying various attributes of the request that are used
43 // when making scheduling decisions.
44 using RequestAttributes = uint8_t;
45 const RequestAttributes kAttributeNone = 0x00;
46 const RequestAttributes kAttributeInFlight = 0x01;
47 const RequestAttributes kAttributeDelayable = 0x02;
48 const RequestAttributes kAttributeLayoutBlocking = 0x04;
49
39 // Post ResourceScheduler histograms of the following forms: 50 // Post ResourceScheduler histograms of the following forms:
40 // If |histogram_suffix| is NULL or the empty string: 51 // If |histogram_suffix| is NULL or the empty string:
41 // ResourceScheduler.base_name.histogram_name 52 // ResourceScheduler.base_name.histogram_name
42 // Else: 53 // Else:
43 // ResourceScheduler.base_name.histogram_name.histogram_suffix 54 // ResourceScheduler.base_name.histogram_name.histogram_suffix
44 void PostHistogram(const char* base_name, 55 void PostHistogram(const char* base_name,
45 const char* histogram_name, 56 const char* histogram_name,
46 const char* histogram_suffix, 57 const char* histogram_suffix,
47 base::TimeDelta time) { 58 base::TimeDelta time) {
48 std::string histogram = 59 std::string histogram =
(...skipping 17 matching lines...) Expand all
66 else if (num_clients <= 15) 77 else if (num_clients <= 15)
67 return "Max15Clients"; 78 return "Max15Clients";
68 else if (num_clients <= 30) 79 else if (num_clients <= 30)
69 return "Max30Clients"; 80 return "Max30Clients";
70 return "Over30Clients"; 81 return "Over30Clients";
71 } 82 }
72 83
73 } // namespace 84 } // namespace
74 85
75 static const size_t kCoalescedTimerPeriod = 5000; 86 static const size_t kCoalescedTimerPeriod = 5000;
76 static const size_t kMaxNumDelayableRequestsPerClient = 10; 87 static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
77 static const size_t kMaxNumDelayableRequestsPerHost = 6; 88 static const size_t kMaxNumDelayableRequestsPerHost = 6;
78 static const size_t kMaxNumThrottledRequestsPerClient = 1; 89 static const size_t kMaxNumThrottledRequestsPerClient = 1;
90 static const size_t kDefaultMaxNumDelayableWhileLayoutBlocking = 1;
91 static const net::RequestPriority
92 kDefaultLayoutBlockingPriorityThreshold = net::LOW;
79 93
80 struct ResourceScheduler::RequestPriorityParams { 94 struct ResourceScheduler::RequestPriorityParams {
81 RequestPriorityParams() 95 RequestPriorityParams()
82 : priority(net::DEFAULT_PRIORITY), 96 : priority(net::DEFAULT_PRIORITY),
83 intra_priority(0) { 97 intra_priority(0) {
84 } 98 }
85 99
86 RequestPriorityParams(net::RequestPriority priority, int intra_priority) 100 RequestPriorityParams(net::RequestPriority priority, int intra_priority)
87 : priority(priority), 101 : priority(priority),
88 intra_priority(intra_priority) { 102 intra_priority(intra_priority) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 net::URLRequest* request, 182 net::URLRequest* request,
169 ResourceScheduler* scheduler, 183 ResourceScheduler* scheduler,
170 const RequestPriorityParams& priority, 184 const RequestPriorityParams& priority,
171 bool is_async) 185 bool is_async)
172 : client_id_(client_id), 186 : client_id_(client_id),
173 client_state_on_creation_(scheduler->GetClientState(client_id_)), 187 client_state_on_creation_(scheduler->GetClientState(client_id_)),
174 request_(request), 188 request_(request),
175 ready_(false), 189 ready_(false),
176 deferred_(false), 190 deferred_(false),
177 is_async_(is_async), 191 is_async_(is_async),
178 classification_(NORMAL_REQUEST), 192 attributes_(kAttributeNone),
179 scheduler_(scheduler), 193 scheduler_(scheduler),
180 priority_(priority), 194 priority_(priority),
181 fifo_ordering_(0) { 195 fifo_ordering_(0) {
182 DCHECK(!request_->GetUserData(kUserDataKey)); 196 DCHECK(!request_->GetUserData(kUserDataKey));
183 request_->SetUserData(kUserDataKey, new UnownedPointer(this)); 197 request_->SetUserData(kUserDataKey, new UnownedPointer(this));
184 } 198 }
185 199
186 ~ScheduledResourceRequest() override { 200 ~ScheduledResourceRequest() override {
187 request_->RemoveUserData(kUserDataKey); 201 request_->RemoveUserData(kUserDataKey);
188 scheduler_->RemoveRequest(this); 202 scheduler_->RemoveRequest(this);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 return priority_; 246 return priority_;
233 } 247 }
234 const ClientId& client_id() const { return client_id_; } 248 const ClientId& client_id() const { return client_id_; }
235 net::URLRequest* url_request() { return request_; } 249 net::URLRequest* url_request() { return request_; }
236 const net::URLRequest* url_request() const { return request_; } 250 const net::URLRequest* url_request() const { return request_; }
237 bool is_async() const { return is_async_; } 251 bool is_async() const { return is_async_; }
238 uint32 fifo_ordering() const { return fifo_ordering_; } 252 uint32 fifo_ordering() const { return fifo_ordering_; }
239 void set_fifo_ordering(uint32 fifo_ordering) { 253 void set_fifo_ordering(uint32 fifo_ordering) {
240 fifo_ordering_ = fifo_ordering; 254 fifo_ordering_ = fifo_ordering;
241 } 255 }
242 RequestClassification classification() const { 256 RequestAttributes attributes() const {
243 return classification_; 257 return attributes_;
244 } 258 }
245 void set_classification(RequestClassification classification) { 259 void set_attributes(RequestAttributes attributes) {
246 classification_ = classification; 260 attributes_ = attributes;
247 } 261 }
248 262
249 private: 263 private:
250 class UnownedPointer : public base::SupportsUserData::Data { 264 class UnownedPointer : public base::SupportsUserData::Data {
251 public: 265 public:
252 explicit UnownedPointer(ScheduledResourceRequest* pointer) 266 explicit UnownedPointer(ScheduledResourceRequest* pointer)
253 : pointer_(pointer) {} 267 : pointer_(pointer) {}
254 268
255 ScheduledResourceRequest* get() const { return pointer_; } 269 ScheduledResourceRequest* get() const { return pointer_; }
256 270
(...skipping 12 matching lines...) Expand all
269 } 283 }
270 284
271 const char* GetNameForLogging() const override { return "ResourceScheduler"; } 285 const char* GetNameForLogging() const override { return "ResourceScheduler"; }
272 286
273 const ClientId client_id_; 287 const ClientId client_id_;
274 const ResourceScheduler::ClientState client_state_on_creation_; 288 const ResourceScheduler::ClientState client_state_on_creation_;
275 net::URLRequest* request_; 289 net::URLRequest* request_;
276 bool ready_; 290 bool ready_;
277 bool deferred_; 291 bool deferred_;
278 bool is_async_; 292 bool is_async_;
279 RequestClassification classification_; 293 RequestAttributes attributes_;
280 ResourceScheduler* scheduler_; 294 ResourceScheduler* scheduler_;
281 RequestPriorityParams priority_; 295 RequestPriorityParams priority_;
282 uint32 fifo_ordering_; 296 uint32 fifo_ordering_;
283 base::TimeTicks time_deferred_; 297 base::TimeTicks time_deferred_;
284 298
285 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); 299 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest);
286 }; 300 };
287 301
288 const void* const ResourceScheduler::ScheduledResourceRequest::kUserDataKey = 302 const void* const ResourceScheduler::ScheduledResourceRequest::kUserDataKey =
289 &ResourceScheduler::ScheduledResourceRequest::kUserDataKey; 303 &ResourceScheduler::ScheduledResourceRequest::kUserDataKey;
(...skipping 24 matching lines...) Expand all
314 // Each client represents a tab. 328 // Each client represents a tab.
315 class ResourceScheduler::Client { 329 class ResourceScheduler::Client {
316 public: 330 public:
317 explicit Client(ResourceScheduler* scheduler, 331 explicit Client(ResourceScheduler* scheduler,
318 bool is_visible, 332 bool is_visible,
319 bool is_audible) 333 bool is_audible)
320 : is_audible_(is_audible), 334 : is_audible_(is_audible),
321 is_visible_(is_visible), 335 is_visible_(is_visible),
322 is_loaded_(false), 336 is_loaded_(false),
323 is_paused_(false), 337 is_paused_(false),
324 has_body_(false), 338 has_html_body_(false),
325 using_spdy_proxy_(false), 339 using_spdy_proxy_(false),
326 load_started_time_(base::TimeTicks::Now()), 340 load_started_time_(base::TimeTicks::Now()),
327 scheduler_(scheduler), 341 scheduler_(scheduler),
328 in_flight_delayable_count_(0), 342 in_flight_delayable_count_(0),
329 total_layout_blocking_count_(0), 343 total_layout_blocking_count_(0),
330 throttle_state_(ResourceScheduler::THROTTLED) {} 344 throttle_state_(ResourceScheduler::THROTTLED) {}
331 345
332 ~Client() { 346 ~Client() {
333 // Update to default state and pause to ensure the scheduler has a 347 // Update to default state and pause to ensure the scheduler has a
334 // correct count of relevant types of clients. 348 // correct count of relevant types of clients.
335 is_visible_ = false; 349 is_visible_ = false;
336 is_audible_ = false; 350 is_audible_ = false;
337 is_paused_ = true; 351 is_paused_ = true;
338 UpdateThrottleState(); 352 UpdateThrottleState();
339 } 353 }
340 354
341 void ScheduleRequest(net::URLRequest* url_request, 355 void ScheduleRequest(net::URLRequest* url_request,
342 ScheduledResourceRequest* request) { 356 ScheduledResourceRequest* request) {
357 SetRequestAttributes(request, DetermineRequestAttributes(request));
343 if (ShouldStartRequest(request) == START_REQUEST) 358 if (ShouldStartRequest(request) == START_REQUEST)
344 StartRequest(request); 359 StartRequest(request);
345 else 360 else
346 pending_requests_.Insert(request); 361 pending_requests_.Insert(request);
347 SetRequestClassification(request, ClassifyRequest(request));
348 } 362 }
349 363
350 void RemoveRequest(ScheduledResourceRequest* request) { 364 void RemoveRequest(ScheduledResourceRequest* request) {
351 if (pending_requests_.IsQueued(request)) { 365 if (pending_requests_.IsQueued(request)) {
352 pending_requests_.Erase(request); 366 pending_requests_.Erase(request);
353 DCHECK(!ContainsKey(in_flight_requests_, request)); 367 DCHECK(!ContainsKey(in_flight_requests_, request));
354 } else { 368 } else {
355 EraseInFlightRequest(request); 369 EraseInFlightRequest(request);
356 370
357 // Removing this request may have freed up another to load. 371 // Removing this request may have freed up another to load.
358 LoadAnyStartablePendingRequests(); 372 LoadAnyStartablePendingRequests();
359 } 373 }
360 } 374 }
361 375
362 RequestSet StartAndRemoveAllRequests() { 376 RequestSet StartAndRemoveAllRequests() {
363 // First start any pending requests so that they will be moved into 377 // First start any pending requests so that they will be moved into
364 // in_flight_requests_. This may exceed the limits 378 // in_flight_requests_. This may exceed the limits
365 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and 379 // kDefaultMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost
366 // kMaxNumThrottledRequestsPerClient, so this method must not do anything 380 // and kMaxNumThrottledRequestsPerClient, so this method must not do
367 // that depends on those limits before calling ClearInFlightRequests() 381 // anything that depends on those limits before calling
368 // below. 382 // ClearInFlightRequests() below.
369 while (!pending_requests_.IsEmpty()) { 383 while (!pending_requests_.IsEmpty()) {
370 ScheduledResourceRequest* request = 384 ScheduledResourceRequest* request =
371 *pending_requests_.GetNextHighestIterator(); 385 *pending_requests_.GetNextHighestIterator();
372 pending_requests_.Erase(request); 386 pending_requests_.Erase(request);
373 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? 387 // StartRequest() may modify pending_requests_. TODO(ricea): Does it?
374 StartRequest(request); 388 StartRequest(request);
375 } 389 }
376 RequestSet unowned_requests; 390 RequestSet unowned_requests;
377 for (RequestSet::iterator it = in_flight_requests_.begin(); 391 for (RequestSet::iterator it = in_flight_requests_.begin();
378 it != in_flight_requests_.end(); ++it) { 392 it != in_flight_requests_.end(); ++it) {
379 unowned_requests.insert(*it); 393 unowned_requests.insert(*it);
380 (*it)->set_classification(NORMAL_REQUEST); 394 (*it)->set_attributes(kAttributeNone);
381 } 395 }
382 ClearInFlightRequests(); 396 ClearInFlightRequests();
383 return unowned_requests; 397 return unowned_requests;
384 } 398 }
385 399
386 bool is_active() const { return is_visible_ || is_audible_; } 400 bool is_active() const { return is_visible_ || is_audible_; }
387 401
388 bool is_loaded() const { return is_loaded_; } 402 bool is_loaded() const { return is_loaded_; }
389 403
390 bool is_visible() const { return is_visible_; } 404 bool is_visible() const { return is_visible_; }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 scheduler_->DecrementActiveClientsLoading(); 489 scheduler_->DecrementActiveClientsLoading();
476 } 490 }
477 if (throttle_state_ == COALESCED) { 491 if (throttle_state_ == COALESCED) {
478 scheduler_->IncrementCoalescedClients(); 492 scheduler_->IncrementCoalescedClients();
479 } else if (old_throttle_state == COALESCED) { 493 } else if (old_throttle_state == COALESCED) {
480 scheduler_->DecrementCoalescedClients(); 494 scheduler_->DecrementCoalescedClients();
481 } 495 }
482 } 496 }
483 497
484 void OnNavigate() { 498 void OnNavigate() {
485 has_body_ = false; 499 has_html_body_ = false;
486 is_loaded_ = false; 500 is_loaded_ = false;
487 } 501 }
488 502
489 void OnWillInsertBody() { 503 void OnWillInsertBody() {
490 has_body_ = true; 504 has_html_body_ = true;
491 LoadAnyStartablePendingRequests(); 505 LoadAnyStartablePendingRequests();
492 } 506 }
493 507
494 void OnReceivedSpdyProxiedHttpResponse() { 508 void OnReceivedSpdyProxiedHttpResponse() {
495 if (!using_spdy_proxy_) { 509 if (!using_spdy_proxy_) {
496 using_spdy_proxy_ = true; 510 using_spdy_proxy_ = true;
497 LoadAnyStartablePendingRequests(); 511 LoadAnyStartablePendingRequests();
498 } 512 }
499 } 513 }
500 514
501 void ReprioritizeRequest(ScheduledResourceRequest* request, 515 void ReprioritizeRequest(ScheduledResourceRequest* request,
502 RequestPriorityParams old_priority_params, 516 RequestPriorityParams old_priority_params,
503 RequestPriorityParams new_priority_params) { 517 RequestPriorityParams new_priority_params) {
504 request->url_request()->SetPriority(new_priority_params.priority); 518 request->url_request()->SetPriority(new_priority_params.priority);
505 request->set_request_priority_params(new_priority_params); 519 request->set_request_priority_params(new_priority_params);
520 SetRequestAttributes(request, DetermineRequestAttributes(request));
506 if (!pending_requests_.IsQueued(request)) { 521 if (!pending_requests_.IsQueued(request)) {
507 DCHECK(ContainsKey(in_flight_requests_, request)); 522 DCHECK(ContainsKey(in_flight_requests_, request));
508 // The priority of the request and priority support of the server may
509 // have changed, so update the delayable count.
510 SetRequestClassification(request, ClassifyRequest(request));
511 // Request has already started. 523 // Request has already started.
512 return; 524 return;
513 } 525 }
514 526
515 pending_requests_.Erase(request); 527 pending_requests_.Erase(request);
516 pending_requests_.Insert(request); 528 pending_requests_.Insert(request);
517 529
518 if (new_priority_params.priority > old_priority_params.priority) { 530 if (new_priority_params.priority > old_priority_params.priority) {
519 // Check if this request is now able to load at its new priority. 531 // Check if this request is now able to load at its new priority.
520 LoadAnyStartablePendingRequests(); 532 LoadAnyStartablePendingRequests();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 579
568 private: 580 private:
569 enum ShouldStartReqResult { 581 enum ShouldStartReqResult {
570 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, 582 DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
571 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, 583 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
572 START_REQUEST, 584 START_REQUEST,
573 }; 585 };
574 586
575 void InsertInFlightRequest(ScheduledResourceRequest* request) { 587 void InsertInFlightRequest(ScheduledResourceRequest* request) {
576 in_flight_requests_.insert(request); 588 in_flight_requests_.insert(request);
577 SetRequestClassification(request, ClassifyRequest(request)); 589 SetRequestAttributes(request, DetermineRequestAttributes(request));
578 } 590 }
579 591
580 void EraseInFlightRequest(ScheduledResourceRequest* request) { 592 void EraseInFlightRequest(ScheduledResourceRequest* request) {
581 size_t erased = in_flight_requests_.erase(request); 593 size_t erased = in_flight_requests_.erase(request);
582 DCHECK_EQ(1u, erased); 594 DCHECK_EQ(1u, erased);
583 // Clear any special state that we were tracking for this request. 595 // Clear any special state that we were tracking for this request.
584 SetRequestClassification(request, NORMAL_REQUEST); 596 SetRequestAttributes(request, kAttributeNone);
585 } 597 }
586 598
587 void ClearInFlightRequests() { 599 void ClearInFlightRequests() {
588 in_flight_requests_.clear(); 600 in_flight_requests_.clear();
589 in_flight_delayable_count_ = 0; 601 in_flight_delayable_count_ = 0;
590 total_layout_blocking_count_ = 0; 602 total_layout_blocking_count_ = 0;
591 } 603 }
592 604
593 size_t CountRequestsWithClassification( 605 size_t CountRequestsWithAttributes(
594 const RequestClassification classification, const bool include_pending) { 606 const RequestAttributes attributes,
595 size_t classification_request_count = 0; 607 ScheduledResourceRequest* current_request) {
608 size_t matching_request_count = 0;
596 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 609 for (RequestSet::const_iterator it = in_flight_requests_.begin();
597 it != in_flight_requests_.end(); ++it) { 610 it != in_flight_requests_.end(); ++it) {
598 if ((*it)->classification() == classification) 611 if (RequestAttributesAreSet((*it)->attributes(), attributes))
599 classification_request_count++; 612 matching_request_count++;
600 } 613 }
601 if (include_pending) { 614 if (!RequestAttributesAreSet(attributes, kAttributeInFlight)) {
615 bool current_request_is_pending = false;
602 for (RequestQueue::NetQueue::const_iterator 616 for (RequestQueue::NetQueue::const_iterator
603 it = pending_requests_.GetNextHighestIterator(); 617 it = pending_requests_.GetNextHighestIterator();
604 it != pending_requests_.End(); ++it) { 618 it != pending_requests_.End(); ++it) {
605 if ((*it)->classification() == classification) 619 if (RequestAttributesAreSet((*it)->attributes(), attributes))
606 classification_request_count++; 620 matching_request_count++;
621 if (*it == current_request)
622 current_request_is_pending = true;
623 }
624 // Account for the current request if it is not in one of the lists yet.
625 if (current_request &&
626 !ContainsKey(in_flight_requests_, current_request) &&
627 !current_request_is_pending) {
628 if (RequestAttributesAreSet(current_request->attributes(), attributes))
629 matching_request_count++;
607 } 630 }
608 } 631 }
609 return classification_request_count; 632 return matching_request_count;
610 } 633 }
611 634
612 void SetRequestClassification(ScheduledResourceRequest* request, 635 bool RequestAttributesAreSet(RequestAttributes request_attributes,
613 RequestClassification classification) { 636 RequestAttributes matching_attributes) const {
614 RequestClassification old_classification = request->classification(); 637 return (request_attributes & matching_attributes) == matching_attributes;
615 if (old_classification == classification) 638 }
639
640 void SetRequestAttributes(ScheduledResourceRequest* request,
641 RequestAttributes attributes) {
642 RequestAttributes old_attributes = request->attributes();
643 if (old_attributes == attributes)
616 return; 644 return;
617 645
618 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) 646 if (RequestAttributesAreSet(old_attributes,
647 kAttributeInFlight | kAttributeDelayable)) {
619 in_flight_delayable_count_--; 648 in_flight_delayable_count_--;
620 if (old_classification == LAYOUT_BLOCKING_REQUEST) 649 }
650 if (RequestAttributesAreSet(old_attributes, kAttributeLayoutBlocking))
621 total_layout_blocking_count_--; 651 total_layout_blocking_count_--;
622 652
623 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) 653 if (RequestAttributesAreSet(attributes,
654 kAttributeInFlight | kAttributeDelayable)) {
624 in_flight_delayable_count_++; 655 in_flight_delayable_count_++;
625 if (classification == LAYOUT_BLOCKING_REQUEST) 656 }
657 if (RequestAttributesAreSet(attributes, kAttributeLayoutBlocking))
626 total_layout_blocking_count_++; 658 total_layout_blocking_count_++;
627 659
628 request->set_classification(classification); 660 request->set_attributes(attributes);
629 DCHECK_EQ( 661 DCHECK_EQ(CountRequestsWithAttributes(
630 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), 662 kAttributeInFlight | kAttributeDelayable, request),
631 in_flight_delayable_count_); 663 in_flight_delayable_count_);
632 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), 664 DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, request),
633 total_layout_blocking_count_); 665 total_layout_blocking_count_);
634 } 666 }
635 667
636 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { 668 RequestAttributes DetermineRequestAttributes(
637 // If a request is already marked as layout-blocking make sure to keep the 669 ScheduledResourceRequest* request) {
638 // classification across redirects unless the priority was lowered. 670 RequestAttributes attributes = kAttributeNone;
639 if (request->classification() == LAYOUT_BLOCKING_REQUEST &&
640 request->url_request()->priority() > net::LOW) {
641 return LAYOUT_BLOCKING_REQUEST;
642 }
643 671
644 if (!has_body_ && request->url_request()->priority() > net::LOW) 672 if (ContainsKey(in_flight_requests_, request))
645 return LAYOUT_BLOCKING_REQUEST; 673 attributes |= kAttributeInFlight;
646 674
647 if (request->url_request()->priority() < net::LOW) { 675 if (RequestAttributesAreSet(request->attributes(),
676 kAttributeLayoutBlocking)) {
677 // If a request is already marked as layout-blocking make sure to keep the
678 // attribute across redirects.
679 attributes |= kAttributeLayoutBlocking;
680 } else if (!has_html_body_ &&
681 request->url_request()->priority() >
682 scheduler_->non_delayable_threshold()) {
683 // Requests that are above the non_delayable threshold before the HTML
684 // body has been parsed are inferred to be layout-blocking.
685 attributes |= kAttributeLayoutBlocking;
686 } else if (request->url_request()->priority() <
687 scheduler_->non_delayable_threshold()) {
688 // Resources below the non_delayable_threshold that are being requested
689 // from a server that does not support native prioritization are
690 // considered delayable.
648 net::HostPortPair host_port_pair = 691 net::HostPortPair host_port_pair =
649 net::HostPortPair::FromURL(request->url_request()->url()); 692 net::HostPortPair::FromURL(request->url_request()->url());
650 net::HttpServerProperties& http_server_properties = 693 net::HttpServerProperties& http_server_properties =
651 *request->url_request()->context()->http_server_properties(); 694 *request->url_request()->context()->http_server_properties();
652 if (!http_server_properties.SupportsRequestPriority(host_port_pair) && 695 if (!http_server_properties.SupportsRequestPriority(host_port_pair))
653 ContainsKey(in_flight_requests_, request)) { 696 attributes |= kAttributeDelayable;
654 return IN_FLIGHT_DELAYABLE_REQUEST;
655 }
656 } 697 }
657 return NORMAL_REQUEST; 698
699 return attributes;
658 } 700 }
659 701
660 bool ShouldKeepSearching( 702 bool ShouldKeepSearching(
661 const net::HostPortPair& active_request_host) const { 703 const net::HostPortPair& active_request_host) const {
662 size_t same_host_count = 0; 704 size_t same_host_count = 0;
663 for (RequestSet::const_iterator it = in_flight_requests_.begin(); 705 for (RequestSet::const_iterator it = in_flight_requests_.begin();
664 it != in_flight_requests_.end(); ++it) { 706 it != in_flight_requests_.end(); ++it) {
665 net::HostPortPair host_port_pair = 707 net::HostPortPair host_port_pair =
666 net::HostPortPair::FromURL((*it)->url_request()->url()); 708 net::HostPortPair::FromURL((*it)->url_request()->url());
667 if (active_request_host.Equals(host_port_pair)) { 709 if (active_request_host.Equals(host_port_pair)) {
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 // * Non-delayable requests are issued imediately. 770 // * Non-delayable requests are issued imediately.
729 // * On a (currently 5 second) heart beat, they load all requests as an 771 // * On a (currently 5 second) heart beat, they load all requests as an
730 // UNTHROTTLED Client, and then return to the COALESCED state. 772 // UNTHROTTLED Client, and then return to the COALESCED state.
731 // * When an active Client makes a request, they are THROTTLED until the 773 // * When an active Client makes a request, they are THROTTLED until the
732 // active Client finishes loading. 774 // active Client finishes loading.
733 ShouldStartReqResult ShouldStartRequest( 775 ShouldStartReqResult ShouldStartRequest(
734 ScheduledResourceRequest* request) const { 776 ScheduledResourceRequest* request) const {
735 const net::URLRequest& url_request = *request->url_request(); 777 const net::URLRequest& url_request = *request->url_request();
736 // Syncronous requests could block the entire render, which could impact 778 // Syncronous requests could block the entire render, which could impact
737 // user-observable Clients. 779 // user-observable Clients.
738 if (!request->is_async()) { 780 if (!request->is_async())
739 return START_REQUEST; 781 return START_REQUEST;
740 }
741 782
742 // TODO(simonjam): This may end up causing disk contention. We should 783 // TODO(simonjam): This may end up causing disk contention. We should
743 // experiment with throttling if that happens. 784 // experiment with throttling if that happens.
744 // TODO(aiolos): We probably want to Coalesce these as well to avoid 785 // TODO(aiolos): We probably want to Coalesce these as well to avoid
745 // waking the disk. 786 // waking the disk.
746 if (!url_request.url().SchemeIsHTTPOrHTTPS()) { 787 if (!url_request.url().SchemeIsHTTPOrHTTPS())
747 return START_REQUEST; 788 return START_REQUEST;
748 }
749 789
750 if (throttle_state_ == COALESCED) { 790 if (throttle_state_ == COALESCED)
751 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 791 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
752 }
753 792
754 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme)) { 793 if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
755 return START_REQUEST; 794 return START_REQUEST;
756 }
757 795
758 // Implementation of the kRequestLimitFieldTrial. 796 // Implementation of the kRequestLimitFieldTrial.
759 if (scheduler_->limit_outstanding_requests() && 797 if (scheduler_->limit_outstanding_requests() &&
760 in_flight_requests_.size() >= scheduler_->outstanding_request_limit()) { 798 in_flight_requests_.size() >= scheduler_->outstanding_request_limit()) {
761 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 799 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
762 } 800 }
763 801
764 net::HostPortPair host_port_pair = 802 net::HostPortPair host_port_pair =
765 net::HostPortPair::FromURL(url_request.url()); 803 net::HostPortPair::FromURL(url_request.url());
766 net::HttpServerProperties& http_server_properties = 804 net::HttpServerProperties& http_server_properties =
767 *url_request.context()->http_server_properties(); 805 *url_request.context()->http_server_properties();
768 806
769 // TODO(willchan): We should really improve this algorithm as described in 807 // TODO(willchan): We should really improve this algorithm as described in
770 // crbug.com/164101. Also, theoretically we should not count a 808 // crbug.com/164101. Also, theoretically we should not count a
771 // request-priority capable request against the delayable requests limit. 809 // request-priority capable request against the delayable requests limit.
772 if (http_server_properties.SupportsRequestPriority(host_port_pair)) { 810 if (http_server_properties.SupportsRequestPriority(host_port_pair))
773 return START_REQUEST; 811 return START_REQUEST;
774 }
775 812
776 if (throttle_state_ == THROTTLED && 813 if (throttle_state_ == THROTTLED &&
777 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) { 814 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) {
778 // There may still be request-priority-capable requests that should be 815 // There may still be request-priority-capable requests that should be
779 // issued. 816 // issued.
780 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 817 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
781 } 818 }
782 819
783 // High-priority and layout-blocking requests. 820 // Non-delayable requests.
784 if (url_request.priority() >= net::LOW) { 821 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
785 return START_REQUEST; 822 return START_REQUEST;
786 }
787 823
788 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) { 824 if (in_flight_delayable_count_ >=
825 scheduler_->max_num_delayable_requests()) {
789 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 826 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
790 } 827 }
791 828
792 if (ShouldKeepSearching(host_port_pair)) { 829 if (ShouldKeepSearching(host_port_pair)) {
793 // There may be other requests for other hosts we'd allow, 830 // There may be other requests for other hosts that may be allowed,
794 // so keep checking. 831 // so keep checking.
795 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; 832 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
796 } 833 }
797 834
798 bool have_immediate_requests_in_flight = 835 // The in-flight requests consist of layout-blocking requests,
799 in_flight_requests_.size() > in_flight_delayable_count_; 836 // normal requests and delayable requests. Everything except for
800 if (have_immediate_requests_in_flight && 837 // delayable requests is handled above here so this is deciding what to
801 (!has_body_ || total_layout_blocking_count_ != 0) && 838 // do with a delayable request while we are in the layout-blocking phase
802 // Do not allow a low priority request through in parallel if 839 // of loading.
803 // we are in a limit field trial. 840 if (!has_html_body_ || total_layout_blocking_count_ != 0) {
804 (scheduler_->limit_outstanding_requests() || 841 size_t non_delayable_requests_in_flight_count =
805 in_flight_delayable_count_ != 0)) { 842 in_flight_requests_.size() - in_flight_delayable_count_;
806 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; 843 if (scheduler_->enable_in_flight_non_delayable_threshold()) {
844 if (non_delayable_requests_in_flight_count >
845 scheduler_->in_flight_non_delayable_threshold()) {
846 // Too many higher priority in-flight requests to allow lower priority
847 // requests through.
848 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
849 }
850 if (in_flight_requests_.size() > 0 &&
851 (scheduler_->limit_outstanding_requests() ||
852 in_flight_delayable_count_ >=
853 scheduler_->max_num_delayable_while_layout_blocking())) {
854 // Block the request if at least one request is in flight and the
855 // number of in-flight delayable requests has hit the configured
856 // limit.
857 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
858 }
859 } else if (non_delayable_requests_in_flight_count > 0 &&
860 (scheduler_->limit_outstanding_requests() ||
861 in_flight_delayable_count_ >=
862 scheduler_->max_num_delayable_while_layout_blocking())) {
863 // If there are no high-priority requests in flight the floodgates open.
864 // If there are high-priority requests in-flight then limit the number
865 // of lower-priority requests (or zero if a limit field trial is
866 // active).
867 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
868 }
807 } 869 }
808 870
809 return START_REQUEST; 871 return START_REQUEST;
810 } 872 }
811 873
812 void LoadAnyStartablePendingRequests() { 874 void LoadAnyStartablePendingRequests() {
813 // We iterate through all the pending requests, starting with the highest 875 // We iterate through all the pending requests, starting with the highest
814 // priority one. For each entry, one of three things can happen: 876 // priority one. For each entry, one of three things can happen:
815 // 1) We start the request, remove it from the list, and keep checking. 877 // 1) We start the request, remove it from the list, and keep checking.
816 // 2) We do NOT start the request, but ShouldStartRequest() signals us that 878 // 2) We do NOT start the request, but ShouldStartRequest() signals us that
(...skipping 26 matching lines...) Expand all
843 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); 905 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
844 break; 906 break;
845 } 907 }
846 } 908 }
847 } 909 }
848 910
849 bool is_audible_; 911 bool is_audible_;
850 bool is_visible_; 912 bool is_visible_;
851 bool is_loaded_; 913 bool is_loaded_;
852 bool is_paused_; 914 bool is_paused_;
853 bool has_body_; 915 // Tracks if the main HTML parser has reached the body which marks the end of
916 // layout-blocking resources.
917 bool has_html_body_;
854 bool using_spdy_proxy_; 918 bool using_spdy_proxy_;
855 RequestQueue pending_requests_; 919 RequestQueue pending_requests_;
856 RequestSet in_flight_requests_; 920 RequestSet in_flight_requests_;
857 base::TimeTicks load_started_time_; 921 base::TimeTicks load_started_time_;
858 // The last time the client switched state between active and background. 922 // The last time the client switched state between active and background.
859 base::TimeTicks last_active_switch_time_; 923 base::TimeTicks last_active_switch_time_;
860 ResourceScheduler* scheduler_; 924 ResourceScheduler* scheduler_;
861 // The number of delayable in-flight requests. 925 // The number of delayable in-flight requests.
862 size_t in_flight_delayable_count_; 926 size_t in_flight_delayable_count_;
863 // The number of layout-blocking in-flight requests. 927 // The number of layout-blocking in-flight requests.
864 size_t total_layout_blocking_count_; 928 size_t total_layout_blocking_count_;
865 ResourceScheduler::ClientThrottleState throttle_state_; 929 ResourceScheduler::ClientThrottleState throttle_state_;
866 }; 930 };
867 931
868 ResourceScheduler::ResourceScheduler() 932 ResourceScheduler::ResourceScheduler()
869 : should_coalesce_(false), 933 : should_coalesce_(false),
870 should_throttle_(false), 934 should_throttle_(false),
871 active_clients_loading_(0), 935 active_clients_loading_(0),
872 coalesced_clients_(0), 936 coalesced_clients_(0),
873 limit_outstanding_requests_(false), 937 limit_outstanding_requests_(false),
874 outstanding_request_limit_(0), 938 outstanding_request_limit_(0),
939 non_delayable_threshold_(
940 kDefaultLayoutBlockingPriorityThreshold),
941 enable_in_flight_non_delayable_threshold_(false),
942 in_flight_non_delayable_threshold_(0),
943 max_num_delayable_while_layout_blocking_(
944 kDefaultMaxNumDelayableWhileLayoutBlocking),
945 max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient),
875 coalescing_timer_(new base::Timer(true /* retain_user_task */, 946 coalescing_timer_(new base::Timer(true /* retain_user_task */,
876 true /* is_repeating */)) { 947 true /* is_repeating */)) {
877 std::string throttling_trial_group = 948 std::string throttling_trial_group =
878 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial); 949 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial);
879 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) { 950 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) {
880 should_throttle_ = true; 951 should_throttle_ = true;
881 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) { 952 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) {
882 should_coalesce_ = true; 953 should_coalesce_ = true;
883 should_throttle_ = true; 954 should_throttle_ = true;
884 } 955 }
885 956
886 std::string outstanding_limit_trial_group = 957 std::string outstanding_limit_trial_group =
887 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial); 958 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial);
888 std::vector<std::string> split_group( 959 std::vector<std::string> split_group(
889 base::SplitString(outstanding_limit_trial_group, "=", 960 base::SplitString(outstanding_limit_trial_group, "=",
890 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)); 961 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
891 int outstanding_limit = 0; 962 int outstanding_limit = 0;
892 if (split_group.size() == 2 && 963 if (split_group.size() == 2 &&
893 split_group[0] == kRequestLimitFieldTrialGroupPrefix && 964 split_group[0] == kRequestLimitFieldTrialGroupPrefix &&
894 base::StringToInt(split_group[1], &outstanding_limit) && 965 base::StringToInt(split_group[1], &outstanding_limit) &&
895 outstanding_limit > 0) { 966 outstanding_limit > 0) {
896 limit_outstanding_requests_ = true; 967 limit_outstanding_requests_ = true;
897 outstanding_request_limit_ = outstanding_limit; 968 outstanding_request_limit_ = outstanding_limit;
898 } 969 }
970
971 // Set up the ResourceScheduling field trial options.
972 // The field trial parameters are also encoded into the group name since
973 // the variations component is not available from here and plumbing the
974 // options through the code is overkill for a short experiment.
975 //
976 // The group name encoding looks like this:
977 // <descriptiveName>_ABCDE_E2_F_G
978 // A - fetchDeferLateScripts (1 for true, 0 for false)
979 // B - fetchIncreaseFontPriority (1 for true, 0 for false)
980 // C - fetchIncreaseAsyncScriptPriority (1 for true, 0 for false)
981 // D - fetchIncreasePriorities (1 for true, 0 for false)
982 // E - fetchEnableLayoutBlockingThreshold (1 for true, 0 for false)
983 // E2 - fetchLayoutBlockingThreshold (Numeric)
984 // F - fetchMaxNumDelayableWhileLayoutBlocking (Numeric)
985 // G - fetchMaxNumDelayableRequests (Numeric)
986 std::string resource_priorities_trial_group =
987 base::FieldTrialList::FindFullName(kResourcePrioritiesFieldTrial);
988 std::vector<std::string> resource_priorities_split_group(
989 base::SplitString(resource_priorities_trial_group, "_",
990 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL));
991 if (resource_priorities_split_group.size() == 5 &&
992 resource_priorities_split_group[1].length() == 5) {
993 // fetchIncreasePriorities
994 if (resource_priorities_split_group[1].at(3) == '1')
995 non_delayable_threshold_ = net::MEDIUM;
996 enable_in_flight_non_delayable_threshold_ =
997 resource_priorities_split_group[1].at(4) == '1';
998 size_t numeric_value = 0;
999 if (base::StringToSizeT(resource_priorities_split_group[2], &numeric_value))
1000 in_flight_non_delayable_threshold_ = numeric_value;
1001 if (base::StringToSizeT(resource_priorities_split_group[3], &numeric_value))
1002 max_num_delayable_while_layout_blocking_ = numeric_value;
1003 if (base::StringToSizeT(resource_priorities_split_group[4], &numeric_value))
1004 max_num_delayable_requests_ = numeric_value;
1005 }
899 } 1006 }
900 1007
901 ResourceScheduler::~ResourceScheduler() { 1008 ResourceScheduler::~ResourceScheduler() {
902 DCHECK(unowned_requests_.empty()); 1009 DCHECK(unowned_requests_.empty());
903 DCHECK(client_map_.empty()); 1010 DCHECK(client_map_.empty());
904 } 1011 }
905 1012
906 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, 1013 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle,
907 bool should_coalesce) { 1014 bool should_coalesce) {
908 should_coalesce_ = should_coalesce; 1015 should_coalesce_ = should_coalesce;
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1225 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params, 1332 client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
1226 new_priority_params); 1333 new_priority_params);
1227 } 1334 }
1228 1335
1229 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( 1336 ResourceScheduler::ClientId ResourceScheduler::MakeClientId(
1230 int child_id, int route_id) { 1337 int child_id, int route_id) {
1231 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; 1338 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
1232 } 1339 }
1233 1340
1234 } // namespace content 1341 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/loader/resource_scheduler.h ('k') | content/browser/loader/resource_scheduler_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698