diff options
| author | 2024-10-17 16:20:30 +0000 | |
|---|---|---|
| committer | 2024-10-17 16:20:30 +0000 | |
| commit | 3e04e29b4ae7590e754cc7501348e74f222a76f4 (patch) | |
| tree | 0dfb39507bb9de1bc99d8f77bb817bf6a8719464 | |
| parent | 6a542f0bac70fe9734800e2670b668cf70ba3439 (diff) | |
| parent | 5158d49f1b9eb6cc26e766b6b0451acb356b8a45 (diff) | |
Merge "Add MessageQueuePerfTest" into main
| -rw-r--r-- | apct-tests/perftests/core/src/android/os/MessageQueuePerfTest.java | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/apct-tests/perftests/core/src/android/os/MessageQueuePerfTest.java b/apct-tests/perftests/core/src/android/os/MessageQueuePerfTest.java new file mode 100644 index 000000000000..b14de836fa78 --- /dev/null +++ b/apct-tests/perftests/core/src/android/os/MessageQueuePerfTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.perftests.utils.Stats; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.Random; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Performance tests for {@link MessageQueue}. + */ +@RunWith(AndroidJUnit4.class) +@LargeTest +public class MessageQueuePerfTest { + static final String TAG = "MessageQueuePerfTest"; + private static final int PER_THREAD_MESSAGE_COUNT = 1000; + private static final int THREAD_COUNT = 8; + private static final int TOTAL_MESSAGE_COUNT = PER_THREAD_MESSAGE_COUNT * THREAD_COUNT; + + static Object sLock = new Object(); + private ArrayList<Long> mResults; + + @Before + public void setUp() { } + + @After + public void tearDown() { } + + class EnqueueThread extends Thread { + CountDownLatch mStartLatch; + CountDownLatch mEndLatch; + Handler mHandler; + int mMessageStartIdx; + Message[] mMessages; + long[] mDelays; + + EnqueueThread(CountDownLatch startLatch, CountDownLatch endLatch, Handler handler, + int startIdx, Message[] messages, long[] delays) { + super(); + mStartLatch = startLatch; + mEndLatch = endLatch; + mHandler = handler; + mMessageStartIdx = startIdx; + mMessages = messages; + mDelays = delays; + } + + @Override + public void run() { + Log.d(TAG, "Enqueue thread started at message index " + mMessageStartIdx); + try { + mStartLatch.await(); + } catch (InterruptedException e) { + + } + long now = SystemClock.uptimeMillis(); + long startTimeNS = SystemClock.elapsedRealtimeNanos(); + for (int i = mMessageStartIdx; i < (mMessageStartIdx + PER_THREAD_MESSAGE_COUNT); i++) { + if (mDelays[i] == 0) { + mHandler.sendMessageAtFrontOfQueue(mMessages[i]); + } else { + mHandler.sendMessageAtTime(mMessages[i], now + mDelays[i]); + } + } + long endTimeNS = SystemClock.elapsedRealtimeNanos(); + + synchronized (sLock) { + mResults.add(endTimeNS - startTimeNS); + } + mEndLatch.countDown(); + } + } + + class TestHandler extends Handler { + TestHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { } + } + + void reportPerf(String prefix, int threadCount, int perThreadMessageCount) { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + Stats stats = new Stats(mResults); + + Log.d(TAG, "Reporting perf now"); + + Bundle status = new Bundle(); + status.putLong(prefix + "_median_ns", stats.getMedian()); + status.putLong(prefix + "_mean_ns", (long) stats.getMean()); + status.putLong(prefix + "_min_ns", stats.getMin()); + status.putLong(prefix + "_max_ns", stats.getMax()); + status.putLong(prefix + "_stddev_ns", (long) stats.getStandardDeviation()); + status.putLong(prefix + "_nr_threads", threadCount); + status.putLong(prefix + "_msgs_per_thread", perThreadMessageCount); + instrumentation.sendStatus(Activity.RESULT_OK, status); + } + + HandlerThread mHandlerThread; + + private void fillMessagesArray(Message[] messages) { + for (int i = 0; i < messages.length; i++) { + messages[i] = mHandlerThread.getThreadHandler().obtainMessage(i); + } + } + + private void startTestAndWaitOnThreads(CountDownLatch threadStartLatch, CountDownLatch threadEndLatch) { + try { + threadStartLatch.countDown(); + Log.e(TAG, "Test threads started"); + threadEndLatch.await(); + } catch (InterruptedException ignored) { + } + Log.e(TAG, "Test threads ended, quitting handler thread"); + } + + @Test + public void benchmarkEnqueueAtFrontOfQueue() { + CountDownLatch threadStartLatch = new CountDownLatch(1); + CountDownLatch threadEndLatch = new CountDownLatch(THREAD_COUNT); + mHandlerThread = new HandlerThread("MessageQueuePerfTest"); + mHandlerThread.start(); + Message[] messages = new Message[TOTAL_MESSAGE_COUNT]; + fillMessagesArray(messages); + + long[] delays = new long[TOTAL_MESSAGE_COUNT]; + mResults = new ArrayList<>(); + + TestHandler handler = new TestHandler(mHandlerThread.getLooper()); + for (int i = 0; i < THREAD_COUNT; i++) { + EnqueueThread thread = new EnqueueThread(threadStartLatch, threadEndLatch, handler, + i * PER_THREAD_MESSAGE_COUNT, messages, delays); + thread.start(); + } + + startTestAndWaitOnThreads(threadStartLatch, threadEndLatch); + + mHandlerThread.quitSafely(); + + reportPerf("enqueueAtFront", THREAD_COUNT, PER_THREAD_MESSAGE_COUNT); + } + + /** + * Fill array with random delays, for benchmarkEnqueueDelayed + */ + public long[] fillDelayArray() { + long[] delays = new long[TOTAL_MESSAGE_COUNT]; + Random rand = new Random(0xDEADBEEF); + for (int i = 0; i < TOTAL_MESSAGE_COUNT; i++) { + delays[i] = Math.abs(rand.nextLong() % 5000); + } + return delays; + } + + @Test + public void benchmarkEnqueueDelayed() { + CountDownLatch threadStartLatch = new CountDownLatch(1); + CountDownLatch threadEndLatch = new CountDownLatch(THREAD_COUNT); + mHandlerThread = new HandlerThread("MessageQueuePerfTest"); + mHandlerThread.start(); + Message[] messages = new Message[TOTAL_MESSAGE_COUNT]; + fillMessagesArray(messages); + + long[] delays = fillDelayArray(); + mResults = new ArrayList<>(); + + TestHandler handler = new TestHandler(mHandlerThread.getLooper()); + for (int i = 0; i < THREAD_COUNT; i++) { + EnqueueThread thread = new EnqueueThread(threadStartLatch, threadEndLatch, handler, + i * PER_THREAD_MESSAGE_COUNT, messages, delays); + thread.start(); + } + + startTestAndWaitOnThreads(threadStartLatch, threadEndLatch); + + mHandlerThread.quitSafely(); + + reportPerf("enqueueDelayed", THREAD_COUNT, PER_THREAD_MESSAGE_COUNT); + } +} |