diff options
author | 2022-03-23 19:36:13 -0700 | |
---|---|---|
committer | 2022-03-26 17:21:38 -0700 | |
commit | 02f0e25661b44d0dfcbda3e0460b9ca46d07d9c5 (patch) | |
tree | 094fe4570f140d260d260e1ee366718e34661394 | |
parent | d7b3be3e0bcc73f433725afc1f84e11a3567d555 (diff) |
Add read/write perf tests for BlobStore.
These tests will help us understand the difference
between local reads/writes vs blobstore reads/writes.
Bug: 226954650
Test: atest ./apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
Change-Id: Ibcc8497b4c32e90824b89e836716bdeb7490227b
4 files changed, 156 insertions, 29 deletions
diff --git a/apct-tests/perftests/blobstore/Android.bp b/apct-tests/perftests/blobstore/Android.bp index 25c4250729c4..9064b4494ed1 100644 --- a/apct-tests/perftests/blobstore/Android.bp +++ b/apct-tests/perftests/blobstore/Android.bp @@ -22,17 +22,18 @@ package { } android_test { - name: "BlobStorePerfTests", - srcs: ["src/**/*.java"], - static_libs: [ - "BlobStoreTestUtils", - "androidx.test.rules", - "androidx.annotation_annotation", - "apct-perftests-utils", - "ub-uiautomator", - "collector-device-lib-platform", - ], - platform_apis: true, - test_suites: ["device-tests"], - certificate: "platform", + name: "BlobStorePerfTests", + srcs: ["src/**/*.java"], + static_libs: [ + "BlobStoreTestUtils", + "androidx.test.rules", + "androidx.annotation_annotation", + "apct-perftests-utils", + "ub-uiautomator", + "collector-device-lib-platform", + "androidx.benchmark_benchmark-macro", + ], + platform_apis: true, + test_suites: ["device-tests"], + certificate: "platform", } diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java index faf61a756170..665e986b91e5 100644 --- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java +++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java @@ -15,15 +15,20 @@ */ package com.android.perftests.blob; +import static com.android.utils.blob.Utils.acquireLease; + import android.app.blob.BlobHandle; import android.app.blob.BlobStoreManager; import android.content.Context; +import android.os.ParcelFileDescriptor; import android.perftests.utils.ManualBenchmarkState; import android.perftests.utils.PerfManualStatusReporter; import android.perftests.utils.TraceMarkParser; import android.perftests.utils.TraceMarkParser.TraceMarkSlice; import android.support.test.uiautomator.UiDevice; +import android.util.DataUnit; +import androidx.benchmark.macro.MacrobenchmarkScope; import androidx.test.filters.LargeTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -36,12 +41,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.List; +import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -53,6 +62,8 @@ public class BlobStorePerfTests { // From f/b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java private static final String ATRACE_COMPUTE_DIGEST_PREFIX = "computeBlobDigest-"; + public static final int BUFFER_SIZE_BYTES = 16 * 1024; + private Context mContext; private BlobStoreManager mBlobStoreManager; private AtraceUtils mAtraceUtils; @@ -85,6 +96,8 @@ public class BlobStorePerfTests { @After public void tearDown() { + mContext.getFilesDir().delete(); + runShellCommand("cmd package clear " + mContext.getPackageName()); runShellCommand("cmd blob_store idle-maintenance"); } @@ -109,6 +122,110 @@ public class BlobStorePerfTests { } } + @Test + public void testDirectReads() throws Exception { + final File file = new File(mContext.getDataDir(), "test_read_file"); + final long sizeBytes = DataUnit.MEBIBYTES.toBytes(fileSizeInMb); + try (FileOutputStream outputStream = new FileOutputStream(file)) { + writeData(outputStream, sizeBytes); + } + + long durationNs = 0; + while (mState.keepRunning(durationNs)) { + dropCache(); + try (FileInputStream inputStream = new FileInputStream(file)) { + final long startTimeNs = System.nanoTime(); + readData(inputStream, sizeBytes); + durationNs = System.nanoTime() - startTimeNs; + } + } + } + + @Test + public void testBlobStoreReads() throws Exception { + final FakeBlobData blobData = prepareDataBlob(fileSizeInMb); + commitBlob(blobData); + acquireLease(mContext, blobData.getBlobHandle(), "Test Desc"); + final long sizeBytes = DataUnit.MEBIBYTES.toBytes(fileSizeInMb); + + long durationNs = 0; + while (mState.keepRunning(durationNs)) { + dropCache(); + try (FileInputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream( + mBlobStoreManager.openBlob(blobData.getBlobHandle()))) { + final long startTimeNs = System.nanoTime(); + readData(inputStream, sizeBytes); + durationNs = System.nanoTime() - startTimeNs; + } + } + + deleteBlob(blobData.getBlobHandle()); + } + + @Test + public void testDirectWrites() throws Exception { + final File file = new File(mContext.getDataDir(), "test_write_file"); + final long sizeBytes = DataUnit.MEBIBYTES.toBytes(fileSizeInMb); + + long durationNs = 0; + while (mState.keepRunning(durationNs)) { + file.delete(); + dropCache(); + try (FileOutputStream outputStream = new FileOutputStream(file)) { + final long startTimeNs = System.nanoTime(); + writeData(outputStream, sizeBytes); + durationNs = System.nanoTime() - startTimeNs; + } + } + } + + @Test + public void testBlobStoreWrites() throws Exception { + final FakeBlobData blobData = prepareDataBlob(fileSizeInMb); + final long sizeBytes = DataUnit.MEBIBYTES.toBytes(fileSizeInMb); + + long durationNs = 0; + while (mState.keepRunning(durationNs)) { + final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle()); + try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) { + dropCache(); + try (FileOutputStream outputStream = new ParcelFileDescriptor + .AutoCloseOutputStream(session.openWrite(0, sizeBytes))) { + final long startTimeNs = System.nanoTime(); + writeData(outputStream, sizeBytes); + durationNs = System.nanoTime() - startTimeNs; + } + } + mBlobStoreManager.abandonSession(sessionId); + } + } + + private void readData(FileInputStream inputStream, long sizeBytes) throws Exception { + final byte[] buffer = new byte[BUFFER_SIZE_BYTES]; + long bytesRead = 0; + while (bytesRead < sizeBytes) { + bytesRead += inputStream.read(buffer); + } + } + + private void writeData(FileOutputStream outputStream, long sizeBytes) throws Exception { + final byte[] buffer = new byte[BUFFER_SIZE_BYTES]; + long bytesWritten = 0; + final Random random = new Random(0); + while (bytesWritten < sizeBytes) { + random.nextBytes(buffer); + final int toWrite = (bytesWritten + buffer.length <= sizeBytes) + ? buffer.length : (int) (sizeBytes - bytesWritten); + outputStream.write(buffer, 0, toWrite); + bytesWritten += toWrite; + } + } + + private void dropCache() { + final MacrobenchmarkScope scope = new MacrobenchmarkScope(mContext.getPackageName(), false); + scope.dropKernelPageCache(); + } + private void collectDigestDurationsFromTrace(TraceMarkParser parser, List<Long> durations) { mAtraceUtils.performDump(parser, (key, slices) -> { for (TraceMarkSlice slice : slices) { @@ -119,7 +236,7 @@ public class BlobStorePerfTests { private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception { final FakeBlobData blobData = new FakeBlobData.Builder(mContext) - .setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */) + .setFileSize(DataUnit.MEBIBYTES.toBytes(fileSizeInMb)) .build(); blobData.prepare(); return blobData; diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java index 56db4f98e160..f4692983675d 100644 --- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java +++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java @@ -17,6 +17,7 @@ package com.android.utils.blob; import static com.android.utils.blob.Utils.BUFFER_SIZE_BYTES; import static com.android.utils.blob.Utils.copy; +import static com.android.utils.blob.Utils.writeRandomData; import static com.google.common.truth.Truth.assertThat; @@ -123,7 +124,7 @@ public class FakeBlobData { public void prepare() throws Exception { try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) { - writeRandomData(file, mFileSize); + writeRandomData(file, mRandom, mFileSize); } mFileDigest = FileUtils.digest(mFile, "SHA-256"); mExpiryTimeMs = System.currentTimeMillis() + mExpiryDurationMs; @@ -239,18 +240,4 @@ public class FakeBlobData { } return digest.digest(); } - - private void writeRandomData(RandomAccessFile file, long fileSize) - throws Exception { - long bytesWritten = 0; - final byte[] buffer = new byte[BUFFER_SIZE_BYTES]; - while (bytesWritten < fileSize) { - mRandom.nextBytes(buffer); - final int toWrite = (bytesWritten + buffer.length <= fileSize) - ? buffer.length : (int) (fileSize - bytesWritten); - file.seek(bytesWritten); - file.write(buffer, 0, toWrite); - bytesWritten += toWrite; - } - } } diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java index 2d230a74a477..f6c0e6dbcf22 100644 --- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java +++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java @@ -30,11 +30,14 @@ import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.uiautomator.UiDevice; +import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.util.Random; public class Utils { public static final String TAG = "BlobStoreTest"; @@ -164,6 +167,25 @@ public class Utils { runShellCmd("cmd blob_store idle-maintenance"); } + public static void writeRandomData(File file, long fileSizeBytes) + throws Exception { + writeRandomData(new RandomAccessFile(file, "rw"), new Random(0), fileSizeBytes); + } + + public static void writeRandomData(RandomAccessFile file, Random random, long fileSizeBytes) + throws Exception { + long bytesWritten = 0; + final byte[] buffer = new byte[BUFFER_SIZE_BYTES]; + while (bytesWritten < fileSizeBytes) { + random.nextBytes(buffer); + final int toWrite = (bytesWritten + buffer.length <= fileSizeBytes) + ? buffer.length : (int) (fileSizeBytes - bytesWritten); + file.seek(bytesWritten); + file.write(buffer, 0, toWrite); + bytesWritten += toWrite; + } + } + public static String runShellCmd(String cmd) throws IOException { final UiDevice uiDevice = UiDevice.getInstance( InstrumentationRegistry.getInstrumentation()); |