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

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: One more divide-by-zero check 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;
vsevik 2014/06/11 12:08:51 Rename to bytes_left or pending_bytes_count?
vsevik 2014/06/11 12:08:51 Looks like we can encapsulate penalty into transac
eustas 2014/06/11 13:18:48 Done.
eustas 2014/06/11 13:18:48 Done.
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 for (size_t i = 0; i < length; ++i) {
51 if (throttles_[i].transaction == transaction)
52 throttles_[i].transaction = NULL;
53 }
40 } 54 }
41 55
42 void DevToolsNetworkController::SetNetworkState( 56 void DevToolsNetworkController::SetNetworkState(
43 const std::string& client_id,
44 const scoped_refptr<DevToolsNetworkConditions> conditions) { 57 const scoped_refptr<DevToolsNetworkConditions> conditions) {
45 DCHECK_CURRENTLY_ON(BrowserThread::UI); 58 DCHECK_CURRENTLY_ON(BrowserThread::UI);
46 BrowserThread::PostTask( 59 BrowserThread::PostTask(
47 content::BrowserThread::IO, 60 content::BrowserThread::IO,
48 FROM_HERE, 61 FROM_HERE,
49 base::Bind( 62 base::Bind(
50 &DevToolsNetworkController::SetNetworkStateOnIO, 63 &DevToolsNetworkController::SetNetworkStateOnIO,
51 weak_ptr_factory_.GetWeakPtr(), 64 weak_ptr_factory_.GetWeakPtr(),
52 client_id,
53 conditions)); 65 conditions));
54 } 66 }
55 67
56 void DevToolsNetworkController::SetNetworkStateOnIO( 68 void DevToolsNetworkController::SetNetworkStateOnIO(
57 const std::string& client_id,
58 const scoped_refptr<DevToolsNetworkConditions> conditions) { 69 const scoped_refptr<DevToolsNetworkConditions> conditions) {
59 DCHECK(thread_checker_.CalledOnValidThread()); 70 DCHECK(thread_checker_.CalledOnValidThread());
60 if (!conditions) { 71 if (conditions_ && conditions_->IsThrottling())
61 if (client_id == active_client_id_) { 72 UpdateThrottles();
62 conditions_ = NULL; 73
63 active_client_id_ = std::string(); 74 conditions_ = conditions;
75 if (!conditions || !conditions->IsThrottling())
76 CancelThrottles();
77 if (!conditions)
78 return;
79
80 FireThrottledCallbacks();
vsevik 2014/06/11 12:08:51 We should only do this in case we are continuing t
eustas 2014/06/11 13:18:48 Done.
81
82 if (conditions_->IsOffline()) {
83 // Iterate over a copy of set, because failing of transaction could
84 // result in creating a new one, or (theoretically) destroying one.
85 Transactions old_transactions(transactions_);
86 for (Transactions::iterator it = old_transactions.begin();
87 it != old_transactions.end(); ++it) {
88 if (transactions_.find(*it) == transactions_.end())
89 continue;
90 if (!(*it)->request() || (*it)->failed())
91 continue;
92 if (ShouldFail((*it)->request()))
93 (*it)->Fail();
64 } 94 }
65 return;
66 } 95 }
67 conditions_ = conditions;
68 active_client_id_ = client_id;
69 96
70 // Iterate over a copy of set, because failing of transaction could result in 97 if (conditions_->IsThrottling()) {
71 // creating a new one, or (theoretically) destroying one. 98 DCHECK(conditions_->maximal_throughput() != 0);
72 Transactions old_transactions(transactions_); 99 offset_ = base::TimeTicks::Now();
73 for (Transactions::iterator it = old_transactions.begin(); 100 last_tick_ = 0;
74 it != old_transactions.end(); ++it) { 101 int64_t us_tick_length =
75 if (transactions_.find(*it) == transactions_.end()) 102 (1000000L * kPacketSize) / conditions_->maximal_throughput();
76 continue; 103 DCHECK(us_tick_length != 0);
77 if (!(*it)->request() || (*it)->failed()) 104 if (us_tick_length == 0)
78 continue; 105 us_tick_length = 1;
79 if (ShouldFail((*it)->request())) 106 tick_length_ = base::TimeDelta::FromMicroseconds(us_tick_length);
80 (*it)->Fail(); 107 ArmTimer();
81 } 108 }
82 } 109 }
83 110
84 bool DevToolsNetworkController::ShouldFail( 111 bool DevToolsNetworkController::ShouldFail(
85 const net::HttpRequestInfo* request) { 112 const net::HttpRequestInfo* request) {
86 DCHECK(thread_checker_.CalledOnValidThread()); 113 DCHECK(thread_checker_.CalledOnValidThread());
87 DCHECK(request); 114 DCHECK(request);
88 if (!conditions_ || !conditions_->IsOffline()) 115 if (!conditions_ || !conditions_->IsOffline())
89 return false; 116 return false;
90 117
91 if (!conditions_->HasMatchingDomain(request->url)) 118 if (!conditions_->HasMatchingDomain(request->url))
92 return false; 119 return false;
93 120
94 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator); 121 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
95 } 122 }
123
124 bool DevToolsNetworkController::ShouldThrottle(
125 const net::HttpRequestInfo* request) {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 DCHECK(request);
128 if (!conditions_ || !conditions_->IsThrottling())
129 return false;
130
131 if (!conditions_->HasMatchingDomain(request->url))
132 return false;
133
134 return !request->extra_headers.HasHeader(kDevToolsRequestInitiator);
135 }
136
137 void DevToolsNetworkController::UpdateThrottles() {
138 int64_t last_tick = (base::TimeTicks::Now() - offset_) / tick_length_;
139 int64_t ticks = last_tick - last_tick_;
140 last_tick_ = last_tick;
141
142 int64_t length = throttles_.size();
143 if (!length)
144 return;
145
146 int64_t delta = (ticks / length) * kPacketSize;
147 int64_t shift = ticks % length;
vsevik 2014/06/11 12:08:51 nit: What is delta and what is shift? Could you pl
148 for (int64_t i = 0; i < length; ++i)
149 throttles_[i].penalty -= delta + (i < shift ? kPacketSize : 0);
150 std::rotate(
151 throttles_.begin(), throttles_.begin() + shift, throttles_.end());
152 }
153
154 void DevToolsNetworkController::CancelThrottles() {
155 timer_.Stop();
156
157 int64_t length = throttles_.size();
158 if (!length)
159 return;
160
161 Throttles throttles;
162 throttles_.swap(throttles);
163 for (int64_t i = 0; i < length; ++i) {
164 DevToolsNetworkTransaction* transaction = throttles[i].transaction;
vsevik 2014/06/11 12:08:51 I am pretty sure transaction is never null here, o
eustas 2014/06/11 13:18:48 Done.
165 if (transaction)
166 transaction->FireThrottledCallback();
167 }
168 }
169
170 void DevToolsNetworkController::FireThrottledCallbacks() {
171 size_t length = throttles_.size();
172 if (!length)
173 return;
174
175 Throttles active;
vsevik 2014/06/11 12:08:51 nit: active_transactions
eustas 2014/06/11 13:18:48 Done.
176 Throttles finished;
vsevik 2014/06/11 12:08:51 ditto
eustas 2014/06/11 13:18:48 Done.
177 for (size_t i = 0; i < length; ++i) {
178 if (throttles_[i].penalty <= 0)
179 finished.push_back(throttles_[i]);
180 else
181 active.push_back(throttles_[i]);
182 }
183 throttles_.swap(active);
184
185 length = finished.size();
186 for (size_t i = 0; i < length; ++i) {
187 DevToolsNetworkTransaction* transaction = finished[i].transaction;
188 if (transaction)
189 transaction->FireThrottledCallback();
190 }
191 }
192
193 void DevToolsNetworkController::OnTimer() {
194 UpdateThrottles();
195 FireThrottledCallbacks();
196 ArmTimer();
197 }
198
199 void DevToolsNetworkController::ArmTimer() {
200 size_t length = throttles_.size();
201 if (!length)
202 return;
203 int64_t min_ticks_left;
204 for (size_t i = 0; i < length; ++i) {
205 int64_t packets_left =
206 (throttles_[i].penalty + kPacketSize - 1) / kPacketSize;
207 int64_t ticks_left = (i + 1) + length * (packets_left - 1);
208 if (i == 0 || ticks_left < min_ticks_left)
209 min_ticks_left = ticks_left;
210 }
211 base::TimeTicks desired_time =
212 offset_ + tick_length_ * (last_tick_ + min_ticks_left);
213 timer_.Start(
214 FROM_HERE,
215 desired_time - base::TimeTicks::Now(),
216 base::Bind(
217 &DevToolsNetworkController::OnTimer,
218 weak_ptr_factory_.GetWeakPtr()));
219 }
220
221 void DevToolsNetworkController::ThrottleTransaction(
222 DevToolsNetworkTransaction* transaction,
223 int64_t penalty) {
224 UpdateThrottles();
225 throttles_.push_back({transaction, penalty});
226 FireThrottledCallbacks();
227 ArmTimer();
228 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698