brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.3 KiB · b88d6e9 Raw
189 lines · plain
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/// \file10/// This file contains the definition of the GpuMathTest class, a test harness11/// that orchestrates running a math function on a device (GPU) and verifying12/// its results.13///14//===----------------------------------------------------------------------===//15 16#ifndef MATHTEST_GPUMATHTEST_HPP17#define MATHTEST_GPUMATHTEST_HPP18 19#include "mathtest/DeviceContext.hpp"20#include "mathtest/DeviceResources.hpp"21#include "mathtest/HostRefChecker.hpp"22#include "mathtest/InputGenerator.hpp"23#include "mathtest/Support.hpp"24#include "mathtest/TestResult.hpp"25 26#include "llvm/ADT/ArrayRef.h"27#include "llvm/ADT/StringRef.h"28#include "llvm/Support/Error.h"29 30#include <cassert>31#include <cstddef>32#include <cstdint>33#include <memory>34#include <string>35#include <tuple>36#include <utility>37 38namespace mathtest {39 40template <auto Func, typename Checker = HostRefChecker<Func>>41class [[nodiscard]] GpuMathTest final {42  using FunctionTraits = FunctionTraits<Func>;43  using OutType = typename FunctionTraits::ReturnType;44  using InTypesTuple = typename FunctionTraits::ArgTypesTuple;45 46  template <typename... Ts>47  using PartialResultType = TestResult<OutType, Ts...>;48  using KernelSignature = KernelSignatureOf_t<Func>;49 50  template <typename... Ts>51  using TypeIdentitiesTuple = std::tuple<TypeIdentityOf<Ts>...>;52  using InTypeIdentitiesTuple =53      ApplyTupleTypes_t<InTypesTuple, TypeIdentitiesTuple>;54 55  static constexpr std::size_t DefaultBufferSize =56      DefaultBufferSizeFor_v<OutType, InTypesTuple>;57  static constexpr uint32_t DefaultGroupSize = 512;58 59public:60  using FunctionConfig = FunctionConfig<Func>;61  using ResultType = ApplyTupleTypes_t<InTypesTuple, PartialResultType>;62  using GeneratorType = ApplyTupleTypes_t<InTypesTuple, InputGenerator>;63 64  [[nodiscard]] static llvm::Expected<GpuMathTest>65  create(std::shared_ptr<DeviceContext> Context, llvm::StringRef Provider,66         llvm::StringRef DeviceBinaryDir) {67    assert(Context && "Context must not be null");68 69    auto ExpectedKernel = getKernel(*Context, Provider, DeviceBinaryDir);70    if (!ExpectedKernel)71      return ExpectedKernel.takeError();72 73    return GpuMathTest(std::move(Context), Provider, *ExpectedKernel);74  }75 76  ResultType run(GeneratorType &Generator,77                 std::size_t BufferSize = DefaultBufferSize,78                 uint32_t GroupSize = DefaultGroupSize) const noexcept {79    assert(BufferSize > 0 && "Buffer size must be a positive value");80    assert(GroupSize > 0 && "Group size must be a positive value");81 82    auto [InBuffersTuple, OutBuffer] = createBuffers(BufferSize);83    ResultType FinalResult;84 85    while (true) {86      const std::size_t BatchSize = std::apply(87          [&](auto &...Buffers) { return Generator.fill(Buffers...); },88          InBuffersTuple);89 90      if (BatchSize == 0)91        break;92 93      const auto BatchResult =94          processBatch(InBuffersTuple, OutBuffer, BatchSize, GroupSize);95 96      FinalResult.accumulate(BatchResult);97    }98 99    return FinalResult;100  }101 102  [[nodiscard]] std::shared_ptr<DeviceContext> getContext() const noexcept {103    return Context;104  }105 106  [[nodiscard]] std::string getProvider() const noexcept { return Provider; }107 108private:109  explicit GpuMathTest(std::shared_ptr<DeviceContext> Context,110                       llvm::StringRef Provider,111                       DeviceKernel<KernelSignature> Kernel)112      : Context(std::move(Context)), Provider(Provider), Kernel(Kernel) {}113 114  static llvm::Expected<DeviceKernel<KernelSignature>>115  getKernel(const DeviceContext &Context, llvm::StringRef Provider,116            llvm::StringRef DeviceBinaryDir) {117    llvm::StringRef BinaryName = Provider;118 119    auto ExpectedImage = Context.loadBinary(DeviceBinaryDir, BinaryName);120    if (!ExpectedImage)121      return ExpectedImage.takeError();122 123    auto ExpectedKernel = Context.getKernel<KernelSignature>(124        *ExpectedImage, FunctionConfig::KernelName);125    if (!ExpectedKernel)126      return ExpectedKernel.takeError();127 128    return *ExpectedKernel;129  }130 131  [[nodiscard]] auto createBuffers(std::size_t BufferSize) const {132    auto InBuffersTuple = std::apply(133        [&](auto... InTypeIdentities) {134          return std::make_tuple(135              Context->createManagedBuffer<136                  typename decltype(InTypeIdentities)::type>(BufferSize)...);137        },138        InTypeIdentitiesTuple{});139    auto OutBuffer = Context->createManagedBuffer<OutType>(BufferSize);140 141    return std::make_pair(std::move(InBuffersTuple), std::move(OutBuffer));142  }143 144  template <typename InBuffersTupleType>145  [[nodiscard]] ResultType146  processBatch(const InBuffersTupleType &InBuffersTuple,147               ManagedBuffer<OutType> &OutBuffer, std::size_t BatchSize,148               uint32_t GroupSize) const noexcept {149    const uint32_t NumGroups = (BatchSize + GroupSize - 1) / GroupSize;150    const auto KernelArgsTuple = std::apply(151        [&](const auto &...InBuffers) {152          return std::make_tuple(InBuffers.data()..., OutBuffer.data(),153                                 BatchSize);154        },155        InBuffersTuple);156 157    std::apply(158        [&](const auto &...KernelArgs) {159          Context->launchKernel(Kernel, NumGroups, GroupSize, KernelArgs...);160        },161        KernelArgsTuple);162 163    return check(InBuffersTuple, OutBuffer, BatchSize);164  }165 166  template <typename InBuffersTupleType>167  [[nodiscard]] static ResultType168  check(const InBuffersTupleType &InBuffersTuple,169        const ManagedBuffer<OutType> &OutBuffer,170        std::size_t BatchSize) noexcept {171    const auto InViewsTuple = std::apply(172        [&](auto &...InBuffers) {173          return std::make_tuple(174              llvm::ArrayRef(InBuffers.data(), BatchSize)...);175        },176        InBuffersTuple);177    const auto OutView = llvm::ArrayRef<OutType>(OutBuffer.data(), BatchSize);178 179    return Checker::check(InViewsTuple, OutView);180  }181 182  std::shared_ptr<DeviceContext> Context;183  std::string Provider;184  DeviceKernel<KernelSignature> Kernel;185};186} // namespace mathtest187 188#endif // MATHTEST_GPUMATHTEST_HPP189