Chromium Code Reviews| 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 | |
| 5 #include <set> | 7 #include <set> |
| 6 | 8 |
| 7 #include "content/browser/loader/resource_scheduler.h" | |
| 8 | |
| 9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 13 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "content/common/resource_messages.h" | 15 #include "content/common/resource_messages.h" |
| 16 #include "content/browser/loader/resource_message_delegate.h" | 16 #include "content/browser/loader/resource_message_delegate.h" |
| 17 #include "content/public/browser/resource_controller.h" | 17 #include "content/public/browser/resource_controller.h" |
| 18 #include "content/public/browser/resource_request_info.h" | 18 #include "content/public/browser/resource_request_info.h" |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 // Field trial constants | 32 // Field trial constants |
| 33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing"; | 33 const char kThrottleCoalesceFieldTrial[] = "RequestThrottlingAndCoalescing"; |
| 34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle"; | 34 const char kThrottleCoalesceFieldTrialThrottle[] = "Throttle"; |
| 35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce"; | 35 const char kThrottleCoalesceFieldTrialCoalesce[] = "Coalesce"; |
| 36 | 36 |
| 37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting"; | 37 const char kRequestLimitFieldTrial[] = "OutstandingRequestLimiting"; |
| 38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit"; | 38 const char kRequestLimitFieldTrialGroupPrefix[] = "Limit"; |
| 39 | 39 |
| 40 const char kResourcePrioritiesFieldTrial[] = "ResourcePriorities"; | |
| 41 | |
| 42 // Flags identifying various attributes of the request that are used | |
| 43 // when making scheduling decisions. | |
| 44 typedef uint8_t RequestAttributes; | |
|
mmenke
2015/08/13 21:27:44
nit: include <stdint.h>
mmenke
2015/08/13 21:27:45
I think "using RequestAttributes = uint8_t;" is no
Pat Meenan
2015/08/14 13:52:47
Done.
Pat Meenan
2015/08/14 13:52:47
Done.
| |
| 45 const RequestAttributes kAttributeNone = 0x00; | |
| 46 const RequestAttributes kAttributeInFlight = 0x01; | |
| 47 const RequestAttributes kAttributeDelayable = 0x02; | |
| 48 const RequestAttributes kAttributeLayoutBlocking = 0x04; | |
| 49 | |
| 40 // Post ResourceScheduler histograms of the following forms: | 50 // Post ResourceScheduler histograms of the following forms: |
| 41 // If |histogram_suffix| is NULL or the empty string: | 51 // If |histogram_suffix| is NULL or the empty string: |
| 42 // ResourceScheduler.base_name.histogram_name | 52 // ResourceScheduler.base_name.histogram_name |
| 43 // Else: | 53 // Else: |
| 44 // ResourceScheduler.base_name.histogram_name.histogram_suffix | 54 // ResourceScheduler.base_name.histogram_name.histogram_suffix |
| 45 void PostHistogram(const char* base_name, | 55 void PostHistogram(const char* base_name, |
| 46 const char* histogram_name, | 56 const char* histogram_name, |
| 47 const char* histogram_suffix, | 57 const char* histogram_suffix, |
| 48 base::TimeDelta time) { | 58 base::TimeDelta time) { |
| 49 std::string histogram = | 59 std::string histogram = |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 67 else if (num_clients <= 15) | 77 else if (num_clients <= 15) |
| 68 return "Max15Clients"; | 78 return "Max15Clients"; |
| 69 else if (num_clients <= 30) | 79 else if (num_clients <= 30) |
| 70 return "Max30Clients"; | 80 return "Max30Clients"; |
| 71 return "Over30Clients"; | 81 return "Over30Clients"; |
| 72 } | 82 } |
| 73 | 83 |
| 74 } // namespace | 84 } // namespace |
| 75 | 85 |
| 76 static const size_t kCoalescedTimerPeriod = 5000; | 86 static const size_t kCoalescedTimerPeriod = 5000; |
| 77 static const size_t kMaxNumDelayableRequestsPerClient = 10; | 87 static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10; |
| 78 static const size_t kMaxNumDelayableRequestsPerHost = 6; | 88 static const size_t kMaxNumDelayableRequestsPerHost = 6; |
| 79 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; | |
| 80 | 93 |
| 81 struct ResourceScheduler::RequestPriorityParams { | 94 struct ResourceScheduler::RequestPriorityParams { |
| 82 RequestPriorityParams() | 95 RequestPriorityParams() |
| 83 : priority(net::DEFAULT_PRIORITY), | 96 : priority(net::DEFAULT_PRIORITY), |
| 84 intra_priority(0) { | 97 intra_priority(0) { |
| 85 } | 98 } |
| 86 | 99 |
| 87 RequestPriorityParams(net::RequestPriority priority, int intra_priority) | 100 RequestPriorityParams(net::RequestPriority priority, int intra_priority) |
| 88 : priority(priority), | 101 : priority(priority), |
| 89 intra_priority(intra_priority) { | 102 intra_priority(intra_priority) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 ScheduledResourceRequest(const ClientId& client_id, | 183 ScheduledResourceRequest(const ClientId& client_id, |
| 171 net::URLRequest* request, | 184 net::URLRequest* request, |
| 172 ResourceScheduler* scheduler, | 185 ResourceScheduler* scheduler, |
| 173 const RequestPriorityParams& priority) | 186 const RequestPriorityParams& priority) |
| 174 : ResourceMessageDelegate(request), | 187 : ResourceMessageDelegate(request), |
| 175 client_id_(client_id), | 188 client_id_(client_id), |
| 176 client_state_on_creation_(scheduler->GetClientState(client_id_)), | 189 client_state_on_creation_(scheduler->GetClientState(client_id_)), |
| 177 request_(request), | 190 request_(request), |
| 178 ready_(false), | 191 ready_(false), |
| 179 deferred_(false), | 192 deferred_(false), |
| 180 classification_(NORMAL_REQUEST), | 193 attributes_(kAttributeNone), |
| 181 scheduler_(scheduler), | 194 scheduler_(scheduler), |
| 182 priority_(priority), | 195 priority_(priority), |
| 183 fifo_ordering_(0) { | 196 fifo_ordering_(0) { |
| 184 } | 197 } |
| 185 | 198 |
| 186 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } | 199 ~ScheduledResourceRequest() override { scheduler_->RemoveRequest(this); } |
| 187 | 200 |
| 188 void Start() { | 201 void Start() { |
| 189 ready_ = true; | 202 ready_ = true; |
| 190 if (!request_->status().is_success()) | 203 if (!request_->status().is_success()) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 223 const RequestPriorityParams& get_request_priority_params() const { | 236 const RequestPriorityParams& get_request_priority_params() const { |
| 224 return priority_; | 237 return priority_; |
| 225 } | 238 } |
| 226 const ClientId& client_id() const { return client_id_; } | 239 const ClientId& client_id() const { return client_id_; } |
| 227 net::URLRequest* url_request() { return request_; } | 240 net::URLRequest* url_request() { return request_; } |
| 228 const net::URLRequest* url_request() const { return request_; } | 241 const net::URLRequest* url_request() const { return request_; } |
| 229 uint32 fifo_ordering() const { return fifo_ordering_; } | 242 uint32 fifo_ordering() const { return fifo_ordering_; } |
| 230 void set_fifo_ordering(uint32 fifo_ordering) { | 243 void set_fifo_ordering(uint32 fifo_ordering) { |
| 231 fifo_ordering_ = fifo_ordering; | 244 fifo_ordering_ = fifo_ordering; |
| 232 } | 245 } |
| 233 RequestClassification classification() const { | 246 RequestAttributes attributes() const { |
| 234 return classification_; | 247 return attributes_; |
| 235 } | 248 } |
| 236 void set_classification(RequestClassification classification) { | 249 void set_attributes(RequestAttributes attributes) { |
| 237 classification_ = classification; | 250 attributes_ = attributes; |
| 238 } | 251 } |
| 239 | 252 |
| 240 private: | 253 private: |
| 241 // ResourceMessageDelegate interface: | 254 // ResourceMessageDelegate interface: |
| 242 bool OnMessageReceived(const IPC::Message& message) override { | 255 bool OnMessageReceived(const IPC::Message& message) override { |
| 243 bool handled = true; | 256 bool handled = true; |
| 244 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) | 257 IPC_BEGIN_MESSAGE_MAP(ScheduledResourceRequest, message) |
| 245 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) | 258 IPC_MESSAGE_HANDLER(ResourceHostMsg_DidChangePriority, DidChangePriority) |
| 246 IPC_MESSAGE_UNHANDLED(handled = false) | 259 IPC_MESSAGE_UNHANDLED(handled = false) |
| 247 IPC_END_MESSAGE_MAP() | 260 IPC_END_MESSAGE_MAP() |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 259 void DidChangePriority(int request_id, net::RequestPriority new_priority, | 272 void DidChangePriority(int request_id, net::RequestPriority new_priority, |
| 260 int intra_priority_value) { | 273 int intra_priority_value) { |
| 261 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); | 274 scheduler_->ReprioritizeRequest(this, new_priority, intra_priority_value); |
| 262 } | 275 } |
| 263 | 276 |
| 264 const ClientId client_id_; | 277 const ClientId client_id_; |
| 265 const ResourceScheduler::ClientState client_state_on_creation_; | 278 const ResourceScheduler::ClientState client_state_on_creation_; |
| 266 net::URLRequest* request_; | 279 net::URLRequest* request_; |
| 267 bool ready_; | 280 bool ready_; |
| 268 bool deferred_; | 281 bool deferred_; |
| 269 RequestClassification classification_; | 282 RequestAttributes attributes_; |
| 270 ResourceScheduler* scheduler_; | 283 ResourceScheduler* scheduler_; |
| 271 RequestPriorityParams priority_; | 284 RequestPriorityParams priority_; |
| 272 uint32 fifo_ordering_; | 285 uint32 fifo_ordering_; |
| 273 base::TimeTicks time_deferred_; | 286 base::TimeTicks time_deferred_; |
| 274 | 287 |
| 275 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); | 288 DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequest); |
| 276 }; | 289 }; |
| 277 | 290 |
| 278 bool ResourceScheduler::ScheduledResourceSorter::operator()( | 291 bool ResourceScheduler::ScheduledResourceSorter::operator()( |
| 279 const ScheduledResourceRequest* a, | 292 const ScheduledResourceRequest* a, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 301 // Each client represents a tab. | 314 // Each client represents a tab. |
| 302 class ResourceScheduler::Client { | 315 class ResourceScheduler::Client { |
| 303 public: | 316 public: |
| 304 explicit Client(ResourceScheduler* scheduler, | 317 explicit Client(ResourceScheduler* scheduler, |
| 305 bool is_visible, | 318 bool is_visible, |
| 306 bool is_audible) | 319 bool is_audible) |
| 307 : is_audible_(is_audible), | 320 : is_audible_(is_audible), |
| 308 is_visible_(is_visible), | 321 is_visible_(is_visible), |
| 309 is_loaded_(false), | 322 is_loaded_(false), |
| 310 is_paused_(false), | 323 is_paused_(false), |
| 311 has_body_(false), | 324 has_html_body_(false), |
| 312 using_spdy_proxy_(false), | 325 using_spdy_proxy_(false), |
| 313 load_started_time_(base::TimeTicks::Now()), | 326 load_started_time_(base::TimeTicks::Now()), |
| 314 scheduler_(scheduler), | 327 scheduler_(scheduler), |
| 315 in_flight_delayable_count_(0), | 328 in_flight_delayable_count_(0), |
| 316 total_layout_blocking_count_(0), | 329 total_layout_blocking_count_(0), |
| 317 throttle_state_(ResourceScheduler::THROTTLED) {} | 330 throttle_state_(ResourceScheduler::THROTTLED) { |
| 331 } | |
| 318 | 332 |
| 319 ~Client() { | 333 ~Client() { |
| 320 // Update to default state and pause to ensure the scheduler has a | 334 // Update to default state and pause to ensure the scheduler has a |
| 321 // correct count of relevant types of clients. | 335 // correct count of relevant types of clients. |
| 322 is_visible_ = false; | 336 is_visible_ = false; |
| 323 is_audible_ = false; | 337 is_audible_ = false; |
| 324 is_paused_ = true; | 338 is_paused_ = true; |
| 325 UpdateThrottleState(); | 339 UpdateThrottleState(); |
| 326 } | 340 } |
| 327 | 341 |
| 328 void ScheduleRequest( | 342 void ScheduleRequest( |
| 329 net::URLRequest* url_request, | 343 net::URLRequest* url_request, |
| 330 ScheduledResourceRequest* request) { | 344 ScheduledResourceRequest* request) { |
| 345 SetRequestAttributes(request, DetermineRequestAttributes(request)); | |
| 331 if (ShouldStartRequest(request) == START_REQUEST) | 346 if (ShouldStartRequest(request) == START_REQUEST) |
| 332 StartRequest(request); | 347 StartRequest(request); |
| 333 else | 348 else |
| 334 pending_requests_.Insert(request); | 349 pending_requests_.Insert(request); |
| 335 SetRequestClassification(request, ClassifyRequest(request)); | |
| 336 } | 350 } |
| 337 | 351 |
| 338 void RemoveRequest(ScheduledResourceRequest* request) { | 352 void RemoveRequest(ScheduledResourceRequest* request) { |
| 339 if (pending_requests_.IsQueued(request)) { | 353 if (pending_requests_.IsQueued(request)) { |
| 340 pending_requests_.Erase(request); | 354 pending_requests_.Erase(request); |
| 341 DCHECK(!ContainsKey(in_flight_requests_, request)); | 355 DCHECK(!ContainsKey(in_flight_requests_, request)); |
| 342 } else { | 356 } else { |
| 343 EraseInFlightRequest(request); | 357 EraseInFlightRequest(request); |
| 344 | 358 |
| 345 // Removing this request may have freed up another to load. | 359 // Removing this request may have freed up another to load. |
| 346 LoadAnyStartablePendingRequests(); | 360 LoadAnyStartablePendingRequests(); |
| 347 } | 361 } |
| 348 } | 362 } |
| 349 | 363 |
| 350 RequestSet StartAndRemoveAllRequests() { | 364 RequestSet StartAndRemoveAllRequests() { |
| 351 // First start any pending requests so that they will be moved into | 365 // First start any pending requests so that they will be moved into |
| 352 // in_flight_requests_. This may exceed the limits | 366 // in_flight_requests_. This may exceed the limits |
| 353 // kMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost and | 367 // kDefaultMaxNumDelayableRequestsPerClient, kMaxNumDelayableRequestsPerHost |
| 354 // kMaxNumThrottledRequestsPerClient, so this method must not do anything | 368 // and kMaxNumThrottledRequestsPerClient, so this method must not do |
| 355 // that depends on those limits before calling ClearInFlightRequests() | 369 // anything that depends on those limits before calling |
| 356 // below. | 370 // ClearInFlightRequests() below. |
| 357 while (!pending_requests_.IsEmpty()) { | 371 while (!pending_requests_.IsEmpty()) { |
| 358 ScheduledResourceRequest* request = | 372 ScheduledResourceRequest* request = |
| 359 *pending_requests_.GetNextHighestIterator(); | 373 *pending_requests_.GetNextHighestIterator(); |
| 360 pending_requests_.Erase(request); | 374 pending_requests_.Erase(request); |
| 361 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? | 375 // StartRequest() may modify pending_requests_. TODO(ricea): Does it? |
| 362 StartRequest(request); | 376 StartRequest(request); |
| 363 } | 377 } |
| 364 RequestSet unowned_requests; | 378 RequestSet unowned_requests; |
| 365 for (RequestSet::iterator it = in_flight_requests_.begin(); | 379 for (RequestSet::iterator it = in_flight_requests_.begin(); |
| 366 it != in_flight_requests_.end(); ++it) { | 380 it != in_flight_requests_.end(); ++it) { |
| 367 unowned_requests.insert(*it); | 381 unowned_requests.insert(*it); |
| 368 (*it)->set_classification(NORMAL_REQUEST); | 382 (*it)->set_attributes(kAttributeNone); |
| 369 } | 383 } |
| 370 ClearInFlightRequests(); | 384 ClearInFlightRequests(); |
| 371 return unowned_requests; | 385 return unowned_requests; |
| 372 } | 386 } |
| 373 | 387 |
| 374 bool is_active() const { return is_visible_ || is_audible_; } | 388 bool is_active() const { return is_visible_ || is_audible_; } |
| 375 | 389 |
| 376 bool is_loaded() const { return is_loaded_; } | 390 bool is_loaded() const { return is_loaded_; } |
| 377 | 391 |
| 378 bool is_visible() const { return is_visible_; } | 392 bool is_visible() const { return is_visible_; } |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 463 scheduler_->DecrementActiveClientsLoading(); | 477 scheduler_->DecrementActiveClientsLoading(); |
| 464 } | 478 } |
| 465 if (throttle_state_ == COALESCED) { | 479 if (throttle_state_ == COALESCED) { |
| 466 scheduler_->IncrementCoalescedClients(); | 480 scheduler_->IncrementCoalescedClients(); |
| 467 } else if (old_throttle_state == COALESCED) { | 481 } else if (old_throttle_state == COALESCED) { |
| 468 scheduler_->DecrementCoalescedClients(); | 482 scheduler_->DecrementCoalescedClients(); |
| 469 } | 483 } |
| 470 } | 484 } |
| 471 | 485 |
| 472 void OnNavigate() { | 486 void OnNavigate() { |
| 473 has_body_ = false; | 487 has_html_body_ = false; |
| 474 is_loaded_ = false; | 488 is_loaded_ = false; |
| 475 } | 489 } |
| 476 | 490 |
| 477 void OnWillInsertBody() { | 491 void OnWillInsertBody() { |
| 478 has_body_ = true; | 492 has_html_body_ = true; |
| 479 LoadAnyStartablePendingRequests(); | 493 LoadAnyStartablePendingRequests(); |
| 480 } | 494 } |
| 481 | 495 |
| 482 void OnReceivedSpdyProxiedHttpResponse() { | 496 void OnReceivedSpdyProxiedHttpResponse() { |
| 483 if (!using_spdy_proxy_) { | 497 if (!using_spdy_proxy_) { |
| 484 using_spdy_proxy_ = true; | 498 using_spdy_proxy_ = true; |
| 485 LoadAnyStartablePendingRequests(); | 499 LoadAnyStartablePendingRequests(); |
| 486 } | 500 } |
| 487 } | 501 } |
| 488 | 502 |
| 489 void ReprioritizeRequest(ScheduledResourceRequest* request, | 503 void ReprioritizeRequest(ScheduledResourceRequest* request, |
| 490 RequestPriorityParams old_priority_params, | 504 RequestPriorityParams old_priority_params, |
| 491 RequestPriorityParams new_priority_params) { | 505 RequestPriorityParams new_priority_params) { |
| 492 request->url_request()->SetPriority(new_priority_params.priority); | 506 request->url_request()->SetPriority(new_priority_params.priority); |
| 493 request->set_request_priority_params(new_priority_params); | 507 request->set_request_priority_params(new_priority_params); |
| 508 SetRequestAttributes(request, DetermineRequestAttributes(request)); | |
| 494 if (!pending_requests_.IsQueued(request)) { | 509 if (!pending_requests_.IsQueued(request)) { |
| 495 DCHECK(ContainsKey(in_flight_requests_, request)); | 510 DCHECK(ContainsKey(in_flight_requests_, request)); |
| 496 // The priority of the request and priority support of the server may | |
| 497 // have changed, so update the delayable count. | |
| 498 SetRequestClassification(request, ClassifyRequest(request)); | |
| 499 // Request has already started. | 511 // Request has already started. |
| 500 return; | 512 return; |
| 501 } | 513 } |
| 502 | 514 |
| 503 pending_requests_.Erase(request); | 515 pending_requests_.Erase(request); |
| 504 pending_requests_.Insert(request); | 516 pending_requests_.Insert(request); |
| 505 | 517 |
| 506 if (new_priority_params.priority > old_priority_params.priority) { | 518 if (new_priority_params.priority > old_priority_params.priority) { |
| 507 // Check if this request is now able to load at its new priority. | 519 // Check if this request is now able to load at its new priority. |
| 508 LoadAnyStartablePendingRequests(); | 520 LoadAnyStartablePendingRequests(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 555 | 567 |
| 556 private: | 568 private: |
| 557 enum ShouldStartReqResult { | 569 enum ShouldStartReqResult { |
| 558 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, | 570 DO_NOT_START_REQUEST_AND_STOP_SEARCHING, |
| 559 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, | 571 DO_NOT_START_REQUEST_AND_KEEP_SEARCHING, |
| 560 START_REQUEST, | 572 START_REQUEST, |
| 561 }; | 573 }; |
| 562 | 574 |
| 563 void InsertInFlightRequest(ScheduledResourceRequest* request) { | 575 void InsertInFlightRequest(ScheduledResourceRequest* request) { |
| 564 in_flight_requests_.insert(request); | 576 in_flight_requests_.insert(request); |
| 565 SetRequestClassification(request, ClassifyRequest(request)); | 577 SetRequestAttributes(request, DetermineRequestAttributes(request)); |
| 566 } | 578 } |
| 567 | 579 |
| 568 void EraseInFlightRequest(ScheduledResourceRequest* request) { | 580 void EraseInFlightRequest(ScheduledResourceRequest* request) { |
| 569 size_t erased = in_flight_requests_.erase(request); | 581 size_t erased = in_flight_requests_.erase(request); |
| 570 DCHECK_EQ(1u, erased); | 582 DCHECK_EQ(1u, erased); |
| 571 // Clear any special state that we were tracking for this request. | 583 // Clear any special state that we were tracking for this request. |
| 572 SetRequestClassification(request, NORMAL_REQUEST); | 584 SetRequestAttributes(request, kAttributeNone); |
| 573 } | 585 } |
| 574 | 586 |
| 575 void ClearInFlightRequests() { | 587 void ClearInFlightRequests() { |
| 576 in_flight_requests_.clear(); | 588 in_flight_requests_.clear(); |
| 577 in_flight_delayable_count_ = 0; | 589 in_flight_delayable_count_ = 0; |
| 578 total_layout_blocking_count_ = 0; | 590 total_layout_blocking_count_ = 0; |
| 579 } | 591 } |
| 580 | 592 |
| 581 size_t CountRequestsWithClassification( | 593 size_t CountRequestsWithAttributes( |
| 582 const RequestClassification classification, const bool include_pending) { | 594 const RequestAttributes attributes, |
| 583 size_t classification_request_count = 0; | 595 const bool include_pending) { |
| 596 size_t matching_request_count = 0; | |
| 584 for (RequestSet::const_iterator it = in_flight_requests_.begin(); | 597 for (RequestSet::const_iterator it = in_flight_requests_.begin(); |
| 585 it != in_flight_requests_.end(); ++it) { | 598 it != in_flight_requests_.end(); ++it) { |
| 586 if ((*it)->classification() == classification) | 599 if (RequestAttributesAreSet((*it)->attributes(), attributes)) |
| 587 classification_request_count++; | 600 matching_request_count++; |
| 588 } | 601 } |
| 589 if (include_pending) { | 602 if (include_pending) { |
| 590 for (RequestQueue::NetQueue::const_iterator | 603 for (RequestQueue::NetQueue::const_iterator |
| 591 it = pending_requests_.GetNextHighestIterator(); | 604 it = pending_requests_.GetNextHighestIterator(); |
| 592 it != pending_requests_.End(); ++it) { | 605 it != pending_requests_.End(); ++it) { |
| 593 if ((*it)->classification() == classification) | 606 if (RequestAttributesAreSet((*it)->attributes(), attributes)) |
| 594 classification_request_count++; | 607 matching_request_count++; |
| 595 } | 608 } |
| 596 } | 609 } |
| 597 return classification_request_count; | 610 return matching_request_count; |
| 598 } | 611 } |
| 599 | 612 |
| 600 void SetRequestClassification(ScheduledResourceRequest* request, | 613 bool RequestAttributesAreSet(RequestAttributes request_attributes, |
| 601 RequestClassification classification) { | 614 RequestAttributes matching_attributes) const { |
| 602 RequestClassification old_classification = request->classification(); | 615 return (request_attributes & matching_attributes) == matching_attributes; |
| 603 if (old_classification == classification) | 616 } |
| 617 | |
| 618 void SetRequestAttributes(ScheduledResourceRequest* request, | |
| 619 RequestAttributes attributes) { | |
| 620 RequestAttributes old_attributes = request->attributes(); | |
| 621 if (old_attributes == attributes) | |
| 604 return; | 622 return; |
| 605 | 623 |
| 606 if (old_classification == IN_FLIGHT_DELAYABLE_REQUEST) | 624 if (RequestAttributesAreSet(old_attributes, |
| 625 kAttributeInFlight | kAttributeDelayable)) { | |
|
mmenke
2015/08/13 21:27:45
nit: +1 indent
Pat Meenan
2015/08/14 13:52:47
Done.
| |
| 607 in_flight_delayable_count_--; | 626 in_flight_delayable_count_--; |
| 608 if (old_classification == LAYOUT_BLOCKING_REQUEST) | 627 } |
| 628 if (RequestAttributesAreSet(old_attributes, kAttributeLayoutBlocking)) | |
| 609 total_layout_blocking_count_--; | 629 total_layout_blocking_count_--; |
| 610 | 630 |
| 611 if (classification == IN_FLIGHT_DELAYABLE_REQUEST) | 631 if (RequestAttributesAreSet(attributes, |
| 632 kAttributeInFlight | kAttributeDelayable)) { | |
|
mmenke
2015/08/13 21:27:45
nit: +1 indent
Pat Meenan
2015/08/14 13:52:47
Done.
| |
| 612 in_flight_delayable_count_++; | 633 in_flight_delayable_count_++; |
| 613 if (classification == LAYOUT_BLOCKING_REQUEST) | 634 } |
| 635 if (RequestAttributesAreSet(attributes, kAttributeLayoutBlocking)) | |
| 614 total_layout_blocking_count_++; | 636 total_layout_blocking_count_++; |
| 615 | 637 |
| 616 request->set_classification(classification); | 638 request->set_attributes(attributes); |
| 617 DCHECK_EQ( | 639 DCHECK_EQ(CountRequestsWithAttributes( |
| 618 CountRequestsWithClassification(IN_FLIGHT_DELAYABLE_REQUEST, false), | 640 kAttributeInFlight | kAttributeDelayable, false), |
| 619 in_flight_delayable_count_); | 641 in_flight_delayable_count_); |
| 620 DCHECK_EQ(CountRequestsWithClassification(LAYOUT_BLOCKING_REQUEST, true), | 642 DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, true), |
| 621 total_layout_blocking_count_); | 643 total_layout_blocking_count_); |
| 622 } | 644 } |
| 623 | 645 |
| 624 RequestClassification ClassifyRequest(ScheduledResourceRequest* request) { | 646 RequestAttributes DetermineRequestAttributes( |
| 625 // If a request is already marked as layout-blocking make sure to keep the | 647 ScheduledResourceRequest* request) { |
| 626 // classification across redirects unless the priority was lowered. | 648 RequestAttributes attributes = kAttributeNone; |
| 627 if (request->classification() == LAYOUT_BLOCKING_REQUEST && | |
| 628 request->url_request()->priority() > net::LOW) { | |
| 629 return LAYOUT_BLOCKING_REQUEST; | |
| 630 } | |
| 631 | 649 |
| 632 if (!has_body_ && request->url_request()->priority() > net::LOW) | 650 if (ContainsKey(in_flight_requests_, request)) |
| 633 return LAYOUT_BLOCKING_REQUEST; | 651 attributes = attributes | kAttributeInFlight; |
|
mmenke
2015/08/13 21:27:45
Any reason not to use |= on all of these?
Pat Meenan
2015/08/14 13:52:47
I wasn't sure if it would look too much like != an
| |
| 634 | 652 |
| 635 if (request->url_request()->priority() < net::LOW) { | 653 if (RequestAttributesAreSet(request->attributes(), |
| 654 kAttributeLayoutBlocking)) { | |
| 655 // If a request is already marked as layout-blocking make sure to keep the | |
| 656 // attribute across redirects. | |
| 657 attributes = attributes | kAttributeLayoutBlocking; | |
| 658 } else if (!has_html_body_ && | |
| 659 request->url_request()->priority() > | |
| 660 scheduler_->non_delayable_threshold()) { | |
| 661 // Requests that are above the non_delayable threshold before the HTML | |
| 662 // body has been parsed are inferred to be layout-blocking. | |
| 663 attributes = attributes | kAttributeLayoutBlocking; | |
| 664 } else if (request->url_request()->priority() < | |
| 665 scheduler_->non_delayable_threshold()) { | |
| 666 // Resources below the non_delayable_threshold that are being requested | |
| 667 // from a server that does not support native prioritization are | |
| 668 // considered delayable. | |
| 636 net::HostPortPair host_port_pair = | 669 net::HostPortPair host_port_pair = |
| 637 net::HostPortPair::FromURL(request->url_request()->url()); | 670 net::HostPortPair::FromURL(request->url_request()->url()); |
| 638 net::HttpServerProperties& http_server_properties = | 671 net::HttpServerProperties& http_server_properties = |
| 639 *request->url_request()->context()->http_server_properties(); | 672 *request->url_request()->context()->http_server_properties(); |
| 640 if (!http_server_properties.SupportsRequestPriority(host_port_pair) && | 673 if (!http_server_properties.SupportsRequestPriority(host_port_pair)) |
| 641 ContainsKey(in_flight_requests_, request)) { | 674 attributes = attributes | kAttributeDelayable; |
| 642 return IN_FLIGHT_DELAYABLE_REQUEST; | |
| 643 } | |
| 644 } | 675 } |
| 645 return NORMAL_REQUEST; | 676 |
| 677 return attributes; | |
| 646 } | 678 } |
| 647 | 679 |
| 648 bool ShouldKeepSearching( | 680 bool ShouldKeepSearching( |
| 649 const net::HostPortPair& active_request_host) const { | 681 const net::HostPortPair& active_request_host) const { |
| 650 size_t same_host_count = 0; | 682 size_t same_host_count = 0; |
| 651 for (RequestSet::const_iterator it = in_flight_requests_.begin(); | 683 for (RequestSet::const_iterator it = in_flight_requests_.begin(); |
| 652 it != in_flight_requests_.end(); ++it) { | 684 it != in_flight_requests_.end(); ++it) { |
| 653 net::HostPortPair host_port_pair = | 685 net::HostPortPair host_port_pair = |
| 654 net::HostPortPair::FromURL((*it)->url_request()->url()); | 686 net::HostPortPair::FromURL((*it)->url_request()->url()); |
| 655 if (active_request_host.Equals(host_port_pair)) { | 687 if (active_request_host.Equals(host_port_pair)) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 761 return START_REQUEST; | 793 return START_REQUEST; |
| 762 } | 794 } |
| 763 | 795 |
| 764 if (throttle_state_ == THROTTLED && | 796 if (throttle_state_ == THROTTLED && |
| 765 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) { | 797 in_flight_requests_.size() >= kMaxNumThrottledRequestsPerClient) { |
| 766 // There may still be request-priority-capable requests that should be | 798 // There may still be request-priority-capable requests that should be |
| 767 // issued. | 799 // issued. |
| 768 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; | 800 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; |
| 769 } | 801 } |
| 770 | 802 |
| 771 // High-priority and layout-blocking requests. | 803 // non-delayable requests. |
|
mmenke
2015/08/13 21:27:45
Nit: "Non-delayable requests." (capitalize)
Pat Meenan
2015/08/14 13:52:47
Done.
| |
| 772 if (url_request.priority() >= net::LOW) { | 804 if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) { |
| 773 return START_REQUEST; | 805 return START_REQUEST; |
| 774 } | 806 } |
|
mmenke
2015/08/13 21:27:45
nit: Remove braces
Pat Meenan
2015/08/14 13:52:47
I had them to be consistent with the rest of the f
| |
| 775 | 807 |
| 776 if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient) { | 808 if (in_flight_delayable_count_ >= |
| 809 scheduler_->max_num_delayable_requests()) { | |
| 777 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 810 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; |
| 778 } | 811 } |
| 779 | 812 |
| 780 if (ShouldKeepSearching(host_port_pair)) { | 813 if (ShouldKeepSearching(host_port_pair)) { |
| 781 // There may be other requests for other hosts we'd allow, | 814 // There may be other requests for other hosts we'd allow, |
| 782 // so keep checking. | 815 // so keep checking. |
| 783 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; | 816 return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING; |
| 784 } | 817 } |
| 785 | 818 |
| 786 bool have_immediate_requests_in_flight = | 819 // The in-flight requests consist of layout-blocking requests, |
| 787 in_flight_requests_.size() > in_flight_delayable_count_; | 820 // normal requests and delayable requests. Everything except for |
| 788 if (have_immediate_requests_in_flight && | 821 // delayable requests is handled above here so this is deciding what to |
| 789 (!has_body_ || total_layout_blocking_count_ != 0) && | 822 // do with a delayable request while we are in the layout-blocking phase |
| 790 // Do not allow a low priority request through in parallel if | 823 // of loading. |
| 791 // we are in a limit field trial. | 824 if (!has_html_body_ || total_layout_blocking_count_ != 0) { |
| 792 (scheduler_->limit_outstanding_requests() || | 825 size_t non_delayable_requests_in_flight_count = |
| 793 in_flight_delayable_count_ != 0)) { | 826 in_flight_requests_.size() - in_flight_delayable_count_; |
| 794 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | 827 if (scheduler_->enable_in_flight_non_delayable_threshold()) { |
| 828 if (non_delayable_requests_in_flight_count > | |
| 829 scheduler_->in_flight_non_delayable_threshold()) { | |
| 830 // Too many higher priority in-flight requests to allow lower priority | |
| 831 // requests through. | |
| 832 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | |
| 833 } | |
| 834 if (in_flight_requests_.size() > 0 && | |
| 835 (scheduler_->limit_outstanding_requests() || | |
| 836 in_flight_delayable_count_ >= | |
| 837 scheduler_->max_num_delayable_while_layout_blocking())) { | |
| 838 // Block the request if at least one request is in flight and the | |
| 839 // number of in-flight delayable requests has hit the configured | |
| 840 // limit. | |
| 841 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | |
| 842 } | |
| 843 } else if (non_delayable_requests_in_flight_count > 0 && | |
| 844 (scheduler_->limit_outstanding_requests() || | |
| 845 in_flight_delayable_count_ >= | |
| 846 scheduler_->max_num_delayable_while_layout_blocking())) { | |
| 847 // If there are no high-priority requests in flight the floodgates open. | |
| 848 // If there are high-priority requests in-flight then limit the number | |
| 849 // of lower-priority requests (or zero if a limit field trial is | |
| 850 // active). | |
| 851 return DO_NOT_START_REQUEST_AND_STOP_SEARCHING; | |
| 852 } | |
| 795 } | 853 } |
| 796 | 854 |
| 797 return START_REQUEST; | 855 return START_REQUEST; |
| 798 } | 856 } |
| 799 | 857 |
| 800 void LoadAnyStartablePendingRequests() { | 858 void LoadAnyStartablePendingRequests() { |
| 801 // We iterate through all the pending requests, starting with the highest | 859 // We iterate through all the pending requests, starting with the highest |
| 802 // priority one. For each entry, one of three things can happen: | 860 // priority one. For each entry, one of three things can happen: |
| 803 // 1) We start the request, remove it from the list, and keep checking. | 861 // 1) We start the request, remove it from the list, and keep checking. |
| 804 // 2) We do NOT start the request, but ShouldStartRequest() signals us that | 862 // 2) We do NOT start the request, but ShouldStartRequest() signals us that |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 831 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); | 889 DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING); |
| 832 break; | 890 break; |
| 833 } | 891 } |
| 834 } | 892 } |
| 835 } | 893 } |
| 836 | 894 |
| 837 bool is_audible_; | 895 bool is_audible_; |
| 838 bool is_visible_; | 896 bool is_visible_; |
| 839 bool is_loaded_; | 897 bool is_loaded_; |
| 840 bool is_paused_; | 898 bool is_paused_; |
| 841 bool has_body_; | 899 // Tracks if the main HTML parser has reached the body which marks the end of |
| 900 // layout-blocking resources. | |
| 901 bool has_html_body_; | |
| 842 bool using_spdy_proxy_; | 902 bool using_spdy_proxy_; |
| 843 RequestQueue pending_requests_; | 903 RequestQueue pending_requests_; |
| 844 RequestSet in_flight_requests_; | 904 RequestSet in_flight_requests_; |
| 845 base::TimeTicks load_started_time_; | 905 base::TimeTicks load_started_time_; |
| 846 // The last time the client switched state between active and background. | 906 // The last time the client switched state between active and background. |
| 847 base::TimeTicks last_active_switch_time_; | 907 base::TimeTicks last_active_switch_time_; |
| 848 ResourceScheduler* scheduler_; | 908 ResourceScheduler* scheduler_; |
| 849 // The number of delayable in-flight requests. | 909 // The number of delayable in-flight requests. |
| 850 size_t in_flight_delayable_count_; | 910 size_t in_flight_delayable_count_; |
| 851 // The number of layout-blocking in-flight requests. | 911 // The number of layout-blocking in-flight requests. |
| 852 size_t total_layout_blocking_count_; | 912 size_t total_layout_blocking_count_; |
| 853 ResourceScheduler::ClientThrottleState throttle_state_; | 913 ResourceScheduler::ClientThrottleState throttle_state_; |
| 854 }; | 914 }; |
| 855 | 915 |
| 856 ResourceScheduler::ResourceScheduler() | 916 ResourceScheduler::ResourceScheduler() |
| 857 : should_coalesce_(false), | 917 : should_coalesce_(false), |
| 858 should_throttle_(false), | 918 should_throttle_(false), |
| 859 active_clients_loading_(0), | 919 active_clients_loading_(0), |
| 860 coalesced_clients_(0), | 920 coalesced_clients_(0), |
| 861 limit_outstanding_requests_(false), | 921 limit_outstanding_requests_(false), |
| 862 outstanding_request_limit_(0), | 922 outstanding_request_limit_(0), |
| 923 non_delayable_threshold_( | |
| 924 kDefaultLayoutBlockingPriorityThreshold), | |
| 925 enable_in_flight_non_delayable_threshold_(false), | |
| 926 in_flight_non_delayable_threshold_(0), | |
| 927 max_num_delayable_while_layout_blocking_( | |
| 928 kDefaultMaxNumDelayableWhileLayoutBlocking), | |
| 929 max_num_delayable_requests_(kDefaultMaxNumDelayableRequestsPerClient), | |
| 863 coalescing_timer_(new base::Timer(true /* retain_user_task */, | 930 coalescing_timer_(new base::Timer(true /* retain_user_task */, |
| 864 true /* is_repeating */)) { | 931 true /* is_repeating */)) { |
| 865 std::string throttling_trial_group = | 932 std::string throttling_trial_group = |
| 866 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial); | 933 base::FieldTrialList::FindFullName(kThrottleCoalesceFieldTrial); |
| 867 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) { | 934 if (throttling_trial_group == kThrottleCoalesceFieldTrialThrottle) { |
| 868 should_throttle_ = true; | 935 should_throttle_ = true; |
| 869 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) { | 936 } else if (throttling_trial_group == kThrottleCoalesceFieldTrialCoalesce) { |
| 870 should_coalesce_ = true; | 937 should_coalesce_ = true; |
| 871 should_throttle_ = true; | 938 should_throttle_ = true; |
| 872 } | 939 } |
| 873 | 940 |
| 874 std::string outstanding_limit_trial_group = | 941 std::string outstanding_limit_trial_group = |
| 875 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial); | 942 base::FieldTrialList::FindFullName(kRequestLimitFieldTrial); |
| 876 std::vector<std::string> split_group( | 943 std::vector<std::string> split_group( |
| 877 base::SplitString(outstanding_limit_trial_group, "=", | 944 base::SplitString(outstanding_limit_trial_group, "=", |
| 878 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)); | 945 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)); |
| 879 int outstanding_limit = 0; | 946 int outstanding_limit = 0; |
| 880 if (split_group.size() == 2 && | 947 if (split_group.size() == 2 && |
| 881 split_group[0] == kRequestLimitFieldTrialGroupPrefix && | 948 split_group[0] == kRequestLimitFieldTrialGroupPrefix && |
| 882 base::StringToInt(split_group[1], &outstanding_limit) && | 949 base::StringToInt(split_group[1], &outstanding_limit) && |
| 883 outstanding_limit > 0) { | 950 outstanding_limit > 0) { |
| 884 limit_outstanding_requests_ = true; | 951 limit_outstanding_requests_ = true; |
| 885 outstanding_request_limit_ = outstanding_limit; | 952 outstanding_request_limit_ = outstanding_limit; |
| 886 } | 953 } |
| 954 | |
| 955 // Set up the ResourceScheduling field trial options. | |
| 956 // The field trial parameters are also encoded into the group name since | |
| 957 // the variations component is not available from here and plumbing the | |
| 958 // options through the code is overkill for a short experiment. | |
| 959 // | |
| 960 // The group name encoding looks like this: | |
| 961 // <descriptiveName>_ABCDE_E2_F_G | |
| 962 // A - fetchDeferLateScripts (1 for true, 0 for false) | |
| 963 // B - fetchIncreaseFontPriority (1 for true, 0 for false) | |
| 964 // C - fetchIncreaseAsyncScriptPriority (1 for true, 0 for false) | |
| 965 // D - fetchIncreasePriorities (1 for true, 0 for false) | |
| 966 // E - fetchEnableLayoutBlockingThreshold (1 for true, 0 for false) | |
| 967 // E2 - fetchLayoutBlockingThreshold (Numeric) | |
| 968 // F - fetchMaxNumDelayableWhileLayoutBlocking (Numeric) | |
| 969 // G - fetchMaxNumDelayableRequests (Numeric) | |
| 970 std::string resource_priorities_trial_group = | |
| 971 base::FieldTrialList::FindFullName(kResourcePrioritiesFieldTrial); | |
| 972 std::vector<std::string> resource_priorities_split_group( | |
| 973 base::SplitString(resource_priorities_trial_group, "_", | |
| 974 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)); | |
| 975 if (resource_priorities_split_group.size() == 5 && | |
| 976 resource_priorities_split_group[1].length() == 5) { | |
| 977 // fetchIncreasePriorities | |
| 978 if (resource_priorities_split_group[1].at(3) == '1') | |
| 979 non_delayable_threshold_ = net::MEDIUM; | |
| 980 enable_in_flight_non_delayable_threshold_ = | |
| 981 resource_priorities_split_group[1].at(4) == '1'; | |
| 982 size_t numeric_value = 0; | |
| 983 if (base::StringToSizeT(resource_priorities_split_group[2], &numeric_value)) | |
| 984 in_flight_non_delayable_threshold_ = numeric_value; | |
| 985 if (base::StringToSizeT(resource_priorities_split_group[3], &numeric_value)) | |
| 986 max_num_delayable_while_layout_blocking_ = numeric_value; | |
| 987 if (base::StringToSizeT(resource_priorities_split_group[4], &numeric_value)) | |
| 988 max_num_delayable_requests_ = numeric_value; | |
| 989 } | |
| 887 } | 990 } |
| 888 | 991 |
| 889 ResourceScheduler::~ResourceScheduler() { | 992 ResourceScheduler::~ResourceScheduler() { |
| 890 DCHECK(unowned_requests_.empty()); | 993 DCHECK(unowned_requests_.empty()); |
| 891 DCHECK(client_map_.empty()); | 994 DCHECK(client_map_.empty()); |
| 892 } | 995 } |
| 893 | 996 |
| 894 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, | 997 void ResourceScheduler::SetThrottleOptionsForTesting(bool should_throttle, |
| 895 bool should_coalesce) { | 998 bool should_coalesce) { |
| 896 should_coalesce_ = should_coalesce; | 999 should_coalesce_ = should_coalesce; |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1202 client->ReprioritizeRequest( | 1305 client->ReprioritizeRequest( |
| 1203 request, old_priority_params, new_priority_params); | 1306 request, old_priority_params, new_priority_params); |
| 1204 } | 1307 } |
| 1205 | 1308 |
| 1206 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( | 1309 ResourceScheduler::ClientId ResourceScheduler::MakeClientId( |
| 1207 int child_id, int route_id) { | 1310 int child_id, int route_id) { |
| 1208 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; | 1311 return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id; |
| 1209 } | 1312 } |
| 1210 | 1313 |
| 1211 } // namespace content | 1314 } // namespace content |
| OLD | NEW |