|
| 1 | +//==--- KPCache.cpp --- KernelProgramCache for multiple devices unit test --==// |
| 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-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#define SYCL2020_DISABLE_DEPRECATION_WARNINGS |
| 10 | + |
| 11 | +#include "HelperKernelInfo.hpp" |
| 12 | +#include "detail/kernel_bundle_impl.hpp" |
| 13 | +#include <CL/sycl.hpp> |
| 14 | +#include <helpers/CommonRedefinitions.hpp> |
| 15 | +#include <helpers/PiImage.hpp> |
| 16 | +#include <helpers/PiMock.hpp> |
| 17 | + |
| 18 | +#include <gtest/gtest.h> |
| 19 | + |
| 20 | +#include <iostream> |
| 21 | + |
| 22 | +using namespace sycl; |
| 23 | + |
| 24 | +class MultTestKernel { |
| 25 | +public: |
| 26 | + void operator()(cl::sycl::item<1>){}; |
| 27 | +}; |
| 28 | + |
| 29 | +__SYCL_INLINE_NAMESPACE(cl) { |
| 30 | +namespace sycl { |
| 31 | +namespace detail { |
| 32 | +template <> struct KernelInfo<MultTestKernel> : public MockKernelInfo { |
| 33 | + static constexpr const char *getName() { return "MultTestKernel"; } |
| 34 | +}; |
| 35 | +} // namespace detail |
| 36 | +} // namespace sycl |
| 37 | +} // __SYCL_INLINE_NAMESPACE(cl) |
| 38 | + |
| 39 | +static sycl::unittest::PiImage generateDefaultImage() { |
| 40 | + using namespace sycl::unittest; |
| 41 | + |
| 42 | + PiPropertySet PropSet; |
| 43 | + |
| 44 | + std::vector<unsigned char> Bin{0, 1, 2, 3, 4, 5}; // Random data |
| 45 | + |
| 46 | + PiArray<PiOffloadEntry> Entries = makeEmptyKernels({"MultTestKernel"}); |
| 47 | + |
| 48 | + PiImage Img{PI_DEVICE_BINARY_TYPE_SPIRV, // Format |
| 49 | + __SYCL_PI_DEVICE_BINARY_TARGET_SPIRV64, // DeviceTargetSpec |
| 50 | + "", // Compile options |
| 51 | + "", // Link options |
| 52 | + std::move(Bin), |
| 53 | + std::move(Entries), |
| 54 | + std::move(PropSet)}; |
| 55 | + |
| 56 | + return Img; |
| 57 | +} |
| 58 | + |
| 59 | +static sycl::unittest::PiImage Img = generateDefaultImage(); |
| 60 | +static sycl::unittest::PiImageArray<1> ImgArray{&Img}; |
| 61 | + |
| 62 | +static pi_result redefinedContextCreate( |
| 63 | + const pi_context_properties *properties, pi_uint32 num_devices, |
| 64 | + const pi_device *devices, |
| 65 | + void (*pfn_notify)(const char *errinfo, const void *private_info, size_t cb, |
| 66 | + void *user_data), |
| 67 | + void *user_data, pi_context *ret_context) { |
| 68 | + *ret_context = reinterpret_cast<pi_context>(123); |
| 69 | + return PI_SUCCESS; |
| 70 | +} |
| 71 | + |
| 72 | +static pi_result redefinedContextRelease(pi_context context) { |
| 73 | + return PI_SUCCESS; |
| 74 | +} |
| 75 | + |
| 76 | +static pi_result redefinedDevicesGet(pi_platform platform, |
| 77 | + pi_device_type device_type, |
| 78 | + pi_uint32 num_entries, pi_device *devices, |
| 79 | + pi_uint32 *num_devices) { |
| 80 | + if (num_devices) { |
| 81 | + *num_devices = static_cast<pi_uint32>(2); |
| 82 | + return PI_SUCCESS; |
| 83 | + } |
| 84 | + |
| 85 | + devices[0] = reinterpret_cast<pi_device>(1111); |
| 86 | + devices[1] = reinterpret_cast<pi_device>(2222); |
| 87 | + return PI_SUCCESS; |
| 88 | +} |
| 89 | + |
| 90 | +static pi_result redefinedDeviceGetInfo(pi_device device, |
| 91 | + pi_device_info param_name, |
| 92 | + size_t param_value_size, |
| 93 | + void *param_value, |
| 94 | + size_t *param_value_size_ret) { |
| 95 | + if (param_name == PI_DEVICE_INFO_TYPE) { |
| 96 | + auto *Result = reinterpret_cast<_pi_device_type *>(param_value); |
| 97 | + *Result = PI_DEVICE_TYPE_GPU; |
| 98 | + } |
| 99 | + return PI_SUCCESS; |
| 100 | +} |
| 101 | + |
| 102 | +static pi_result redefinedDeviceRetain(pi_device device) { return PI_SUCCESS; } |
| 103 | + |
| 104 | +static pi_result redefinedDeviceRelease(pi_device device) { return PI_SUCCESS; } |
| 105 | + |
| 106 | +static pi_result redefinedQueueCreate(pi_context context, pi_device device, |
| 107 | + pi_queue_properties properties, |
| 108 | + pi_queue *queue) { |
| 109 | + *queue = reinterpret_cast<pi_queue>(1234); |
| 110 | + return PI_SUCCESS; |
| 111 | +} |
| 112 | + |
| 113 | +static pi_result redefinedQueueRelease(pi_queue command_queue) { |
| 114 | + return PI_SUCCESS; |
| 115 | +} |
| 116 | + |
| 117 | +static int ProgramNum = 12345; |
| 118 | +static pi_result redefinedProgramCreate(pi_context context, const void *il, |
| 119 | + size_t length, |
| 120 | + pi_program *res_program) { |
| 121 | + int CurrentProgram = ProgramNum; |
| 122 | + *res_program = reinterpret_cast<pi_program>(CurrentProgram); |
| 123 | + ++ProgramNum; |
| 124 | + return PI_SUCCESS; |
| 125 | +} |
| 126 | + |
| 127 | +static int RetainCounter = 0; |
| 128 | +static pi_result redefinedProgramRetain(pi_program program) { |
| 129 | + ++RetainCounter; |
| 130 | + return PI_SUCCESS; |
| 131 | +} |
| 132 | + |
| 133 | +static int KernelReleaseCounter = 0; |
| 134 | +static pi_result redefinedKernelRelease(pi_kernel kernel) { |
| 135 | + ++KernelReleaseCounter; |
| 136 | + return PI_SUCCESS; |
| 137 | +} |
| 138 | + |
| 139 | +class MultipleDeviceCacheTest : public ::testing::Test { |
| 140 | +public: |
| 141 | + MultipleDeviceCacheTest() : Plt{default_selector()} {} |
| 142 | + |
| 143 | +protected: |
| 144 | + void SetUp() override { |
| 145 | + if (Plt.is_host() || Plt.get_backend() != backend::opencl) { |
| 146 | + std::clog << "This test is only supported on OpenCL devices\n"; |
| 147 | + std::clog << "Current platform is " |
| 148 | + << Plt.get_info<info::platform::name>(); |
| 149 | + return; |
| 150 | + } |
| 151 | + |
| 152 | + Mock = std::make_unique<unittest::PiMock>(Plt); |
| 153 | + |
| 154 | + setupDefaultMockAPIs(*Mock); |
| 155 | + Mock->redefine<detail::PiApiKind::piDevicesGet>(redefinedDevicesGet); |
| 156 | + Mock->redefine<detail::PiApiKind::piDeviceGetInfo>(redefinedDeviceGetInfo); |
| 157 | + Mock->redefine<detail::PiApiKind::piDeviceRetain>(redefinedDeviceRetain); |
| 158 | + Mock->redefine<detail::PiApiKind::piDeviceRelease>(redefinedDeviceRelease); |
| 159 | + Mock->redefine<detail::PiApiKind::piContextCreate>(redefinedContextCreate); |
| 160 | + Mock->redefine<detail::PiApiKind::piContextRelease>( |
| 161 | + redefinedContextRelease); |
| 162 | + Mock->redefine<detail::PiApiKind::piQueueCreate>(redefinedQueueCreate); |
| 163 | + Mock->redefine<detail::PiApiKind::piQueueRelease>(redefinedQueueRelease); |
| 164 | + Mock->redefine<detail::PiApiKind::piProgramRetain>(redefinedProgramRetain); |
| 165 | + Mock->redefine<detail::PiApiKind::piProgramCreate>(redefinedProgramCreate); |
| 166 | + Mock->redefine<detail::PiApiKind::piKernelRelease>(redefinedKernelRelease); |
| 167 | + } |
| 168 | + |
| 169 | +protected: |
| 170 | + std::unique_ptr<unittest::PiMock> Mock; |
| 171 | + platform Plt; |
| 172 | +}; |
| 173 | + |
| 174 | +// Test that program is retained for each device |
| 175 | +TEST_F(MultipleDeviceCacheTest, ProgramRetain) { |
| 176 | + if (Plt.is_host()) { |
| 177 | + return; |
| 178 | + } |
| 179 | + |
| 180 | + std::vector<sycl::device> Devices = Plt.get_devices(info::device_type::gpu); |
| 181 | + sycl::context Context(Devices); |
| 182 | + sycl::queue Queue(Context, Devices[0]); |
| 183 | + assert(Devices.size() == 2); |
| 184 | + |
| 185 | + auto Bundle = cl::sycl::get_kernel_bundle<sycl::bundle_state::input>( |
| 186 | + Queue.get_context()); |
| 187 | + |
| 188 | + Queue.submit([&](cl::sycl::handler &cgh) { |
| 189 | + cgh.parallel_for<MultTestKernel>(cl::sycl::nd_range<1>(10, 10), |
| 190 | + MultTestKernel{}); |
| 191 | + }); |
| 192 | + |
| 193 | + auto BundleObject = cl::sycl::build(Bundle, Bundle.get_devices()); |
| 194 | + auto KernelID = cl::sycl::get_kernel_id<MultTestKernel>(); |
| 195 | + auto Kernel = BundleObject.get_kernel(KernelID); |
| 196 | + auto BundleImpl = getSyclObjImpl(Bundle); |
| 197 | + int NumRetains = BundleImpl->size() * 2; |
| 198 | + |
| 199 | + EXPECT_EQ(RetainCounter, NumRetains) |
| 200 | + << "Expect " << NumRetains << " piProgramRetain calls"; |
| 201 | +} |
| 202 | + |
| 203 | +// Test that each kernel released only 1 time in ~KernelProgramCache() |
| 204 | +TEST_F(MultipleDeviceCacheTest, KernelRelease) { |
| 205 | + platform Plt{default_selector()}; |
| 206 | + if (Plt.is_host()) { |
| 207 | + return; |
| 208 | + } |
| 209 | + EXPECT_EQ(KernelReleaseCounter, 3) << "Expect 3 piKernelRelease calls"; |
| 210 | +} |
0 commit comments