Skip to content

Commit 5ee066e

Browse files
author
Andrew Lamzed-Short
authored
[SYCL] Add queue shortcut functions with placeholder accessors (#7266)
Implementation of the explicit copy-based queue shortcut functions defined in Table 29 of [Section 4.6.5.2 of the specification](https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html#sec:queue-shortcuts) (the last 7 rows of the table to be precise).
1 parent 98dda9d commit 5ee066e

File tree

3 files changed

+354
-0
lines changed

3 files changed

+354
-0
lines changed

sycl/include/sycl/queue.hpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,124 @@ class __SYCL_EXPORT queue {
11331133
CodeLoc);
11341134
}
11351135

1136+
/// Copies data from a memory region pointed to by a placeholder accessor to
1137+
/// another memory region pointed to by a shared_ptr.
1138+
///
1139+
/// \param Src is a placeholder accessor to the source memory.
1140+
/// \param Dest is a shared_ptr to the destination memory.
1141+
/// \return an event representing copy operation.
1142+
template <typename SrcT, int SrcDims, access_mode SrcMode, target SrcTgt,
1143+
access::placeholder IsPlaceholder, typename DestT>
1144+
event copy(accessor<SrcT, SrcDims, SrcMode, SrcTgt, IsPlaceholder> Src,
1145+
std::shared_ptr<DestT> Dest _CODELOCPARAM(&CodeLoc)) {
1146+
return submit([&](handler &CGH) {
1147+
CGH.require(Src);
1148+
CGH.copy(Src, Dest);
1149+
} _CODELOCFW(CodeLoc));
1150+
}
1151+
1152+
/// Copies data from a memory region pointed to by a shared_ptr to another
1153+
/// memory region pointed to by a placeholder accessor.
1154+
///
1155+
/// \param Src is a shared_ptr to the source memory.
1156+
/// \param Dest is a placeholder accessor to the destination memory.
1157+
/// \return an event representing copy operation.
1158+
template <typename SrcT, typename DestT, int DestDims, access_mode DestMode,
1159+
target DestTgt, access::placeholder IsPlaceholder>
1160+
event copy(std::shared_ptr<SrcT> Src,
1161+
accessor<DestT, DestDims, DestMode, DestTgt, IsPlaceholder> Dest
1162+
_CODELOCPARAM(&CodeLoc)) {
1163+
return submit([&](handler &CGH) {
1164+
CGH.require(Dest);
1165+
CGH.copy(Src, Dest);
1166+
} _CODELOCFW(CodeLoc));
1167+
}
1168+
1169+
/// Copies data from a memory region pointed to by a placeholder accessor to
1170+
/// another memory region pointed to by a raw pointer.
1171+
///
1172+
/// \param Src is a placeholder accessor to the source memory.
1173+
/// \param Dest is a raw pointer to the destination memory.
1174+
/// \return an event representing copy operation.
1175+
template <typename SrcT, int SrcDims, access_mode SrcMode, target SrcTgt,
1176+
access::placeholder IsPlaceholder, typename DestT>
1177+
event copy(accessor<SrcT, SrcDims, SrcMode, SrcTgt, IsPlaceholder> Src,
1178+
DestT *Dest _CODELOCPARAM(&CodeLoc)) {
1179+
return submit([&](handler &CGH) {
1180+
CGH.require(Src);
1181+
CGH.copy(Src, Dest);
1182+
} _CODELOCFW(CodeLoc));
1183+
}
1184+
1185+
/// Copies data from a memory region pointed to by a raw pointer to another
1186+
/// memory region pointed to by a placeholder accessor.
1187+
///
1188+
/// \param Src is a raw pointer to the source memory.
1189+
/// \param Dest is a placeholder accessor to the destination memory.
1190+
/// \return an event representing copy operation.
1191+
template <typename SrcT, typename DestT, int DestDims, access_mode DestMode,
1192+
target DestTgt, access::placeholder IsPlaceholder>
1193+
event copy(const SrcT *Src,
1194+
accessor<DestT, DestDims, DestMode, DestTgt, IsPlaceholder> Dest
1195+
_CODELOCPARAM(&CodeLoc)) {
1196+
return submit([&](handler &CGH) {
1197+
CGH.require(Dest);
1198+
CGH.copy(Src, Dest);
1199+
} _CODELOCFW(CodeLoc));
1200+
}
1201+
1202+
/// Copies data from one memory region to another, both pointed by placeholder
1203+
/// accessors.
1204+
///
1205+
/// \param Src is a placeholder accessor to the source memory.
1206+
/// \param Dest is a placeholder accessor to the destination memory.
1207+
/// \return an event representing copy operation.
1208+
template <typename SrcT, int SrcDims, access_mode SrcMode, target SrcTgt,
1209+
access::placeholder IsSrcPlaceholder, typename DestT, int DestDims,
1210+
access_mode DestMode, target DestTgt,
1211+
access::placeholder IsDestPlaceholder>
1212+
event
1213+
copy(accessor<SrcT, SrcDims, SrcMode, SrcTgt, IsSrcPlaceholder> Src,
1214+
accessor<DestT, DestDims, DestMode, DestTgt, IsDestPlaceholder> Dest
1215+
_CODELOCPARAM(&CodeLoc)) {
1216+
return submit([&](handler &CGH) {
1217+
CGH.require(Src);
1218+
CGH.require(Dest);
1219+
CGH.copy(Src, Dest);
1220+
} _CODELOCFW(CodeLoc));
1221+
}
1222+
1223+
/// Provides guarantees that the memory object accessed via Acc is updated
1224+
/// on the host after operation is complete.
1225+
///
1226+
/// \param Acc is a SYCL accessor that needs to be updated on host.
1227+
/// \return an event representing update_host operation.
1228+
template <typename T, int Dims, access_mode Mode, target Tgt,
1229+
access::placeholder IsPlaceholder>
1230+
event update_host(
1231+
accessor<T, Dims, Mode, Tgt, IsPlaceholder> Acc _CODELOCPARAM(&CodeLoc)) {
1232+
return submit([&](handler &CGH) {
1233+
CGH.require(Acc);
1234+
CGH.update_host(Acc);
1235+
} _CODELOCFW(CodeLoc));
1236+
}
1237+
1238+
/// Fills the specified memory with the specified data.
1239+
///
1240+
/// \param Dest is the placeholder accessor to the memory to fill.
1241+
/// \param Src is the data to fill the memory with. T should be
1242+
/// trivially copyable.
1243+
/// \return an event representing fill operation.
1244+
template <typename T, int Dims, access_mode Mode, target Tgt,
1245+
access::placeholder IsPlaceholder>
1246+
event fill(accessor<T, Dims, Mode, Tgt, IsPlaceholder> Dest,
1247+
const T &Src _CODELOCPARAM(&CodeLoc)) {
1248+
return submit([&](handler &CGH) {
1249+
CGH.require(Dest);
1250+
CGH.fill<T>(Dest, Src);
1251+
} _CODELOCFW(CodeLoc));
1252+
}
1253+
11361254
// Clean KERNELFUNC macros.
11371255
#undef _KERNELFUNCPARAM
11381256

sycl/unittests/queue/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ add_sycl_unittest(QueueTests OBJECT
44
USM.cpp
55
Wait.cpp
66
GetProfilingInfo.cpp
7+
ShortcutFunctions.cpp
78
)
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
//==-------------- ShortcutFunctions.cpp --- queue 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 <detail/context_impl.hpp>
10+
#include <gtest/gtest.h>
11+
#include <helpers/PiMock.hpp>
12+
#include <sycl/ext/oneapi/accessor_property_list.hpp>
13+
#include <sycl/handler.hpp>
14+
#include <sycl/queue.hpp>
15+
#include <sycl/sycl.hpp>
16+
17+
#include <memory>
18+
19+
using namespace sycl;
20+
21+
namespace {
22+
struct TestCtx {
23+
bool BufferFillCalled = false;
24+
bool BufferReadCalled = false;
25+
bool BufferWriteCalled = false;
26+
bool BufferCopyCalled = false;
27+
};
28+
} // namespace
29+
30+
static std::unique_ptr<TestCtx> TestContext;
31+
32+
pi_result redefinedEnqueueMemBufferWrite(pi_queue command_queue, pi_mem buffer,
33+
pi_bool blocking_write, size_t offset,
34+
size_t size, const void *ptr,
35+
pi_uint32 num_events_in_wait_list,
36+
const pi_event *event_wait_list,
37+
pi_event *event) {
38+
TestContext->BufferWriteCalled = true;
39+
return PI_SUCCESS;
40+
}
41+
42+
pi_result redefinedEnqueueMemBufferRead(pi_queue queue, pi_mem buffer,
43+
pi_bool blocking_read, size_t offset,
44+
size_t size, void *ptr,
45+
pi_uint32 num_events_in_wait_list,
46+
const pi_event *event_wait_list,
47+
pi_event *event) {
48+
TestContext->BufferReadCalled = true;
49+
return PI_SUCCESS;
50+
}
51+
52+
pi_result redefinedEnqueueMemBufferCopy(pi_queue command_queue,
53+
pi_mem src_buffer, pi_mem dst_buffer,
54+
size_t src_offset, size_t dst_offset,
55+
size_t size,
56+
pi_uint32 num_events_in_wait_list,
57+
const pi_event *event_wait_list,
58+
pi_event *event) {
59+
TestContext->BufferCopyCalled = true;
60+
return PI_SUCCESS;
61+
}
62+
63+
pi_result redefinedEnqueueMemBufferFill(pi_queue command_queue, pi_mem buffer,
64+
const void *pattern,
65+
size_t pattern_size, size_t offset,
66+
size_t size,
67+
pi_uint32 num_events_in_wait_list,
68+
const pi_event *event_wait_list,
69+
pi_event *event) {
70+
TestContext->BufferFillCalled = true;
71+
return PI_SUCCESS;
72+
}
73+
74+
TEST(ShortcutFunctions, ShortcutsCallCorrectPIFunctions) {
75+
unittest::PiMock Mock;
76+
platform Plt = Mock.getPlatform();
77+
78+
Mock.redefine<detail::PiApiKind::piEnqueueMemBufferWrite>(
79+
redefinedEnqueueMemBufferWrite);
80+
Mock.redefine<detail::PiApiKind::piEnqueueMemBufferRead>(
81+
redefinedEnqueueMemBufferRead);
82+
Mock.redefine<detail::PiApiKind::piEnqueueMemBufferCopy>(
83+
redefinedEnqueueMemBufferCopy);
84+
85+
Mock.redefine<detail::PiApiKind::piEnqueueMemBufferFill>(
86+
redefinedEnqueueMemBufferFill);
87+
88+
context Ctx(Plt);
89+
queue Q{Ctx, default_selector()};
90+
91+
constexpr std::size_t Size = 1;
92+
93+
// Queue.copy(accessor src, shared_ptr dest);
94+
{
95+
TestContext.reset(new TestCtx());
96+
97+
int Data[Size];
98+
buffer<int> Buf(Data, Size);
99+
100+
accessor<int, 1, access::mode::read, access::target::device,
101+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
102+
Src(Buf);
103+
ASSERT_TRUE(Src.is_placeholder());
104+
105+
std::shared_ptr<int> Dest = std::make_shared<int>(0);
106+
107+
Q.copy(Src, Dest);
108+
Q.wait();
109+
110+
EXPECT_TRUE(TestContext->BufferReadCalled);
111+
}
112+
113+
// Queue.copy(shared_ptr src, accessor dest);
114+
{
115+
TestContext.reset(new TestCtx());
116+
117+
int Data[Size];
118+
buffer<int> Buf(Data, Size);
119+
120+
std::shared_ptr<int> Src = std::make_shared<int>(42);
121+
122+
accessor<int, 1, access::mode::write, access::target::device,
123+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
124+
Dest(Buf);
125+
ASSERT_TRUE(Dest.is_placeholder());
126+
127+
Q.copy(Src, Dest);
128+
Q.wait();
129+
130+
EXPECT_TRUE(TestContext->BufferWriteCalled);
131+
}
132+
133+
// Queue.copy(accessor src, ptr* dest);
134+
{
135+
TestContext.reset(new TestCtx());
136+
137+
int Data[Size];
138+
buffer<int> Buf(Data, Size);
139+
140+
accessor<int, 1, access::mode::read, access::target::device,
141+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
142+
Src(Buf);
143+
ASSERT_TRUE(Src.is_placeholder());
144+
145+
std::unique_ptr<int> Dest = std::make_unique<int>(0);
146+
147+
Q.copy(Src, Dest.get());
148+
Q.wait();
149+
150+
EXPECT_TRUE(TestContext->BufferReadCalled);
151+
}
152+
153+
// Queue.copy(ptr* src, accessor dest);
154+
{
155+
TestContext.reset(new TestCtx());
156+
157+
int Data[Size];
158+
buffer<int> Buf(Data, Size);
159+
160+
std::unique_ptr<int> Src = std::make_unique<int>(42);
161+
162+
accessor<int, 1, access::mode::write, access::target::device,
163+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
164+
Dest(Buf);
165+
ASSERT_TRUE(Dest.is_placeholder());
166+
167+
Q.copy(Src.get(), Dest);
168+
Q.wait();
169+
170+
EXPECT_TRUE(TestContext->BufferWriteCalled);
171+
}
172+
173+
// Queue.copy(accessor src, accessor dest);
174+
{
175+
TestContext.reset(new TestCtx());
176+
177+
int SrcData[Size];
178+
buffer<int> SrcBuf(SrcData, Size);
179+
180+
int DestData[Size];
181+
buffer<int> DestBuf(DestData, Size);
182+
183+
accessor<int, 1, access::mode::read, access::target::device,
184+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
185+
Src(SrcBuf);
186+
accessor<int, 1, access::mode::write, access::target::device,
187+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
188+
Dest(DestBuf);
189+
190+
ASSERT_TRUE(Src.is_placeholder());
191+
ASSERT_TRUE(Dest.is_placeholder());
192+
193+
Q.copy(Src, Dest);
194+
Q.wait();
195+
196+
EXPECT_TRUE(TestContext->BufferCopyCalled);
197+
}
198+
199+
// Queue.update_host(accessor acc);
200+
{
201+
TestContext.reset(new TestCtx());
202+
203+
int Data[Size];
204+
buffer<int> Buf(Data, Size);
205+
206+
accessor<int, 1, access::mode::read_write, access::target::device,
207+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
208+
Acc(Buf);
209+
210+
ASSERT_TRUE(Acc.is_placeholder());
211+
212+
Q.update_host(Acc);
213+
Q.wait();
214+
215+
// No PI functions expected.
216+
}
217+
218+
// Queue.fill<T>(accessor Dest, T src)
219+
{
220+
TestContext.reset(new TestCtx());
221+
222+
int Data[Size];
223+
buffer<int> Buf(Data, Size);
224+
225+
accessor<int, 1, access::mode::read_write, access::target::device,
226+
access::placeholder::true_t, ext::oneapi::accessor_property_list<>>
227+
Acc(Buf);
228+
ASSERT_TRUE(Acc.is_placeholder());
229+
230+
Q.fill(Acc, 42);
231+
Q.wait();
232+
233+
EXPECT_TRUE(TestContext->BufferFillCalled);
234+
}
235+
}

0 commit comments

Comments
 (0)