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 |