Merge "Add read/write perf tests for BlobStore." into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
31f41f729f
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user