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