| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |