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