VSyncMonitorTest.java revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
1// Copyright (c) 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.
4
5package org.chromium.content.browser;
6
7import android.content.Context;
8import android.test.InstrumentationTestCase;
9import android.test.suitebuilder.annotation.MediumTest;
10import java.util.Arrays;
11import java.util.concurrent.Callable;
12
13import org.chromium.base.ThreadUtils;
14
15public class VSyncMonitorTest extends InstrumentationTestCase {
16    private static class VSyncDataCollector implements VSyncMonitor.Listener {
17        public long mFramePeriods[];
18        public int mFrameCount;
19
20        private final boolean mActivelyRequestUpdate;
21        private boolean mDone;
22        private long mPreviousVSyncTimeMicros;
23        private Object mSyncRoot = new Object();
24
25        VSyncDataCollector(int frames, boolean activelyRequestUpdate) {
26            mFramePeriods = new long[frames];
27            mActivelyRequestUpdate = activelyRequestUpdate;
28        }
29
30        public boolean isDone() {
31            synchronized (mSyncRoot) {
32                return mDone;
33            }
34        }
35
36        @Override
37        public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
38            if (mPreviousVSyncTimeMicros == 0) {
39                mPreviousVSyncTimeMicros = vsyncTimeMicros;
40                return;
41            }
42            if (mFrameCount >= mFramePeriods.length) {
43                synchronized (mSyncRoot) {
44                    mDone = true;
45                    mSyncRoot.notify();
46                }
47                return;
48            }
49            mFramePeriods[mFrameCount++] = vsyncTimeMicros - mPreviousVSyncTimeMicros;
50            mPreviousVSyncTimeMicros = vsyncTimeMicros;
51            if (mActivelyRequestUpdate) monitor.requestUpdate();
52        }
53
54        public void waitTillDone() throws InterruptedException {
55            synchronized (mSyncRoot) {
56                while (!isDone()) {
57                    mSyncRoot.wait();
58                }
59            }
60        }
61    }
62
63    // The vsync monitor must be created on the UI thread to avoid associating the underlying
64    // Choreographer with the Looper from the test runner thread.
65    private VSyncMonitor createVSyncMonitor(
66            final VSyncMonitor.Listener listener, final boolean enableJBVSync) {
67        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<VSyncMonitor>() {
68            @Override
69            public VSyncMonitor call() {
70                Context context = getInstrumentation().getContext();
71                return new VSyncMonitor(context, listener, enableJBVSync);
72            }
73        });
74    }
75
76    // Check that the vsync period roughly matches the timestamps that the monitor generates.
77    private void performVSyncPeriodTest(boolean enableJBVSync) throws InterruptedException {
78        // Collect roughly one second of data on a 60 fps display.
79        collectAndCheckVSync(enableJBVSync, 60, true);
80        collectAndCheckVSync(enableJBVSync, VSyncMonitor.MAX_AUTO_ONVSYNC_COUNT, false);
81    }
82
83    private void collectAndCheckVSync(
84            boolean enableJBVSync, final int totalFrames, final boolean activeFrames)
85            throws InterruptedException {
86        VSyncDataCollector collector = new VSyncDataCollector(totalFrames, activeFrames);
87        VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync);
88
89        long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds();
90        assertTrue(reportedFramePeriod > 0);
91
92        assertFalse(collector.isDone());
93        monitor.requestUpdate();
94        collector.waitTillDone();
95        assertTrue(collector.isDone());
96        monitor.stop();
97
98        // Check that the median frame rate is within 10% of the reported frame period.
99        assertTrue(collector.mFrameCount == totalFrames);
100        Arrays.sort(collector.mFramePeriods, 0, collector.mFramePeriods.length);
101        long medianFramePeriod = collector.mFramePeriods[collector.mFramePeriods.length / 2];
102        if (Math.abs(medianFramePeriod - reportedFramePeriod) > reportedFramePeriod * .1) {
103            fail("Measured median frame period " + medianFramePeriod
104                    + " differs by more than 10% from the reported frame period "
105                    + reportedFramePeriod + " for "
106                    + (activeFrames ? "requested" : "automatically sent") + " frames");
107        }
108    }
109
110    // Check that the vsync period roughly matches the timestamps that the monitor generates.
111    @MediumTest
112    public void testVSyncPeriodAllowJBVSync() throws InterruptedException {
113        performVSyncPeriodTest(true);
114    }
115
116    // Check that the vsync period roughly matches the timestamps that the monitor generates.
117    @MediumTest
118    public void testVSyncPeriodDisallowJBVSync() throws InterruptedException {
119        performVSyncPeriodTest(false);
120    }
121}
122