1 // Copyright 2012 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.
5 package org.chromium.content.browser;
7 import android.content.Context;
8 import android.os.SystemClock;
9 import android.test.InstrumentationTestCase;
10 import android.test.suitebuilder.annotation.MediumTest;
12 import org.chromium.base.ThreadUtils;
13 import org.chromium.ui.VSyncMonitor;
15 import java.util.Arrays;
16 import java.util.concurrent.Callable;
18 public class VSyncMonitorTest extends InstrumentationTestCase {
19 private static class VSyncDataCollector implements VSyncMonitor.Listener {
20 public long mFramePeriods[];
21 public int mFrameCount;
22 public long mLastVSyncCpuTimeMillis;
24 private final boolean mActivelyRequestUpdate;
25 private boolean mDone;
26 private long mPreviousVSyncTimeMicros;
27 private Object mSyncRoot = new Object();
29 VSyncDataCollector(int frames, boolean activelyRequestUpdate) {
30 mFramePeriods = new long[frames];
31 mActivelyRequestUpdate = activelyRequestUpdate;
34 public boolean isDone() {
35 synchronized (mSyncRoot) {
41 public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
42 mLastVSyncCpuTimeMillis = SystemClock.uptimeMillis();
43 if (mPreviousVSyncTimeMicros == 0) {
44 mPreviousVSyncTimeMicros = vsyncTimeMicros;
47 if (mFrameCount >= mFramePeriods.length) {
48 synchronized (mSyncRoot) {
54 mFramePeriods[mFrameCount++] = vsyncTimeMicros - mPreviousVSyncTimeMicros;
55 mPreviousVSyncTimeMicros = vsyncTimeMicros;
56 if (mActivelyRequestUpdate) monitor.requestUpdate();
59 public void waitTillDone() throws InterruptedException {
60 synchronized (mSyncRoot) {
68 // The vsync monitor must be created on the UI thread to avoid associating the underlying
69 // Choreographer with the Looper from the test runner thread.
70 private VSyncMonitor createVSyncMonitor(
71 final VSyncMonitor.Listener listener, final boolean enableJBVSync) {
72 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<VSyncMonitor>() {
74 public VSyncMonitor call() {
75 Context context = getInstrumentation().getContext();
76 return new VSyncMonitor(context, listener, enableJBVSync);
81 // Check that the vsync period roughly matches the timestamps that the monitor generates.
82 private void performVSyncPeriodTest(boolean enableJBVSync) throws InterruptedException {
83 // Collect roughly one second of data on a 60 fps display.
84 collectAndCheckVSync(enableJBVSync, 60, true);
85 collectAndCheckVSync(enableJBVSync, VSyncMonitor.MAX_AUTO_ONVSYNC_COUNT, false);
88 private void collectAndCheckVSync(
89 boolean enableJBVSync, final int totalFrames, final boolean activeFrames)
90 throws InterruptedException {
91 VSyncDataCollector collector = new VSyncDataCollector(totalFrames, activeFrames);
92 VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync);
94 long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds();
95 assertTrue(reportedFramePeriod > 0);
97 assertFalse(collector.isDone());
98 monitor.requestUpdate();
99 collector.waitTillDone();
100 assertTrue(collector.isDone());
103 // Check that the median frame rate is within 10% of the reported frame period.
104 assertTrue(collector.mFrameCount == totalFrames);
105 Arrays.sort(collector.mFramePeriods, 0, collector.mFramePeriods.length);
106 long medianFramePeriod = collector.mFramePeriods[collector.mFramePeriods.length / 2];
107 if (Math.abs(medianFramePeriod - reportedFramePeriod) > reportedFramePeriod * .1) {
108 fail("Measured median frame period " + medianFramePeriod
109 + " differs by more than 10% from the reported frame period "
110 + reportedFramePeriod + " for "
111 + (activeFrames ? "requested" : "automatically sent") + " frames");
115 // Check that the vsync period roughly matches the timestamps that the monitor generates.
117 public void testVSyncPeriodAllowJBVSync() throws InterruptedException {
118 performVSyncPeriodTest(true);
121 // Check that the vsync period roughly matches the timestamps that the monitor generates.
123 public void testVSyncPeriodDisallowJBVSync() throws InterruptedException {
124 performVSyncPeriodTest(false);
127 // Check that the vsync period roughly matches the timestamps that the monitor generates.
128 private void performVSyncActivationFromIdle(boolean enableJBVSync) throws InterruptedException {
129 VSyncDataCollector collector = new VSyncDataCollector(1, false);
130 VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync);
132 monitor.requestUpdate();
133 collector.waitTillDone();
134 assertTrue(collector.isDone());
137 long period = monitor.getVSyncPeriodInMicroseconds() / 1000;
138 long delay = SystemClock.uptimeMillis() - collector.mLastVSyncCpuTimeMillis;
140 // The VSync should have activated immediately instead of at the next real vsync.
141 assertTrue(delay < period);
145 public void testVSyncActivationFromIdleAllowJBVSync() throws InterruptedException {
146 performVSyncActivationFromIdle(true);
150 public void testVSyncActivationFromIdleDisallowJBVSync() throws InterruptedException {
151 performVSyncActivationFromIdle(false);