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