Merge "[benchmark][authfs] Add benchmarks for authfs random read"
diff --git a/authfs/tests/Android.bp b/authfs/tests/Android.bp
index b662bee..0177254 100644
--- a/authfs/tests/Android.bp
+++ b/authfs/tests/Android.bp
@@ -23,6 +23,7 @@
":authfs_test_files",
":CtsApkVerityTestPrebuiltFiles",
":MicrodroidTestApp",
+ ":measure_io",
],
}
@@ -42,3 +43,13 @@
test_suites: ["general-tests"],
test_harness: false,
}
+
+cc_binary {
+ name: "measure_io",
+ srcs: [
+ "measure_io.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+}
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java b/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
index 0dd4613..fb8c0cc 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
@@ -18,6 +18,8 @@
import static com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
+import static com.google.common.truth.Truth.assertThat;
+
import android.platform.test.annotations.RootPermissionTest;
import com.android.microdroid.test.common.MetricsProcessor;
@@ -36,6 +38,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -44,8 +47,13 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public class AuthFsBenchmarks extends BaseHostJUnit4Test {
private static final int TRIAL_COUNT = 5;
- private static final double NANO_SECS_PER_SEC = 1_000_000_000.;
- private static final double INPUT_SIZE_IN_MB = 4.;
+ private static final int FILE_SIZE_IN_MB = 4;
+
+ /** Name of the measure_io binary on host. */
+ private static final String MEASURE_IO_BIN_NAME = "measure_io";
+
+ /** Path to measure_io on Microdroid. */
+ private static final String MEASURE_IO_BIN_PATH = "/data/local/tmp/measure_io";
/** fs-verity digest (sha256) of testdata/input.4m */
private static final String DIGEST_4M =
@@ -76,27 +84,41 @@
@Test
public void seqReadRemoteFile() throws Exception {
- List<Double> transferRates = new ArrayList<>(TRIAL_COUNT);
+ readRemoteFile("seq");
+ }
+
+ @Test
+ public void randReadRemoteFile() throws Exception {
+ readRemoteFile("rand");
+ }
+
+ private void readRemoteFile(String mode) throws DeviceNotAvailableException {
+ pushMeasureIoBinToMicrodroid();
// Cache the file in memory for the host.
- String cmd = "cat " + mAuthFsTestRule.TEST_DIR + "/input.4m > /dev/null";
- mAuthFsTestRule.getAndroid().run(cmd);
+ mAuthFsTestRule
+ .getAndroid()
+ .run("cat " + mAuthFsTestRule.TEST_DIR + "/input.4m > /dev/null");
+
+ String filePath = mAuthFsTestRule.MOUNT_DIR + "/3";
+ String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + FILE_SIZE_IN_MB + " " + mode;
+ List<Double> rates = new ArrayList<>(TRIAL_COUNT);
for (int i = 0; i < TRIAL_COUNT + 1; ++i) {
mAuthFsTestRule.runFdServerOnAndroid(
"--open-ro 3:input.4m --open-ro 4:input.4m.fsv_meta", "--ro-fds 3:4");
mAuthFsTestRule.runAuthFsOnMicrodroid("--remote-ro-file 3:" + DIGEST_4M);
- double elapsedSeconds = measureSeqReadOnMicrodroid("3");
- transferRates.add(INPUT_SIZE_IN_MB / elapsedSeconds);
+
+ String rate = mAuthFsTestRule.getMicrodroid().run(cmd);
+ rates.add(Double.parseDouble(rate));
}
- reportMetrics(transferRates, "seq_read", "mb_per_sec");
+ reportMetrics(rates, mode + "_read", "mb_per_sec");
}
- private double measureSeqReadOnMicrodroid(String filename) throws DeviceNotAvailableException {
- String cmd = "cat " + mAuthFsTestRule.MOUNT_DIR + "/" + filename + " > /dev/null";
- // Ideally, we should measure the time in the VM to avoid the adb and host tests latency.
- double startTime = System.nanoTime();
- mAuthFsTestRule.getMicrodroid().run(cmd);
- double elapsedSeconds = (System.nanoTime() - startTime) / NANO_SECS_PER_SEC;
- return elapsedSeconds;
+ private void pushMeasureIoBinToMicrodroid() throws DeviceNotAvailableException {
+ File measureReadBin = mAuthFsTestRule.findTestFile(getBuild(), MEASURE_IO_BIN_NAME);
+ assertThat(measureReadBin.exists()).isTrue();
+ mAuthFsTestRule.getMicrodroidDevice().pushFile(measureReadBin, MEASURE_IO_BIN_PATH);
+ assertThat(mAuthFsTestRule.getMicrodroid().run("ls " + MEASURE_IO_BIN_PATH))
+ .isEqualTo(MEASURE_IO_BIN_PATH);
}
private void reportMetrics(List<Double> metrics, String name, String unit) {
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
index 2deb490..14dc88b 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
@@ -52,7 +52,7 @@
private static final String FSVERITY_BIN = "/data/local/tmp/fsverity";
/** Mount point of authfs on Microdroid during the test */
- private static final String MOUNT_DIR = "/data/local/tmp";
+ private static final String MOUNT_DIR = AuthFsTestRule.MOUNT_DIR;
/** Input manifest path in the VM. */
private static final String INPUT_MANIFEST_PATH = "/mnt/apk/assets/input_manifest.pb";
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java b/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
index 34a403e..ebeac4f 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
@@ -65,7 +65,7 @@
private static final String TEST_OUTPUT_DIR = "/data/local/tmp/authfs/output_dir";
/** Mount point of authfs on Microdroid during the test */
- static final String MOUNT_DIR = "/data/local/tmp";
+ static final String MOUNT_DIR = "/data/local/tmp/mnt";
/** VM's log file */
private static final String LOG_PATH = TEST_OUTPUT_DIR + "/log.txt";
@@ -85,6 +85,7 @@
private static final int VMADDR_CID_HOST = 2;
private static TestInformation sTestInfo;
+ private static ITestDevice sMicrodroidDevice;
private static CommandRunner sAndroid;
private static CommandRunner sMicrodroid;
@@ -110,18 +111,21 @@
// For each test case, boot and adb connect to a new Microdroid
CLog.i("Starting the shared VM");
- ITestDevice microdroidDevice =
+ sMicrodroidDevice =
MicrodroidBuilder.fromFile(
- findTestApk(testInfo.getBuildInfo()), VM_CONFIG_PATH_IN_APK)
+ findTestFile(testInfo.getBuildInfo(), TEST_APK_NAME),
+ VM_CONFIG_PATH_IN_APK)
.debugLevel("full")
.build((TestDevice) androidDevice);
// From this point on, we need to tear down the Microdroid instance
- sMicrodroid = new CommandRunner(microdroidDevice);
+ sMicrodroid = new CommandRunner(sMicrodroidDevice);
+
+ sMicrodroid.runForResult("mkdir -p " + MOUNT_DIR);
// Root because authfs (started from shell in this test) currently require root to open
// /dev/fuse and mount the FUSE.
- assertThat(microdroidDevice.enableAdbRoot()).isTrue();
+ assertThat(sMicrodroidDevice.enableAdbRoot()).isTrue();
}
static void tearDownClass(TestInformation testInfo) throws DeviceNotAvailableException {
@@ -148,6 +152,11 @@
return sMicrodroid;
}
+ static ITestDevice getMicrodroidDevice() {
+ assertThat(sMicrodroidDevice).isNotNull();
+ return sMicrodroidDevice;
+ }
+
@Override
public Statement apply(final Statement base, Description description) {
return super.apply(
@@ -205,11 +214,11 @@
}
}
- private static File findTestApk(IBuildInfo buildInfo) {
+ static File findTestFile(IBuildInfo buildInfo, String fileName) {
try {
- return (new CompatibilityBuildHelper(buildInfo)).getTestFile(TEST_APK_NAME);
+ return (new CompatibilityBuildHelper(buildInfo)).getTestFile(fileName);
} catch (FileNotFoundException e) {
- fail("Missing test file: " + TEST_APK_NAME);
+ fail("Missing test file: " + fileName);
return null;
}
}
diff --git a/authfs/tests/measure_io.cpp b/authfs/tests/measure_io.cpp
new file mode 100644
index 0000000..736c244
--- /dev/null
+++ b/authfs/tests/measure_io.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <android-base/unique_fd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <iostream>
+#include <random>
+
+using android::base::unique_fd;
+
+constexpr int kBlockSizeBytes = 4096;
+constexpr int kNumBytesPerMB = 1024 * 1024;
+
+int main(int argc, const char *argv[]) {
+ if (argc != 4 || !(strcmp(argv[3], "rand") == 0 || strcmp(argv[3], "seq") == 0)) {
+ std::cerr << "Usage: " << argv[0] << " <filename> <file_size_mb> <rand|seq>" << std::endl;
+ return EXIT_FAILURE;
+ }
+ int file_size_mb = std::stoi(argv[2]);
+ bool is_rand = (strcmp(argv[3], "rand") == 0);
+ const int block_count = file_size_mb * kNumBytesPerMB / kBlockSizeBytes;
+ std::vector<int> offsets(block_count);
+ for (auto i = 0; i < block_count; ++i) {
+ offsets[i] = i * kBlockSizeBytes;
+ }
+ if (is_rand) {
+ std::mt19937 rd{std::random_device{}()};
+ std::shuffle(offsets.begin(), offsets.end(), rd);
+ }
+ unique_fd fd(open(argv[1], O_RDONLY | O_CLOEXEC));
+ if (fd.get() == -1) {
+ std::cerr << "failed to open file: " << argv[1] << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ char buf[kBlockSizeBytes];
+ clock_t start = clock();
+ for (auto i = 0; i < block_count; ++i) {
+ auto bytes = pread(fd, buf, kBlockSizeBytes, offsets[i]);
+ if (bytes == 0) {
+ std::cerr << "unexpected end of file" << std::endl;
+ return EXIT_FAILURE;
+ } else if (bytes == -1) {
+ std::cerr << "failed to read" << std::endl;
+ return EXIT_FAILURE;
+ }
+ }
+ double elapsed_seconds = ((double)clock() - start) / CLOCKS_PER_SEC;
+ double rate = (double)file_size_mb / elapsed_seconds;
+ std::cout << std::setprecision(12) << rate << std::endl;
+
+ return EXIT_SUCCESS;
+}