OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/browser/devtools/devtools_network_interceptor.h" | 5 #include "chrome/browser/devtools/devtools_network_interceptor.h" |
6 | 6 |
7 #include <limits> | |
8 | |
7 #include "base/time/time.h" | 9 #include "base/time/time.h" |
8 #include "chrome/browser/devtools/devtools_network_conditions.h" | 10 #include "chrome/browser/devtools/devtools_network_conditions.h" |
9 #include "chrome/browser/devtools/devtools_network_transaction.h" | 11 #include "chrome/browser/devtools/devtools_network_transaction.h" |
12 #include "net/base/load_timing_info.h" | |
10 | 13 |
11 namespace { | 14 namespace { |
12 | 15 |
13 int64_t kPacketSize = 1500; | 16 int64_t kPacketSize = 1500; |
14 | 17 |
15 } // namespace | 18 } // namespace |
16 | 19 |
17 DevToolsNetworkInterceptor::DevToolsNetworkInterceptor() | 20 DevToolsNetworkInterceptor::DevToolsNetworkInterceptor() |
18 : conditions_(new DevToolsNetworkConditions()), | 21 : conditions_(new DevToolsNetworkConditions()), |
19 weak_ptr_factory_(this) { | 22 weak_ptr_factory_(this) { |
(...skipping 14 matching lines...) Expand all Loading... | |
34 } | 37 } |
35 | 38 |
36 void DevToolsNetworkInterceptor::RemoveTransaction( | 39 void DevToolsNetworkInterceptor::RemoveTransaction( |
37 DevToolsNetworkTransaction* transaction) { | 40 DevToolsNetworkTransaction* transaction) { |
38 DCHECK(transactions_.find(transaction) != transactions_.end()); | 41 DCHECK(transactions_.find(transaction) != transactions_.end()); |
39 transactions_.erase(transaction); | 42 transactions_.erase(transaction); |
40 | 43 |
41 if (!conditions_->IsThrottling()) | 44 if (!conditions_->IsThrottling()) |
42 return; | 45 return; |
43 | 46 |
44 UpdateThrottles(); | 47 base::TimeTicks now = base::TimeTicks::Now(); |
48 UpdateThrottledTransactions(now); | |
45 throttled_transactions_.erase(std::remove(throttled_transactions_.begin(), | 49 throttled_transactions_.erase(std::remove(throttled_transactions_.begin(), |
46 throttled_transactions_.end(), transaction), | 50 throttled_transactions_.end(), transaction), |
47 throttled_transactions_.end()); | 51 throttled_transactions_.end()); |
48 ArmTimer(); | 52 |
53 SuspendedTransactions::iterator it = suspended_transactions_.begin(); | |
54 for (; it != suspended_transactions_.end(); ++it) { | |
55 if (it->first == transaction) { | |
56 suspended_transactions_.erase(it); | |
vsevik
2014/06/18 14:40:24
Let's use HashMap?
eustas
2014/06/19 09:00:14
We iterate over the whole collection more often th
| |
57 break; | |
58 } | |
59 } | |
60 | |
61 ArmTimer(now); | |
49 } | 62 } |
50 | 63 |
51 void DevToolsNetworkInterceptor::UpdateConditions( | 64 void DevToolsNetworkInterceptor::UpdateConditions( |
52 const scoped_refptr<DevToolsNetworkConditions> conditions) { | 65 const scoped_refptr<DevToolsNetworkConditions> conditions) { |
53 DCHECK(conditions); | 66 DCHECK(conditions); |
67 base::TimeTicks now = base::TimeTicks::Now(); | |
54 if (conditions_->IsThrottling()) | 68 if (conditions_->IsThrottling()) |
55 UpdateThrottles(); | 69 UpdateThrottledTransactions(now); |
56 | 70 |
57 conditions_ = conditions; | 71 conditions_ = conditions; |
58 | 72 |
59 if (conditions->offline()) { | 73 if (conditions->offline()) { |
60 timer_.Stop(); | 74 timer_.Stop(); |
61 throttled_transactions_.clear(); | 75 throttled_transactions_.clear(); |
76 suspended_transactions_.clear(); | |
62 Transactions old_transactions(transactions_); | 77 Transactions old_transactions(transactions_); |
63 Transactions::iterator it = old_transactions.begin(); | 78 Transactions::iterator it = old_transactions.begin(); |
64 for (;it != old_transactions.end(); ++it) { | 79 for (;it != old_transactions.end(); ++it) { |
65 if (transactions_.find(*it) == transactions_.end()) | 80 if (transactions_.find(*it) == transactions_.end()) |
66 continue; | 81 continue; |
67 if (!(*it)->request() || (*it)->failed()) | 82 if (!(*it)->request() || (*it)->failed()) |
68 continue; | 83 continue; |
69 if (ShouldFail(*it)) | 84 if (ShouldFail(*it)) |
70 (*it)->Fail(); | 85 (*it)->Fail(); |
71 } | 86 } |
72 return; | 87 return; |
73 } | 88 } |
74 | 89 |
75 if (conditions->IsThrottling()) { | 90 if (conditions->IsThrottling()) { |
76 DCHECK(conditions->download_throughput() != 0); | 91 DCHECK(conditions->download_throughput() != 0); |
77 offset_ = base::TimeTicks::Now(); | 92 offset_ = now; |
78 last_tick_ = 0; | 93 last_tick_ = 0; |
79 int64_t us_tick_length = | 94 int64_t us_tick_length = |
80 (1000000L * kPacketSize) / conditions->download_throughput(); | 95 (1000000L * kPacketSize) / conditions->download_throughput(); |
81 DCHECK(us_tick_length != 0); | 96 DCHECK(us_tick_length != 0); |
82 if (us_tick_length == 0) | 97 if (us_tick_length == 0) |
83 us_tick_length = 1; | 98 us_tick_length = 1; |
84 tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length); | 99 tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length); |
85 ArmTimer(); | 100 latency_length_ = base::TimeDelta(); |
101 double latency = conditions_->latency(); | |
102 if (latency > 0) | |
103 latency_length_ = base::TimeDelta::FromMillisecondsD(latency); | |
104 ArmTimer(now); | |
86 } else { | 105 } else { |
87 timer_.Stop(); | 106 timer_.Stop(); |
88 int64_t length = throttled_transactions_.size(); | 107 |
89 for (int64_t i = 0; i < length; ++i) | 108 std::vector<DevToolsNetworkTransaction*> throttled_transactions; |
90 throttled_transactions_[i]->FireThrottledCallback(); | 109 throttled_transactions.swap(throttled_transactions_); |
91 throttled_transactions_.clear(); | 110 size_t throttle_count = throttled_transactions.size(); |
111 for (size_t i = 0; i < throttle_count; ++i) { | |
112 DevToolsNetworkTransaction* transaction = throttled_transactions[i]; | |
113 if (transactions_.find(transaction) != transactions_.end()) | |
114 transaction->FireThrottledCallback(); | |
115 } | |
116 | |
117 SuspendedTransactions suspended_transactions; | |
118 suspended_transactions_.swap(suspended_transactions_); | |
119 size_t suspend_count = suspended_transactions.size(); | |
120 for (size_t i = 0; i < suspend_count; ++i) { | |
121 DevToolsNetworkTransaction* transaction = | |
122 suspended_transactions[i].first; | |
123 if (transactions_.find(transaction) != transactions_.end()) | |
124 transaction->FireThrottledCallback(); | |
125 } | |
92 } | 126 } |
93 } | 127 } |
94 | 128 |
95 void DevToolsNetworkInterceptor::UpdateThrottles() { | 129 void DevToolsNetworkInterceptor::UpdateThrottledTransactions( |
96 int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_; | 130 base::TimeTicks now) { |
131 int64_t last_tick = (now - offset_) / tick_length_; | |
97 int64_t ticks = last_tick - last_tick_; | 132 int64_t ticks = last_tick - last_tick_; |
98 last_tick_ = last_tick; | 133 last_tick_ = last_tick; |
99 | 134 |
100 int64_t length = throttled_transactions_.size(); | 135 int64_t length = throttled_transactions_.size(); |
101 if (!length) | 136 if (!length) { |
137 UpdateSuspendedTransactions(now); | |
102 return; | 138 return; |
139 } | |
103 | 140 |
104 int64_t shift = ticks % length; | 141 int64_t shift = ticks % length; |
105 for (int64_t i = 0; i < length; ++i) { | 142 for (int64_t i = 0; i < length; ++i) { |
106 throttled_transactions_[i]->DecreaseThrottledByteCount( | 143 throttled_transactions_[i]->DecreaseThrottledByteCount( |
107 (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0)); | 144 (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0)); |
108 } | 145 } |
109 std::rotate(throttled_transactions_.begin(), | 146 std::rotate(throttled_transactions_.begin(), |
110 throttled_transactions_.begin() + shift, throttled_transactions_.end()); | 147 throttled_transactions_.begin() + shift, throttled_transactions_.end()); |
148 | |
149 UpdateSuspendedTransactions(now); | |
150 } | |
151 | |
152 void DevToolsNetworkInterceptor::UpdateSuspendedTransactions( | |
153 base::TimeTicks now) { | |
154 int64_t activation_baseline = | |
155 (now - latency_length_ - base::TimeTicks()).InMicroseconds(); | |
156 SuspendedTransactions suspended_transactions; | |
157 SuspendedTransactions::iterator it = suspended_transactions_.begin(); | |
158 for (; it != suspended_transactions_.end(); ++it) { | |
159 if (it->second <= activation_baseline) | |
160 throttled_transactions_.push_back(it->first); | |
161 else | |
162 suspended_transactions.push_back(*it); | |
163 } | |
164 suspended_transactions_.swap(suspended_transactions); | |
111 } | 165 } |
112 | 166 |
113 void DevToolsNetworkInterceptor::OnTimer() { | 167 void DevToolsNetworkInterceptor::OnTimer() { |
114 UpdateThrottles(); | 168 base::TimeTicks now = base::TimeTicks::Now(); |
169 UpdateThrottledTransactions(now); | |
115 | 170 |
116 std::vector<DevToolsNetworkTransaction*> active_transactions; | 171 std::vector<DevToolsNetworkTransaction*> active_transactions; |
117 std::vector<DevToolsNetworkTransaction*> finished_transactions; | 172 std::vector<DevToolsNetworkTransaction*> finished_transactions; |
118 size_t length = throttled_transactions_.size(); | 173 size_t length = throttled_transactions_.size(); |
119 for (size_t i = 0; i < length; ++i) { | 174 for (size_t i = 0; i < length; ++i) { |
120 if (throttled_transactions_[i]->throttled_byte_count() < 0) | 175 if (throttled_transactions_[i]->throttled_byte_count() < 0) |
121 finished_transactions.push_back(throttled_transactions_[i]); | 176 finished_transactions.push_back(throttled_transactions_[i]); |
122 else | 177 else |
123 active_transactions.push_back(throttled_transactions_[i]); | 178 active_transactions.push_back(throttled_transactions_[i]); |
124 } | 179 } |
125 throttled_transactions_.swap(active_transactions); | 180 throttled_transactions_.swap(active_transactions); |
126 | 181 |
127 length = finished_transactions.size(); | 182 length = finished_transactions.size(); |
128 for (size_t i = 0; i < length; ++i) | 183 for (size_t i = 0; i < length; ++i) |
129 finished_transactions[i]->FireThrottledCallback(); | 184 finished_transactions[i]->FireThrottledCallback(); |
130 | 185 |
131 ArmTimer(); | 186 ArmTimer(now); |
132 } | 187 } |
133 | 188 |
134 void DevToolsNetworkInterceptor::ArmTimer() { | 189 void DevToolsNetworkInterceptor::ArmTimer(base::TimeTicks now) { |
135 size_t length = throttled_transactions_.size(); | 190 size_t throttle_count = throttled_transactions_.size(); |
136 if (!length) | 191 size_t suspend_count = suspended_transactions_.size(); |
192 if (!throttle_count && !suspend_count) | |
137 return; | 193 return; |
138 int64_t min_ticks_left = 0x10000L; | 194 int64_t min_ticks_left = 0x10000L; |
139 for (size_t i = 0; i < length; ++i) { | 195 for (size_t i = 0; i < throttle_count; ++i) { |
140 int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() + | 196 int64_t packets_left = (throttled_transactions_[i]->throttled_byte_count() + |
141 kPacketSize - 1) / kPacketSize; | 197 kPacketSize - 1) / kPacketSize; |
142 int64_t ticks_left = (i + 1) + length * (packets_left - 1); | 198 int64_t ticks_left = (i + 1) + throttle_count * (packets_left - 1); |
143 if (i == 0 || ticks_left < min_ticks_left) | 199 if (i == 0 || ticks_left < min_ticks_left) |
144 min_ticks_left = ticks_left; | 200 min_ticks_left = ticks_left; |
145 } | 201 } |
146 base::TimeTicks desired_time = | 202 base::TimeTicks desired_time = |
147 offset_ + tick_length_ * (last_tick_ + min_ticks_left); | 203 offset_ + tick_length_ * (last_tick_ + min_ticks_left); |
204 | |
205 int64_t min_baseline = std::numeric_limits<int64>::max(); | |
206 for (size_t i = 0; i < suspend_count; ++i) { | |
207 if (suspended_transactions_[i].second < min_baseline) | |
208 min_baseline = suspended_transactions_[i].second; | |
209 } | |
210 if (suspend_count) { | |
211 base::TimeTicks activation_time = base::TimeTicks() + | |
212 base::TimeDelta::FromMicroseconds(min_baseline) + latency_length_; | |
213 if (activation_time < desired_time) | |
214 desired_time = activation_time; | |
215 } | |
216 | |
148 timer_.Start( | 217 timer_.Start( |
149 FROM_HERE, | 218 FROM_HERE, |
150 desired_time - base::TimeTicks::Now(), | 219 desired_time - now, |
151 base::Bind( | 220 base::Bind( |
152 &DevToolsNetworkInterceptor::OnTimer, | 221 &DevToolsNetworkInterceptor::OnTimer, |
153 base::Unretained(this))); | 222 base::Unretained(this))); |
154 } | 223 } |
155 | 224 |
156 void DevToolsNetworkInterceptor::ThrottleTransaction( | 225 void DevToolsNetworkInterceptor::ThrottleTransaction( |
157 DevToolsNetworkTransaction* transaction) { | 226 DevToolsNetworkTransaction* transaction, bool start) { |
158 UpdateThrottles(); | 227 base::TimeTicks now = base::TimeTicks::Now(); |
159 throttled_transactions_.push_back(transaction); | 228 UpdateThrottledTransactions(now); |
160 ArmTimer(); | 229 if (start && latency_length_ != base::TimeDelta()) { |
230 net::LoadTimingInfo load_timing_info; | |
231 base::TimeTicks send_end; | |
232 if (transaction->GetLoadTimingInfo(&load_timing_info)) | |
233 send_end = load_timing_info.send_end; | |
234 if (send_end.is_null()) | |
235 send_end = now; | |
236 int64_t us_send_end = (send_end - base::TimeTicks()).InMicroseconds(); | |
237 suspended_transactions_.push_back( | |
238 SuspendedTransaction(transaction, us_send_end)); | |
239 UpdateSuspendedTransactions(now); | |
240 } else { | |
241 throttled_transactions_.push_back(transaction); | |
242 } | |
243 ArmTimer(now); | |
161 } | 244 } |
162 | 245 |
163 bool DevToolsNetworkInterceptor::ShouldFail( | 246 bool DevToolsNetworkInterceptor::ShouldFail( |
164 const DevToolsNetworkTransaction* transaction) { | 247 const DevToolsNetworkTransaction* transaction) { |
165 if (!conditions_->offline()) | 248 if (!conditions_->offline()) |
166 return false; | 249 return false; |
167 | 250 |
168 if (!transaction->request_initiator().empty()) | 251 if (!transaction->request_initiator().empty()) |
169 return false; | 252 return false; |
170 | 253 |
171 return true; | 254 return true; |
172 } | 255 } |
173 | 256 |
174 bool DevToolsNetworkInterceptor::ShouldThrottle( | 257 bool DevToolsNetworkInterceptor::ShouldThrottle( |
175 const DevToolsNetworkTransaction* transaction) { | 258 const DevToolsNetworkTransaction* transaction) { |
176 if (!conditions_->IsThrottling()) | 259 if (!conditions_->IsThrottling()) |
177 return false; | 260 return false; |
178 | 261 |
179 if (!transaction->request_initiator().empty()) | 262 if (!transaction->request_initiator().empty()) |
180 return false; | 263 return false; |
181 | 264 |
182 return true; | 265 return true; |
183 } | 266 } |
OLD | NEW |