| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/performance_tracker.h" | 5 #include "remoting/protocol/performance_tracker.h" |
| 6 | 6 |
| 7 #include "remoting/proto/video.pb.h" | 7 #include "remoting/proto/video.pb.h" |
| 8 | 8 |
| 9 namespace { | 9 namespace { |
| 10 | 10 |
| 11 // We take the last 10 latency numbers and report the average. | 11 // We take the last 10 latency numbers and report the average. |
| 12 const int kLatencySampleSize = 10; | 12 const int kLatencySampleSize = 10; |
| 13 | 13 |
| 14 // UMA histogram names. | 14 // UMA histogram names. |
| 15 const char kRoundTripLatencyHistogram[] = "Chromoting.Video.RoundTripLatency"; | 15 const char kRoundTripLatencyHistogram[] = "Chromoting.Video.RoundTripLatency"; |
| 16 const char kVideoCaptureLatencyHistogram[] = "Chromoting.Video.CaptureLatency"; | 16 const char kVideoCaptureLatencyHistogram[] = "Chromoting.Video.CaptureLatency"; |
| 17 const char kVideoEncodeLatencyHistogram[] = "Chromoting.Video.EncodeLatency"; | 17 const char kVideoEncodeLatencyHistogram[] = "Chromoting.Video.EncodeLatency"; |
| 18 const char kVideoDecodeLatencyHistogram[] = "Chromoting.Video.DecodeLatency"; | 18 const char kVideoDecodeLatencyHistogram[] = "Chromoting.Video.DecodeLatency"; |
| 19 const char kVideoPaintLatencyHistogram[] = "Chromoting.Video.PaintLatency"; | 19 const char kVideoPaintLatencyHistogram[] = "Chromoting.Video.PaintLatency"; |
| 20 const char kVideoFrameRateHistogram[] = "Chromoting.Video.FrameRate"; | 20 const char kVideoFrameRateHistogram[] = "Chromoting.Video.FrameRate"; |
| 21 const char kVideoPacketRateHistogram[] = "Chromoting.Video.PacketRate"; | 21 const char kVideoPacketRateHistogram[] = "Chromoting.Video.PacketRate"; |
| 22 const char kVideoBandwidthHistogram[] = "Chromoting.Video.Bandwidth"; | 22 const char kVideoBandwidthHistogram[] = "Chromoting.Video.Bandwidth"; |
| 23 const char kCapturePendingLatencyHistogram[] = |
| 24 "Chromoting.Video.CapturePendingLatency"; |
| 25 const char kCaptureOverheadHistogram[] = "Chromoting.Video.CaptureOverhead"; |
| 26 const char kEncodePendingLatencyHistogram[] = |
| 27 "Chromoting.Video.EncodePendingLatency"; |
| 28 const char kSendPendingLatencyHistogram[] = |
| 29 "Chromoting.Video.SendPendingLatency"; |
| 23 | 30 |
| 24 // Custom count and custom time histograms are log-scaled by default. This | 31 // Custom count and custom time histograms are log-scaled by default. This |
| 25 // results in fine-grained buckets at lower values and wider-ranged buckets | 32 // results in fine-grained buckets at lower values and wider-ranged buckets |
| 26 // closer to the maximum. | 33 // closer to the maximum. |
| 27 // The values defined for each histogram below are based on the 99th percentile | 34 // The values defined for each histogram below are based on the 99th percentile |
| 28 // numbers for the corresponding metric over a recent 28-day period. | 35 // numbers for the corresponding metric over a recent 28-day period. |
| 29 // Values above the maximum defined for a histogram end up in the max-bucket. | 36 // Values above the maximum defined for a histogram end up in the max-bucket. |
| 30 // If the minimum for a UMA histogram is set to be < 1, it is implicitly | 37 // If the minimum for a UMA histogram is set to be < 1, it is implicitly |
| 31 // normalized to 1. | 38 // normalized to 1. |
| 32 // See $/src/base/metrics/histogram.h for more details. | 39 // See $/src/base/metrics/histogram.h for more details. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 47 const int kBandwidthHistogramBuckets = 100; | 54 const int kBandwidthHistogramBuckets = 100; |
| 48 | 55 |
| 49 // Frame rate is stored in a custom enum histogram, because we we want to record | 56 // Frame rate is stored in a custom enum histogram, because we we want to record |
| 50 // the frequency of each discrete value, rather than using log-scaled buckets. | 57 // the frequency of each discrete value, rather than using log-scaled buckets. |
| 51 // We don't expect video frame rate to be greater than 40fps. Setting a maximum | 58 // We don't expect video frame rate to be greater than 40fps. Setting a maximum |
| 52 // of 100fps will leave some room for future improvements, and account for any | 59 // of 100fps will leave some room for future improvements, and account for any |
| 53 // bursts of packets. Enum histograms expect samples to be less than the | 60 // bursts of packets. Enum histograms expect samples to be less than the |
| 54 // boundary value, so set to 101. | 61 // boundary value, so set to 101. |
| 55 const int kMaxFramesPerSec = 101; | 62 const int kMaxFramesPerSec = 101; |
| 56 | 63 |
| 64 |
| 65 void UpdateUmaEnumHistogramStub(const std::string& histogram_name, |
| 66 int64_t value, |
| 67 int histogram_max) {} |
| 68 |
| 69 void UpdateUmaCustomHistogramStub(const std::string& histogram_name, |
| 70 int64_t value, |
| 71 int histogram_min, |
| 72 int histogram_max, |
| 73 int histogram_buckets) {} |
| 57 } // namespace | 74 } // namespace |
| 58 | 75 |
| 59 namespace remoting { | 76 namespace remoting { |
| 60 namespace protocol { | 77 namespace protocol { |
| 61 | 78 |
| 62 PerformanceTracker::PerformanceTracker() | 79 PerformanceTracker::PerformanceTracker() |
| 63 : video_bandwidth_(base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), | 80 : video_bandwidth_(base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), |
| 64 video_frame_rate_( | 81 video_frame_rate_( |
| 65 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), | 82 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), |
| 66 video_packet_rate_( | 83 video_packet_rate_( |
| 67 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), | 84 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), |
| 68 video_capture_ms_(kLatencySampleSize), | 85 video_capture_ms_(kLatencySampleSize), |
| 69 video_encode_ms_(kLatencySampleSize), | 86 video_encode_ms_(kLatencySampleSize), |
| 70 video_decode_ms_(kLatencySampleSize), | 87 video_decode_ms_(kLatencySampleSize), |
| 71 video_paint_ms_(kLatencySampleSize), | 88 video_paint_ms_(kLatencySampleSize), |
| 72 round_trip_ms_(kLatencySampleSize) {} | 89 round_trip_ms_(kLatencySampleSize) { |
| 90 uma_custom_counts_updater_ = base::Bind(&UpdateUmaCustomHistogramStub); |
| 91 uma_custom_times_updater_ = base::Bind(&UpdateUmaCustomHistogramStub); |
| 92 uma_enum_histogram_updater_ = base::Bind(&UpdateUmaEnumHistogramStub); |
| 93 } |
| 73 | 94 |
| 74 PerformanceTracker::~PerformanceTracker() {} | 95 PerformanceTracker::~PerformanceTracker() {} |
| 75 | 96 |
| 76 void PerformanceTracker::SetUpdateUmaCallbacks( | 97 void PerformanceTracker::SetUpdateUmaCallbacks( |
| 77 UpdateUmaCustomHistogramCallback update_uma_custom_counts_callback, | 98 UpdateUmaCustomHistogramCallback update_uma_custom_counts_callback, |
| 78 UpdateUmaCustomHistogramCallback update_uma_custom_times_callback, | 99 UpdateUmaCustomHistogramCallback update_uma_custom_times_callback, |
| 79 UpdateUmaEnumHistogramCallback update_uma_enum_histogram_callback) { | 100 UpdateUmaEnumHistogramCallback update_uma_enum_histogram_callback) { |
| 101 DCHECK(!update_uma_custom_counts_callback.is_null()); |
| 102 DCHECK(!update_uma_custom_times_callback.is_null()); |
| 103 DCHECK(!update_uma_enum_histogram_callback.is_null()); |
| 104 |
| 80 uma_custom_counts_updater_ = update_uma_custom_counts_callback; | 105 uma_custom_counts_updater_ = update_uma_custom_counts_callback; |
| 81 uma_custom_times_updater_ = update_uma_custom_times_callback; | 106 uma_custom_times_updater_ = update_uma_custom_times_callback; |
| 82 uma_enum_histogram_updater_ = update_uma_enum_histogram_callback; | 107 uma_enum_histogram_updater_ = update_uma_enum_histogram_callback; |
| 83 } | 108 } |
| 84 | 109 |
| 85 void PerformanceTracker::RecordVideoPacketStats(const VideoPacket& packet) { | 110 void PerformanceTracker::RecordVideoPacketStats(const VideoPacket& packet) { |
| 86 if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) { | 111 if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) { |
| 87 upload_uma_stats_timer_.Start( | 112 upload_uma_stats_timer_.Start( |
| 88 FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds), | 113 FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds), |
| 89 base::Bind(&PerformanceTracker::UploadRateStatsToUma, | 114 base::Bind(&PerformanceTracker::UploadRateStatsToUma, |
| 90 base::Unretained(this))); | 115 base::Unretained(this))); |
| 91 } | 116 } |
| 92 | 117 |
| 93 // Record this received packet, even if it is empty. | 118 // Record this received packet, even if it is empty. |
| 94 video_packet_rate_.Record(1); | 119 video_packet_rate_.Record(1); |
| 95 | 120 |
| 96 // Record the RTT, even for empty packets, otherwise input events that | 121 // Record the RTT, even for empty packets, otherwise input events that |
| 97 // do not cause an on-screen change can give very large, bogus RTTs. | 122 // do not cause an on-screen change can give very large, bogus RTTs. |
| 98 if (packet.has_latest_event_timestamp() && | 123 if (packet.has_latest_event_timestamp() && |
| 99 packet.latest_event_timestamp() > latest_input_event_timestamp_) { | 124 packet.latest_event_timestamp() > latest_input_event_timestamp_) { |
| 100 latest_input_event_timestamp_ = packet.latest_event_timestamp(); | 125 latest_input_event_timestamp_ = packet.latest_event_timestamp(); |
| 101 | 126 |
| 102 base::TimeDelta round_trip_latency = | 127 base::TimeDelta round_trip_latency = |
| 103 base::Time::Now() - | 128 base::Time::Now() - |
| 104 base::Time::FromInternalValue(packet.latest_event_timestamp()); | 129 base::Time::FromInternalValue(packet.latest_event_timestamp()); |
| 105 | 130 |
| 106 round_trip_ms_.Record(round_trip_latency.InMilliseconds()); | 131 round_trip_ms_.Record(round_trip_latency.InMilliseconds()); |
| 107 | 132 |
| 108 if (!uma_custom_times_updater_.is_null()) | 133 uma_custom_times_updater_.Run( |
| 109 uma_custom_times_updater_.Run( | 134 kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(), |
| 110 kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(), | 135 kLatencyHistogramMinMs, kLatencyHistogramMaxMs, |
| 111 kLatencyHistogramMinMs, kLatencyHistogramMaxMs, | 136 kLatencyHistogramBuckets); |
| 112 kLatencyHistogramBuckets); | |
| 113 } | 137 } |
| 114 | 138 |
| 115 // If the packet is empty, there are no other stats to update. | 139 // If the packet is empty, there are no other stats to update. |
| 116 if (!packet.data().size()) | 140 if (!packet.data().size()) |
| 117 return; | 141 return; |
| 118 | 142 |
| 119 video_frame_rate_.Record(1); | 143 video_frame_rate_.Record(1); |
| 120 video_bandwidth_.Record(packet.data().size()); | 144 video_bandwidth_.Record(packet.data().size()); |
| 121 | 145 |
| 122 if (packet.has_capture_time_ms()) { | 146 if (packet.has_capture_time_ms()) { |
| 123 video_capture_ms_.Record(packet.capture_time_ms()); | 147 video_capture_ms_.Record(packet.capture_time_ms()); |
| 124 if (!uma_custom_times_updater_.is_null()) | 148 uma_custom_times_updater_.Run( |
| 125 uma_custom_times_updater_.Run( | 149 kVideoCaptureLatencyHistogram, packet.capture_time_ms(), |
| 126 kVideoCaptureLatencyHistogram, packet.capture_time_ms(), | 150 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 127 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, | 151 kVideoActionsHistogramsBuckets); |
| 128 kVideoActionsHistogramsBuckets); | |
| 129 } | 152 } |
| 130 | 153 |
| 131 if (packet.has_encode_time_ms()) { | 154 if (packet.has_encode_time_ms()) { |
| 132 video_encode_ms_.Record(packet.encode_time_ms()); | 155 video_encode_ms_.Record(packet.encode_time_ms()); |
| 133 if (!uma_custom_times_updater_.is_null()) | 156 uma_custom_times_updater_.Run( |
| 134 uma_custom_times_updater_.Run( | 157 kVideoEncodeLatencyHistogram, packet.encode_time_ms(), |
| 135 kVideoEncodeLatencyHistogram, packet.encode_time_ms(), | 158 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 136 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, | 159 kVideoActionsHistogramsBuckets); |
| 137 kVideoActionsHistogramsBuckets); | 160 } |
| 161 |
| 162 if (packet.has_capture_pending_time_ms()) { |
| 163 uma_custom_times_updater_.Run( |
| 164 kCapturePendingLatencyHistogram, packet.capture_pending_time_ms(), |
| 165 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 166 kVideoActionsHistogramsBuckets); |
| 167 } |
| 168 |
| 169 if (packet.has_capture_overhead_time_ms()) { |
| 170 uma_custom_times_updater_.Run( |
| 171 kCaptureOverheadHistogram, packet.capture_overhead_time_ms(), |
| 172 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 173 kVideoActionsHistogramsBuckets); |
| 174 } |
| 175 |
| 176 if (packet.has_encode_pending_time_ms()) { |
| 177 uma_custom_times_updater_.Run( |
| 178 kEncodePendingLatencyHistogram, packet.encode_pending_time_ms(), |
| 179 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 180 kVideoActionsHistogramsBuckets); |
| 181 } |
| 182 |
| 183 if (packet.has_send_pending_time_ms()) { |
| 184 uma_custom_times_updater_.Run( |
| 185 kSendPendingLatencyHistogram, packet.send_pending_time_ms(), |
| 186 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, |
| 187 kVideoActionsHistogramsBuckets); |
| 138 } | 188 } |
| 139 } | 189 } |
| 140 | 190 |
| 141 void PerformanceTracker::RecordDecodeTime(double value) { | 191 void PerformanceTracker::RecordDecodeTime(double value) { |
| 142 video_decode_ms_.Record(value); | 192 video_decode_ms_.Record(value); |
| 143 if (!uma_custom_times_updater_.is_null()) | 193 uma_custom_times_updater_.Run( |
| 144 uma_custom_times_updater_.Run( | 194 kVideoDecodeLatencyHistogram, value, kVideoActionsHistogramsMinMs, |
| 145 kVideoDecodeLatencyHistogram, value, kVideoActionsHistogramsMinMs, | 195 kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets); |
| 146 kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets); | |
| 147 } | 196 } |
| 148 | 197 |
| 149 void PerformanceTracker::RecordPaintTime(double value) { | 198 void PerformanceTracker::RecordPaintTime(double value) { |
| 150 video_paint_ms_.Record(value); | 199 video_paint_ms_.Record(value); |
| 151 if (!uma_custom_times_updater_.is_null()) | 200 uma_custom_times_updater_.Run( |
| 152 uma_custom_times_updater_.Run( | 201 kVideoPaintLatencyHistogram, value, kVideoActionsHistogramsMinMs, |
| 153 kVideoPaintLatencyHistogram, value, kVideoActionsHistogramsMinMs, | 202 kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets); |
| 154 kVideoActionsHistogramsMaxMs, kVideoActionsHistogramsBuckets); | |
| 155 } | 203 } |
| 156 | 204 |
| 157 void PerformanceTracker::UploadRateStatsToUma() { | 205 void PerformanceTracker::UploadRateStatsToUma() { |
| 158 if (!uma_enum_histogram_updater_.is_null()) { | 206 uma_enum_histogram_updater_.Run(kVideoFrameRateHistogram, video_frame_rate(), |
| 159 uma_enum_histogram_updater_.Run(kVideoFrameRateHistogram, | 207 kMaxFramesPerSec); |
| 160 video_frame_rate(), kMaxFramesPerSec); | 208 uma_enum_histogram_updater_.Run(kVideoPacketRateHistogram, |
| 161 uma_enum_histogram_updater_.Run(kVideoPacketRateHistogram, | 209 video_packet_rate(), kMaxFramesPerSec); |
| 162 video_packet_rate(), kMaxFramesPerSec); | 210 uma_custom_counts_updater_.Run( |
| 163 uma_custom_counts_updater_.Run( | 211 kVideoBandwidthHistogram, video_bandwidth(), kBandwidthHistogramMinBps, |
| 164 kVideoBandwidthHistogram, video_bandwidth(), kBandwidthHistogramMinBps, | 212 kBandwidthHistogramMaxBps, kBandwidthHistogramBuckets); |
| 165 kBandwidthHistogramMaxBps, kBandwidthHistogramBuckets); | |
| 166 } | |
| 167 } | 213 } |
| 168 | 214 |
| 169 void PerformanceTracker::OnPauseStateChanged(bool paused) { | 215 void PerformanceTracker::OnPauseStateChanged(bool paused) { |
| 170 is_paused_ = paused; | 216 is_paused_ = paused; |
| 171 if (is_paused_) { | 217 if (is_paused_) { |
| 172 // Pause the UMA timer when the video is paused. It will be unpaused in | 218 // Pause the UMA timer when the video is paused. It will be unpaused in |
| 173 // RecordVideoPacketStats() when a new frame is received. | 219 // RecordVideoPacketStats() when a new frame is received. |
| 174 upload_uma_stats_timer_.Stop(); | 220 upload_uma_stats_timer_.Stop(); |
| 175 } | 221 } |
| 176 } | 222 } |
| 177 | 223 |
| 178 } // namespace protocol | 224 } // namespace protocol |
| 179 } // namespace remoting | 225 } // namespace remoting |
| OLD | NEW |