VSyncMonitorTest.java revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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; 13 14import java.util.Arrays; 15import java.util.concurrent.Callable; 16 17public class VSyncMonitorTest extends InstrumentationTestCase { 18 private static class VSyncDataCollector implements VSyncMonitor.Listener { 19 public long mFramePeriods[]; 20 public int mFrameCount; 21 public long mLastVSyncCpuTimeMillis; 22 23 private final boolean mActivelyRequestUpdate; 24 private boolean mDone; 25 private long mPreviousVSyncTimeMicros; 26 private Object mSyncRoot = new Object(); 27 28 VSyncDataCollector(int frames, boolean activelyRequestUpdate) { 29 mFramePeriods = new long[frames]; 30 mActivelyRequestUpdate = activelyRequestUpdate; 31 } 32 33 public boolean isDone() { 34 synchronized (mSyncRoot) { 35 return mDone; 36 } 37 } 38 39 @Override 40 public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) { 41 mLastVSyncCpuTimeMillis = SystemClock.uptimeMillis(); 42 if (mPreviousVSyncTimeMicros == 0) { 43 mPreviousVSyncTimeMicros = vsyncTimeMicros; 44 return; 45 } 46 if (mFrameCount >= mFramePeriods.length) { 47 synchronized (mSyncRoot) { 48 mDone = true; 49 mSyncRoot.notify(); 50 } 51 return; 52 } 53 mFramePeriods[mFrameCount++] = vsyncTimeMicros - mPreviousVSyncTimeMicros; 54 mPreviousVSyncTimeMicros = vsyncTimeMicros; 55 if (mActivelyRequestUpdate) monitor.requestUpdate(); 56 } 57 58 public void waitTillDone() throws InterruptedException { 59 synchronized (mSyncRoot) { 60 while (!isDone()) { 61 mSyncRoot.wait(); 62 } 63 } 64 } 65 } 66 67 // The vsync monitor must be created on the UI thread to avoid associating the underlying 68 // Choreographer with the Looper from the test runner thread. 69 private VSyncMonitor createVSyncMonitor( 70 final VSyncMonitor.Listener listener, final boolean enableJBVSync) { 71 return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<VSyncMonitor>() { 72 @Override 73 public VSyncMonitor call() { 74 Context context = getInstrumentation().getContext(); 75 return new VSyncMonitor(context, listener, enableJBVSync); 76 } 77 }); 78 } 79 80 // Check that the vsync period roughly matches the timestamps that the monitor generates. 81 private void performVSyncPeriodTest(boolean enableJBVSync) throws InterruptedException { 82 // Collect roughly one second of data on a 60 fps display. 83 collectAndCheckVSync(enableJBVSync, 60, true); 84 collectAndCheckVSync(enableJBVSync, VSyncMonitor.MAX_AUTO_ONVSYNC_COUNT, false); 85 } 86 87 private void collectAndCheckVSync( 88 boolean enableJBVSync, final int totalFrames, final boolean activeFrames) 89 throws InterruptedException { 90 VSyncDataCollector collector = new VSyncDataCollector(totalFrames, activeFrames); 91 VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync); 92 93 long reportedFramePeriod = monitor.getVSyncPeriodInMicroseconds(); 94 assertTrue(reportedFramePeriod > 0); 95 96 assertFalse(collector.isDone()); 97 monitor.requestUpdate(); 98 collector.waitTillDone(); 99 assertTrue(collector.isDone()); 100 monitor.stop(); 101 102 // Check that the median frame rate is within 10% of the reported frame period. 103 assertTrue(collector.mFrameCount == totalFrames); 104 Arrays.sort(collector.mFramePeriods, 0, collector.mFramePeriods.length); 105 long medianFramePeriod = collector.mFramePeriods[collector.mFramePeriods.length / 2]; 106 if (Math.abs(medianFramePeriod - reportedFramePeriod) > reportedFramePeriod * .1) { 107 fail("Measured median frame period " + medianFramePeriod 108 + " differs by more than 10% from the reported frame period " 109 + reportedFramePeriod + " for " 110 + (activeFrames ? "requested" : "automatically sent") + " frames"); 111 } 112 } 113 114 // Check that the vsync period roughly matches the timestamps that the monitor generates. 115 @MediumTest 116 public void testVSyncPeriodAllowJBVSync() throws InterruptedException { 117 performVSyncPeriodTest(true); 118 } 119 120 // Check that the vsync period roughly matches the timestamps that the monitor generates. 121 @MediumTest 122 public void testVSyncPeriodDisallowJBVSync() throws InterruptedException { 123 performVSyncPeriodTest(false); 124 } 125 126 // Check that the vsync period roughly matches the timestamps that the monitor generates. 127 private void performVSyncActivationFromIdle(boolean enableJBVSync) throws InterruptedException { 128 VSyncDataCollector collector = new VSyncDataCollector(1, false); 129 VSyncMonitor monitor = createVSyncMonitor(collector, enableJBVSync); 130 131 monitor.requestUpdate(); 132 collector.waitTillDone(); 133 assertTrue(collector.isDone()); 134 monitor.stop(); 135 136 long period = monitor.getVSyncPeriodInMicroseconds() / 1000; 137 long delay = SystemClock.uptimeMillis() - collector.mLastVSyncCpuTimeMillis; 138 139 // The VSync should have activated immediately instead of at the next real vsync. 140 assertTrue(delay < period); 141 } 142 143 @MediumTest 144 public void testVSyncActivationFromIdleAllowJBVSync() throws InterruptedException { 145 performVSyncActivationFromIdle(true); 146 } 147 148 @MediumTest 149 public void testVSyncActivationFromIdleDisallowJBVSync() throws InterruptedException { 150 performVSyncActivationFromIdle(false); 151 } 152} 153