1 // Copyright (c) 2013 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 "content/browser/renderer_host/media/video_capture_oracle.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/time/time.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 11 namespace content { 12 namespace { 13 14 void SteadyStateSampleAndAdvance(base::TimeDelta vsync, 15 SmoothEventSampler* sampler, base::Time* t) { 16 ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t)); 17 ASSERT_TRUE(sampler->HasUnrecordedEvent()); 18 sampler->RecordSample(); 19 ASSERT_FALSE(sampler->HasUnrecordedEvent()); 20 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); 21 *t += vsync; 22 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); 23 } 24 25 void SteadyStateNoSampleAndAdvance(base::TimeDelta vsync, 26 SmoothEventSampler* sampler, base::Time* t) { 27 ASSERT_FALSE(sampler->AddEventAndConsiderSampling(*t)); 28 ASSERT_TRUE(sampler->HasUnrecordedEvent()); 29 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); 30 *t += vsync; 31 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)); 32 } 33 34 void TestRedundantCaptureStrategy(base::TimeDelta capture_period, 35 int redundant_capture_goal, 36 SmoothEventSampler* sampler, base::Time* t) { 37 // Before any events have been considered, we're overdue for sampling. 38 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)); 39 40 // Consider the first event. We want to sample that. 41 ASSERT_FALSE(sampler->HasUnrecordedEvent()); 42 ASSERT_TRUE(sampler->AddEventAndConsiderSampling(*t)); 43 ASSERT_TRUE(sampler->HasUnrecordedEvent()); 44 sampler->RecordSample(); 45 ASSERT_FALSE(sampler->HasUnrecordedEvent()); 46 47 // After more than one capture period has passed without considering an event, 48 // we should repeatedly be overdue for sampling. However, once the redundant 49 // capture goal is achieved, we should no longer be overdue for sampling. 50 *t += capture_period * 4; 51 for (int i = 0; i < redundant_capture_goal; i++) { 52 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 53 ASSERT_FALSE(sampler->HasUnrecordedEvent()); 54 ASSERT_TRUE(sampler->IsOverdueForSamplingAt(*t)) 55 << "Should sample until redundant capture goal is hit"; 56 sampler->RecordSample(); 57 *t += capture_period; // Timer fires once every capture period. 58 } 59 ASSERT_FALSE(sampler->IsOverdueForSamplingAt(*t)) 60 << "Should not be overdue once redundant capture goal achieved."; 61 } 62 63 // 60Hz sampled at 30Hz should produce 30Hz. In addition, this test contains 64 // much more comprehensive before/after/edge-case scenarios than the others. 65 TEST(SmoothEventSamplerTest, Sample60HertzAt30Hertz) { 66 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 67 const int redundant_capture_goal = 200; 68 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 60; 69 70 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal); 71 base::Time t; 72 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 73 74 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, 75 &sampler, &t); 76 77 // Steady state, we should capture every other vsync, indefinitely. 78 for (int i = 0; i < 100; i++) { 79 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 80 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 81 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 82 } 83 84 // Now pretend we're limited by backpressure in the pipeline. In this scenario 85 // case we are adding events but not sampling them. 86 for (int i = 0; i < 20; i++) { 87 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 88 ASSERT_EQ(i >= 7, sampler.IsOverdueForSamplingAt(t)); 89 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 90 ASSERT_TRUE(sampler.HasUnrecordedEvent()); 91 t += vsync; 92 } 93 94 // Now suppose we can sample again. We should be back in the steady state, 95 // but at a different phase. 96 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); 97 for (int i = 0; i < 100; i++) { 98 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 99 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 100 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 101 } 102 } 103 104 // 50Hz sampled at 30Hz should produce a sequence where some frames are skipped. 105 TEST(SmoothEventSamplerTest, Sample50HertzAt30Hertz) { 106 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 107 const int redundant_capture_goal = 2; 108 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 50; 109 110 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal); 111 base::Time t; 112 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 113 114 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, 115 &sampler, &t); 116 117 // Steady state, we should capture 1st, 2nd and 4th frames out of every five 118 // frames, indefinitely. 119 for (int i = 0; i < 100; i++) { 120 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 121 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 122 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 123 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 124 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 125 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 126 } 127 128 // Now pretend we're limited by backpressure in the pipeline. In this scenario 129 // case we are adding events but not sampling them. 130 for (int i = 0; i < 12; i++) { 131 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 132 ASSERT_EQ(i >= 5, sampler.IsOverdueForSamplingAt(t)); 133 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 134 t += vsync; 135 } 136 137 // Now suppose we can sample again. We should be back in the steady state 138 // again. 139 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); 140 for (int i = 0; i < 100; i++) { 141 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 142 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 143 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 144 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 145 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 146 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 147 } 148 } 149 150 // 75Hz sampled at 30Hz should produce a sequence where some frames are skipped. 151 TEST(SmoothEventSamplerTest, Sample75HertzAt30Hertz) { 152 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 153 const int redundant_capture_goal = 32; 154 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 75; 155 156 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal); 157 base::Time t; 158 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 159 160 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, 161 &sampler, &t); 162 163 // Steady state, we should capture 1st and 3rd frames out of every five 164 // frames, indefinitely. 165 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 166 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 167 for (int i = 0; i < 100; i++) { 168 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 169 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 170 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 171 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 172 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 173 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 174 } 175 176 // Now pretend we're limited by backpressure in the pipeline. In this scenario 177 // case we are adding events but not sampling them. 178 for (int i = 0; i < 20; i++) { 179 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 180 ASSERT_EQ(i >= 8, sampler.IsOverdueForSamplingAt(t)); 181 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 182 t += vsync; 183 } 184 185 // Now suppose we can sample again. We capture the next frame, and not the one 186 // after that, and then we're back in the steady state again. 187 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); 188 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 189 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 190 for (int i = 0; i < 100; i++) { 191 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 192 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 193 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 194 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 195 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 196 SteadyStateNoSampleAndAdvance(vsync, &sampler, &t); 197 } 198 } 199 200 // 30Hz sampled at 30Hz should produce 30Hz. 201 TEST(SmoothEventSamplerTest, Sample30HertzAt30Hertz) { 202 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 203 const int redundant_capture_goal = 1; 204 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 30; 205 206 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal); 207 base::Time t; 208 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 209 210 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, 211 &sampler, &t); 212 213 // Steady state, we should capture every vsync, indefinitely. 214 for (int i = 0; i < 200; i++) { 215 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 216 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 217 } 218 219 // Now pretend we're limited by backpressure in the pipeline. In this scenario 220 // case we are adding events but not sampling them. 221 for (int i = 0; i < 7; i++) { 222 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 223 ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t)); 224 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 225 t += vsync; 226 } 227 228 // Now suppose we can sample again. We should be back in the steady state. 229 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); 230 for (int i = 0; i < 100; i++) { 231 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 232 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 233 } 234 } 235 236 // 24Hz sampled at 30Hz should produce 24Hz. 237 TEST(SmoothEventSamplerTest, Sample24HertzAt30Hertz) { 238 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 239 const int redundant_capture_goal = 333; 240 const base::TimeDelta vsync = base::TimeDelta::FromSeconds(1) / 24; 241 242 SmoothEventSampler sampler(capture_period, true, redundant_capture_goal); 243 base::Time t; 244 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 245 246 TestRedundantCaptureStrategy(capture_period, redundant_capture_goal, 247 &sampler, &t); 248 249 // Steady state, we should capture every vsync, indefinitely. 250 for (int i = 0; i < 200; i++) { 251 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 252 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 253 } 254 255 // Now pretend we're limited by backpressure in the pipeline. In this scenario 256 // case we are adding events but not sampling them. 257 for (int i = 0; i < 7; i++) { 258 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 259 ASSERT_EQ(i >= 3, sampler.IsOverdueForSamplingAt(t)); 260 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 261 t += vsync; 262 } 263 264 // Now suppose we can sample again. We should be back in the steady state. 265 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t)); 266 for (int i = 0; i < 100; i++) { 267 SCOPED_TRACE(base::StringPrintf("Iteration %d", i)); 268 SteadyStateSampleAndAdvance(vsync, &sampler, &t); 269 } 270 } 271 272 TEST(SmoothEventSamplerTest, DoubleDrawAtOneTimeStillDirties) { 273 const base::TimeDelta capture_period = base::TimeDelta::FromSeconds(1) / 30; 274 const base::TimeDelta overdue_period = base::TimeDelta::FromSeconds(1); 275 276 SmoothEventSampler sampler(capture_period, true, 1); 277 base::Time t; 278 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 279 280 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 281 sampler.RecordSample(); 282 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t)) 283 << "Sampled last event; should not be dirty."; 284 t += overdue_period; 285 286 // Now simulate 2 events with the same clock value. 287 ASSERT_TRUE(sampler.AddEventAndConsiderSampling(t)); 288 sampler.RecordSample(); 289 ASSERT_FALSE(sampler.AddEventAndConsiderSampling(t)) 290 << "Two events at same time -- expected second not to be sampled."; 291 ASSERT_TRUE(sampler.IsOverdueForSamplingAt(t + overdue_period)) 292 << "Second event should dirty the capture state."; 293 sampler.RecordSample(); 294 ASSERT_FALSE(sampler.IsOverdueForSamplingAt(t + overdue_period)); 295 } 296 297 TEST(SmoothEventSamplerTest, FallbackToPollingIfUpdatesUnreliable) { 298 const base::TimeDelta timer_interval = base::TimeDelta::FromSeconds(1) / 30; 299 300 SmoothEventSampler should_not_poll(timer_interval, true, 1); 301 SmoothEventSampler should_poll(timer_interval, false, 1); 302 base::Time t; 303 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 304 305 // Do one round of the "happy case" where an event was received and 306 // RecordSample() was called by the client. 307 ASSERT_TRUE(should_not_poll.AddEventAndConsiderSampling(t)); 308 ASSERT_TRUE(should_poll.AddEventAndConsiderSampling(t)); 309 should_not_poll.RecordSample(); 310 should_poll.RecordSample(); 311 312 // One time period ahead, neither sampler says we're overdue. 313 for (int i = 0; i < 3; i++) { 314 t += timer_interval; 315 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t)) 316 << "Sampled last event; should not be dirty."; 317 ASSERT_FALSE(should_poll.IsOverdueForSamplingAt(t)) 318 << "Dirty interval has not elapsed yet."; 319 } 320 321 // Next time period ahead, both samplers say we're overdue. The non-polling 322 // sampler is returning true here because it has been configured to allow one 323 // redundant capture. 324 t += timer_interval; 325 ASSERT_TRUE(should_not_poll.IsOverdueForSamplingAt(t)) 326 << "Sampled last event; is dirty one time only to meet redundancy goal."; 327 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t)) 328 << "If updates are unreliable, must fall back to polling when idle."; 329 should_not_poll.RecordSample(); 330 should_poll.RecordSample(); 331 332 // Forever more, the non-polling sampler returns false while the polling one 333 // returns true. 334 for (int i = 0; i < 100; ++i) { 335 t += timer_interval; 336 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t)) 337 << "Sampled last event; should not be dirty."; 338 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t)) 339 << "If updates are unreliable, must fall back to polling when idle."; 340 should_poll.RecordSample(); 341 } 342 t += timer_interval / 3; 343 ASSERT_FALSE(should_not_poll.IsOverdueForSamplingAt(t)) 344 << "Sampled last event; should not be dirty."; 345 ASSERT_TRUE(should_poll.IsOverdueForSamplingAt(t)) 346 << "If updates are unreliable, must fall back to polling when idle."; 347 should_poll.RecordSample(); 348 } 349 350 struct DataPoint { 351 bool should_capture; 352 double increment_ms; 353 }; 354 355 void ReplayCheckingSamplerDecisions(const DataPoint* data_points, 356 size_t num_data_points, 357 SmoothEventSampler* sampler) { 358 base::Time t; 359 ASSERT_TRUE(base::Time::FromString("Sat, 23 Mar 2013 1:21:08 GMT", &t)); 360 for (size_t i = 0; i < num_data_points; ++i) { 361 t += base::TimeDelta::FromMicroseconds( 362 static_cast<int64>(data_points[i].increment_ms * 1000)); 363 ASSERT_EQ(data_points[i].should_capture, 364 sampler->AddEventAndConsiderSampling(t)) 365 << "at data_points[" << i << ']'; 366 if (data_points[i].should_capture) 367 sampler->RecordSample(); 368 } 369 } 370 371 TEST(SmoothEventSamplerTest, DrawingAt24FpsWith60HzVsyncSampledAt30Hertz) { 372 // Actual capturing of timing data: Initial instability as a 24 FPS video was 373 // started from a still screen, then clearly followed by steady-state. 374 static const DataPoint data_points[] = { 375 { true, 1437.93 }, { true, 150.484 }, { true, 217.362 }, { true, 50.161 }, 376 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 66.88 }, 377 { true, 50.161 }, { false, 0 }, { false, 0 }, { true, 50.16 }, 378 { true, 33.441 }, { true, 16.72 }, { false, 16.72 }, { true, 117.041 }, 379 { true, 16.72 }, { false, 16.72 }, { true, 50.161 }, { true, 50.16 }, 380 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 16.72 }, 381 { false, 0 }, { true, 50.161 }, { false, 0 }, { true, 33.44 }, 382 { true, 16.72 }, { false, 16.721 }, { true, 66.881 }, { false, 0 }, 383 { true, 33.441 }, { true, 16.72 }, { true, 50.16 }, { true, 16.72 }, 384 { false, 16.721 }, { true, 50.161 }, { true, 50.16 }, { false, 0 }, 385 { true, 33.441 }, { true, 50.337 }, { true, 50.183 }, { true, 16.722 }, 386 { true, 50.161 }, { true, 33.441 }, { true, 50.16 }, { true, 33.441 }, 387 { true, 50.16 }, { true, 33.441 }, { true, 50.16 }, { true, 33.44 }, 388 { true, 50.161 }, { true, 50.16 }, { true, 33.44 }, { true, 33.441 }, 389 { true, 50.16 }, { true, 50.161 }, { true, 33.44 }, { true, 33.441 }, 390 { true, 50.16 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 }, 391 { true, 50.161 }, { true, 33.44 }, { true, 50.161 }, { true, 33.44 }, 392 { true, 83.601 }, { true, 16.72 }, { true, 33.44 }, { false, 0 } 393 }; 394 395 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3); 396 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); 397 } 398 399 TEST(SmoothEventSamplerTest, DrawingAt30FpsWith60HzVsyncSampledAt30Hertz) { 400 // Actual capturing of timing data: Initial instability as a 30 FPS video was 401 // started from a still screen, then followed by steady-state. Drawing 402 // framerate from the video rendering was a bit volatile, but averaged 30 FPS. 403 static const DataPoint data_points[] = { 404 { true, 2407.69 }, { true, 16.733 }, { true, 217.362 }, { true, 33.441 }, 405 { true, 33.44 }, { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, 406 { true, 33.44 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, 407 { true, 16.721 }, { true, 33.44 }, { false, 0 }, { true, 50.161 }, 408 { true, 50.16 }, { false, 0 }, { true, 50.161 }, { true, 33.44 }, 409 { true, 16.72 }, { false, 0 }, { false, 16.72 }, { true, 66.881 }, 410 { false, 0 }, { true, 33.44 }, { true, 16.72 }, { true, 50.161 }, 411 { false, 0 }, { true, 33.538 }, { true, 33.526 }, { true, 33.447 }, 412 { true, 33.445 }, { true, 33.441 }, { true, 16.721 }, { true, 33.44 }, 413 { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, { true, 33.44 }, 414 { true, 33.441 }, { true, 33.44 }, { false, 0 }, { false, 16.72 }, 415 { true, 66.881 }, { true, 16.72 }, { false, 16.72 }, { true, 50.16 }, 416 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { true, 33.44 }, 417 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { false, 0 }, 418 { true, 33.44 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, 419 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 66.88 }, 420 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 }, 421 { true, 33.441 }, { true, 33.44 }, { true, 33.44 }, { false, 0 }, 422 { true, 16.72 }, { true, 50.161 }, { false, 0 }, { true, 50.16 }, 423 { false, 0.001 }, { true, 16.721 }, { true, 66.88 }, { true, 33.44 }, 424 { true, 33.441 }, { true, 33.44 }, { true, 50.161 }, { true, 16.72 }, 425 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 66.881 }, 426 { true, 33.44 }, { true, 16.72 }, { true, 33.441 }, { false, 16.72 }, 427 { true, 66.88 }, { true, 16.721 }, { true, 50.16 }, { true, 33.44 }, 428 { true, 16.72 }, { true, 33.441 }, { true, 33.44 }, { true, 33.44 } 429 }; 430 431 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3); 432 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); 433 } 434 435 TEST(SmoothEventSamplerTest, DrawingAt60FpsWith60HzVsyncSampledAt30Hertz) { 436 // Actual capturing of timing data: WebGL Acquarium demo 437 // (http://webglsamples.googlecode.com/hg/aquarium/aquarium.html) which ran 438 // between 55-60 FPS in the steady-state. 439 static const DataPoint data_points[] = { 440 { true, 16.72 }, { true, 16.72 }, { true, 4163.29 }, { true, 50.193 }, 441 { true, 117.041 }, { true, 50.161 }, { true, 50.16 }, { true, 33.441 }, 442 { true, 50.16 }, { true, 33.44 }, { false, 0 }, { false, 0 }, 443 { true, 50.161 }, { true, 83.601 }, { true, 50.16 }, { true, 16.72 }, 444 { true, 33.441 }, { false, 16.72 }, { true, 50.16 }, { true, 16.72 }, 445 { false, 0.001 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, 446 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, 447 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 }, 448 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 }, 449 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 }, 450 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, 451 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 33.44 }, 452 { false, 0 }, { true, 16.721 }, { true, 50.161 }, { false, 0 }, 453 { true, 33.44 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, 454 { false, 0 }, { true, 33.44 }, { false, 16.72 }, { true, 16.72 }, 455 { true, 50.16 }, { false, 0 }, { true, 16.721 }, { true, 33.44 }, 456 { false, 0 }, { true, 33.44 }, { false, 16.721 }, { true, 16.721 }, 457 { true, 50.161 }, { false, 0 }, { true, 16.72 }, { true, 33.44 }, 458 { false, 0 }, { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, 459 { true, 50.16 }, { false, 0 }, { true, 16.72 }, { true, 33.441 }, 460 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { true, 33.441 }, 461 { false, 0 }, { true, 33.44 }, { true, 33.441 }, { false, 0 }, 462 { true, 33.44 }, { false, 0 }, { true, 33.44 }, { false, 16.72 }, 463 { true, 16.721 }, { true, 50.161 }, { false, 0 }, { true, 16.72 }, 464 { true, 33.44 }, { true, 33.441 }, { false, 0 }, { true, 33.44 }, 465 { true, 33.44 }, { false, 0 }, { true, 33.441 }, { false, 16.72 }, 466 { true, 16.72 }, { true, 50.16 }, { false, 0 }, { true, 16.72 }, 467 { true, 33.441 }, { false, 0 }, { true, 33.44 }, { false, 16.72 }, 468 { true, 33.44 }, { false, 0 }, { true, 16.721 }, { true, 50.161 }, 469 { false, 0 }, { true, 16.72 }, { true, 33.44 }, { false, 0 }, 470 { true, 33.441 }, { false, 16.72 }, { true, 16.72 }, { true, 50.16 } 471 }; 472 473 SmoothEventSampler sampler(base::TimeDelta::FromSeconds(1) / 30, true, 3); 474 ReplayCheckingSamplerDecisions(data_points, arraysize(data_points), &sampler); 475 } 476 477 } // namespace 478 } // namespace content 479