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.
5
#ifndef NET_BASE_BANDWIDTH_METRICS_H_
6
#define NET_BASE_BANDWIDTH_METRICS_H_
10
#include "base/logging.h"
11
#include "base/metrics/histogram.h"
12
#include "base/time/time.h"
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.
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
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.
33
// Time --------------------------------------->
34
// s1 +----------------+
35
// s2 +----------------+
36
// s3 +--------------+
37
// s4 +--------------+
41
// BandwidthMetrics tracker;
43
// // When a stream is created
44
// tracker.StartStream();
46
// // When data is transferred on any stream
47
// tracker.RecordSample(bytes);
49
// // When the stream is finished
50
// tracker.StopStream();
52
// NOTE: This class is not thread safe.
54
class BandwidthMetrics {
57
: num_streams_in_progress_(0),
60
bytes_since_last_start_(0) {
63
// Get the bandwidth. Returns Kbps (kilo-bits-per-second).
64
double bandwidth() const {
65
return data_sum_ / num_data_samples_;
68
// Record that we've started a stream.
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;
78
// Track that we've completed a stream.
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)
89
base::TimeDelta delta = base::TimeTicks::HighResNow() - last_start_;
90
double ms = delta.InMillisecondsF();
92
double kbps = static_cast<double>(bytes_since_last_start_) * 8 / ms;
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);
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);
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".
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 {
123
ScopedBandwidthMetrics();
124
~ScopedBandwidthMetrics();
128
void RecordBytes(int bytes);
136
#endif // NET_BASE_BANDWIDTH_METRICS_H_