Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: chrome/browser/devtools/devtools_network_interceptor.cc

Issue 346503002: DevTools: emulate latency network condition. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@twin
Patch Set: Rebase Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW
« no previous file with comments | « chrome/browser/devtools/devtools_network_interceptor.h ('k') | chrome/browser/devtools/devtools_network_transaction.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698