• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace 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 //
55 class BandwidthMetrics {
56  public:
BandwidthMetrics()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).
bandwidth()65   double bandwidth() const {
66     return data_sum_ / num_data_samples_;
67   }
68 
69   // Record that we've started a stream.
StartStream()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.
StopStream()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.
RecordBytes(int bytes)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.
122 class 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