[benchmark] Add benchmarks for authfs seq/rand write

This CL adds benchmarks for authfs remote write in sequential
and random modes.

Test: atest AuthFsBenchmarks
Bug: 236123069
Change-Id: Ib13aa46a0e8bf17f89d80ff88d6dc1ca02582be2
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java b/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
index fb8c0cc..f84785b 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsBenchmarks.java
@@ -47,7 +47,6 @@
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class AuthFsBenchmarks extends BaseHostJUnit4Test {
     private static final int TRIAL_COUNT = 5;
-    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";
@@ -92,6 +91,16 @@
         readRemoteFile("rand");
     }
 
+    @Test
+    public void seqWriteRemoteFile() throws Exception {
+        writeRemoteFile("seq");
+    }
+
+    @Test
+    public void randWriteRemoteFile() throws Exception {
+        writeRemoteFile("rand");
+    }
+
     private void readRemoteFile(String mode) throws DeviceNotAvailableException {
         pushMeasureIoBinToMicrodroid();
         // Cache the file in memory for the host.
@@ -100,7 +109,8 @@
                 .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;
+        int fileSizeMb = 4;
+        String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + fileSizeMb + " " + mode + " r";
         List<Double> rates = new ArrayList<>(TRIAL_COUNT);
         for (int i = 0; i < TRIAL_COUNT + 1; ++i) {
             mAuthFsTestRule.runFdServerOnAndroid(
@@ -113,6 +123,23 @@
         reportMetrics(rates, mode + "_read", "mb_per_sec");
     }
 
+    private void writeRemoteFile(String mode) throws DeviceNotAvailableException {
+        pushMeasureIoBinToMicrodroid();
+        String filePath = mAuthFsTestRule.MOUNT_DIR + "/5";
+        int fileSizeMb = 8;
+        String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + fileSizeMb + " " + mode + " w";
+        List<Double> rates = new ArrayList<>(TRIAL_COUNT);
+        for (int i = 0; i < TRIAL_COUNT + 1; ++i) {
+            mAuthFsTestRule.runFdServerOnAndroid(
+                    "--open-rw 5:" + mAuthFsTestRule.TEST_OUTPUT_DIR + "/out.file", "--rw-fds 5");
+            mAuthFsTestRule.runAuthFsOnMicrodroid("--remote-new-rw-file 5");
+
+            String rate = mAuthFsTestRule.getMicrodroid().run(cmd);
+            rates.add(Double.parseDouble(rate));
+        }
+        reportMetrics(rates, mode + "_write", "mb_per_sec");
+    }
+
     private void pushMeasureIoBinToMicrodroid() throws DeviceNotAvailableException {
         File measureReadBin = mAuthFsTestRule.findTestFile(getBuild(), MEASURE_IO_BIN_NAME);
         assertThat(measureReadBin.exists()).isTrue();
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java b/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
index ebeac4f..045ecc0 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsTestRule.java
@@ -62,7 +62,7 @@
     private static final String TEST_APK_NAME = "MicrodroidTestApp.apk";
 
     /** Output directory where the test can generate output on Android */
-    private static final String TEST_OUTPUT_DIR = "/data/local/tmp/authfs/output_dir";
+    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/mnt";
diff --git a/authfs/tests/measure_io.cpp b/authfs/tests/measure_io.cpp
index e9548ae..e1f2fb8 100644
--- a/authfs/tests/measure_io.cpp
+++ b/authfs/tests/measure_io.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/unique_fd.h>
+#include <assert.h>
 #include <err.h>
 #include <fcntl.h>
 #include <string.h>
@@ -32,11 +33,13 @@
 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)) {
-        errx(EXIT_FAILURE, "Usage: %s <filename> <file_size_mb> <rand|seq>", argv[0]);
+    if (argc != 5 || !(strcmp(argv[3], "rand") == 0 || strcmp(argv[3], "seq") == 0) ||
+        !(strcmp(argv[4], "r") == 0 || strcmp(argv[4], "w") == 0)) {
+        errx(EXIT_FAILURE, "Usage: %s <filename> <file_size_mb> <rand|seq> <r|w>", argv[0]);
     }
     int file_size_mb = std::stoi(argv[2]);
     bool is_rand = (strcmp(argv[3], "rand") == 0);
+    bool is_read = (strcmp(argv[4], "r") == 0);
     const int block_count = file_size_mb * kNumBytesPerMB / kBlockSizeBytes;
     std::vector<int> offsets(block_count);
     for (auto i = 0; i < block_count; ++i) {
@@ -46,7 +49,7 @@
         std::mt19937 rd{std::random_device{}()};
         std::shuffle(offsets.begin(), offsets.end(), rd);
     }
-    unique_fd fd(open(argv[1], O_RDONLY | O_CLOEXEC));
+    unique_fd fd(open(argv[1], (is_read ? O_RDONLY : O_WRONLY) | O_CLOEXEC));
     if (fd.get() == -1) {
         errx(EXIT_FAILURE, "failed to open file: %s", argv[1]);
     }
@@ -54,13 +57,18 @@
     char buf[kBlockSizeBytes];
     clock_t start = clock();
     for (auto i = 0; i < block_count; ++i) {
-        auto bytes = pread(fd, buf, kBlockSizeBytes, offsets[i]);
+        auto bytes = is_read ? pread(fd, buf, kBlockSizeBytes, offsets[i])
+                             : pwrite(fd, buf, kBlockSizeBytes, offsets[i]);
         if (bytes == 0) {
             errx(EXIT_FAILURE, "unexpected end of file");
         } else if (bytes == -1) {
             errx(EXIT_FAILURE, "failed to read");
         }
     }
+    if (!is_read) {
+        // Writes all the buffered modifications to the open file.
+        assert(syncfs(fd) == 0);
+    }
     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;