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

Commit 5eb36cfc authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Integrate Simpleperf profiling into MessageQueuePerfTest." into main

parents 74daaf11 55623bdf
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@
    <uses-permission android:name="android.permission.DEVICE_POWER" />
    <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <!-- permission needed to read/write simpleperf report -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application>
        <uses-library android:name="android.test.runner" />
        <profileable android:shell="true" />
+12 −0
Original line number Diff line number Diff line
@@ -67,5 +67,17 @@
        <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />

        <option name="instrumentation-arg" key="newRunListenerMode" value="true" />

        <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.SimpleperfListener" />

        <option name="instrumentation-arg" key="profiling-iterations" value="525" />

        <!-- SimpleperfListener related arguments -->
        <option name="instrumentation-arg" key="record" value="false"/>
        <option name="instrumentation-arg" key="report" value="true" />
        <option name="instrumentation-arg" key="arguments" value="-g" />
        <option name="instrumentation-arg" key="events_to_record" value="cpu-cycles" />
        <option name="instrumentation-arg" key="processes_to_record" value="com.android.perftests.core" />
    </test>
</configuration>
+158 −63
Original line number Diff line number Diff line
@@ -32,18 +32,23 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.helpers.SimpleperfHelper;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

/**
 * Performance tests for {@link MessageQueue}.
 */
