| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_BASE_BANDWIDTH_METRICS_H_ |
| #define NET_BASE_BANDWIDTH_METRICS_H_ |
| |
| #include <list> |
| |
| #include "base/metrics/histogram.h" |
| #include "base/logging.h" |
| #include "base/time.h" |
| |
| namespace net { |
| |
| // Tracks statistics about the bandwidth metrics over time. In order to |
| // measure, this class needs to know when individual streams are in progress, |
| // so that it can know when to discount idle time. The BandwidthMetrics |
| // is unidirectional - it should only be used to record upload or download |
| // bandwidth, but not both. |
| // |
| // Note, the easiest thing to do is to just measure each stream and average |
| // them or add them. However, this does not work. If multiple streams are in |
| // progress concurrently, you have to look at the aggregate bandwidth at any |
| // point in time. |
| // |
| // Example: |
| // Imagine 4 streams opening and closing with overlapping time. |
| // We can't measure bandwidth by looking at any individual stream. |
| // We can only measure actual bandwidth by looking at the bandwidth |
| // across all open streams. |
| // |
| // Time ---------------------------------------> |
| // s1 +----------------+ |
| // s2 +----------------+ |
| // s3 +--------------+ |
| // s4 +--------------+ |
| // |
| // Example usage: |
| // |
| // BandwidthMetrics tracker; |
| // |
| // // When a stream is created |
| // tracker.StartStream(); |
| // |
| // // When data is transferred on any stream |
| // tracker.RecordSample(bytes); |
| // |
| // // When the stream is finished |
| // tracker.StopStream(); |
| // |
| // NOTE: This class is not thread safe. |
| // |
| class BandwidthMetrics { |
| public: |
| BandwidthMetrics() |
| : num_streams_in_progress_(0), |
| num_data_samples_(0), |
| data_sum_(0.0), |
| bytes_since_last_start_(0) { |
| } |
| |
| // Get the bandwidth. Returns Kbps (kilo-bits-per-second). |
| double bandwidth() const { |
| return data_sum_ / num_data_samples_; |
| } |
| |
| // Record that we've started a stream. |
| void StartStream() { |
| // If we're the only stream, we've finished some idle time. Record a new |
| // timestamp to indicate the start of data flow. |
| if (++num_streams_in_progress_ == 1) { |
| last_start_ = base::TimeTicks::HighResNow(); |
| bytes_since_last_start_ = 0; |
| } |
| } |
| |
| // Track that we've completed a stream. |
| void StopStream() { |
| if (--num_streams_in_progress_ == 0) { |
| // We don't use small streams when tracking bandwidth because they are not |
| // precise; imagine a 25 byte stream. The sample is too small to make |
| // a good measurement. |
| // 20KB is an arbitrary value. We might want to use a lesser value. |
| static const int64 kRecordSizeThreshold = 20 * 1024; |
| if (bytes_since_last_start_ < kRecordSizeThreshold) |
| return; |
| |
| base::TimeDelta delta = base::TimeTicks::HighResNow() - last_start_; |
| double ms = delta.InMillisecondsF(); |
| if (ms > 0.0) { |
| double kbps = static_cast<double>(bytes_since_last_start_) * 8 / ms; |
| ++num_data_samples_; |
| data_sum_ += kbps; |
| VLOG(1) << "Bandwidth: " << kbps |
| << "Kbps (avg " << bandwidth() << "Kbps)"; |
| int kbps_int = static_cast<int>(kbps); |
| UMA_HISTOGRAM_COUNTS_10000("Net.DownloadBandwidth", kbps_int); |
| } |
| } |
| } |
| |
| // Add a sample of the number of bytes read from the network into the tracker. |
| void RecordBytes(int bytes) { |
| DCHECK(num_streams_in_progress_); |
| bytes_since_last_start_ += static_cast<int64>(bytes); |
| } |
| |
| private: |
| int num_streams_in_progress_; // The number of streams in progress. |
| // TODO(mbelshe): Use a rolling buffer of 30 samples instead of an average. |
| int num_data_samples_; // The number of samples collected. |
| double data_sum_; // The sum of all samples collected. |
| int64 bytes_since_last_start_; // Bytes tracked during this "session". |
| base::TimeTicks last_start_; // Timestamp of the begin of this "session". |
| }; |
| |
| // A utility class for managing the lifecycle of a measured stream. |
| // It is important that we not leave unclosed streams, and this class helps |
| // ensure we always stop them. |
| class ScopedBandwidthMetrics { |
| public: |
| ScopedBandwidthMetrics(); |
| ~ScopedBandwidthMetrics(); |
| |
| void StartStream(); |
| void StopStream(); |
| void RecordBytes(int bytes); |
| |
| private: |
| bool started_; |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_BASE_BANDWIDTH_METRICS_H_ |