brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · f5559be Raw
240 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/Program.h"10#include "llvm/CAS/MappedFileRegionArena.h"11#include "llvm/Config/llvm-config.h"12#include "llvm/Support/ConvertUTF.h"13#include "llvm/Support/ExponentialBackoff.h"14#include "llvm/Support/FileSystem.h"15#include "llvm/Support/Path.h"16#include "llvm/Support/ThreadPool.h"17#include "llvm/Testing/Support/Error.h"18#include "gtest/gtest.h"19#if defined(__APPLE__)20#include <crt_externs.h>21#elif !defined(_MSC_VER)22// Forward declare environ in case it's not provided by stdlib.h.23extern char **environ;24#endif25 26using namespace llvm;27using namespace llvm::cas;28 29#if LLVM_ENABLE_ONDISK_CAS30 31extern const char *TestMainArgv0;32static char ProgramID = 0;33 34class CASProgramTest : public testing::Test {35  std::vector<StringRef> EnvTable;36  std::vector<std::string> EnvStorage;37 38protected:39  void SetUp() override {40    auto EnvP = [] {41#if defined(_WIN32)42      _wgetenv(L"TMP"); // Populate _wenviron, initially is null43      return _wenviron;44#elif defined(__APPLE__)45      return *_NSGetEnviron();46#else47      return environ;48#endif49    }();50    ASSERT_TRUE(EnvP);51 52    auto prepareEnvVar = [this](decltype(*EnvP) Var) -> StringRef {53#if defined(_WIN32)54      // On Windows convert UTF16 encoded variable to UTF855      auto Len = wcslen(Var);56      ArrayRef<char> Ref{reinterpret_cast<char const *>(Var),57                         Len * sizeof(*Var)};58      EnvStorage.emplace_back();59      auto convStatus = llvm::convertUTF16ToUTF8String(Ref, EnvStorage.back());60      EXPECT_TRUE(convStatus);61      return EnvStorage.back();62#else63      (void)this;64      return StringRef(Var);65#endif66    };67 68    while (*EnvP != nullptr) {69      auto S = prepareEnvVar(*EnvP);70      if (!StringRef(S).starts_with("GTEST_"))71        EnvTable.emplace_back(S);72      ++EnvP;73    }74  }75 76  void TearDown() override {77    EnvTable.clear();78    EnvStorage.clear();79  }80 81  void addEnvVar(StringRef Var) { EnvTable.emplace_back(Var); }82 83  ArrayRef<StringRef> getEnviron() const { return EnvTable; }84};85 86static Error emptyConstructor(MappedFileRegionArena &) {87  return Error::success();88}89 90TEST_F(CASProgramTest, MappedFileRegionArenaTest) {91  auto TestAllocator = [](StringRef Path) {92    std::optional<MappedFileRegionArena> Alloc;93    ASSERT_THAT_ERROR(94        MappedFileRegionArena::create(Path, /*Capacity=*/10 * 1024 * 1024,95                                      /*HeaderOffset=*/0, emptyConstructor)96            .moveInto(Alloc),97        Succeeded());98 99    std::vector<unsigned *> AllocatedPtr;100    AllocatedPtr.resize(100);101    DefaultThreadPool Threads;102    for (unsigned I = 0; I < 100; ++I) {103      Threads.async(104          [&](unsigned Idx) {105            // Allocate a buffer that is larger than needed so allocator hits106            // additional pages for test coverage.107            unsigned *P = (unsigned *)cantFail(Alloc->allocate(100));108            *P = Idx;109            AllocatedPtr[Idx] = P;110          },111          I);112    }113 114    Threads.wait();115    for (unsigned I = 0; I < 100; ++I)116      EXPECT_EQ(*AllocatedPtr[I], I);117  };118 119  if (const char *File = getenv("LLVM_CAS_TEST_MAPPED_FILE_REGION")) {120    TestAllocator(File);121    exit(0);122  }123 124  SmallString<128> FilePath;125  sys::fs::createUniqueDirectory("MappedFileRegionArena", FilePath);126  sys::path::append(FilePath, "allocation-file");127 128  std::string Executable =129      sys::fs::getMainExecutable(TestMainArgv0, &ProgramID);130  StringRef Argv[] = {131      Executable, "--gtest_filter=CASProgramTest.MappedFileRegionArenaTest"};132 133  // Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child.134  std::string EnvVar = "LLVM_CAS_TEST_MAPPED_FILE_REGION=";135  EnvVar += FilePath.str();136  addEnvVar(EnvVar);137 138  std::string Error;139  bool ExecutionFailed;140  sys::ProcessInfo PI = sys::ExecuteNoWait(Executable, Argv, getEnviron(), {},141                                           0, &Error, &ExecutionFailed);142  TestAllocator(FilePath);143 144  ASSERT_FALSE(ExecutionFailed) << Error;145  ASSERT_NE(PI.Pid, sys::ProcessInfo::InvalidPid) << "Invalid process id";146  PI = llvm::sys::Wait(PI, /*SecondsToWait=*/5, &Error);147  ASSERT_TRUE(PI.ReturnCode == 0);148  ASSERT_TRUE(Error.empty());149 150  // Clean up after both processes finish testing.151  sys::fs::remove(FilePath);152  sys::fs::remove_directories(sys::path::parent_path(FilePath));153}154 155TEST_F(CASProgramTest, MappedFileRegionArenaSizeTest) {156  using namespace std::chrono_literals;157  if (const char *File = getenv("LLVM_CAS_TEST_MAPPED_FILE_REGION")) {158    ExponentialBackoff Backoff(5s);159    do {160      if (sys::fs::exists(File)) {161        break;162      }163    } while (Backoff.waitForNextAttempt());164 165    std::optional<MappedFileRegionArena> Alloc;166    ASSERT_THAT_ERROR(MappedFileRegionArena::create(File, /*Capacity=*/1024,167                                                    /*HeaderOffset=*/0,168                                                    emptyConstructor)169                          .moveInto(Alloc),170                      Succeeded());171    ASSERT_TRUE(Alloc->capacity() == 2048);172 173    Alloc.reset();174    ASSERT_THAT_ERROR(MappedFileRegionArena::create(File, /*Capacity=*/4096,175                                                    /*HeaderOffset=*/0,176                                                    emptyConstructor)177                          .moveInto(Alloc),178                      Succeeded());179    ASSERT_TRUE(Alloc->capacity() == 2048);180    Alloc.reset();181 182    ASSERT_THAT_ERROR(183        MappedFileRegionArena::create(File, /*Capacity=*/2048,184                                      /*HeaderOffset=*/32, emptyConstructor)185            .moveInto(Alloc),186        FailedWithMessage(187            "specified header offset (32) does not match existing config (0)"));188 189    ASSERT_THAT_ERROR(MappedFileRegionArena::create(File, /*Capacity=*/2048,190                                                    /*HeaderOffset=*/0,191                                                    emptyConstructor)192                          .moveInto(Alloc),193                      Succeeded());194 195    exit(0);196  }197 198  SmallString<128> FilePath;199  sys::fs::createUniqueDirectory("MappedFileRegionArena", FilePath);200  sys::path::append(FilePath, "allocation-file");201 202  std::string Executable =203      sys::fs::getMainExecutable(TestMainArgv0, &ProgramID);204  StringRef Argv[] = {205      Executable,206      "--gtest_filter=CASProgramTest.MappedFileRegionArenaSizeTest"};207 208  // Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child.209  std::string EnvVar = "LLVM_CAS_TEST_MAPPED_FILE_REGION=";210  EnvVar += FilePath.str();211  addEnvVar(EnvVar);212 213  std::optional<MappedFileRegionArena> Alloc;214  ASSERT_THAT_ERROR(MappedFileRegionArena::create(FilePath, /*Capacity=*/2048,215                                                  /*HeaderOffset=*/0,216                                                  emptyConstructor)217                        .moveInto(Alloc),218                    Succeeded());219 220  std::string Error;221  bool ExecutionFailed;222  sys::ProcessInfo PI = sys::ExecuteNoWait(Executable, Argv, getEnviron(), {},223                                           0, &Error, &ExecutionFailed);224 225  ASSERT_FALSE(ExecutionFailed) << Error;226  ASSERT_NE(PI.Pid, sys::ProcessInfo::InvalidPid) << "Invalid process id";227  PI = llvm::sys::Wait(PI, /*SecondsToWait=*/100, &Error);228  ASSERT_TRUE(PI.ReturnCode == 0);229  ASSERT_TRUE(Error.empty());230 231  // Size is still the requested 2048.232  ASSERT_TRUE(Alloc->capacity() == 2048);233 234  // Clean up after both processes finish testing.235  sys::fs::remove(FilePath);236  sys::fs::remove_directories(sys::path::parent_path(FilePath));237}238 239#endif // LLVM_ENABLE_ONDISK_CAS240