[automerge] Add read/write perf tests for BlobStore. 2p: 02f0e25661
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17366256 Bug: 226954650 Change-Id: I35df33c98bf6dcb4ad84bec3884e022e22368a14
This commit is contained in:
@@ -22,17 +22,18 @@ package {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android_test {
|
android_test {
|
||||||
name: "BlobStorePerfTests",
|
name: "BlobStorePerfTests",
|
||||||
srcs: ["src/**/*.java"],
|
srcs: ["src/**/*.java"],
|
||||||
static_libs: [
|
static_libs: [
|
||||||
"BlobStoreTestUtils",
|
"BlobStoreTestUtils",
|
||||||
"androidx.test.rules",
|
"androidx.test.rules",
|
||||||
"androidx.annotation_annotation",
|
"androidx.annotation_annotation",
|
||||||
"apct-perftests-utils",
|
"apct-perftests-utils",
|
||||||
"ub-uiautomator",
|
"ub-uiautomator",
|
||||||
"collector-device-lib-platform",
|
"collector-device-lib-platform",
|
||||||
],
|
"androidx.benchmark_benchmark-macro",
|
||||||
platform_apis: true,
|
],
|
||||||
test_suites: ["device-tests"],
|
platform_apis: true,
|
||||||
certificate: "platform",
|
test_suites: ["device-tests"],
|
||||||
|
certificate: "platform",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,15 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.perftests.blob;
|
package com.android.perftests.blob;
|
||||||
|
|
||||||
|
import static com.android.utils.blob.Utils.acquireLease;
|
||||||
|
|
||||||
import android.app.blob.BlobHandle;
|
import android.app.blob.BlobHandle;
|
||||||
import android.app.blob.BlobStoreManager;
|
import android.app.blob.BlobStoreManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.perftests.utils.ManualBenchmarkState;
|
import android.perftests.utils.ManualBenchmarkState;
|
||||||
import android.perftests.utils.PerfManualStatusReporter;
|
import android.perftests.utils.PerfManualStatusReporter;
|
||||||
import android.perftests.utils.TraceMarkParser;
|
import android.perftests.utils.TraceMarkParser;
|
||||||
import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
|
import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
|
||||||
import android.support.test.uiautomator.UiDevice;
|
import android.support.test.uiautomator.UiDevice;
|
||||||
|
import android.util.DataUnit;
|
||||||
|
|
||||||
|
import androidx.benchmark.macro.MacrobenchmarkScope;
|
||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
|
||||||
@@ -36,12 +41,16 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
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
|
// From f/b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
|
||||||
private static final String ATRACE_COMPUTE_DIGEST_PREFIX = "computeBlobDigest-";
|
private static final String ATRACE_COMPUTE_DIGEST_PREFIX = "computeBlobDigest-";
|
||||||
|
|
||||||
|
public static final int BUFFER_SIZE_BYTES = 16 * 1024;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private BlobStoreManager mBlobStoreManager;
|
private BlobStoreManager mBlobStoreManager;
|
||||||
private AtraceUtils mAtraceUtils;
|
private AtraceUtils mAtraceUtils;
|
||||||
@@ -85,6 +96,8 @@ public class BlobStorePerfTests {
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
|
mContext.getFilesDir().delete();
|
||||||
|
runShellCommand("cmd package clear " + mContext.getPackageName());
|
||||||
runShellCommand("cmd blob_store idle-maintenance");
|
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) {
|
private void collectDigestDurationsFromTrace(TraceMarkParser parser, List<Long> durations) {
|
||||||
mAtraceUtils.performDump(parser, (key, slices) -> {
|
mAtraceUtils.performDump(parser, (key, slices) -> {
|
||||||
for (TraceMarkSlice slice : slices) {
|
for (TraceMarkSlice slice : slices) {
|
||||||
@@ -119,7 +236,7 @@ public class BlobStorePerfTests {
|
|||||||
|
|
||||||
private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
|
private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
|
||||||
final FakeBlobData blobData = new FakeBlobData.Builder(mContext)
|
final FakeBlobData blobData = new FakeBlobData.Builder(mContext)
|
||||||
.setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
|
.setFileSize(DataUnit.MEBIBYTES.toBytes(fileSizeInMb))
|
||||||
.build();
|
.build();
|
||||||
blobData.prepare();
|
blobData.prepare();
|
||||||
return blobData;
|
return blobData;
|
||||||
|
|||||||
@@ -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.BUFFER_SIZE_BYTES;
|
||||||
import static com.android.utils.blob.Utils.copy;
|
import static com.android.utils.blob.Utils.copy;
|
||||||
|
import static com.android.utils.blob.Utils.writeRandomData;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ public class FakeBlobData {
|
|||||||
|
|
||||||
public void prepare() throws Exception {
|
public void prepare() throws Exception {
|
||||||
try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
|
try (RandomAccessFile file = new RandomAccessFile(mFile, "rw")) {
|
||||||
writeRandomData(file, mFileSize);
|
writeRandomData(file, mRandom, mFileSize);
|
||||||
}
|
}
|
||||||
mFileDigest = FileUtils.digest(mFile, "SHA-256");
|
mFileDigest = FileUtils.digest(mFile, "SHA-256");
|
||||||
mExpiryTimeMs = System.currentTimeMillis() + mExpiryDurationMs;
|
mExpiryTimeMs = System.currentTimeMillis() + mExpiryDurationMs;
|
||||||
@@ -239,18 +240,4 @@ public class FakeBlobData {
|
|||||||
}
|
}
|
||||||
return digest.digest();
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,14 @@ import android.util.Log;
|
|||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
import androidx.test.uiautomator.UiDevice;
|
import androidx.test.uiautomator.UiDevice;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class Utils {
|
public class Utils {
|
||||||
public static final String TAG = "BlobStoreTest";
|
public static final String TAG = "BlobStoreTest";
|
||||||
@@ -164,6 +167,25 @@ public class Utils {
|
|||||||
runShellCmd("cmd blob_store idle-maintenance");
|
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 {
|
public static String runShellCmd(String cmd) throws IOException {
|
||||||
final UiDevice uiDevice = UiDevice.getInstance(
|
final UiDevice uiDevice = UiDevice.getInstance(
|
||||||
InstrumentationRegistry.getInstrumentation());
|
InstrumentationRegistry.getInstrumentation());
|
||||||
|
|||||||
Reference in New Issue
Block a user