OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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_BASE_BANDWIDTH_METRICS_H_ | |
6 #define NET_BASE_BANDWIDTH_METRICS_H_ | |
7 | |
8 #include <list> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/metrics/histogram.h" | |
12 #include "base/time/time.h" | |
13 | |
14 namespace net { | |
15 | |
16 // Tracks statistics about the bandwidth metrics over time. In order to | |
17 // measure, this class needs to know when individual streams are in progress, | |
18 // so that it can know when to discount idle time. The BandwidthMetrics | |
19 // is unidirectional - it should only be used to record upload or download | |
20 // bandwidth, but not both. | |
21 // | |
22 // Note, the easiest thing to do is to just measure each stream and average | |
23 // them or add them. However, this does not work. If multiple streams are in | |
24 // progress concurrently, you have to look at the aggregate bandwidth at any | |
25 // point in time. | |
26 // | |
27 // Example: | |
28 // Imagine 4 streams opening and closing with overlapping time. | |
29 // We can't measure bandwidth by looking at any individual stream. | |
30 // We can only measure actual bandwidth by looking at the bandwidth | |
31 // across all open streams. | |
32 // | |
33 // Time ---------------------------------------> | |
34 // s1 +----------------+ | |
35 // s2 +----------------+ | |
36 // s3 +--------------+ | |
37 // s4 +--------------+ | |
38 // | |
39 // Example usage: | |
40 // | |
41 // BandwidthMetrics tracker; | |
42 // | |
43 // // When a stream is created | |
44 // tracker.StartStream(); | |
45 // | |
46 // // When data is transferred on any stream | |
47 // tracker.RecordSample(bytes); | |
48 // | |
49 // // When the stream is finished | |
50 // tracker.StopStream(); | |
51 // | |
52 // NOTE: This class is not thread safe. | |
53 // | |
54 class BandwidthMetrics { | |
55 public: | |
56 BandwidthMetrics() | |
57 : num_streams_in_progress_(0), | |
58 num_data_samples_(0), | |
59 data_sum_(0.0), | |
60 bytes_since_last_start_(0) { | |
61 } | |
62 | |
63 // Get the bandwidth. Returns Kbps (kilo-bits-per-second). | |
64 double bandwidth() const { | |
65 return data_sum_ / num_data_samples_; | |
66 } | |
67 | |
68 // Record that we've started a stream. | |
69 void StartStream() { | |
70 // If we're the only stream, we've finished some idle time. Record a new | |
71 // timestamp to indicate the start of data flow. | |
72 if (++num_streams_in_progress_ == 1) { | |
73 last_start_ = base::TimeTicks::Now(); | |
74 bytes_since_last_start_ = 0; | |
75 } | |
76 } | |
77 | |
78 // Track that we've completed a stream. | |
79 void StopStream() { | |
80 if (--num_streams_in_progress_ == 0) { | |
81 // We don't use small streams when tracking bandwidth because they are not | |
82 // precise; imagine a 25 byte stream. The sample is too small to make | |
83 // a good measurement. | |
84 // 20KB is an arbitrary value. We might want to use a lesser value. | |
85 static const int64 kRecordSizeThreshold = 20 * 1024; | |
86 if (bytes_since_last_start_ < kRecordSizeThreshold) | |
87 return; | |
88 | |
89 base::TimeDelta delta = base::TimeTicks::Now() - last_start_; | |
90 double ms = delta.InMillisecondsF(); | |
91 if (ms > 0.0) { | |
92 double kbps = static_cast<double>(bytes_since_last_start_) * 8 / ms; | |
93 ++num_data_samples_; | |
94 data_sum_ += kbps; | |
95 VLOG(1) << "Bandwidth: " << kbps | |
96 << "Kbps (avg " << bandwidth() << "Kbps)"; | |
97 int kbps_int = static_cast<int>(kbps); | |
98 UMA_HISTOGRAM_COUNTS_10000("Net.DownloadBandwidth", kbps_int); | |
99 } | |
100 } | |
101 } | |
102 | |
103 // Add a sample of the number of bytes read from the network into the tracker. | |
104 void RecordBytes(int bytes) { | |
105 DCHECK(num_streams_in_progress_); | |
106 bytes_since_last_start_ += static_cast<int64>(bytes); | |
107 } | |
108 | |
109 private: | |
110 int num_streams_in_progress_; // The number of streams in progress. | |
111 // TODO(mbelshe): Use a rolling buffer of 30 samples instead of an average. | |
112 int num_data_samples_; // The number of samples collected. | |
113 double data_sum_; // The sum of all samples collected. | |
114 int64 bytes_since_last_start_; // Bytes tracked during this "session". | |
115 base::TimeTicks last_start_; // Timestamp of the begin of this "session". | |
116 }; | |
117 | |
118 // A utility class for managing the lifecycle of a measured stream. | |
119 // It is important that we not leave unclosed streams, and this class helps | |
120 // ensure we always stop them. | |
121 class ScopedBandwidthMetrics { | |
122 public: | |
123 ScopedBandwidthMetrics(); | |
124 ~ScopedBandwidthMetrics(); | |
125 | |
126 void StartStream(); | |
127 void StopStream(); | |
128 void RecordBytes(int bytes); | |
129 | |
130 private: | |
131 bool started_; | |
132 }; | |
133 | |
134 } // namespace net | |
135 | |
136 #endif // NET_BASE_BANDWIDTH_METRICS_H_ | |
OLD | NEW |