blob: 70c68849198d233e9678e259a2864b714dbe003d [file] [log] [blame]
Inseob Kim5d5476b2022-06-27 13:22:09 +09001/*
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 */
Alice Wang246108f2022-07-25 14:44:13 +000016
Alice Wang246108f2022-07-25 14:44:13 +000017#include <aidl/com/android/microdroid/testservice/BnBenchmarkService.h>
Alice Wang98e6e8a2022-08-08 15:31:58 +000018#include <android-base/logging.h>
19#include <android-base/parseint.h>
Alice Wang246108f2022-07-25 14:44:13 +000020#include <android-base/result.h>
Alice Wang98e6e8a2022-08-08 15:31:58 +000021#include <android-base/strings.h>
Alice Wang246108f2022-07-25 14:44:13 +000022#include <android-base/unique_fd.h>
23#include <fcntl.h>
24#include <linux/vm_sockets.h>
25#include <stdio.h>
Alice Wang98e6e8a2022-08-08 15:31:58 +000026#include <time.h>
Inseob Kim5d5476b2022-06-27 13:22:09 +090027#include <unistd.h>
Alan Stokes52d3c722022-10-04 17:27:13 +010028#include <vm_main.h>
Alice Wang4d370e62022-10-11 08:33:34 +000029#include <vm_payload.h>
Inseob Kim5d5476b2022-06-27 13:22:09 +090030
David Brazdila2129e02022-08-19 14:01:44 +010031#include <fstream>
Alice Wang246108f2022-07-25 14:44:13 +000032#include <random>
33#include <string>
34
Alice Wang98e6e8a2022-08-08 15:31:58 +000035#include "io_vsock.h"
Alice Wang246108f2022-07-25 14:44:13 +000036
Alice Wang246108f2022-07-25 14:44:13 +000037using android::base::ErrnoError;
38using android::base::Error;
39using android::base::Result;
40using android::base::unique_fd;
41
42namespace {
43constexpr uint64_t kBlockSizeBytes = 4096;
Alice Wangf2685f62022-09-06 07:26:53 +000044constexpr uint64_t kNumBytesPerMB = 1024 * 1024;
Alice Wang246108f2022-07-25 14:44:13 +000045
David Brazdila2129e02022-08-19 14:01:44 +010046template <typename T>
47static ndk::ScopedAStatus resultStatus(const T& result) {
48 if (!result.ok()) {
49 std::stringstream error;
50 error << result.error();
51 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
52 error.str().c_str());
53 }
54 return ndk::ScopedAStatus::ok();
55}
56
Alice Wang246108f2022-07-25 14:44:13 +000057class IOBenchmarkService : public aidl::com::android::microdroid::testservice::BnBenchmarkService {
58public:
Alice Wangf2685f62022-09-06 07:26:53 +000059 ndk::ScopedAStatus measureReadRate(const std::string& filename, int64_t fileSizeBytes,
60 bool isRand, double* out) override {
61 auto res = measure_read_rate(filename, fileSizeBytes, isRand);
David Brazdila2129e02022-08-19 14:01:44 +010062 if (res.ok()) {
Alice Wang246108f2022-07-25 14:44:13 +000063 *out = res.value();
Alice Wang246108f2022-07-25 14:44:13 +000064 }
David Brazdila2129e02022-08-19 14:01:44 +010065 return resultStatus(res);
66 }
67
68 ndk::ScopedAStatus getMemInfoEntry(const std::string& name, int64_t* out) override {
69 auto value = read_meminfo_entry(name);
70 if (!value.ok()) {
71 return resultStatus(value);
72 }
73
74 *out = (int64_t)value.value();
Alice Wang246108f2022-07-25 14:44:13 +000075 return ndk::ScopedAStatus::ok();
Inseob Kim5d5476b2022-06-27 13:22:09 +090076 }
Alice Wang246108f2022-07-25 14:44:13 +000077
Alice Wang98e6e8a2022-08-08 15:31:58 +000078 ndk::ScopedAStatus initVsockServer(int32_t port, int32_t* out) override {
79 auto res = io_vsock::init_vsock_server(port);
80 if (res.ok()) {
81 *out = res.value();
82 }
83 return resultStatus(res);
84 }
85
86 ndk::ScopedAStatus runVsockServerAndReceiveData(int32_t server_fd,
87 int32_t num_bytes_to_receive) override {
88 auto res = io_vsock::run_vsock_server_and_receive_data(server_fd, num_bytes_to_receive);
89 return resultStatus(res);
90 }
91
Alice Wang246108f2022-07-25 14:44:13 +000092private:
Alice Wangf2685f62022-09-06 07:26:53 +000093 /** Measures the read rate for reading the given file. */
94 Result<double> measure_read_rate(const std::string& filename, int64_t fileSizeBytes,
95 bool is_rand) {
Alice Wang246108f2022-07-25 14:44:13 +000096 const int64_t block_count = fileSizeBytes / kBlockSizeBytes;
Alice Wang3e963dc2022-11-14 08:43:04 +000097 std::vector<uint64_t> offsets(block_count);
98 for (auto i = 0; i < block_count; ++i) {
Alice Wang7067a702022-11-15 09:49:57 +000099 offsets[i] = i * kBlockSizeBytes;
Alice Wang3e963dc2022-11-14 08:43:04 +0000100 }
Alice Wang246108f2022-07-25 14:44:13 +0000101 if (is_rand) {
102 std::mt19937 rd{std::random_device{}()};
Alice Wang246108f2022-07-25 14:44:13 +0000103 std::shuffle(offsets.begin(), offsets.end(), rd);
104 }
105 char buf[kBlockSizeBytes];
106
107 clock_t start = clock();
Alice Wangfc24b372022-07-28 16:45:42 +0000108 unique_fd fd(open(filename.c_str(), O_RDONLY | O_CLOEXEC));
Alice Wang246108f2022-07-25 14:44:13 +0000109 if (fd.get() == -1) {
110 return ErrnoError() << "Read: opening " << filename << " failed";
111 }
112 for (auto i = 0; i < block_count; ++i) {
Alice Wang3e963dc2022-11-14 08:43:04 +0000113 auto bytes = pread(fd, buf, kBlockSizeBytes, offsets[i]);
Alice Wang246108f2022-07-25 14:44:13 +0000114 if (bytes == 0) {
115 return Error() << "unexpected end of file";
116 } else if (bytes == -1) {
117 return ErrnoError() << "failed to read";
118 }
119 }
Alice Wangf2685f62022-09-06 07:26:53 +0000120 double elapsed_seconds = ((double)clock() - start) / CLOCKS_PER_SEC;
121 double read_rate = (double)fileSizeBytes / kNumBytesPerMB / elapsed_seconds;
122 return {read_rate};
Alice Wang246108f2022-07-25 14:44:13 +0000123 }
David Brazdila2129e02022-08-19 14:01:44 +0100124
125 Result<size_t> read_meminfo_entry(const std::string& stat) {
126 std::ifstream fs("/proc/meminfo");
127 if (!fs.is_open()) {
128 return Error() << "could not open /proc/meminfo";
129 }
130
131 std::string line;
132 while (std::getline(fs, line)) {
133 auto elems = android::base::Split(line, ":");
134 if (elems[0] != stat) continue;
135
136 std::string str = android::base::Trim(elems[1]);
137 if (android::base::EndsWith(str, " kB")) {
138 str = str.substr(0, str.length() - 3);
139 }
140
141 size_t value;
142 if (!android::base::ParseUint(str, &value)) {
143 return ErrnoError() << "failed to parse \"" << str << "\" as size_t";
144 }
145 return {value};
146 }
147
148 return Error() << "entry \"" << stat << "\" not found";
149 }
Alice Wang246108f2022-07-25 14:44:13 +0000150};
151
152Result<void> run_io_benchmark_tests() {
153 auto test_service = ndk::SharedRefBase::make<IOBenchmarkService>();
154 auto callback = []([[maybe_unused]] void* param) {
Andrew Scull655e98e2022-10-10 22:24:58 +0000155 if (!AVmPayload_notifyPayloadReady()) {
Alice Wang4d370e62022-10-11 08:33:34 +0000156 LOG(ERROR) << "failed to notify payload ready to virtualizationservice";
Alice Wang246108f2022-07-25 14:44:13 +0000157 abort();
158 }
159 };
Alice Wang1a5d6ac2022-10-17 07:43:31 +0000160 if (!AVmPayload_runVsockRpcServer(test_service->asBinder().get(), test_service->SERVICE_PORT,
161 callback, nullptr)) {
Alice Wang246108f2022-07-25 14:44:13 +0000162 return Error() << "RPC Server failed to run";
163 }
164 return {};
165}
166} // Anonymous namespace
167
Alan Stokes52d3c722022-10-04 17:27:13 +0100168extern "C" int AVmPayload_main() {
Alan Stokes38d00f82022-10-03 17:43:45 +0100169 if (auto res = run_io_benchmark_tests(); !res.ok()) {
170 LOG(ERROR) << "IO benchmark test failed: " << res.error() << "\n";
171 return EXIT_FAILURE;
Alice Wang246108f2022-07-25 14:44:13 +0000172 }
Alice Wang98e6e8a2022-08-08 15:31:58 +0000173 return EXIT_SUCCESS;
Inseob Kim5d5476b2022-06-27 13:22:09 +0900174}