OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 #include "chromecast/base/metrics/cast_metrics_helper.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/location.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" |
| 11 #include "base/metrics/histogram.h" |
| 12 #include "base/metrics/user_metrics.h" |
| 13 #include "chromecast/base/metrics/cast_histograms.h" |
| 14 |
| 15 namespace chromecast { |
| 16 namespace metrics { |
| 17 |
| 18 // A useful macro to make sure current member function runs on the valid thread. |
| 19 #define MAKE_SURE_THREAD(callback, ...) \ |
| 20 if (!message_loop_proxy_->BelongsToCurrentThread()) { \ |
| 21 message_loop_proxy_->PostTask(FROM_HERE, base::Bind( \ |
| 22 &CastMetricsHelper::callback, \ |
| 23 base::Unretained(this), ##__VA_ARGS__)); \ |
| 24 return; \ |
| 25 } |
| 26 |
| 27 namespace { |
| 28 |
| 29 CastMetricsHelper* g_instance = NULL; |
| 30 |
| 31 // Displayed frames are logged in frames per second (but sampling can be over |
| 32 // a longer period of time, e.g. 5 seconds). |
| 33 const int kDisplayedFramesPerSecondPeriod = 1000000; |
| 34 |
| 35 // Sample every 5 seconds, represented in microseconds. |
| 36 const int kNominalVideoSamplePeriod = 5000000; |
| 37 |
| 38 } // namespace |
| 39 |
| 40 CastMetricsHelper* CastMetricsHelper::GetInstance() { |
| 41 DCHECK(g_instance); |
| 42 return g_instance; |
| 43 } |
| 44 |
| 45 CastMetricsHelper::CastMetricsHelper( |
| 46 scoped_refptr<base::MessageLoopProxy> message_loop_proxy) |
| 47 : message_loop_proxy_(message_loop_proxy), |
| 48 metrics_sink_(NULL) { |
| 49 DCHECK(message_loop_proxy_.get()); |
| 50 DCHECK(!g_instance); |
| 51 g_instance = this; |
| 52 } |
| 53 |
| 54 CastMetricsHelper::CastMetricsHelper() |
| 55 : metrics_sink_(NULL) { |
| 56 DCHECK(!g_instance); |
| 57 g_instance = this; |
| 58 } |
| 59 |
| 60 CastMetricsHelper::~CastMetricsHelper() { |
| 61 DCHECK_EQ(g_instance, this); |
| 62 g_instance = NULL; |
| 63 } |
| 64 |
| 65 void CastMetricsHelper::TagAppStart(const std::string& arg_app_name) { |
| 66 MAKE_SURE_THREAD(TagAppStart, arg_app_name); |
| 67 app_name_ = arg_app_name; |
| 68 app_start_time_ = base::TimeTicks::Now(); |
| 69 new_startup_time_ = true; |
| 70 } |
| 71 |
| 72 void CastMetricsHelper::LogMediaPlay() { |
| 73 MAKE_SURE_THREAD(LogMediaPlay); |
| 74 base::RecordComputedAction(GetMetricsNameWithAppName("MediaPlay", "")); |
| 75 } |
| 76 |
| 77 void CastMetricsHelper::LogMediaPause() { |
| 78 MAKE_SURE_THREAD(LogMediaPause); |
| 79 base::RecordComputedAction(GetMetricsNameWithAppName("MediaPause", "")); |
| 80 } |
| 81 |
| 82 void CastMetricsHelper::LogTimeToDisplayVideo() { |
| 83 if (!new_startup_time_) { // For faster check. |
| 84 return; |
| 85 } |
| 86 MAKE_SURE_THREAD(LogTimeToDisplayVideo); |
| 87 new_startup_time_ = false; |
| 88 base::TimeDelta launch_time = base::TimeTicks::Now() - app_start_time_; |
| 89 const std::string uma_name(GetMetricsNameWithAppName("Startup", |
| 90 "TimeToDisplayVideo")); |
| 91 LogMediumTimeHistogramEvent(uma_name, launch_time); |
| 92 LOG(INFO) << uma_name << " is " << launch_time.InSecondsF() << " seconds."; |
| 93 } |
| 94 |
| 95 void CastMetricsHelper::LogTimeToBufferAv(BufferingType buffering_type, |
| 96 base::TimeDelta time) { |
| 97 MAKE_SURE_THREAD(LogTimeToBufferAv, buffering_type, time); |
| 98 if (time < base::TimeDelta::FromSeconds(0)) { |
| 99 LOG(WARNING) << "Negative time"; |
| 100 return; |
| 101 } |
| 102 |
| 103 const std::string uma_name(GetMetricsNameWithAppName( |
| 104 "Media", |
| 105 (buffering_type == kInitialBuffering ? "TimeToBufferAv" : |
| 106 buffering_type == kBufferingAfterUnderrun ? |
| 107 "TimeToBufferAvAfterUnderrun" : |
| 108 buffering_type == kAbortedBuffering ? "TimeToBufferAvAfterAbort" : ""))); |
| 109 |
| 110 // Histogram from 250ms to 30s with 50 buckets. |
| 111 // The ratio between 2 consecutive buckets is: |
| 112 // exp( (ln(30000) - ln(250)) / 50 ) = 1.1 |
| 113 LogTimeHistogramEvent( |
| 114 uma_name, |
| 115 time, |
| 116 base::TimeDelta::FromMilliseconds(250), |
| 117 base::TimeDelta::FromMilliseconds(30000), |
| 118 50); |
| 119 } |
| 120 |
| 121 void CastMetricsHelper::ResetVideoFrameSampling() { |
| 122 MAKE_SURE_THREAD(ResetVideoFrameSampling); |
| 123 previous_video_stat_sample_time_ = base::TimeTicks(); |
| 124 } |
| 125 |
| 126 void CastMetricsHelper::LogFramesPer5Seconds(int displayed_frames, |
| 127 int dropped_frames, |
| 128 int delayed_frames, |
| 129 int error_frames) { |
| 130 MAKE_SURE_THREAD(LogFramesPer5Seconds, displayed_frames, dropped_frames, |
| 131 delayed_frames, error_frames); |
| 132 base::TimeTicks sample_time = base::TimeTicks::Now(); |
| 133 |
| 134 if (!previous_video_stat_sample_time_.is_null()) { |
| 135 base::TimeDelta time_diff = sample_time - previous_video_stat_sample_time_; |
| 136 int value = 0; |
| 137 const int64 rounding = time_diff.InMicroseconds() / 2; |
| 138 |
| 139 if (displayed_frames >= 0) { |
| 140 value = (displayed_frames * kDisplayedFramesPerSecondPeriod + rounding) / |
| 141 time_diff.InMicroseconds(); |
| 142 LogEnumerationHistogramEvent( |
| 143 GetMetricsNameWithAppName("Media", "DisplayedFramesPerSecond"), |
| 144 value, 50); |
| 145 } |
| 146 if (delayed_frames >= 0) { |
| 147 value = (delayed_frames * kNominalVideoSamplePeriod + rounding) / |
| 148 time_diff.InMicroseconds(); |
| 149 LogEnumerationHistogramEvent( |
| 150 GetMetricsNameWithAppName("Media", "DelayedVideoFramesPer5Sec"), |
| 151 value, 50); |
| 152 } |
| 153 if (dropped_frames >= 0) { |
| 154 value = (dropped_frames * kNominalVideoSamplePeriod + rounding) / |
| 155 time_diff.InMicroseconds(); |
| 156 LogEnumerationHistogramEvent( |
| 157 GetMetricsNameWithAppName("Media", "DroppedVideoFramesPer5Sec"), |
| 158 value, 50); |
| 159 } |
| 160 if (error_frames >= 0) { |
| 161 value = (error_frames * kNominalVideoSamplePeriod + rounding) / |
| 162 time_diff.InMicroseconds(); |
| 163 LogEnumerationHistogramEvent( |
| 164 GetMetricsNameWithAppName("Media", "ErrorVideoFramesPer5Sec"), |
| 165 value, 50); |
| 166 } |
| 167 } |
| 168 |
| 169 previous_video_stat_sample_time_ = sample_time; |
| 170 } |
| 171 |
| 172 std::string CastMetricsHelper::GetMetricsNameWithAppName( |
| 173 const std::string& prefix, |
| 174 const std::string& suffix) const { |
| 175 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 176 std::string metrics_name(prefix); |
| 177 if (!app_name_.empty()) { |
| 178 if (!metrics_name.empty()) |
| 179 metrics_name.push_back('.'); |
| 180 metrics_name.append(app_name_); |
| 181 } |
| 182 if (!suffix.empty()) { |
| 183 if (!metrics_name.empty()) |
| 184 metrics_name.push_back('.'); |
| 185 metrics_name.append(suffix); |
| 186 } |
| 187 return metrics_name; |
| 188 } |
| 189 |
| 190 void CastMetricsHelper::SetMetricsSink(MetricsSink* delegate) { |
| 191 MAKE_SURE_THREAD(SetMetricsSink, delegate); |
| 192 metrics_sink_ = delegate; |
| 193 } |
| 194 |
| 195 void CastMetricsHelper::LogEnumerationHistogramEvent( |
| 196 const std::string& name, int value, int num_buckets) { |
| 197 MAKE_SURE_THREAD(LogEnumerationHistogramEvent, name, value, num_buckets); |
| 198 |
| 199 if (metrics_sink_) { |
| 200 metrics_sink_->OnEnumerationEvent(name, value, num_buckets); |
| 201 } else { |
| 202 UMA_HISTOGRAM_ENUMERATION_NO_CACHE(name, value, num_buckets); |
| 203 } |
| 204 } |
| 205 |
| 206 void CastMetricsHelper::LogTimeHistogramEvent(const std::string& name, |
| 207 const base::TimeDelta& value, |
| 208 const base::TimeDelta& min, |
| 209 const base::TimeDelta& max, |
| 210 int num_buckets) { |
| 211 MAKE_SURE_THREAD(LogTimeHistogramEvent, name, value, min, max, num_buckets); |
| 212 |
| 213 if (metrics_sink_) { |
| 214 metrics_sink_->OnTimeEvent(name, value, min, max, num_buckets); |
| 215 } else { |
| 216 UMA_HISTOGRAM_CUSTOM_TIMES_NO_CACHE(name, value, min, max, num_buckets); |
| 217 } |
| 218 } |
| 219 |
| 220 void CastMetricsHelper::LogMediumTimeHistogramEvent( |
| 221 const std::string& name, |
| 222 const base::TimeDelta& value) { |
| 223 // Follow UMA_HISTOGRAM_MEDIUM_TIMES definition. |
| 224 LogTimeHistogramEvent(name, value, |
| 225 base::TimeDelta::FromMilliseconds(10), |
| 226 base::TimeDelta::FromMinutes(3), |
| 227 50); |
| 228 } |
| 229 |
| 230 } // namespace metrics |
| 231 } // namespace chromecast |
OLD | NEW |