Newer
Older
/*
* 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 <aidl/android/system/virtualmachineservice/IVirtualMachineService.h>
#include <aidl/com/android/microdroid/testservice/BnBenchmarkService.h>
#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <fcntl.h>
#include <linux/vm_sockets.h>
#include <stdio.h>
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <binder_rpc_unstable.hpp>
#include <chrono>
#include <random>
#include <string>
#include "android-base/logging.h"
using aidl::android::system::virtualmachineservice::IVirtualMachineService;
using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
using android::base::unique_fd;
namespace {
constexpr uint64_t kBlockSizeBytes = 4096;
class IOBenchmarkService : public aidl::com::android::microdroid::testservice::BnBenchmarkService {
public:
ndk::ScopedAStatus readFile(const std::string& filename, int64_t fileSizeBytes, bool isRand,
double* out) override {
if (auto res = read_file(filename, fileSizeBytes, isRand); res.ok()) {
*out = res.value();
} else {
std::stringstream error;
error << "Failed reading file: " << res.error();
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
error.str().c_str());
}
return ndk::ScopedAStatus::ok();
}
private:
/** Returns the elapsed seconds for reading the file. */
Result<double> read_file(const std::string& filename, int64_t fileSizeBytes, bool is_rand) {
const int64_t block_count = fileSizeBytes / kBlockSizeBytes;
std::vector<uint64_t> offsets;
if (is_rand) {
std::mt19937 rd{std::random_device{}()};
offsets.reserve(block_count);
for (auto i = 0; i < block_count; ++i) offsets.push_back(i * kBlockSizeBytes);
std::shuffle(offsets.begin(), offsets.end(), rd);
}
char buf[kBlockSizeBytes];
clock_t start = clock();
unique_fd fd(open(filename.c_str(), O_RDONLY | O_CLOEXEC));
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
if (fd.get() == -1) {
return ErrnoError() << "Read: opening " << filename << " failed";
}
for (auto i = 0; i < block_count; ++i) {
if (is_rand) {
if (lseek(fd.get(), offsets[i], SEEK_SET) == -1) {
return ErrnoError() << "failed to lseek";
}
}
auto bytes = read(fd.get(), buf, kBlockSizeBytes);
if (bytes == 0) {
return Error() << "unexpected end of file";
} else if (bytes == -1) {
return ErrnoError() << "failed to read";
}
}
return {((double)clock() - start) / CLOCKS_PER_SEC};
}
};
Result<void> run_io_benchmark_tests() {
auto test_service = ndk::SharedRefBase::make<IOBenchmarkService>();
auto callback = []([[maybe_unused]] void* param) {
// Tell microdroid_manager that we're ready.
// If we can't, abort in order to fail fast - the host won't proceed without
// receiving the onReady signal.
ndk::SpAIBinder binder(
RpcClient(VMADDR_CID_HOST, IVirtualMachineService::VM_BINDER_SERVICE_PORT));
auto vm_service = IVirtualMachineService::fromBinder(binder);
if (vm_service == nullptr) {
LOG(ERROR) << "failed to connect VirtualMachineService\n";
abort();
}
if (auto status = vm_service->notifyPayloadReady(); !status.isOk()) {
LOG(ERROR) << "failed to notify payload ready to virtualizationservice: "
<< status.getDescription();
abort();
}
};
if (!RunRpcServerCallback(test_service->asBinder().get(), test_service->SERVICE_PORT, callback,
nullptr)) {
return Error() << "RPC Server failed to run";
}
return {};
}
} // Anonymous namespace
extern "C" int android_native_main([[maybe_unused]] int argc, char* argv[]) {
if (strcmp(argv[1], "no_io") == 0) {
// do nothing for now; just leave it alive. good night.
for (;;) {
sleep(1000);
}
} else if (strcmp(argv[1], "io") == 0) {
if (auto res = run_io_benchmark_tests(); res.ok()) {
return 0;
} else {
LOG(ERROR) << "IO benchmark test failed: " << res.error() << "\n";
return 1;
}