1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.virt.fs.benchmarks; 18 19 import static com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics; 20 21 22 import static org.junit.Assume.assumeFalse; 23 import static org.junit.Assume.assumeTrue; 24 25 import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters; 26 import android.cts.host.utils.DeviceJUnit4Parameterized; 27 import android.platform.test.annotations.RootPermissionTest; 28 29 import com.android.fs.common.AuthFsTestRule; 30 import com.android.microdroid.test.common.DeviceProperties; 31 import com.android.microdroid.test.common.MetricsProcessor; 32 import com.android.tradefed.device.DeviceNotAvailableException; 33 import com.android.tradefed.metrics.proto.MetricMeasurement.DataType; 34 import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements; 35 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 36 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 37 38 import org.junit.After; 39 import org.junit.AfterClass; 40 import org.junit.Before; 41 import org.junit.Rule; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.junit.runners.Parameterized; 45 import org.junit.runners.Parameterized.UseParametersRunnerFactory; 46 47 import java.util.ArrayList; 48 import java.util.Collection; 49 import java.util.List; 50 import java.util.Map; 51 52 @RootPermissionTest 53 @RunWith(DeviceJUnit4Parameterized.class) 54 @UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class) 55 public class AuthFsBenchmarks extends BaseHostJUnit4Test { 56 private static final int TRIAL_COUNT = 5; 57 58 /** Path to measure_io on Microdroid. */ 59 private static final String MEASURE_IO_BIN_PATH = "/mnt/apk/bin/measure_io"; 60 61 /** fs-verity digest (sha256) of testdata/input.4m */ 62 private static final String DIGEST_4M = 63 "sha256-f18a268d565348fb4bbf11f10480b198f98f2922eb711de149857b3cecf98a8d"; 64 65 @Parameterized.Parameter(0) 66 public boolean mProtectedVm; 67 68 @Rule public final AuthFsTestRule mAuthFsTestRule = new AuthFsTestRule(); 69 @Rule public final TestMetrics mTestMetrics = new TestMetrics(); 70 private MetricsProcessor mMetricsProcessor; 71 72 @Parameterized.Parameters(name = "protectedVm={0}") params()73 public static Collection<Object[]> params() { 74 return List.of(new Object[] {true}, new Object[] {false}); 75 } 76 77 @Before setUp()78 public void setUp() throws Exception { 79 AuthFsTestRule.setUpAndroid(getTestInformation()); 80 mAuthFsTestRule.setUpTest(); 81 assumeTrue(AuthFsTestRule.getDevice().supportsMicrodroid(mProtectedVm)); 82 DeviceProperties deviceProperties = DeviceProperties.create(getDevice()::getProperty); 83 assumeFalse( 84 "Skip on CF; no need to collect metrics on CF", deviceProperties.isCuttlefish()); 85 String metricsPrefix = MetricsProcessor.getMetricPrefix(deviceProperties.getMetricsTag()); 86 mMetricsProcessor = new MetricsProcessor(metricsPrefix + "authfs/"); 87 AuthFsTestRule.startMicrodroid(mProtectedVm); 88 } 89 90 @After tearDown()91 public void tearDown() throws DeviceNotAvailableException { 92 AuthFsTestRule.shutdownMicrodroid(); 93 } 94 95 @AfterClass tearDownClass()96 public static void tearDownClass() { 97 AuthFsTestRule.tearDownAndroid(); 98 } 99 100 @Test seqReadRemoteFile()101 public void seqReadRemoteFile() throws Exception { 102 readRemoteFile("seq"); 103 } 104 105 @Test randReadRemoteFile()106 public void randReadRemoteFile() throws Exception { 107 readRemoteFile("rand"); 108 } 109 110 @Test seqWriteRemoteFile()111 public void seqWriteRemoteFile() throws Exception { 112 writeRemoteFile("seq"); 113 } 114 115 @Test randWriteRemoteFile()116 public void randWriteRemoteFile() throws Exception { 117 writeRemoteFile("rand"); 118 } 119 readRemoteFile(String mode)120 private void readRemoteFile(String mode) throws DeviceNotAvailableException { 121 // Cache the file in memory for the host. 122 mAuthFsTestRule 123 .getAndroid() 124 .run("cat " + mAuthFsTestRule.TEST_DIR + "/input.4m > /dev/null"); 125 126 String filePath = mAuthFsTestRule.MOUNT_DIR + "/3"; 127 int fileSizeMb = 4; 128 String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + fileSizeMb + " " + mode + " r"; 129 List<Double> rates = new ArrayList<>(TRIAL_COUNT); 130 for (int i = 0; i < TRIAL_COUNT + 1; ++i) { 131 mAuthFsTestRule.runFdServerOnAndroid( 132 "--open-ro 3:input.4m --open-ro 4:input.4m.fsv_meta", "--ro-fds 3:4"); 133 mAuthFsTestRule.runAuthFsOnMicrodroid("--remote-ro-file 3:" + DIGEST_4M); 134 135 String rate = mAuthFsTestRule.getMicrodroid().run(cmd); 136 rates.add(Double.parseDouble(rate)); 137 mAuthFsTestRule.killFdServerOnAndroid(); 138 } 139 reportMetrics(rates, mode + "_read", "mb_per_sec"); 140 } 141 writeRemoteFile(String mode)142 private void writeRemoteFile(String mode) throws DeviceNotAvailableException { 143 String filePath = mAuthFsTestRule.MOUNT_DIR + "/5"; 144 int fileSizeMb = 8; 145 String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + fileSizeMb + " " + mode + " w"; 146 List<Double> rates = new ArrayList<>(TRIAL_COUNT); 147 for (int i = 0; i < TRIAL_COUNT + 1; ++i) { 148 mAuthFsTestRule.runFdServerOnAndroid( 149 "--open-rw 5:" + AuthFsTestRule.TEST_OUTPUT_DIR + "/out.file", "--rw-fds 5"); 150 mAuthFsTestRule.runAuthFsOnMicrodroid("--remote-new-rw-file 5"); 151 152 String rate = mAuthFsTestRule.getMicrodroid().run(cmd); 153 rates.add(Double.parseDouble(rate)); 154 mAuthFsTestRule.killFdServerOnAndroid(); 155 AuthFsTestRule.getAndroid() 156 .runForResult("rm", "-rf", AuthFsTestRule.TEST_OUTPUT_DIR + "/out.file"); 157 } 158 reportMetrics(rates, mode + "_write", "mb_per_sec"); 159 } 160 reportMetrics(List<Double> metrics, String name, String unit)161 private void reportMetrics(List<Double> metrics, String name, String unit) { 162 Map<String, Double> stats = mMetricsProcessor.computeStats(metrics, name, unit); 163 for (Map.Entry<String, Double> entry : stats.entrySet()) { 164 Metric metric = 165 Metric.newBuilder() 166 .setType(DataType.RAW) 167 .setMeasurements( 168 Measurements.newBuilder().setSingleDouble(entry.getValue())) 169 .build(); 170 mTestMetrics.addTestMetric(entry.getKey(), metric); 171 } 172 } 173 } 174