blob: 446a9022164ed68e4b4e9a21bec724f0e0b4b275 [file] [log] [blame]
tbansal80a52162016-05-20 17:55:041// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef NET_NQE_THROUGHPUT_ANALYZER_H_
6#define NET_NQE_THROUGHPUT_ANALYZER_H_
7
8#include <stdint.h>
9
10#include "base/callback.h"
11#include "base/containers/hash_tables.h"
12#include "base/macros.h"
13#include "base/memory/ref_counted.h"
14#include "base/threading/thread_checker.h"
15#include "base/time/time.h"
16#include "net/base/net_export.h"
tbansal82edab42017-06-19 05:55:2517#include "net/log/net_log_with_source.h"
tbansal80a52162016-05-20 17:55:0418
19namespace {
20typedef base::Callback<void(int32_t)> ThroughputObservationCallback;
21}
22
23namespace base {
24class SingleThreadTaskRunner;
Tarun Bansal00943112017-10-10 22:49:1425class TickClock;
tbansal80a52162016-05-20 17:55:0426}
27
28namespace net {
29
tbansal4a4305a2017-06-08 05:03:1930class NetworkQualityEstimatorParams;
Tarun Bansal00943112017-10-10 22:49:1431class NetworkQualityProvider;
tbansal80a52162016-05-20 17:55:0432class URLRequest;
33
34namespace nqe {
35
36namespace internal {
37
38// Makes throughput observations. Polls NetworkActivityMonitor
39// (TrafficStats on Android) to count number of bits received over throughput
40// observation windows in accordance with the following rules:
41// (1) A new window of observation begins any time a URL request header is
42// about to be sent, or a request completes or is destroyed.
43// (2) A request is "active" if its headers are sent, but it hasn't completed,
44// and "local" if destined to local host. If at any time during a
45// throughput observation window there is an active, local request, the
46// window is discarded.
47// (3) If less than 32KB is received over the network during a window of
48// observation, that window is discarded.
49class NET_EXPORT_PRIVATE ThroughputAnalyzer {
50 public:
51 // |throughput_observation_callback| is called on the |task_runner| when
52 // |this| has a new throughput observation.
53 // |use_local_host_requests_for_tests| should only be true when testing
54 // against local HTTP server and allows the requests to local host to be
55 // used for network quality estimation. |use_smaller_responses_for_tests|
56 // should only be true when testing, and allows the responses smaller than
57 // |kMinTransferSizeInBits| or shorter than
58 // |kMinRequestDurationMicroseconds| to be used for network quality
59 // estimation.
60 // Virtualized for testing.
61 ThroughputAnalyzer(
Tarun Bansal00943112017-10-10 22:49:1462 const NetworkQualityProvider* network_quality_provider,
tbansalff83205e2017-05-23 00:09:4563 const NetworkQualityEstimatorParams* params,
tbansal80a52162016-05-20 17:55:0464 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
65 ThroughputObservationCallback throughput_observation_callback,
Greg Thompsonaa48ce8d2018-04-03 06:11:4366 const base::TickClock* tick_clock,
tbansal82edab42017-06-19 05:55:2567 const NetLogWithSource& net_log);
tbansal80a52162016-05-20 17:55:0468 virtual ~ThroughputAnalyzer();
69
70 // Notifies |this| that the headers of |request| are about to be sent.
71 void NotifyStartTransaction(const URLRequest& request);
72
Tarun Bansal00943112017-10-10 22:49:1473 // Notifies |this| that unfiltered bytes have been read for |request|.
74 void NotifyBytesRead(const URLRequest& request);
75
tbansal80a52162016-05-20 17:55:0476 // Notifies |this| that |request| has completed.
77 void NotifyRequestCompleted(const URLRequest& request);
78
79 // Notifies |this| of a change in connection type.
80 void OnConnectionTypeChanged();
81
tbansal7018e2a2016-06-25 00:40:3982 // |use_localhost_requests| should only be true when testing against local
83 // HTTP server and allows the requests to local host to be used for network
84 // quality estimation.
85 void SetUseLocalHostRequestsForTesting(bool use_localhost_requests);
86
tbansal82edab42017-06-19 05:55:2587 // Returns true if throughput is currently tracked by a throughput
88 // observation window.
89 bool IsCurrentlyTrackingThroughput() const;
90
Tarun Bansal00943112017-10-10 22:49:1491 // Overrides the tick clock used by |this| for testing.
Greg Thompsonaa48ce8d2018-04-03 06:11:4392 void SetTickClockForTesting(const base::TickClock* tick_clock);
Tarun Bansal00943112017-10-10 22:49:1493
tbansal80a52162016-05-20 17:55:0494 protected:
95 // Exposed for testing.
96 bool disable_throughput_measurements() const {
97 return disable_throughput_measurements_;
98 }
99
100 // Returns the number of bits received by Chromium so far. The count may not
101 // start from zero, so the caller should only look at difference from a prior
102 // call. The count is obtained by polling TrafficStats on Android, and
103 // net::NetworkActivityMonitor on all other platforms. Virtualized for
104 // testing.
105 virtual int64_t GetBitsReceived() const;
106
Tarun Bansal00943112017-10-10 22:49:14107 // Returns the number of in-flight requests that can be used for computing
108 // throughput.
109 size_t CountInFlightRequests() const;
110
111 // Removes hanging requests from |requests_|. If any hanging requests are
112 // detected to be in-flight, the observation window is ended. Protected for
113 // testing.
114 void EraseHangingRequests(const URLRequest& request);
115
Tarun Bansal8914dbba2017-12-12 21:03:59116 // Returns true if the current throughput observation window is heuristically
117 // determined to contain hanging requests.
118 bool IsHangingWindow(int64_t bits_received,
119 base::TimeDelta duration,
120 double downstream_kbps_double) const;
121
tbansal80a52162016-05-20 17:55:04122 private:
123 friend class TestThroughputAnalyzer;
124
Tarun Bansal00943112017-10-10 22:49:14125 // Mapping from URL request to the last time data was received for that
126 // request.
127 typedef base::hash_map<const URLRequest*, base::TimeTicks> Requests;
128
129 // Set of URL requests to hold the requests that reduce the accuracy of
130 // throughput computation. These requests are not used in throughput
131 // computation.
132 typedef base::hash_set<const URLRequest*> AccuracyDegradingRequests;
tbansal80a52162016-05-20 17:55:04133
134 // Returns true if downstream throughput can be recorded. In that case,
135 // |downstream_kbps| is set to the computed downstream throughput (in
136 // kilobits per second). If a downstream throughput observation is taken,
137 // then the throughput observation window is reset so as to continue
138 // tracking throughput. A throughput observation can be taken only if the
139 // time-window is currently active, and enough bytes have accumulated in
140 // that window. |downstream_kbps| should not be null.
tbansalff83205e2017-05-23 00:09:45141 bool MaybeGetThroughputObservation(int32_t* downstream_kbps);
tbansal80a52162016-05-20 17:55:04142
143 // Starts the throughput observation window that keeps track of network
144 // bytes if the following conditions are true:
145 // (i) All active requests are non-local;
146 // (ii) There is at least one active, non-local request; and,
147 // (iii) The throughput observation window is not already tracking
148 // throughput. The window is started by setting the |start_| and
149 // |bits_received_|.
150 void MaybeStartThroughputObservationWindow();
151
152 // EndThroughputObservationWindow ends the throughput observation window.
153 void EndThroughputObservationWindow();
154
tbansal80a52162016-05-20 17:55:04155 // Returns true if the |request| degrades the accuracy of the throughput
156 // observation window. A local request or a request that spans a connection
157 // change degrades the accuracy of the throughput computation.
158 bool DegradesAccuracy(const URLRequest& request) const;
159
160 // Bounds |accuracy_degrading_requests_| and |requests_| to ensure their sizes
161 // do not exceed their capacities.
162 void BoundRequestsSize();
163
Tarun Bansal00943112017-10-10 22:49:14164 // Guaranteed to be non-null during the duration of |this|.
165 const NetworkQualityProvider* network_quality_provider_;
166
167 // Guaranteed to be non-null during the duration of |this|.
tbansalff83205e2017-05-23 00:09:45168 const NetworkQualityEstimatorParams* params_;
Tarun Bansal00943112017-10-10 22:49:14169
tbansal80a52162016-05-20 17:55:04170 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
171
172 // Called every time a new throughput observation is available.
173 ThroughputObservationCallback throughput_observation_callback_;
174
Tarun Bansal00943112017-10-10 22:49:14175 // Guaranteed to be non-null during the lifetime of |this|.
Greg Thompsonaa48ce8d2018-04-03 06:11:43176 const base::TickClock* tick_clock_;
Tarun Bansal00943112017-10-10 22:49:14177
tbansal80a52162016-05-20 17:55:04178 // Time when last connection change was observed.
179 base::TimeTicks last_connection_change_;
180
181 // Start time of the current throughput observation window. Set to null if
182 // the window is not currently active.
183 base::TimeTicks window_start_time_;
184
185 // Number of bits received prior to |start_| as reported by
186 // NetworkActivityMonitor.
187 int64_t bits_received_at_window_start_;
188
189 // Container that holds active requests that reduce the accuracy of
190 // throughput computation. These requests are not used in throughput
191 // computation.
Tarun Bansal00943112017-10-10 22:49:14192 AccuracyDegradingRequests accuracy_degrading_requests_;
tbansal80a52162016-05-20 17:55:04193
194 // Container that holds active requests that do not reduce the accuracy of
195 // throughput computation. These requests are used in throughput computation.
196 Requests requests_;
197
Tarun Bansal00943112017-10-10 22:49:14198 // Last time when the check for hanging requests was run.
199 base::TimeTicks last_hanging_request_check_;
200
tbansal80a52162016-05-20 17:55:04201 // If true, then |this| throughput analyzer stops tracking the throughput
202 // observations until Chromium is restarted. This may happen if the throughput
203 // analyzer has lost track of the requests that degrade throughput computation
204 // accuracy.
205 bool disable_throughput_measurements_;
206
207 // Determines if the requests to local host can be used in estimating the
208 // network quality. Set to true only for tests.
tbansal7018e2a2016-06-25 00:40:39209 bool use_localhost_requests_for_tests_;
tbansal80a52162016-05-20 17:55:04210
tbansal80a52162016-05-20 17:55:04211 base::ThreadChecker thread_checker_;
212
tbansal82edab42017-06-19 05:55:25213 NetLogWithSource net_log_;
214
tbansal80a52162016-05-20 17:55:04215 DISALLOW_COPY_AND_ASSIGN(ThroughputAnalyzer);
216};
217
218} // namespace internal
219
220} // namespace nqe
221
222} // namespace net
223
bnc3698b0a02016-12-09 23:36:50224#endif // NET_NQE_THROUGHPUT_ANALYZER_H_