Skip to content

Commit aa5910c

Browse files
committed
Add a test for capturing kernel arguments, if the kernel lambda is deallocated
1 parent 2708774 commit aa5910c

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

sycl/unittests/kernel-and-program/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_sycl_unittest(KernelAndProgramTests OBJECT
88
KernelBuildOptions.cpp
99
OutOfResources.cpp
1010
InMemCacheEviction.cpp
11+
KernelArgs.cpp
1112
)
1213
target_compile_definitions(KernelAndProgramTests_non_preview PRIVATE __SYCL_INTERNAL_API)
1314
target_compile_definitions(KernelAndProgramTests_preview PRIVATE __SYCL_INTERNAL_API __INTEL_PREVIEW_BREAKING_CHANGES)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//==------------ KernelArgs.cpp ------ Kernel arguments unit tests ---------==//
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+
#include <helpers/CommandSubmitWrappers.hpp>
10+
#include <helpers/MockDeviceImage.hpp>
11+
#include <helpers/MockKernelInfo.hpp>
12+
#include <helpers/UrMock.hpp>
13+
14+
#include <gtest/gtest.h>
15+
16+
#include <condition_variable>
17+
18+
#include <sycl/sycl.hpp>
19+
20+
using namespace sycl;
21+
22+
class TestKernelWithIntPtr;
23+
24+
namespace sycl {
25+
inline namespace _V1 {
26+
namespace detail {
27+
28+
template <>
29+
struct KernelInfo<TestKernelWithIntPtr> : public unittest::MockKernelInfoBase {
30+
static constexpr unsigned getNumParams() { return 2; }
31+
static constexpr const char *getName() { return "TestKernelWithIntPtr"; }
32+
static constexpr int64_t getKernelSize() {
33+
return sizeof(int) + sizeof(void *);
34+
}
35+
36+
static constexpr const detail::kernel_param_desc_t &getParamDesc(int Index) {
37+
if (Index == 0) {
38+
return IntParamDesc;
39+
} else if (Index == 1) {
40+
return PointerParamDesc;
41+
}
42+
return Dummy;
43+
}
44+
45+
private:
46+
static constexpr detail::kernel_param_desc_t IntParamDesc = {
47+
detail::kernel_param_kind_t::kind_std_layout, 0, 0};
48+
static constexpr detail::kernel_param_desc_t PointerParamDesc = {
49+
detail::kernel_param_kind_t::kind_pointer, 0, sizeof(int)};
50+
};
51+
52+
} // namespace detail
53+
} // namespace _V1
54+
} // namespace sycl
55+
56+
static sycl::unittest::MockDeviceImage Img =
57+
sycl::unittest::generateDefaultImage({"TestKernelWithIntPtr"});
58+
static sycl::unittest::MockDeviceImageArray<1> ImgArray{&Img};
59+
60+
static int ArgInt = 123;
61+
static void *ArgPointer = &ArgInt;
62+
63+
ur_result_t redefined_urKernelSetArgValue(void *pParams) {
64+
auto params = *static_cast<ur_kernel_set_arg_value_params_t *>(pParams);
65+
66+
int ArgValue = *static_cast<const int *>(*params.ppArgValue);
67+
EXPECT_EQ(ArgValue, ArgInt);
68+
69+
return UR_RESULT_SUCCESS;
70+
}
71+
72+
ur_result_t redefined_urKernelSetArgPointer(void *pParams) {
73+
auto params = *static_cast<ur_kernel_set_arg_pointer_params_t *>(pParams);
74+
75+
int ArgValue = *static_cast<const int *>(*params.ppArgValue);
76+
EXPECT_EQ(ArgValue, ArgInt);
77+
78+
return UR_RESULT_SUCCESS;
79+
}
80+
81+
void runKernelWithArgs(queue &Queue, int ArgI, void *ArgP) {
82+
// Pack to 1-byte boundaries, so the kernel size is not padded
83+
#pragma pack(push, 1)
84+
auto KernelLambda = [=]([[maybe_unused]] nd_item<1> i) {
85+
[[maybe_unused]] volatile int ArgILocal = ArgI;
86+
[[maybe_unused]] volatile void *ArgPLocal = ArgP;
87+
};
88+
#pragma pack(pop)
89+
90+
Queue.parallel_for<TestKernelWithIntPtr>(nd_range<1>{32, 32}, KernelLambda);
91+
}
92+
93+
// This test checks, if the kernel lambda is copied properly,
94+
// so the arguments extraction can happen after the local copy
95+
// of the kernel lambda is deallocated.
96+
TEST(KernelArgsTest, KernelCopy) {
97+
sycl::unittest::UrMock<> Mock;
98+
mock::getCallbacks().set_before_callback("urKernelSetArgValue",
99+
&redefined_urKernelSetArgValue);
100+
mock::getCallbacks().set_before_callback("urKernelSetArgPointer",
101+
&redefined_urKernelSetArgPointer);
102+
103+
platform Plt = sycl::platform();
104+
105+
context Ctx{Plt};
106+
queue Queue{Ctx, default_selector_v, property::queue::in_order()};
107+
108+
std::mutex CvMutex;
109+
std::condition_variable Cv;
110+
bool ready = false;
111+
112+
// The kernel submission is queued behind a host task,
113+
// to force the scheduler-based submission.
114+
Queue.submit([&](sycl::handler &CGH) {
115+
CGH.host_task([&] {
116+
std::unique_lock<std::mutex> lk(CvMutex);
117+
Cv.wait(lk, [&ready] { return ready; });
118+
});
119+
});
120+
121+
// The kernel lambda is defined in a separate function,
122+
// so it will be deallocated before the argument extraction
123+
// and kernel submission happens.
124+
runKernelWithArgs(Queue, ArgInt, ArgPointer);
125+
126+
{
127+
std::unique_lock<std::mutex> lk(CvMutex);
128+
ready = true;
129+
}
130+
Cv.notify_one();
131+
132+
Queue.wait();
133+
}

0 commit comments

Comments
 (0)