VSyncMonitorTest.java revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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. 4 5package org.chromium.content.browser; 6 7import android.content.Context; 8import android.os.SystemClock; 9import android.test.InstrumentationTestCase; 10import android.test.suitebuilder.annotation.MediumTest; 11 12import org.chromium.base.ThreadUtils; 13import org.chromium.ui.VSyncMonitor; 14 15import java.util.Arrays; 16import java.util.concurrent.Callable; 17 18public class VSyncMonitorTest extends InstrumentationTestCase { 19 private static class VSyncDataCollector implements VSyncMonitor.Listener { 20 public long mFramePeriods[]; 21 public int mFrameCount; 22 public long mLastVSyncCpuTimeMillis; 23 24 private final boolean mActivelyRequestUpdate; 25 private boolean mDone; 26 private long mPreviousVSyncTimeMicros; 27 private Object mSyncRoot = new Object(); 28 29 VSyncDataCollector(int frames, boolean activelyRequestUpdate) { 30 mFramePeriods = new long[frames]; 31 mActivelyRequestUpdate = activelyRequestUpdate; 32 } 33 34 public boolean isDone() { 35 synchronized (mSyncRoot) { 36 return mDone; 37 } 38 } 39 40 @Override 41 public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) { 42 mLastVSyncCpuTimeMillis = SystemClock.uptimeMillis(); 43 if (mPreviousVSyncTimeMicros == 0) { 44 mPreviousVSyncTimeMicros = vsyncTimeMicros; 45 return; 46 } 47 if (mFrameCount >= mFramePeriods.length) { 48 synchronized (mSyncRoot) { 49 mDone = true; 50 mSyncRoot.notify(); 51 } 52 return; 53 } 54 mFramePeriods[mFrameCount++] = vsyncTimeMicros - mPreviousVSyncTimeMicros; 55 mPreviousVSyncTimeMicros = vsyncTimeMicros; 56 if (mActivelyRequestUpdate) monitor.requestUpdate(); 57 } 58 59 public void waitTillDone() throws InterruptedException { 60 synchronized (mSyncRoot) { 61 while (!isDone()) { 62 mSyncRoot.wait(); 63 } 64 } 65 } 66 } 67 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>() { 73 @Override 74 public VSyncMonitor call() { 75 Context context = getInstrumentation().getContext(); 76 return new VSyncMonitor(context, listener, enableJBVSync); 77 } 78 }); 79 } 80 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); 86 } 87 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); 93 94 long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds(); 95 assertTrue(reportedFramePeriod > 0); 96 97 assertFalse(collector.isDone()); 98 monitor.requestUpdate(); 99 collector.waitTillDone(); 100 assertTrue(collector.isDone()); 101 monitor.stop(); 102 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"); 112 } 113 } 114 115 // Check that the vsync period roughly matches the timestamps that the monitor generates. 116 @MediumTest 117 public void testVSyncPeriodAllowJBVSync() throws InterruptedException { 118 performVSyncPeriodTest(true); 119 } 120 121 // Check that the vsync period roughly matches the timestamps that the monitor generates. 122 @MediumTest 123 public void testVSyncPeriodDisallowJBVSync() throws InterruptedException { 124 performVSyncPeriodTest(false); 125 } 126 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); 131 132 monitor.requestUpdate(); 133 collector.waitTillDone(); 134 assertTrue(collector.isDone()); 135 monitor.stop(); 136 137 long period = monitor.getVSyncPeriodInMicroseconds() / 1000; 138 long delay = SystemClock.uptimeMillis() - collector.mLastVSyncCpuTimeMillis; 139 140 // The VSync should have activated immediately instead of at the next real vsync. 141 assertTrue(delay < period); 142 } 143 144 @MediumTest 145 public void testVSyncActivationFromIdleAllowJBVSync() throws InterruptedException { 146 performVSyncActivationFromIdle(true); 147 } 148 149 @MediumTest 150 public void testVSyncActivationFromIdleDisallowJBVSync() throws InterruptedException { 151 performVSyncActivationFromIdle(false); 152 } 153} 154