Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(324)

Side by Side Diff: remoting/protocol/performance_tracker.cc

Issue 2096643003: Rework PerformanceTracker to make it usable with WebRTC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address feedback Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/protocol/frame_stats.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";
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 const int kBandwidthHistogramBuckets = 100; 55 const int kBandwidthHistogramBuckets = 100;
56 56
57 // Frame rate is stored in a custom enum histogram, because we we want to record 57 // Frame rate is stored in a custom enum histogram, because we we want to record
58 // the frequency of each discrete value, rather than using log-scaled buckets. 58 // the frequency of each discrete value, rather than using log-scaled buckets.
59 // We don't expect video frame rate to be greater than 40fps. Setting a maximum 59 // We don't expect video frame rate to be greater than 40fps. Setting a maximum
60 // of 100fps will leave some room for future improvements, and account for any 60 // of 100fps will leave some room for future improvements, and account for any
61 // bursts of packets. Enum histograms expect samples to be less than the 61 // bursts of packets. Enum histograms expect samples to be less than the
62 // boundary value, so set to 101. 62 // boundary value, so set to 101.
63 const int kMaxFramesPerSec = 101; 63 const int kMaxFramesPerSec = 101;
64 64
65
66 void UpdateUmaEnumHistogramStub(const std::string& histogram_name, 65 void UpdateUmaEnumHistogramStub(const std::string& histogram_name,
67 int64_t value, 66 int64_t value,
68 int histogram_max) {} 67 int histogram_max) {}
69 68
70 void UpdateUmaCustomHistogramStub(const std::string& histogram_name, 69 void UpdateUmaCustomHistogramStub(const std::string& histogram_name,
71 int64_t value, 70 int64_t value,
72 int histogram_min, 71 int histogram_min,
73 int histogram_max, 72 int histogram_max,
74 int histogram_buckets) {} 73 int histogram_buckets) {}
75 } // namespace 74 } // namespace
76 75
77 namespace remoting { 76 namespace remoting {
78 namespace protocol { 77 namespace protocol {
79 78
80 PerformanceTracker::FrameTimestamps::FrameTimestamps() {}
81 PerformanceTracker::FrameTimestamps::~FrameTimestamps() {}
82
83 PerformanceTracker::PerformanceTracker() 79 PerformanceTracker::PerformanceTracker()
84 : video_bandwidth_(base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), 80 : video_bandwidth_(base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)),
85 video_frame_rate_( 81 video_frame_rate_(
86 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), 82 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)),
87 video_packet_rate_( 83 video_packet_rate_(
88 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)), 84 base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds)),
89 video_capture_ms_(kLatencySampleSize), 85 video_capture_ms_(kLatencySampleSize),
90 video_encode_ms_(kLatencySampleSize), 86 video_encode_ms_(kLatencySampleSize),
91 video_decode_ms_(kLatencySampleSize), 87 video_decode_ms_(kLatencySampleSize),
92 video_paint_ms_(kLatencySampleSize), 88 video_paint_ms_(kLatencySampleSize),
(...skipping 11 matching lines...) Expand all
104 UpdateUmaEnumHistogramCallback update_uma_enum_histogram_callback) { 100 UpdateUmaEnumHistogramCallback update_uma_enum_histogram_callback) {
105 DCHECK(!update_uma_custom_counts_callback.is_null()); 101 DCHECK(!update_uma_custom_counts_callback.is_null());
106 DCHECK(!update_uma_custom_times_callback.is_null()); 102 DCHECK(!update_uma_custom_times_callback.is_null());
107 DCHECK(!update_uma_enum_histogram_callback.is_null()); 103 DCHECK(!update_uma_enum_histogram_callback.is_null());
108 104
109 uma_custom_counts_updater_ = update_uma_custom_counts_callback; 105 uma_custom_counts_updater_ = update_uma_custom_counts_callback;
110 uma_custom_times_updater_ = update_uma_custom_times_callback; 106 uma_custom_times_updater_ = update_uma_custom_times_callback;
111 uma_enum_histogram_updater_ = update_uma_enum_histogram_callback; 107 uma_enum_histogram_updater_ = update_uma_enum_histogram_callback;
112 } 108 }
113 109
114 void PerformanceTracker::RecordVideoPacketStats(const VideoPacket& packet) { 110 void PerformanceTracker::RecordVideoFrameStats(const FrameStats& stats) {
115 if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) { 111 if (!is_paused_ && !upload_uma_stats_timer_.IsRunning()) {
116 upload_uma_stats_timer_.Start( 112 upload_uma_stats_timer_.Start(
117 FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds), 113 FROM_HERE, base::TimeDelta::FromSeconds(kStatsUpdatePeriodSeconds),
118 base::Bind(&PerformanceTracker::UploadRateStatsToUma, 114 base::Bind(&PerformanceTracker::UploadRateStatsToUma,
119 base::Unretained(this))); 115 base::Unretained(this)));
120 } 116 }
121 117
122 // Record this received packet, even if it is empty. 118 // Record this received packet, even if it is empty.
123 video_packet_rate_.Record(1); 119 video_packet_rate_.Record(1);
124 120
125 FrameTimestamps timestamps; 121 // Use only non-empty frames to estimate frame rate.
126 timestamps.time_received = base::TimeTicks::Now(); 122 if (stats.frame_size)
127 if (packet.has_latest_event_timestamp()) { 123 video_frame_rate_.Record(1);
128 base::TimeTicks timestamp =
129 base::TimeTicks::FromInternalValue(packet.latest_event_timestamp());
130 // Only use latest_event_timestamp field if it has changed from the
131 // previous frame.
132 if (timestamp > latest_event_timestamp_) {
133 timestamps.latest_event_timestamp = timestamp;
134 latest_event_timestamp_ = timestamp;
135 }
136 }
137 124
138 // If the host didn't specify any of the latency fields then set 125 video_bandwidth_.Record(stats.frame_size);
139 // |total_host_latency| to Max, to indicate that the latency is unknown.
140 timestamps.total_host_latency = base::TimeDelta::Max();
141 if (packet.has_capture_time_ms() && packet.has_encode_time_ms() &&
142 packet.has_capture_pending_time_ms() &&
143 packet.has_capture_overhead_time_ms() &&
144 packet.has_encode_pending_time_ms() &&
145 packet.has_send_pending_time_ms()) {
146 timestamps.total_host_latency = base::TimeDelta::FromMilliseconds(
147 packet.capture_time_ms() + packet.encode_time_ms() +
148 packet.capture_pending_time_ms() + packet.capture_overhead_time_ms() +
149 packet.encode_pending_time_ms() + packet.send_pending_time_ms());
150 }
151 126
152 // If the packet is empty, there are no other stats to update. 127 if (stats.capture_delay != base::TimeDelta::Max()) {
153 if (!packet.data().size()) { 128 video_capture_ms_.Record(stats.capture_delay.InMilliseconds());
154 // Record the RTT, even for empty packets, otherwise input events that
155 // do not cause an on-screen change can give very large, bogus RTTs.
156 RecordRoundTripLatency(timestamps);
157 return;
158 }
159
160 DCHECK(packet.has_frame_id());
161 frame_timestamps_[packet.frame_id()] = timestamps;
162
163 video_frame_rate_.Record(1);
164 video_bandwidth_.Record(packet.data().size());
165
166 if (packet.has_capture_time_ms()) {
167 video_capture_ms_.Record(packet.capture_time_ms());
168 uma_custom_times_updater_.Run( 129 uma_custom_times_updater_.Run(
169 kVideoCaptureLatencyHistogram, packet.capture_time_ms(), 130 kVideoCaptureLatencyHistogram, stats.capture_delay.InMilliseconds(),
170 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, 131 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
171 kVideoActionsHistogramsBuckets); 132 kVideoActionsHistogramsBuckets);
172 } 133 }
173 134
174 if (packet.has_encode_time_ms()) { 135 if (stats.encode_delay != base::TimeDelta::Max()) {
175 video_encode_ms_.Record(packet.encode_time_ms()); 136 video_encode_ms_.Record(stats.encode_delay.InMilliseconds());
176 uma_custom_times_updater_.Run( 137 uma_custom_times_updater_.Run(
177 kVideoEncodeLatencyHistogram, packet.encode_time_ms(), 138 kVideoEncodeLatencyHistogram, stats.encode_delay.InMilliseconds(),
178 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, 139 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
179 kVideoActionsHistogramsBuckets); 140 kVideoActionsHistogramsBuckets);
180 } 141 }
181 142
182 if (packet.has_capture_pending_time_ms()) { 143 if (stats.capture_pending_delay != base::TimeDelta::Max()) {
144 uma_custom_times_updater_.Run(kCapturePendingLatencyHistogram,
145 stats.capture_pending_delay.InMilliseconds(),
146 kVideoActionsHistogramsMinMs,
147 kVideoActionsHistogramsMaxMs,
148 kVideoActionsHistogramsBuckets);
149 }
150
151 if (stats.capture_overhead_delay != base::TimeDelta::Max()) {
152 uma_custom_times_updater_.Run(kCaptureOverheadHistogram,
153 stats.capture_overhead_delay.InMilliseconds(),
154 kVideoActionsHistogramsMinMs,
155 kVideoActionsHistogramsMaxMs,
156 kVideoActionsHistogramsBuckets);
157 }
158
159 if (stats.encode_pending_delay != base::TimeDelta::Max()) {
160 uma_custom_times_updater_.Run(kEncodePendingLatencyHistogram,
161 stats.encode_pending_delay.InMilliseconds(),
162 kVideoActionsHistogramsMinMs,
163 kVideoActionsHistogramsMaxMs,
164 kVideoActionsHistogramsBuckets);
165 }
166
167 if (stats.send_pending_delay != base::TimeDelta::Max()) {
183 uma_custom_times_updater_.Run( 168 uma_custom_times_updater_.Run(
184 kCapturePendingLatencyHistogram, packet.capture_pending_time_ms(), 169 kSendPendingLatencyHistogram, stats.send_pending_delay.InMilliseconds(),
185 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, 170 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
186 kVideoActionsHistogramsBuckets); 171 kVideoActionsHistogramsBuckets);
187 } 172 }
188 173
189 if (packet.has_capture_overhead_time_ms()) { 174 DCHECK(!stats.time_received.is_null());
175
176 // Report decode and render delay only for non-empty frames.
177 if (stats.frame_size > 0) {
178 DCHECK(!stats.time_rendered.is_null());
179 DCHECK(!stats.time_decoded.is_null());
180 base::TimeDelta decode_delay = stats.time_decoded - stats.time_received;
181 video_decode_ms_.Record(decode_delay.InMilliseconds());
190 uma_custom_times_updater_.Run( 182 uma_custom_times_updater_.Run(
191 kCaptureOverheadHistogram, packet.capture_overhead_time_ms(), 183 kVideoDecodeLatencyHistogram, decode_delay.InMilliseconds(),
184 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
185 kVideoActionsHistogramsBuckets);
186
187 base::TimeDelta render_delay = stats.time_rendered - stats.time_decoded;
188 video_paint_ms_.Record(render_delay.InMilliseconds());
189 uma_custom_times_updater_.Run(
190 kVideoPaintLatencyHistogram, render_delay.InMilliseconds(),
192 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, 191 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
193 kVideoActionsHistogramsBuckets); 192 kVideoActionsHistogramsBuckets);
194 } 193 }
195 194
196 if (packet.has_encode_pending_time_ms()) { 195 // |latest_event_timestamp| is set only for the first frame after an input
197 uma_custom_times_updater_.Run( 196 // event.
198 kEncodePendingLatencyHistogram, packet.encode_pending_time_ms(), 197 if (stats.latest_event_timestamp.is_null())
199 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
200 kVideoActionsHistogramsBuckets);
201 }
202
203 if (packet.has_send_pending_time_ms()) {
204 uma_custom_times_updater_.Run(
205 kSendPendingLatencyHistogram, packet.send_pending_time_ms(),
206 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
207 kVideoActionsHistogramsBuckets);
208 }
209 }
210
211 void PerformanceTracker::OnFrameDecoded(int32_t frame_id) {
212 FramesTimestampsMap::iterator it = frame_timestamps_.find(frame_id);
213 DCHECK(it != frame_timestamps_.end());
214 it->second.time_decoded = base::TimeTicks::Now();
215 base::TimeDelta delay = it->second.time_decoded - it->second.time_received;
216
217 video_decode_ms_.Record(delay.InMilliseconds());
218 uma_custom_times_updater_.Run(
219 kVideoDecodeLatencyHistogram, delay.InMilliseconds(),
220 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
221 kVideoActionsHistogramsBuckets);
222 }
223
224 void PerformanceTracker::OnFramePainted(int32_t frame_id) {
225 base::TimeTicks now = base::TimeTicks::Now();
226
227 while (!frame_timestamps_.empty() &&
228 frame_timestamps_.begin()->first <= frame_id) {
229 FrameTimestamps& timestamps = frame_timestamps_.begin()->second;
230
231 // time_decoded may be null if OnFrameDecoded() was never called, e.g. if
232 // the frame was dropped or decoding has failed.
233 if (!timestamps.time_decoded.is_null()) {
234 base::TimeDelta delay = now - timestamps.time_decoded;
235 video_paint_ms_.Record(delay.InMilliseconds());
236 uma_custom_times_updater_.Run(
237 kVideoPaintLatencyHistogram, delay.InMilliseconds(),
238 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
239 kVideoActionsHistogramsBuckets);
240 }
241
242 RecordRoundTripLatency(timestamps);
243 frame_timestamps_.erase(frame_timestamps_.begin());
244 }
245 }
246
247 void PerformanceTracker::RecordRoundTripLatency(
248 const FrameTimestamps& timestamps) {
249 if (timestamps.latest_event_timestamp.is_null())
250 return; 198 return;
251 199
252 base::TimeTicks now = base::TimeTicks::Now(); 200 // For empty frames use time_received as time_rendered.
201 base::TimeTicks time_rendered =
202 (stats.frame_size > 0) ? stats.time_rendered : stats.time_received;
253 base::TimeDelta round_trip_latency = 203 base::TimeDelta round_trip_latency =
254 now - timestamps.latest_event_timestamp; 204 time_rendered - stats.latest_event_timestamp;
255
256 round_trip_ms_.Record(round_trip_latency.InMilliseconds()); 205 round_trip_ms_.Record(round_trip_latency.InMilliseconds());
257 uma_custom_times_updater_.Run( 206 uma_custom_times_updater_.Run(
258 kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(), 207 kRoundTripLatencyHistogram, round_trip_latency.InMilliseconds(),
259 kLatencyHistogramMinMs, kLatencyHistogramMaxMs, kLatencyHistogramBuckets); 208 kLatencyHistogramMinMs, kLatencyHistogramMaxMs, kLatencyHistogramBuckets);
260 209
261 if (!timestamps.total_host_latency.is_max()) { 210 // Report estimated network latency.
211 if (stats.capture_delay != base::TimeDelta::Max() &&
212 stats.encode_delay != base::TimeDelta::Max() &&
213 stats.capture_pending_delay != base::TimeDelta::Max() &&
214 stats.capture_overhead_delay != base::TimeDelta::Max() &&
215 stats.encode_pending_delay != base::TimeDelta::Max() &&
216 stats.send_pending_delay != base::TimeDelta::Max()) {
262 // Calculate total processing time on host and client. 217 // Calculate total processing time on host and client.
263 base::TimeDelta total_processing_latency = 218 base::TimeDelta total_processing_latency =
264 timestamps.total_host_latency + (now - timestamps.time_received); 219 stats.capture_delay + stats.encode_delay + stats.capture_pending_delay +
220 stats.capture_overhead_delay + stats.encode_pending_delay +
221 stats.send_pending_delay + (time_rendered - stats.time_received);
265 base::TimeDelta network_latency = 222 base::TimeDelta network_latency =
266 round_trip_latency - total_processing_latency; 223 round_trip_latency - total_processing_latency;
267 uma_custom_times_updater_.Run( 224 uma_custom_times_updater_.Run(
268 kNetworkLatencyHistogram, network_latency.InMilliseconds(), 225 kNetworkLatencyHistogram, network_latency.InMilliseconds(),
269 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs, 226 kVideoActionsHistogramsMinMs, kVideoActionsHistogramsMaxMs,
270 kVideoActionsHistogramsBuckets); 227 kVideoActionsHistogramsBuckets);
271 } 228 }
272 } 229 }
273 230
274 void PerformanceTracker::UploadRateStatsToUma() { 231 void PerformanceTracker::UploadRateStatsToUma() {
275 uma_enum_histogram_updater_.Run(kVideoFrameRateHistogram, video_frame_rate(), 232 uma_enum_histogram_updater_.Run(kVideoFrameRateHistogram, video_frame_rate(),
276 kMaxFramesPerSec); 233 kMaxFramesPerSec);
277 uma_enum_histogram_updater_.Run(kVideoPacketRateHistogram, 234 uma_enum_histogram_updater_.Run(kVideoPacketRateHistogram,
278 video_packet_rate(), kMaxFramesPerSec); 235 video_packet_rate(), kMaxFramesPerSec);
279 uma_custom_counts_updater_.Run( 236 uma_custom_counts_updater_.Run(
280 kVideoBandwidthHistogram, video_bandwidth(), kBandwidthHistogramMinBps, 237 kVideoBandwidthHistogram, video_bandwidth(), kBandwidthHistogramMinBps,
281 kBandwidthHistogramMaxBps, kBandwidthHistogramBuckets); 238 kBandwidthHistogramMaxBps, kBandwidthHistogramBuckets);
282 } 239 }
283 240
284 void PerformanceTracker::OnPauseStateChanged(bool paused) { 241 void PerformanceTracker::OnPauseStateChanged(bool paused) {
285 is_paused_ = paused; 242 is_paused_ = paused;
286 if (is_paused_) { 243 if (is_paused_) {
287 // Pause the UMA timer when the video is paused. It will be unpaused in 244 // Pause the UMA timer when the video is paused. It will be unpaused in
288 // RecordVideoPacketStats() when a new frame is received. 245 // RecordVideoFrameStats() when a new frame is received.
289 upload_uma_stats_timer_.Stop(); 246 upload_uma_stats_timer_.Stop();
290 } 247 }
291 } 248 }
292 249
293 } // namespace protocol 250 } // namespace protocol
294 } // namespace remoting 251 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/protocol/performance_tracker.h ('k') | remoting/protocol/webrtc_video_renderer_adapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698