github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/perf/linux/randread_benchmark.cc (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <fcntl.h> 16 #include <stdlib.h> 17 #include <sys/stat.h> 18 #include <sys/uio.h> 19 #include <unistd.h> 20 21 #include "gtest/gtest.h" 22 #include "benchmark/benchmark.h" 23 #include "test/util/file_descriptor.h" 24 #include "test/util/logging.h" 25 #include "test/util/temp_path.h" 26 #include "test/util/test_util.h" 27 28 namespace gvisor { 29 namespace testing { 30 31 namespace { 32 33 // Create a 1GB file that will be read from at random positions. This should 34 // invalid any performance gains from caching. 35 const uint64_t kFileSize = 1ULL << 30; 36 37 // How many bytes to write at once to initialize the file used to read from. 38 const uint32_t kWriteSize = 65536; 39 40 // Largest benchmarked read unit. 41 const uint32_t kMaxRead = 1UL << 26; 42 43 TempPath CreateFile(uint64_t file_size) { 44 auto path = TempPath::CreateFile().ValueOrDie(); 45 FileDescriptor fd = Open(path.path(), O_WRONLY).ValueOrDie(); 46 47 // Try to minimize syscalls by using maximum size writev() requests. 48 std::vector<char> buffer(kWriteSize); 49 RandomizeBuffer(buffer.data(), buffer.size()); 50 const std::vector<std::vector<struct iovec>> iovecs_list = 51 GenerateIovecs(file_size, buffer.data(), buffer.size()); 52 for (const auto& iovecs : iovecs_list) { 53 TEST_CHECK(writev(fd.get(), iovecs.data(), iovecs.size()) >= 0); 54 } 55 56 return path; 57 } 58 59 // Global test state, initialized once per process lifetime. 60 struct GlobalState { 61 const TempPath tmpfile; 62 explicit GlobalState(TempPath tfile) : tmpfile(std::move(tfile)) {} 63 }; 64 65 GlobalState& GetGlobalState() { 66 // This gets created only once throughout the lifetime of the process. 67 // Use a dynamically allocated object (that is never deleted) to avoid order 68 // of destruction of static storage variables issues. 69 static GlobalState* const state = 70 // The actual file size is the maximum random seek range (kFileSize) + the 71 // maximum read size so we can read that number of bytes at the end of the 72 // file. 73 new GlobalState(CreateFile(kFileSize + kMaxRead)); 74 return *state; 75 } 76 77 void BM_RandRead(benchmark::State& state) { 78 const int size = state.range(0); 79 80 GlobalState& global_state = GetGlobalState(); 81 FileDescriptor fd = 82 ASSERT_NO_ERRNO_AND_VALUE(Open(global_state.tmpfile.path(), O_RDONLY)); 83 std::vector<char> buf(size); 84 85 unsigned int seed = 1; 86 for (auto _ : state) { 87 TEST_CHECK(PreadFd(fd.get(), buf.data(), buf.size(), 88 rand_r(&seed) % kFileSize) == size); 89 } 90 91 state.SetBytesProcessed(static_cast<int64_t>(size) * 92 static_cast<int64_t>(state.iterations())); 93 } 94 95 BENCHMARK(BM_RandRead)->Range(1, kMaxRead)->UseRealTime(); 96 97 } // namespace 98 99 } // namespace testing 100 } // namespace gvisor