gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 - buf.size())) == 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