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