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

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

Issue 324953002: DevToolsNetworkController: support "limit throughput" network condition. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resolved TODO 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_controller.h" 5 #include "chrome/browser/devtools/devtools_network_controller.h"
6 6
7 #include "base/time/time.h"
7 #include "chrome/browser/devtools/devtools_network_conditions.h" 8 #include "chrome/browser/devtools/devtools_network_conditions.h"
8 #include "chrome/browser/devtools/devtools_network_transaction.h" 9 #include "chrome/browser/devtools/devtools_network_transaction.h"
9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/profiles/profile_io_data.h" 11 #include "chrome/browser/profiles/profile_io_data.h"
11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/resource_context.h" 13 #include "content/public/browser/resource_context.h"
13 14
14 using content::BrowserThread; 15 using content::BrowserThread;
15 16
16 namespace { 17 namespace {
17 18
18 const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator"; 19 const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator";
19 20
21 struct Throttle {
22 DevToolsNetworkTransaction* transaction;
23 int64_t penalty;
24 };
25
26 int64_t kPacketSize = 1500;
27
20 } // namespace 28 } // namespace
21 29
22 DevToolsNetworkController::DevToolsNetworkController() 30 DevToolsNetworkController::DevToolsNetworkController()
23 : weak_ptr_factory_(this) { 31 : weak_ptr_factory_(this) {
24 } 32 }
25 33
26 DevToolsNetworkController::~DevToolsNetworkController() { 34 DevToolsNetworkController::~DevToolsNetworkController() {
27 } 35 }
28 36
29 void DevToolsNetworkController::AddTransaction( 37 void DevToolsNetworkController::AddTransaction(
30 DevToolsNetworkTransaction* transaction) { 38 DevToolsNetworkTransaction* transaction) {
31 DCHECK(thread_checker_.CalledOnValidThread()); 39 DCHECK(thread_checker_.CalledOnValidThread());
32 transactions_.insert(transaction); 40 transactions_.insert(transaction);
33 } 41 }
34 42
35 void DevToolsNetworkController::RemoveTransaction( 43 void DevToolsNetworkController::RemoveTransaction(
36 DevToolsNetworkTransaction* transaction) { 44 DevToolsNetworkTransaction* transaction) {
37 DCHECK(thread_checker_.CalledOnValidThread()); 45 DCHECK(thread_checker_.CalledOnValidThread());
38 DCHECK(transactions_.find(transaction) != transactions_.end()); 46 DCHECK(transactions_.find(transaction) != transactions_.end());
39 transactions_.erase(transaction); 47 transactions_.erase(transaction);
48
49 size_t length = throttles_.size();
50 if (!length)
vsevik 2014/06/10 17:24:19 redundant
eustas 2014/06/11 10:54:25 Done.
51 return;
52
53 for (size_t i = 0; i < length; ++i) {
54 if (throttles_[i].transaction == transaction)
55 throttles_[i].transaction = NULL;
56 }
40 } 57 }
41 58
42 void DevToolsNetworkController::SetNetworkState( 59 void DevToolsNetworkController::SetNetworkState(
43 const std::string& client_id, 60 const std::string& client_id,
44 const scoped_refptr<DevToolsNetworkConditions> conditions) { 61 const scoped_refptr<DevToolsNetworkConditions> conditions) {
45 DCHECK_CURRENTLY_ON(BrowserThread::UI); 62 DCHECK_CURRENTLY_ON(BrowserThread::UI);
46 BrowserThread::PostTask( 63 BrowserThread::PostTask(
47 content::BrowserThread::IO, 64 content::BrowserThread::IO,
48 FROM_HERE, 65 FROM_HERE,
49 base::Bind( 66 base::Bind(
50 &DevToolsNetworkController::SetNetworkStateOnIO, 67 &DevToolsNetworkController::SetNetworkStateOnIO,
51 weak_ptr_factory_.GetWeakPtr(), 68 weak_ptr_factory_.GetWeakPtr(),
52 client_id, 69 client_id,
53 conditions)); 70 conditions));
54 } 71 }
55 72
56 void DevToolsNetworkController::SetNetworkStateOnIO( 73 void DevToolsNetworkController::SetNetworkStateOnIO(
57 const std::string& client_id, 74 const std::string& client_id,
58 const scoped_refptr<DevToolsNetworkConditions> conditions) { 75 const scoped_refptr<DevToolsNetworkConditions> conditions) {
59 DCHECK(thread_checker_.CalledOnValidThread()); 76 DCHECK(thread_checker_.CalledOnValidThread());
77 bool was_throttling = conditions_ && conditions_->IsThrottling();
vsevik 2014/06/10 17:24:19 Can we put the line below to the beginning of this
eustas 2014/06/11 10:54:26 Done.
78
60 if (!conditions) { 79 if (!conditions) {
61 if (client_id == active_client_id_) { 80 if (client_id == active_client_id_) {
62 conditions_ = NULL; 81 conditions_ = NULL;
63 active_client_id_ = std::string(); 82 active_client_id_ = std::string();
83 if (was_throttling)
84 CancelThrottles();
64 } 85 }
65 return; 86 return;
66 } 87 }
88
89 // Prepare to update throughput.
90 if (was_throttling)
vsevik 2014/06/10 17:24:19 I think this calls should be noops in case we were
eustas 2014/06/11 10:54:25 Done.
91 UpdateThrottles();
92
67 conditions_ = conditions; 93 conditions_ = conditions;
68 active_client_id_ = client_id; 94 active_client_id_ = client_id;
69 95
70 // Iterate over a copy of set, because failing of transaction could result in 96 if (was_throttling)
71 // creating a new one, or (theoretically) destroying one. 97 FireThrottledCallbacks();
72 Transactions old_transactions(transactions_); 98
73 for (Transactions::iterator it = old_transactions.begin(); 99 if (conditions_->IsOffline()) {
74 it != old_transactions.end(); ++it) { 100 // Iterate over a copy of set, because failing of transaction could
75 if (transactions_.find(*it) == transactions_.end()) 101 // result in creating a new one, or (theoretically) destroying one.
76 continue; 102 Transactions old_transactions(transactions_);
77 if (!(*it)->request() || (*it)->failed()) 103 for (Transactions::iterator it = old_transactions.begin();
78 continue; 104 it != old_transactions.end(); ++it) {
79 if (ShouldFail((*it)->request())) 105 if (transactions_.find(*it) == transactions_.end())
80 (*it)->Fail(); 106 continue;
107 if (!(*it)->request() || (*it)->failed())
108 continue;
109 if (ShouldFail((*it)->request()))
110 (*it)->Fail();
111 }
112 }
113
114 if (conditions_->IsThrottling()) {
115 DCHECK(conditions_->maximal_throughput() != 0);
116 offset_ = base::TimeTicks::Now();
117 last_tick_ = 0;
118 tick_length_ = base::TimeDelta::FromMicroseconds(
119 1000000L * kPacketSize / conditions_->maximal_throughput());
120 ArmTimer();
121 } else if (was_throttling) {
122 CancelThrottles();
vsevik 2014/06/10 17:24:19 Can we join two Cancel... calls?
eustas 2014/06/11 10:54:26 Done.
81 } 123 }
82 } 124 }
83 125
84 bool DevToolsNetworkController::ShouldFail( 126 bool DevToolsNetworkController::ShouldFail(
85 const net::HttpRequestInfo* request) { 127 const net::HttpRequestInfo* request) {
86 DCHECK(thread_checker_.CalledOnValidThread()); 128 DCHECK(thread_checker_.CalledOnValidThread());
87 DCHECK(request); 129 DCHECK(request);
88 if (!conditions_ || !conditions_->IsOffline()) 130 if (!conditions_ || !conditions_->IsOffline())
89 return false; 131 return false;
90 132
91 if (!conditions_->HasMatchingDomain(request->url)) 133 if (!conditions_->HasMatchingDomain(request->url))
92 return false; 134 return false;
93 135
94 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator); 136 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
95 } 137 }
138
139 bool DevToolsNetworkController::ShouldThrottle(
140 const net::HttpRequestInfo* request) {
141 DCHECK(thread_checker_.CalledOnValidThread());
142 DCHECK(request);
143 if (!conditions_ || !conditions_->IsThrottling())
144 return false;
145
146 if (!conditions_->HasMatchingDomain(request->url))
147 return false;
148
149 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
150 }
151
152 void DevToolsNetworkController::UpdateThrottles() {
153 int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_;
154 int64_t ticks = last_tick - last_tick_;
155 last_tick_ = last_tick;
156
157 int64_t length = throttles_.size();
158 if (!length)
159 return;
160
161 int64_t full_rounds = ticks / length;
162 int64_t reminder = ticks % length;
vsevik 2014/06/10 17:24:19 remainder :)
vsevik 2014/06/11 08:39:32 last_throttle_to_get_packet
eustas 2014/06/11 10:54:25 Done.
eustas 2014/06/11 10:54:26 Thanks =)
163 Throttles throttles;
164 for (int64_t i = reminder; i < length; ++i) {
165 throttles.push_back(throttles_[i]);
vsevik 2014/06/11 08:39:32 std::rotate FTW!
eustas 2014/06/11 10:54:25 Done.
166 throttles.back().penalty -= (full_rounds * kPacketSize);
167 }
168 for (int64_t i = 0; i < reminder; ++i) {
169 throttles.push_back(throttles_[i]);
170 throttles.back().penalty -= ((full_rounds + 1) * kPacketSize);
171 }
172 throttles_.swap(throttles);
173 }
174
175 void DevToolsNetworkController::CancelThrottles() {
176 int64_t length = throttles_.size();
177 if (!length)
178 return;
179
180 Throttles throttles;
181 throttles_.swap(throttles);
182 for (int64_t i = 0; i < length; ++i) {
183 DevToolsNetworkTransaction* transaction = throttles[i].transaction;
184 if (transaction)
185 transaction->FireThrottledCallback();
186 }
187 }
188
189 void DevToolsNetworkController::FireThrottledCallbacks() {
190 size_t length = throttles_.size();
191 if (!length)
192 return;
193
194 Throttles active;
195 Throttles finished;
196 for (size_t i = 0; i < length; ++i) {
197 if (throttles_[i].penalty <= 0)
198 finished.push_back(throttles_[i]);
199 else
200 active.push_back(throttles_[i]);
201 }
202 throttles_.swap(active);
203
204 length = finished.size();
205 for (size_t i = 0; i < length; ++i) {
206 DevToolsNetworkTransaction* transaction = finished[i].transaction;
207 if (transaction)
208 transaction->FireThrottledCallback();
209 }
210 }
211
212 void DevToolsNetworkController::OnTimer() {
213 UpdateThrottles();
214 FireThrottledCallbacks();
215 ArmTimer();
216 }
217
218 void DevToolsNetworkController::ArmTimer() {
219 size_t length = throttles_.size();
220 if (!length)
221 return;
222 int64_t best_n;
vsevik 2014/06/11 08:39:32 min_ticks_left
eustas 2014/06/11 10:54:25 Done.
223 for (size_t i = 0; i < length; ++i) {
224 int64_t n1 = (throttles_[i].penalty + kPacketSize - 1) / kPacketSize;
vsevik 2014/06/11 08:39:32 penalty_packets_left
eustas 2014/06/11 10:54:25 Done.
225 int64_t n = (i + 1) + length * (n1 - 1);
vsevik 2014/06/11 08:39:32 ticksLeft
eustas 2014/06/11 10:54:26 Done.
226 if (i == 0 || n < best_n)
227 best_n = n;
228 }
229 base::TimeDelta desired_time = offset_ + tick_length_ * (last_tick_ + best_n);
230 timer_.Start(
231 FROM_HERE,
232 desired_time - base::TimeTicks::Now(),
233 base::Bind(
234 &DevToolsNetworkController::OnTimer,
235 weak_ptr_factory_.GetWeakPtr()));
236 }
237
238 void DevToolsNetworkController::ThrottleTransaction(
239 DevToolsNetworkTransaction* transaction,
240 int64_t penalty) {
241 UpdateThrottles();
242 throttles_.push_back({transaction, penalty});
243 FireThrottledCallbacks();
244 ArmTimer();
245 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698