/** Performance tests for {@link MessageQueue}. */
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MessageQueuePerfTest {
@@ -53,15 +58,53 @@ public class MessageQueuePerfTest {
    private static final int TOTAL_MESSAGE_COUNT = PER_THREAD_MESSAGE_COUNT * THREAD_COUNT;
    private static final int DEFAULT_MESSAGE_WHAT = 2;

    private SimpleperfHelper mSimpleperfHelper = new SimpleperfHelper();
    private boolean mEnableSimpleperf = true;

    @Rule public TestName mTestName = new TestName();

    /** Start simpleperf sampling. */
    public void startSimpleperf(String subcommand, String arguments) {
        if (!mSimpleperfHelper.startCollecting(subcommand, arguments)) {
            Log.e(TAG, "Simpleperf did not start successfully.");
        }
    }

    /** Stop simpleperf sampling and dump the collected file into the given path. */
    private void stopSimpleperf(Path path) {
        if (!mSimpleperfHelper.stopCollecting(path.toString())) {
            Log.e(TAG, "Failed to collect the simpleperf output.");
        }
    }

    @Before
    public void setUp() {
        mHandlerThread = new HandlerThread("MessageQueuePerfTest");
        mHandlerThread.start();

        Bundle arguments = androidx.test.platform.app.InstrumentationRegistry.getArguments();
        if (arguments != null && arguments.getString("no-simpleperf") != null) {
            mEnableSimpleperf = false;
        }

        if (mEnableSimpleperf) {
            String args =
                    "-o /data/local/tmp/perf.data -g -e cpu-cycles -p "
                            + mSimpleperfHelper.getPID("com.android.perftests.core");
            startSimpleperf("record", args);
        }
    }

    @After
    public void tearDown() {
        mHandlerThread.quitSafely();

        if (mEnableSimpleperf) {
            final File outputDir = InstrumentationRegistry.getContext().getExternalFilesDir(null);
            final Path outputPath =
                    new File(outputDir, mTestName.getMethodName() + ".perf.data").toPath();
            stopSimpleperf(outputPath);
        }
    }

    static class EnqueueThread extends Thread {
@@ -73,8 +116,13 @@ public class MessageQueuePerfTest {
        long[] mDelays;
        ArrayList<Long> mResults;

        EnqueueThread(CountDownLatch startLatch, CountDownLatch endLatch, Handler handler,
                int startIdx, Message[] messages, long[] delays) {
        EnqueueThread(
                CountDownLatch startLatch,
                CountDownLatch endLatch,
                Handler handler,
                int startIdx,
                Message[] messages,
                long[] delays) {
            super();
            mStartLatch = startLatch;
            mEndLatch = endLatch;
@@ -117,8 +165,12 @@ public class MessageQueuePerfTest {
        int mWhat;
        ArrayList<Long> mResults;

        RemoveThread(CountDownLatch startLatch, CountDownLatch endLatch, Handler handler,
                Thread blockingThread, int what) {
        RemoveThread(
                CountDownLatch startLatch,
                CountDownLatch endLatch,
                Handler handler,
                Thread blockingThread,
                int what) {
            super();
            mStartLatch = startLatch;
            mEndLatch = endLatch;
@@ -149,7 +201,6 @@ public class MessageQueuePerfTest {
            mResults.add(endTimeNS - startTimeNS);
            mEndLatch.countDown();
        }

    }

    class TestHandler extends Handler {
@@ -160,8 +211,12 @@ public class MessageQueuePerfTest {
        public void handleMessage(Message msg) {}
    }

    void reportPerf(String prefix, int threadCount, int perThreadMessageCount,
            EnqueueThread[] enqueueThreads, RemoveThread[] removeThreads) {
    void reportPerf(
            String prefix,
            int threadCount,
            int perThreadMessageCount,
            EnqueueThread[] enqueueThreads,
            RemoveThread[] removeThreads) {
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();

        // Accumulate enqueue/remove results.
@@ -211,7 +266,8 @@ public class MessageQueuePerfTest {
        fillMessagesArray(messages, DEFAULT_MESSAGE_WHAT, 0, messages.length);
    }

    private void startTestAndWaitOnThreads(CountDownLatch threadStartLatch, CountDownLatch threadEndLatch) {
    private void startTestAndWaitOnThreads(
            CountDownLatch threadStartLatch, CountDownLatch threadEndLatch) {
        try {
            threadStartLatch.countDown();
            Log.e(TAG, "Test threads started");
@@ -240,8 +296,14 @@ public class MessageQueuePerfTest {
        TestHandler handler = new TestHandler(mHandlerThread.getLooper());
        EnqueueThread[] enqueueThreads = new EnqueueThread[THREAD_COUNT];
        for (int i = 0; i < THREAD_COUNT; i++) {
            EnqueueThread thread = new EnqueueThread(threadStartLatch, threadEndLatch, handler,
                    i * PER_THREAD_MESSAGE_COUNT, messages, delays);
            EnqueueThread thread =
                    new EnqueueThread(
                            threadStartLatch,
                            threadEndLatch,
                            handler,
                            i * PER_THREAD_MESSAGE_COUNT,
                            messages,
                            delays);
            enqueueThreads[i] = thread;
            thread.start();
        }
@@ -251,9 +313,7 @@ public class MessageQueuePerfTest {
        reportPerf("enqueueAtFront", THREAD_COUNT, PER_THREAD_MESSAGE_COUNT, enqueueThreads, null);
    }

    /**
     * Fill array with random delays, for benchmarkEnqueueDelayed
     */
    /** Fill array with random delays, for benchmarkEnqueueDelayed */
    public long[] fillDelayArray() {
        long[] delays = new long[TOTAL_MESSAGE_COUNT];
        Random rand = new Random(0xDEADBEEF);
@@ -281,8 +341,14 @@ public class MessageQueuePerfTest {
        TestHandler handler = new TestHandler(mHandlerThread.getLooper());
        EnqueueThread[] enqueueThreads = new EnqueueThread[THREAD_COUNT];
        for (int i = 0; i < THREAD_COUNT; i++) {
            EnqueueThread thread = new EnqueueThread(threadStartLatch, threadEndLatch, handler,
                    i * PER_THREAD_MESSAGE_COUNT, messages, delays);
            EnqueueThread thread =
                    new EnqueueThread(
                            threadStartLatch,
                            threadEndLatch,
                            handler,
                            i * PER_THREAD_MESSAGE_COUNT,
                            messages,
                            delays);
            enqueueThreads[i] = thread;
            thread.start();
        }
@@ -316,8 +382,10 @@ public class MessageQueuePerfTest {
        // Fill with taskThreadCount blocks of PER_THREAD_MESSAGE_COUNT messages.
        Message[] messages = new Message[messageCount];
        for (int i = 0; i < taskThreadCount; i++) {
            fillMessagesArray(messages,
                    /* what = */ i, /* startIdx = */ i * PER_THREAD_MESSAGE_COUNT,
            fillMessagesArray(
                    messages,
                    /* what= */ i,
                    /* startIdx= */ i * PER_THREAD_MESSAGE_COUNT,
                    /* endIdx= */ (i + 1) * PER_THREAD_MESSAGE_COUNT);
        }

@@ -325,33 +393,57 @@ public class MessageQueuePerfTest {
        RemoveThread[] removeThreads = new RemoveThread[taskThreadCount];

        // Start by enqueuing the first block of messages.
        enqueueThreads[0] = new EnqueueThread(threadStartLatch, threadEndLatch, handler,
                /* startIdx = */ 0, messages, delays);
        enqueueThreads[0] =
                new EnqueueThread(
                        threadStartLatch,
                        threadEndLatch,
                        handler,
                        /* startIdx= */ 0,
                        messages,
                        delays);
        enqueueThreads[0].start();

        for (int i = 1; i < taskThreadCount; i++) {
            // Remove messages from the corresponding enqueue thread from the previous iteration.
            removeThreads[i - 1] = new RemoveThread(
                    threadStartLatch, threadEndLatch, handler, enqueueThreads[i - 1],
            removeThreads[i - 1] =
                    new RemoveThread(
                            threadStartLatch,
                            threadEndLatch,
                            handler,
                            enqueueThreads[i - 1],
                            /* what= */ i - 1);
            removeThreads[i - 1].start();

            // Concurrently enqueue the next set of messages.
            enqueueThreads[i] = new EnqueueThread(threadStartLatch, threadEndLatch,
                    handler, i * PER_THREAD_MESSAGE_COUNT, messages, delays);
            enqueueThreads[i] =
                    new EnqueueThread(
                            threadStartLatch,
                            threadEndLatch,
                            handler,
                            i * PER_THREAD_MESSAGE_COUNT,
                            messages,
                            delays);
            enqueueThreads[i].start();
        }

        // End by removing the last block of messages.
        removeThreads[taskThreadCount - 1] = new RemoveThread(
                threadStartLatch, threadEndLatch, handler, enqueueThreads[taskThreadCount - 1],
        removeThreads[taskThreadCount - 1] =
                new RemoveThread(
                        threadStartLatch,
                        threadEndLatch,
                        handler,
                        enqueueThreads[taskThreadCount - 1],
                        /* what= */ taskThreadCount - 1);
        removeThreads[taskThreadCount - 1].start();

        startTestAndWaitOnThreads(threadStartLatch, threadEndLatch);

        reportPerf("concurrentEnqueueDelayedAndRemove", THREAD_COUNT, PER_THREAD_MESSAGE_COUNT,
                enqueueThreads, removeThreads);
        reportPerf(
                "concurrentEnqueueDelayedAndRemove",
                THREAD_COUNT,
                PER_THREAD_MESSAGE_COUNT,
                enqueueThreads,
                removeThreads);
    }

    /**
@@ -365,10 +457,12 @@ public class MessageQueuePerfTest {
        final CountDownLatch threadEndLatch = new CountDownLatch(1);
        final TestHandler handler = new TestHandler(mHandlerThread.getLooper());

        Runnable runTest = new Runnable() {
        Runnable runTest =
                new Runnable() {
                    @Override
                    public void run() {
                // Can't make this an @Rule otherwise the multi threaded tests that don't use
                        // Can't make this an @Rule otherwise the multi threaded tests that don't
                        // use
                        // PerfStatusReporter will throw the error:
                        // "java.lang.IllegalStateException: The benchmark hasn't finished"
                        final PerfStatusReporter perfStatusReporter = new PerfStatusReporter();
@@ -380,7 +474,8 @@ public class MessageQueuePerfTest {
                            handler.removeMessages(DEFAULT_MESSAGE_WHAT);
                        }

                state.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
                        state.sendFullStatusReport(
                                InstrumentationRegistry.getInstrumentation(),
                                "singleThreadedEnqueueAndRemove");

                        threadEndLatch.countDown();