Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 451eb138 authored by Vishnu Nair's avatar Vishnu Nair
Browse files

SurfaceFlingerPerfTests: Reduce variability in results

- use custom interation counter since simpleperf is run over entire test
- move all setup to @Before so its not recorded by simpleperf
- make test activity fullscreen to remove buffer updates from statusbar

Bug: 230039226
Test: atest SurfaceFlingerPerfTest

Change-Id: Id8c03b4dd32c012f091ab602fff780308420742f
Merged-In: Id8c03b4dd32c012f091ab602fff780308420742f
parent 4b73f2a5
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -49,16 +49,20 @@
        <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />

        <option name="instrumentation-arg" key="profiling-iterations" value="525" />
        <!-- PerfettoListener related arguments -->
        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />

        <!-- SimpleperfListener related arguments -->
        <option name="instrumentation-arg" key="report" value="true" />
        <option name="instrumentation-arg" key="arguments" value="&quot;&quot;" />
        <option name="instrumentation-arg" key="arguments" value="-g" />
        <option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
        <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger" />
        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;android::SurfaceFlinger::commit(;android::SurfaceFlinger::composite(&quot;" />
        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;commit;android::SurfaceFlinger::commit(;composite;android::SurfaceFlinger::composite(&quot;" />

        <!-- should match profiling-iterations -->
        <option name="instrumentation-arg" key="test_iterations" value="525" />

        <!-- ProcLoadListener related arguments -->
        <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+11 −9
Original line number Diff line number Diff line
@@ -53,15 +53,17 @@ public class BufferFlinger {
        }
    }

    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl)
            throws InterruptedException {
        GraphicBuffer buffer = mBufferQ.take();
    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl) {
        try {
            final GraphicBuffer buffer = mBufferQ.take();
            t.setBuffer(surfaceControl,
                    HardwareBuffer.createFromGraphicBuffer(buffer),
                    null,
                    (SyncFence fence) -> {
                        releaseCallback(fence, buffer);
                    });
        } catch (InterruptedException ignore) {
        }
    }

    public void releaseCallback(SyncFence fence, GraphicBuffer buffer) {
+73 −104
Original line number Diff line number Diff line
@@ -18,8 +18,8 @@ package android.surfaceflinger;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceControl;

import androidx.test.ext.junit.rules.ActivityScenarioRule;
@@ -29,6 +29,7 @@ import androidx.test.runner.AndroidJUnit4;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
@@ -40,37 +41,66 @@ import java.util.Random;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class SurfaceFlingerPerfTest {
    protected ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
    private static final String TAG = "SurfaceFlingerPerfTest";
    private final ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
            new ActivityScenarioRule<>(SurfaceFlingerTestActivity.class);
    protected PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
    private SurfaceFlingerTestActivity mActivity;
    static final int BUFFER_COUNT = 2;
    private static final int BUFFER_COUNT = 2;
    private static final int MAX_BUFFERS = 10;
    private static final int MAX_POSITION = 10;
    private static final float MAX_SCALE = 2.0f;

    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
    private static final String DEFAULT_PROFILING_ITERATIONS = "100";
    private static int sProfilingIterations;
    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();

    @Rule
    public final RuleChain mAllRules = RuleChain
            .outerRule(mPerfStatusReporter)
            .around(mActivityRule);
            .outerRule(mActivityRule);

    @BeforeClass
    public static void suiteSetup() {
        final Bundle arguments = InstrumentationRegistry.getArguments();
        sProfilingIterations = Integer.parseInt(
                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
        Log.d(TAG, "suiteSetup: mProfilingIterations = " + sProfilingIterations);
    }

    @Before
    public void setup() {
        mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        for (int i = 0; i < MAX_BUFFERS; i++) {
            SurfaceControl sc = createSurfaceControl();
            BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
                    getRandomColorComponent(), getRandomColorComponent(),
                    getRandomColorComponent()));
            bufferTracker.addBuffer(t, sc);
            t.setPosition(sc, i * 10, i * 10);
        }
        t.apply(true);
    }

    @After
    public void teardown() {
        mSurfaceControls.forEach(SurfaceControl::release);
        mByfferTrackers.forEach(BufferFlinger::freeBuffers);
        mBufferTrackers.forEach(BufferFlinger::freeBuffers);
    }

    static int getRandomColorComponent() {
        return new Random().nextInt(155) + 100;
    }

    private ArrayList<BufferFlinger> mByfferTrackers = new ArrayList<>();
    private final ArrayList<BufferFlinger> mBufferTrackers = new ArrayList<>();
    private BufferFlinger createBufferTracker(int color) {
        BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
        mByfferTrackers.add(bufferTracker);
        mBufferTrackers.add(bufferTracker);
        return bufferTracker;
    }

    private ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
    private SurfaceControl createSurfaceControl() throws InterruptedException {
    private final ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
    private SurfaceControl createSurfaceControl() {
        SurfaceControl sc = mActivity.createChildSurfaceControl();
        mSurfaceControls.add(sc);
        return sc;
@@ -78,151 +108,90 @@ public class SurfaceFlingerPerfTest {

    @Test
    public void singleBuffer() throws Exception {
        SurfaceControl sc = createSurfaceControl();
        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        bufferTracker.addBuffer(t, sc);
        t.show(sc);

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            bufferTracker.addBuffer(t, sc);
            t.apply();
        for (int i = 0; i < sProfilingIterations; i++) {
            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
            mTransaction.show(mSurfaceControls.get(0)).apply(true);
        }
    }

    static int getRandomColorComponent() {
        return new Random().nextInt(155) + 100;
    }

    @Test
    public void multipleBuffers() throws Exception {
        final int MAX_BUFFERS = 10;

        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        for (int j = 0; j < sProfilingIterations; j++) {
            for (int i = 0; i < MAX_BUFFERS; i++) {
            SurfaceControl sc = createSurfaceControl();
            BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
                    getRandomColorComponent(), getRandomColorComponent(),
                    getRandomColorComponent()));
            bufferTracker.addBuffer(t, sc);
            t.setPosition(sc, i * 10, i * 10);
            t.show(sc);
        }
        t.apply(true);
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            for (int i = 0; i < MAX_BUFFERS; i++) {
                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
                mTransaction.show(mSurfaceControls.get(i));
            }
            t.apply();
            mTransaction.apply(true);
        }
    }

    @Test
    public void multipleOpaqueBuffers() throws Exception {
        final int MAX_BUFFERS = 10;

        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        for (int j = 0; j < sProfilingIterations; j++) {
            for (int i = 0; i < MAX_BUFFERS; i++) {
            SurfaceControl sc = createSurfaceControl();
            BufferFlinger bufferTracker = createBufferTracker(Color.rgb(getRandomColorComponent(),
                    getRandomColorComponent(), getRandomColorComponent()));
            bufferTracker.addBuffer(t, sc);
            t.setOpaque(sc, true);
            t.setPosition(sc, i * 10, i * 10);
            t.show(sc);
                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
                mTransaction.show(mSurfaceControls.get(i)).setOpaque(mSurfaceControls.get(i), true);
            }
        t.apply(true);
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
            for (int i = 0; i < MAX_BUFFERS; i++) {
                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
            }
            t.apply();
            mTransaction.apply(true);
        }
    }

    @Test
    public void geometryChanges() throws Exception {
        final int MAX_POSITION = 10;
        final float MAX_SCALE = 2.0f;

        SurfaceControl sc = createSurfaceControl();
        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        bufferTracker.addBuffer(t, sc);
        t.show(sc).apply(true);

        int step = 0;
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
        for (int i = 0; i < sProfilingIterations; i++) {
            step = ++step % MAX_POSITION;
            t.setPosition(sc, step, step);
            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
            float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
            t.setScale(sc, scale, scale);
            t.apply();
            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
            mTransaction.show(mSurfaceControls.get(0)).apply(true);
        }
    }

    @Test
    public void geometryWithBufferChanges() throws Exception {
        final int MAX_POSITION = 10;

        SurfaceControl sc = createSurfaceControl();
        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        bufferTracker.addBuffer(t, sc);
        t.show(sc).apply(true);

        int step = 0;
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
        for (int i = 0; i < sProfilingIterations; i++) {
            step = ++step % MAX_POSITION;
            t.setPosition(sc, step, step);
            float scale = ((step * 2.0f) / MAX_POSITION) + 0.5f;
            t.setScale(sc, scale, scale);
            bufferTracker.addBuffer(t, sc);
            t.apply();
            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
            float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
            mTransaction.show(mSurfaceControls.get(0)).apply(true);
        }
    }

    @Test
    public void addRemoveLayers() throws Exception {
        SurfaceControl sc = createSurfaceControl();
        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();

        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
        for (int i = 0; i < sProfilingIterations; i++) {
            SurfaceControl childSurfaceControl =  new SurfaceControl.Builder()
                    .setName("childLayer").setBLASTLayer().build();
            bufferTracker.addBuffer(t, childSurfaceControl);
            t.reparent(childSurfaceControl, sc);
            t.apply();
            t.remove(childSurfaceControl).apply();
            mBufferTrackers.get(0).addBuffer(mTransaction, childSurfaceControl);
            mTransaction.reparent(childSurfaceControl, mSurfaceControls.get(0));
            mTransaction.show(childSurfaceControl).show(mSurfaceControls.get(0));
            mTransaction.apply(true);
            mTransaction.remove(childSurfaceControl).apply(true);
        }
    }

    @Test
    public void displayScreenshot() throws Exception {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
        for (int i = 0; i < sProfilingIterations; i++) {
            Bitmap screenshot =
                    InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
            screenshot.recycle();
            mTransaction.apply(true);
        }
    }

    @Test
    public void layerScreenshot() throws Exception {
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
        while (state.keepRunning()) {
        for (int i = 0; i < sProfilingIterations; i++) {
            Bitmap screenshot =
                    InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(
                            mActivity.getWindow());
            screenshot.recycle();
            mTransaction.apply(true);
        }
    }

}
+10 −3
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;

import java.util.concurrent.CountDownLatch;
@@ -38,12 +39,15 @@ public class SurfaceFlingerTestActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        mTestSurfaceView = new TestSurfaceView(this);
        setContentView(mTestSurfaceView);
    }

    public SurfaceControl createChildSurfaceControl() throws InterruptedException {
    public SurfaceControl createChildSurfaceControl() {
        return mTestSurfaceView.getChildSurfaceControlHelper();
    }

@@ -65,8 +69,11 @@ public class SurfaceFlingerTestActivity extends Activity {
            });
        }

        public SurfaceControl getChildSurfaceControlHelper() throws InterruptedException {
        public SurfaceControl getChildSurfaceControlHelper() {
            try {
                mIsReady.await();
            } catch (InterruptedException ignore) {
            }
            SurfaceHolder holder = getHolder();

            // check to see if surface is valid