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

Side by Side Diff: media/cast/logging/stats_event_subscriber_unittest.cc

Issue 236123003: Cast: Provide more meaningful stats. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed miu's comments Created 6 years, 8 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 2014 The Chromium Authors. All rights reserved. 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 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 "base/memory/ref_counted.h" 5 #include "base/memory/ref_counted.h"
6 #include "base/memory/scoped_ptr.h" 6 #include "base/memory/scoped_ptr.h"
7 #include "base/rand_util.h"
7 #include "base/test/simple_test_tick_clock.h" 8 #include "base/test/simple_test_tick_clock.h"
8 #include "base/time/tick_clock.h" 9 #include "base/time/tick_clock.h"
9 #include "media/cast/cast_environment.h" 10 #include "media/cast/cast_environment.h"
10 #include "media/cast/logging/logging_defines.h" 11 #include "media/cast/logging/logging_defines.h"
11 #include "media/cast/logging/stats_event_subscriber.h" 12 #include "media/cast/logging/stats_event_subscriber.h"
13 #include "media/cast/test/fake_receiver_time_offset_estimator.h"
12 #include "media/cast/test/fake_single_thread_task_runner.h" 14 #include "media/cast/test/fake_single_thread_task_runner.h"
13 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
14 16
17 namespace {
18 const int kReceiverOffsetSecs = 100;
19 }
20
15 namespace media { 21 namespace media {
16 namespace cast { 22 namespace cast {
17 23
18 class StatsEventSubscriberTest : public ::testing::Test { 24 class StatsEventSubscriberTest : public ::testing::Test {
19 protected: 25 protected:
20 StatsEventSubscriberTest() 26 StatsEventSubscriberTest()
21 : testing_clock_(new base::SimpleTestTickClock()), 27 : sender_clock_(new base::SimpleTestTickClock()),
22 task_runner_(new test::FakeSingleThreadTaskRunner(testing_clock_)), 28 task_runner_(new test::FakeSingleThreadTaskRunner(sender_clock_)),
23 cast_environment_(new CastEnvironment( 29 cast_environment_(new CastEnvironment(
24 scoped_ptr<base::TickClock>(testing_clock_).Pass(), 30 scoped_ptr<base::TickClock>(sender_clock_).Pass(),
25 task_runner_, 31 task_runner_,
26 task_runner_, 32 task_runner_,
27 task_runner_)) {} 33 task_runner_)),
34 fake_offset_estimator_(
35 base::TimeDelta::FromSeconds(kReceiverOffsetSecs)) {
36 receiver_clock_.Advance(base::TimeDelta::FromSeconds(kReceiverOffsetSecs));
37 cast_environment_->Logging()->AddRawEventSubscriber(
38 &fake_offset_estimator_);
39 }
28 40
29 virtual ~StatsEventSubscriberTest() { 41 virtual ~StatsEventSubscriberTest() {
30 if (subscriber_.get()) 42 if (subscriber_.get())
31 cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get()); 43 cast_environment_->Logging()->RemoveRawEventSubscriber(subscriber_.get());
44 cast_environment_->Logging()->RemoveRawEventSubscriber(
45 &fake_offset_estimator_);
46 }
47
48 void AdvanceClocks(base::TimeDelta delta) {
49 sender_clock_->Advance(delta);
50 receiver_clock_.Advance(delta);
32 } 51 }
33 52
34 void Init(EventMediaType event_media_type) { 53 void Init(EventMediaType event_media_type) {
35 DCHECK(!subscriber_.get()); 54 DCHECK(!subscriber_.get());
36 subscriber_.reset(new StatsEventSubscriber(event_media_type)); 55 subscriber_.reset(new StatsEventSubscriber(
56 event_media_type, cast_environment_->Clock(), &fake_offset_estimator_));
37 cast_environment_->Logging()->AddRawEventSubscriber(subscriber_.get()); 57 cast_environment_->Logging()->AddRawEventSubscriber(subscriber_.get());
38 } 58 }
39 59
40 base::SimpleTestTickClock* testing_clock_; // Owned by CastEnvironment. 60 base::SimpleTestTickClock* sender_clock_; // Owned by CastEnvironment.
61 base::SimpleTestTickClock receiver_clock_;
41 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_; 62 scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
42 scoped_refptr<CastEnvironment> cast_environment_; 63 scoped_refptr<CastEnvironment> cast_environment_;
64 test::FakeReceiverTimeOffsetEstimator fake_offset_estimator_;
43 scoped_ptr<StatsEventSubscriber> subscriber_; 65 scoped_ptr<StatsEventSubscriber> subscriber_;
44 }; 66 };
45 67
46 TEST_F(StatsEventSubscriberTest, FrameStats) { 68 TEST_F(StatsEventSubscriberTest, Capture) {
47 Init(VIDEO_EVENT); 69 Init(VIDEO_EVENT);
48 uint32 rtp_timestamp = 0; 70
49 uint32 frame_id = 0; 71 uint32 rtp_timestamp = 0;
50 int num_frames = 10; 72 uint32 frame_id = 0;
51 int frame_size = 123; 73 int num_frames = 10;
52 int delay_base_ms = 10; 74 base::TimeTicks start_time = sender_clock_->NowTicks();
53 base::TimeTicks now; 75 for (int i = 0; i < num_frames; i++) {
54 for (int i = 0; i < num_frames; i++) { 76 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
55 now = testing_clock_->NowTicks(); 77 kVideoFrameCaptured,
56 cast_environment_->Logging()->InsertFrameEvent( 78 rtp_timestamp,
57 now, kVideoFrameReceived, rtp_timestamp, frame_id); 79 frame_id);
58 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); 80
59 81 AdvanceClocks(base::TimeDelta::FromMicroseconds(34567));
82 rtp_timestamp += 90;
83 frame_id++;
84 }
85
86 base::TimeTicks end_time = sender_clock_->NowTicks();
87
88 StatsEventSubscriber::StatsMap stats_map;
89 subscriber_->GetStatsInternal(&stats_map);
90
91 StatsEventSubscriber::StatsMap::iterator it =
92 stats_map.find(StatsEventSubscriber::CAPTURE_FPS);
93 ASSERT_NE(it, stats_map.end());
94
95 base::TimeDelta duration = end_time - start_time;
96 EXPECT_DOUBLE_EQ(
97 it->second,
98 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
99 }
100
101 TEST_F(StatsEventSubscriberTest, Encode) {
102 Init(VIDEO_EVENT);
103
104 uint32 rtp_timestamp = 0;
105 uint32 frame_id = 0;
106 int num_frames = 10;
107 base::TimeTicks start_time = sender_clock_->NowTicks();
108 int total_size = 0;
109 for (int i = 0; i < num_frames; i++) {
110 int size = 1000 + base::RandInt(-100, 100);
111 total_size += size;
60 cast_environment_->Logging()->InsertEncodedFrameEvent( 112 cast_environment_->Logging()->InsertEncodedFrameEvent(
61 now, kVideoFrameEncoded, rtp_timestamp, i, frame_size, true); 113 sender_clock_->NowTicks(),
62 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); 114 kVideoFrameEncoded,
63 115 rtp_timestamp,
116 frame_id,
117 size,
118 true);
119
120 AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
121 rtp_timestamp += 90;
122 frame_id++;
123 }
124
125 base::TimeTicks end_time = sender_clock_->NowTicks();
126
127 StatsEventSubscriber::StatsMap stats_map;
128 subscriber_->GetStatsInternal(&stats_map);
129
130 StatsEventSubscriber::StatsMap::iterator it =
131 stats_map.find(StatsEventSubscriber::ENCODE_FPS);
132 ASSERT_NE(it, stats_map.end());
133
134 base::TimeDelta duration = end_time - start_time;
135 EXPECT_DOUBLE_EQ(
136 it->second,
137 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
138
139 it = stats_map.find(StatsEventSubscriber::ENCODE_KBPS);
140 ASSERT_NE(it, stats_map.end());
141
142 EXPECT_DOUBLE_EQ(it->second,
143 static_cast<double>(total_size) / duration.InMillisecondsF() * 8);
144 }
145
146 TEST_F(StatsEventSubscriberTest, Decode) {
147 Init(VIDEO_EVENT);
148
149 uint32 rtp_timestamp = 0;
150 uint32 frame_id = 0;
151 int num_frames = 10;
152 base::TimeTicks start_time = sender_clock_->NowTicks();
153 for (int i = 0; i < num_frames; i++) {
154 cast_environment_->Logging()->InsertFrameEvent(receiver_clock_.NowTicks(),
155 kVideoFrameDecoded,
156 rtp_timestamp,
157 frame_id);
158
159 AdvanceClocks(base::TimeDelta::FromMicroseconds(36789));
160 rtp_timestamp += 90;
161 frame_id++;
162 }
163
164 base::TimeTicks end_time = sender_clock_->NowTicks();
165
166 StatsEventSubscriber::StatsMap stats_map;
167 subscriber_->GetStatsInternal(&stats_map);
168
169 StatsEventSubscriber::StatsMap::iterator it =
170 stats_map.find(StatsEventSubscriber::DECODE_FPS);
171 ASSERT_NE(it, stats_map.end());
172
173 base::TimeDelta duration = end_time - start_time;
174 EXPECT_DOUBLE_EQ(
175 it->second,
176 static_cast<double>(num_frames) / duration.InMillisecondsF() * 1000);
177 }
178
179 TEST_F(StatsEventSubscriberTest, PlayoutDelay) {
180 Init(VIDEO_EVENT);
181
182 uint32 rtp_timestamp = 0;
183 uint32 frame_id = 0;
184 int num_frames = 10;
185 int total_delay_ms = 0;
186 for (int i = 0; i < num_frames; i++) {
187 int delay_ms = base::RandInt(-50, 50);
188 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms);
189 total_delay_ms += delay_ms;
64 cast_environment_->Logging()->InsertFrameEventWithDelay( 190 cast_environment_->Logging()->InsertFrameEventWithDelay(
65 now, 191 receiver_clock_.NowTicks(),
66 kVideoRenderDelay, 192 kVideoRenderDelay,
67 rtp_timestamp, 193 rtp_timestamp,
68 i, 194 frame_id,
69 base::TimeDelta::FromMilliseconds(i * delay_base_ms)); 195 delay);
70 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); 196
71 197 AdvanceClocks(base::TimeDelta::FromMicroseconds(37890));
72 rtp_timestamp += 90; 198 rtp_timestamp += 90;
73 } 199 frame_id++;
74 200 }
75 // Verify stats. 201
76 FrameStatsMap frame_stats; 202 StatsEventSubscriber::StatsMap stats_map;
77 subscriber_->GetFrameStats(&frame_stats); 203 subscriber_->GetStatsInternal(&stats_map);
78 204
79 // Size of stats equals the number of events. 205 StatsEventSubscriber::StatsMap::iterator it =
80 EXPECT_EQ(3u, frame_stats.size()); 206 stats_map.find(StatsEventSubscriber::AVG_PLAYOUT_DELAY_MS);
81 FrameStatsMap::const_iterator it = frame_stats.find(kVideoFrameReceived); 207 ASSERT_NE(it, stats_map.end());
82 ASSERT_TRUE(it != frame_stats.end()); 208
83 EXPECT_EQ(num_frames, it->second.event_counter); 209 EXPECT_DOUBLE_EQ(
84 210 it->second, static_cast<double>(total_delay_ms) / num_frames);
85 it = frame_stats.find(kVideoFrameEncoded); 211 }
86 ASSERT_TRUE(it != frame_stats.end()); 212
87 213 TEST_F(StatsEventSubscriberTest, E2ELatency) {
88 EXPECT_EQ(num_frames * frame_size, static_cast<int>(it->second.sum_size)); 214 Init(VIDEO_EVENT);
89 215
90 it = frame_stats.find(kVideoRenderDelay); 216 uint32 rtp_timestamp = 0;
91 ASSERT_TRUE(it != frame_stats.end()); 217 uint32 frame_id = 0;
92 218 int num_frames = 10;
93 EXPECT_EQ(0, it->second.min_delay.InMilliseconds()); 219 base::TimeDelta total_latency;
94 EXPECT_EQ((num_frames - 1) * delay_base_ms, 220 for (int i = 0; i < num_frames; i++) {
95 it->second.max_delay.InMilliseconds()); 221 cast_environment_->Logging()->InsertFrameEvent(sender_clock_->NowTicks(),
96 EXPECT_EQ((num_frames - 1) * num_frames / 2 * delay_base_ms, 222 kVideoFrameCaptured,
97 it->second.sum_delay.InMilliseconds()); 223 rtp_timestamp,
98 } 224 frame_id);
99 225
100 TEST_F(StatsEventSubscriberTest, PacketStats) { 226 int latency_micros = 100000 + base::RandInt(-5000, 50000);
101 Init(AUDIO_EVENT); 227 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
102 uint32 rtp_timestamp = 0; 228 AdvanceClocks(latency);
103 uint32 frame_id = 0; 229
230 int delay_micros = base::RandInt(-50000, 50000);
231 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_micros);
232 total_latency += latency + delay;
233
234 cast_environment_->Logging()->InsertFrameEventWithDelay(
235 receiver_clock_.NowTicks(),
236 kVideoRenderDelay,
237 rtp_timestamp,
238 frame_id,
239 delay);
240
241 rtp_timestamp += 90;
242 frame_id++;
243 }
244
245 StatsEventSubscriber::StatsMap stats_map;
246 subscriber_->GetStatsInternal(&stats_map);
247
248 StatsEventSubscriber::StatsMap::iterator it =
249 stats_map.find(StatsEventSubscriber::AVG_E2E_LATENCY_MS);
250 ASSERT_NE(it, stats_map.end());
251
252 EXPECT_DOUBLE_EQ(
253 it->second, total_latency.InMillisecondsF() / num_frames);
254 }
255
256 TEST_F(StatsEventSubscriberTest, Packets) {
257 Init(VIDEO_EVENT);
258
259 uint32 rtp_timestamp = 0;
104 int num_packets = 10; 260 int num_packets = 10;
105 int packet_size = 123; 261 int num_latency_recorded_packets = 0;
106 base::TimeTicks first_event_time = testing_clock_->NowTicks(); 262 base::TimeTicks start_time = sender_clock_->NowTicks();
107 base::TimeTicks now; 263 int total_size = 0;
264 int retransmit_total_size = 0;
265 base::TimeDelta total_latency;
266 int num_packets_sent = 0;
267 int num_packets_retransmitted = 0;
268 // Every 2nd packet will be retransmitted once.
269 // Every 4th packet will be retransmitted twice.
270 // Every 8th packet will be retransmitted 3 times.
108 for (int i = 0; i < num_packets; i++) { 271 for (int i = 0; i < num_packets; i++) {
109 now = testing_clock_->NowTicks(); 272 int size = 1000 + base::RandInt(-100, 100);
110 cast_environment_->Logging()->InsertPacketEvent(now, 273 total_size += size;
111 kAudioPacketSentToPacer, 274
275 cast_environment_->Logging()->InsertPacketEvent(sender_clock_->NowTicks(),
276 kVideoPacketSentToNetwork,
112 rtp_timestamp, 277 rtp_timestamp,
113 frame_id,
114 0, 278 0,
115 10, 279 i,
116 packet_size); 280 num_packets - 1,
117 testing_clock_->Advance(base::TimeDelta::FromMilliseconds(30)); 281 size);
118 } 282 num_packets_sent++;
119 283
120 PacketStatsMap stats_map; 284 int latency_micros = 20000 + base::RandInt(-10000, 10000);
121 subscriber_->GetPacketStats(&stats_map); 285 base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
122 286 // Latency is only recorded for packets that aren't retransmitted.
123 // Size of stats equals the number of event types. 287 if (i % 2 != 0) {
124 EXPECT_EQ(1u, stats_map.size()); 288 total_latency += latency;
125 PacketStatsMap::const_iterator it = stats_map.find(kAudioPacketSentToPacer); 289 num_latency_recorded_packets++;
126 ASSERT_NE(stats_map.end(), it); 290 }
127 291
128 EXPECT_EQ(first_event_time, it->second.first_event_time); 292 AdvanceClocks(latency);
129 EXPECT_EQ(now, it->second.last_event_time); 293
130 EXPECT_EQ(num_packets, it->second.event_counter); 294 base::TimeTicks received_time = receiver_clock_.NowTicks();
131 EXPECT_EQ(num_packets * packet_size, static_cast<int>(it->second.sum_size)); 295
132 } 296 // Retransmission 1.
133 297 AdvanceClocks(base::TimeDelta::FromMicroseconds(12345));
134 TEST_F(StatsEventSubscriberTest, GenericStats) { 298 if (i % 2 == 0) {
135 Init(OTHER_EVENT); 299 cast_environment_->Logging()->InsertPacketEvent(
136 int num_generic_events = 10; 300 receiver_clock_.NowTicks(),
137 int value = 123; 301 kVideoPacketRetransmitted,
138 for (int i = 0; i < num_generic_events; i++) { 302 rtp_timestamp,
139 cast_environment_->Logging()->InsertGenericEvent( 303 0,
140 testing_clock_->NowTicks(), kRttMs, value); 304 i,
141 } 305 num_packets - 1,
142 306 size);
143 GenericStatsMap stats_map; 307 retransmit_total_size += size;
144 subscriber_->GetGenericStats(&stats_map); 308 num_packets_sent++;
145 309 num_packets_retransmitted++;
146 EXPECT_EQ(1u, stats_map.size()); 310 }
147 GenericStatsMap::const_iterator it = stats_map.find(kRttMs); 311
148 ASSERT_NE(stats_map.end(), it); 312 // Retransmission 2.
149 313 AdvanceClocks(base::TimeDelta::FromMicroseconds(13456));
150 EXPECT_EQ(num_generic_events, it->second.event_counter); 314 if (i % 4 == 0) {
151 EXPECT_EQ(num_generic_events * value, it->second.sum); 315 cast_environment_->Logging()->InsertPacketEvent(
152 EXPECT_EQ(static_cast<uint64>(num_generic_events * value * value), 316 receiver_clock_.NowTicks(),
153 it->second.sum_squared); 317 kVideoPacketRetransmitted,
154 EXPECT_LE(value, it->second.min); 318 rtp_timestamp,
155 EXPECT_GE(value, it->second.max); 319 0,
156 } 320 i,
157 321 num_packets - 1,
158 TEST_F(StatsEventSubscriberTest, Reset) { 322 size);
159 Init(VIDEO_EVENT); 323 retransmit_total_size += size;
160 cast_environment_->Logging()->InsertFrameEvent( 324 num_packets_sent++;
161 testing_clock_->NowTicks(), kVideoFrameReceived, 0, 0); 325 num_packets_retransmitted++;
162 326 }
163 FrameStatsMap frame_stats; 327
164 subscriber_->GetFrameStats(&frame_stats); 328 // Retransmission 3.
165 EXPECT_EQ(1u, frame_stats.size()); 329 AdvanceClocks(base::TimeDelta::FromMicroseconds(14567));
166 330 if (i % 8 == 0) {
167 subscriber_->Reset(); 331 cast_environment_->Logging()->InsertPacketEvent(
168 subscriber_->GetFrameStats(&frame_stats); 332 receiver_clock_.NowTicks(),
169 EXPECT_TRUE(frame_stats.empty()); 333 kVideoPacketRetransmitted,
334 rtp_timestamp,
335 0,
336 i,
337 num_packets - 1,
338 size);
339 retransmit_total_size += size;
340 num_packets_sent++;
341 num_packets_retransmitted++;
342 }
343
344 cast_environment_->Logging()->InsertPacketEvent(received_time,
345 kVideoPacketReceived,
346 rtp_timestamp,
347 0,
348 i,
349 num_packets - 1,
350 size);
351 }
352
353 base::TimeTicks end_time = sender_clock_->NowTicks();
354 base::TimeDelta duration = end_time - start_time;
355
356 StatsEventSubscriber::StatsMap stats_map;
357 subscriber_->GetStatsInternal(&stats_map);
358
359 // Measure AVG_NETWORK_LATENCY_MS, TRANSMISSION_KBPS, RETRANSMISSION_KBPS,
360 // and PACKET_LOSS_FRACTION.
361 StatsEventSubscriber::StatsMap::iterator it =
362 stats_map.find(StatsEventSubscriber::AVG_NETWORK_LATENCY_MS);
363 ASSERT_NE(it, stats_map.end());
364
365 EXPECT_DOUBLE_EQ(
366 it->second,
367 total_latency.InMillisecondsF() / num_latency_recorded_packets);
368
369 it = stats_map.find(StatsEventSubscriber::TRANSMISSION_KBPS);
370 ASSERT_NE(it, stats_map.end());
371
372 EXPECT_DOUBLE_EQ(it->second,
373 static_cast<double>(total_size) / duration.InMillisecondsF() * 8);
374
375 it = stats_map.find(StatsEventSubscriber::RETRANSMISSION_KBPS);
376 ASSERT_NE(it, stats_map.end());
377
378 EXPECT_DOUBLE_EQ(it->second,
379 static_cast<double>(retransmit_total_size) /
380 duration.InMillisecondsF() * 8);
381
382 it = stats_map.find(StatsEventSubscriber::PACKET_LOSS_FRACTION);
383 ASSERT_NE(it, stats_map.end());
384
385 EXPECT_DOUBLE_EQ(
386 it->second,
387 static_cast<double>(num_packets_retransmitted) / num_packets_sent);
170 } 388 }
171 389
172 } // namespace cast 390 } // namespace cast
173 } // namespace media 391 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698