| Index: chrome/browser/devtools/devtools_network_interceptor.cc
|
| diff --git a/chrome/browser/devtools/devtools_network_interceptor.cc b/chrome/browser/devtools/devtools_network_interceptor.cc
|
| index 0399b8d4038358f95ec729629e3bce9245883f68..31cc5aacce465938b0725d8b972982ec75996584 100644
|
| --- a/chrome/browser/devtools/devtools_network_interceptor.cc
|
| +++ b/chrome/browser/devtools/devtools_network_interceptor.cc
|
| @@ -4,9 +4,12 @@
|
|
|
| #include "chrome/browser/devtools/devtools_network_interceptor.h"
|
|
|
| +#include <limits>
|
| +
|
| #include "base/time/time.h"
|
| #include "chrome/browser/devtools/devtools_network_conditions.h"
|
| #include "chrome/browser/devtools/devtools_network_transaction.h"
|
| +#include "net/base/load_timing_info.h"
|
|
|
| namespace {
|
|
|
| @@ -41,24 +44,36 @@ void DevToolsNetworkInterceptor::RemoveTransaction(
|
| if (!conditions_->IsThrottling())
|
| return;
|
|
|
| - UpdateThrottles();
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| + UpdateThrottledTransactions(now);
|
| throttled_transactions_.erase(std::remove(throttled_transactions_.begin(),
|
| throttled_transactions_.end(), transaction),
|
| throttled_transactions_.end());
|
| - ArmTimer();
|
| +
|
| + SuspendedTransactions::iterator it = suspended_transactions_.begin();
|
| + for (; it != suspended_transactions_.end(); ++it) {
|
| + if (it->first == transaction) {
|
| + suspended_transactions_.erase(it);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + ArmTimer(now);
|
| }
|
|
|
| void DevToolsNetworkInterceptor::UpdateConditions(
|
| const scoped_refptr<DevToolsNetworkConditions> conditions) {
|
| DCHECK(conditions);
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| if (conditions_->IsThrottling())
|
| - UpdateThrottles();
|
| + UpdateThrottledTransactions(now);
|
|
|
| conditions_ = conditions;
|
|
|
| if (conditions->offline()) {
|
| timer_.Stop();
|
| throttled_transactions_.clear();
|
| + suspended_transactions_.clear();
|
| Transactions old_transactions(transactions_);
|
| Transactions::iterator it = old_transactions.begin();
|
| for (;it != old_transactions.end(); ++it) {
|
| @@ -74,7 +89,7 @@ void DevToolsNetworkInterceptor::UpdateConditions(
|
|
|
| if (conditions->IsThrottling()) {
|
| DCHECK(conditions->download_throughput() != 0);
|
| - offset_ = base::TimeTicks::Now();
|
| + offset_ = now;
|
| last_tick_ = 0;
|
| int64_t us_tick_length =
|
| (1000000L * kPacketSize) / conditions->download_throughput();
|
| @@ -82,24 +97,46 @@ void DevToolsNetworkInterceptor::UpdateConditions(
|
| if (us_tick_length == 0)
|
| us_tick_length = 1;
|
| tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
|
| - ArmTimer();
|
| + latency_length_ = base::TimeDelta();
|
| + double latency = conditions_->latency();
|
| + if (latency > 0)
|
| + latency_length_ = base::TimeDelta::FromMillisecondsD(latency);
|
| + ArmTimer(now);
|
| } else {
|
| timer_.Stop();
|
| - int64_t length = throttled_transactions_.size();
|
| - for (int64_t i = 0; i < length; ++i)
|
| - throttled_transactions_[i]->FireThrottledCallback();
|
| - throttled_transactions_.clear();
|
| +
|
| + std::vector<DevToolsNetworkTransaction*> throttled_transactions;
|
| + throttled_transactions.swap(throttled_transactions_);
|
| + size_t throttle_count = throttled_transactions.size();
|
| + for (size_t i = 0; i < throttle_count; ++i) {
|
| + DevToolsNetworkTransaction* transaction = throttled_transactions[i];
|
| + if (transactions_.find(transaction) != transactions_.end())
|
| + transaction->FireThrottledCallback();
|
| + }
|
| +
|
| + SuspendedTransactions suspended_transactions;
|
| + suspended_transactions_.swap(suspended_transactions_);
|
| + size_t suspend_count = suspended_transactions.size();
|
| + for (size_t i = 0; i < suspend_count; ++i) {
|
| + DevToolsNetworkTransaction* transaction =
|
| + suspended_transactions[i].first;
|
| + if (transactions_.find(transaction) != transactions_.end())
|
| + transaction->FireThrottledCallback();
|
| + }
|
| }
|
| }
|
|
|
| -void DevToolsNetworkInterceptor::UpdateThrottles() {
|
| - int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_;
|
| +void DevToolsNetworkInterceptor::UpdateThrottledTransactions(
|
| + base::TimeTicks now) {
|
| + int64_t last_tick = (now - offset_) / tick_length_;
|
| int64_t ticks = last_tick - last_tick_;
|
| last_tick_ = last_tick;
|
|
|
| int64_t length = throttled_transactions_.size();
|
| - if (!length)
|
| + if (!length) {
|
| + UpdateSuspendedTransactions(now);
|
| return;
|
| + }
|
|
|
| int64_t shift = ticks % length;
|
| for (int64_t i = 0; i < length; ++i) {
|
| @@ -108,10 +145,28 @@ void DevToolsNetworkInterceptor::UpdateThrottles() {
|
| }
|
| std::rotate(throttled_transactions_.begin(),
|
| throttled_transactions_.begin() + shift, throttled_transactions_.end());
|
| +
|
| + UpdateSuspendedTransactions(now);
|
| +}
|
| +
|
| +void DevToolsNetworkInterceptor::UpdateSuspendedTransactions(
|
| + base::TimeTicks now) {
|
| + int64_t activation_baseline =
|
| + (now - latency_length_ - base::TimeTicks()).InMicroseconds();
|
| + SuspendedTransactions suspended_transactions;
|
| + SuspendedTransactions::iterator it = suspended_transactions_.begin();
|
| + for (; it != suspended_transactions_.end(); ++it) {
|
| + if (it->second <= activation_baseline)
|
| + throttled_transactions_.push_back(it->first);
|
| + else
|
| + suspended_transactions.push_back(*it);
|
| + }
|
| + suspended_transactions_.swap(suspended_transactions);
|
| }
|
|
|
| void DevToolsNetworkInterceptor::OnTimer() {
|
| - UpdateThrottles();
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| + UpdateThrottledTransactions(now);
|
|
|
| std::vector<DevToolsNetworkTransaction*> active_transactions;
|
| std::vector<DevToolsNetworkTransaction*> finished_transactions;
|
| @@ -128,36 +183,64 @@ void DevToolsNetworkInterceptor::OnTimer() {
|
| for (size_t i = 0; i < length; ++i)
|
| finished_transactions[i]->FireThrottledCallback();
|
|
|
| - ArmTimer();
|
| + ArmTimer(now);
|
| }
|
|
|
| -void DevToolsNetworkInterceptor::ArmTimer() {
|
| - size_t length = throttled_transactions_.size();
|
| - if (!length)
|
| +void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) {
|
| + size_t throttle_count = throttled_transactions_.size();
|
| + size_t suspend_count = suspended_transactions_.size();
|
| + if (!throttle_count && !suspend_count)
|
| return;
|
| int64_t min_ticks_left = 0x10000L;
|
| - for (size_t i = 0; i < length; ++i) {
|
| + for (size_t i = 0; i < throttle_count; ++i) {
|
| int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() +
|
| kPacketSize - 1) / kPacketSize;
|
| - int64_t ticks_left = (i + 1) + length * (packets_left - 1);
|
| + int64_t ticks_left = (i + 1) + throttle_count * (packets_left - 1);
|
| if (i == 0 || ticks_left < min_ticks_left)
|
| min_ticks_left = ticks_left;
|
| }
|
| base::TimeTicks desired_time =
|
| offset_ + tick_length_ * (last_tick_ + min_ticks_left);
|
| +
|
| + int64_t min_baseline = std::numeric_limits<int64>::max();
|
| + for (size_t i = 0; i < suspend_count; ++i) {
|
| + if (suspended_transactions_[i].second < min_baseline)
|
| + min_baseline = suspended_transactions_[i].second;
|
| + }
|
| + if (suspend_count) {
|
| + base::TimeTicks activation_time = base::TimeTicks() +
|
| + base::TimeDelta::FromMicroseconds(min_baseline) + latency_length_;
|
| + if (activation_time < desired_time)
|
| + desired_time = activation_time;
|
| + }
|
| +
|
| timer_.Start(
|
| FROM_HERE,
|
| - desired_time - base::TimeTicks::Now(),
|
| + desired_time - now,
|
| base::Bind(
|
| &DevToolsNetworkInterceptor::OnTimer,
|
| base::Unretained(this)));
|
| }
|
|
|
| void DevToolsNetworkInterceptor::ThrottleTransaction(
|
| - DevToolsNetworkTransaction* transaction) {
|
| - UpdateThrottles();
|
| - throttled_transactions_.push_back(transaction);
|
| - ArmTimer();
|
| + DevToolsNetworkTransaction* transaction, bool start) {
|
| + base::TimeTicks now = base::TimeTicks::Now();
|
| + UpdateThrottledTransactions(now);
|
| + if (start && latency_length_ != base::TimeDelta()) {
|
| + net::LoadTimingInfo load_timing_info;
|
| + base::TimeTicks send_end;
|
| + if (transaction->GetLoadTimingInfo(&load_timing_info))
|
| + send_end = load_timing_info.send_end;
|
| + if (send_end.is_null())
|
| + send_end = now;
|
| + int64_t us_send_end = (send_end - base::TimeTicks()).InMicroseconds();
|
| + suspended_transactions_.push_back(
|
| + SuspendedTransaction(transaction, us_send_end));
|
| + UpdateSuspendedTransactions(now);
|
| + } else {
|
| + throttled_transactions_.push_back(transaction);
|
| + }
|
| + ArmTimer(now);
|
| }
|
|
|
| bool DevToolsNetworkInterceptor::ShouldFail(
|
|
|