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::HighResNow(); 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::HighResNow() - 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_ 137