Skip to content

Commit dcfb6b1

Browse files
authored
[SYCL] Add implementation of kernel_bundle. Part 2 (#3287)
The patch adds implementation of basic API and data structures. Error handling will added in a separate patch.
1 parent 20c5aea commit dcfb6b1

File tree

10 files changed

+743
-11
lines changed

10 files changed

+743
-11
lines changed

sycl/include/CL/sycl/kernel_bundle.hpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,15 @@ class __SYCL_EXPORT kernel_bundle_plain {
164164

165165
// Sets the specialization constant with specified ID to the value pointed by
166166
// Value + ValueSize
167-
void set_specialization_constant(unsigned int SpecID, const void *Value,
168-
size_t ValueSize);
167+
void set_specialization_constant_raw_value(unsigned int SpecID,
168+
const void *Value,
169+
size_t ValueSize);
169170

170171
// \returns pointer to the value of the specialization constant with specified
171172
// ID
172-
const void *get_specialization_constant(unsigned int SpecID) const;
173+
void get_specialization_constant_raw_value(unsigned int SpecID,
174+
void *ValueRet,
175+
size_t ValueSize) const;
173176

174177
// \returns a kernel object which represents the kernel identified by
175178
// kernel_id passed
@@ -274,8 +277,8 @@ class kernel_bundle : public detail::kernel_bundle_plain {
274277
typename std::remove_reference_t<decltype(SpecName)>::type Value) {
275278
assert(false && "set_specialization_constant is not implemented yet");
276279
unsigned int SpecID = 0; // TODO: Convert SpecName to a numeric ID
277-
return kernel_bundle_plain::set_specialization_constant(SpecID, &Value,
278-
sizeof(Value));
280+
return kernel_bundle_plain::set_specialization_constant_raw_value(
281+
SpecID, &Value, sizeof(Value));
279282
}
280283

281284
/// The value of the specialization constant whose address is SpecName for
@@ -285,9 +288,10 @@ class kernel_bundle : public detail::kernel_bundle_plain {
285288
get_specialization_constant() const {
286289
assert(false && "get_specialization_constant is not implemented yet");
287290
unsigned int SpecID = 0; // TODO: Convert SpecName to a numeric ID
288-
typename std::remove_reference_t<decltype(SpecName)>::type *ValuePtr =
289-
kernel_bundle_plain::get_specialization_constant(SpecID);
290-
return *ValuePtr;
291+
typename std::remove_reference_t<decltype(SpecName)>::type Value;
292+
kernel_bundle_plain::get_specialization_constant_raw_value(
293+
SpecID, (void *)&Value, sizeof(Value));
294+
return Value;
291295
}
292296
#endif
293297

@@ -334,7 +338,7 @@ namespace detail {
334338

335339
// Internal non-template versions of get_kernel_bundle API which is used by
336340
// public onces
337-
detail::KernelBundleImplPtr
341+
__SYCL_EXPORT detail::KernelBundleImplPtr
338342
get_kernel_bundle_impl(const context &Ctx, const std::vector<device> &Devs,
339343
bundle_state State);
340344
} // namespace detail
@@ -360,7 +364,7 @@ namespace detail {
360364

361365
// Internal non-template versions of get_kernel_bundle API which is used by
362366
// public onces
363-
detail::KernelBundleImplPtr
367+
__SYCL_EXPORT detail::KernelBundleImplPtr
364368
get_kernel_bundle_impl(const context &Ctx, const std::vector<device> &Devs,
365369
const std::vector<kernel_id> &KernelIDs,
366370
bundle_state State);
@@ -409,7 +413,7 @@ using DevImgSelectorImpl =
409413

410414
// Internal non-template versions of get_kernel_bundle API which is used by
411415
// public onces
412-
detail::KernelBundleImplPtr
416+
__SYCL_EXPORT detail::KernelBundleImplPtr
413417
get_kernel_bundle_impl(const context &Ctx, const std::vector<device> &Devs,
414418
bundle_state State, const DevImgSelectorImpl &Selector);
415419
} // namespace detail

sycl/source/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ set(SYCL_SOURCES
161161
"interop_handle.cpp"
162162
"interop_handler.cpp"
163163
"kernel.cpp"
164+
"kernel_bundle.cpp"
164165
"platform.cpp"
165166
"program.cpp"
166167
"queue.cpp"
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//==------- device_image_impl.hpp - SYCL device_image_impl -----------------==//
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+
#pragma once
10+
11+
#include <CL/sycl/context.hpp>
12+
#include <CL/sycl/detail/common.hpp>
13+
#include <CL/sycl/detail/pi.h>
14+
#include <CL/sycl/device.hpp>
15+
#include <CL/sycl/kernel_bundle.hpp>
16+
#include <detail/device_impl.hpp>
17+
#include <detail/kernel_id_impl.hpp>
18+
#include <detail/program_manager/program_manager.hpp>
19+
20+
#include <algorithm>
21+
#include <cassert>
22+
#include <cstring>
23+
#include <memory>
24+
#include <mutex>
25+
#include <vector>
26+
27+
__SYCL_INLINE_NAMESPACE(cl) {
28+
namespace sycl {
29+
namespace detail {
30+
31+
// Used for sorting vector of kernel_id's
32+
struct LessByNameComp {
33+
bool operator()(const sycl::kernel_id &LHS, const sycl::kernel_id &RHS) {
34+
return std::strcmp(LHS.get_name(), RHS.get_name()) < 0;
35+
}
36+
};
37+
38+
// The class is impl counterpart for sycl::device_image
39+
// It can represent a program in different states, kernel_id's it has and state
40+
// of specialization constants for it
41+
class device_image_impl {
42+
public:
43+
device_image_impl(RTDeviceBinaryImage *BinImage, context Context,
44+
std::vector<device> Devices, bundle_state State)
45+
: MBinImage(BinImage), MContext(std::move(Context)),
46+
MDevices(std::move(Devices)), MState(State) {
47+
48+
// Collect kernel names for the image
49+
pi_device_binary DevBin =
50+
const_cast<pi_device_binary>(&BinImage->getRawData());
51+
for (_pi_offload_entry EntriesIt = DevBin->EntriesBegin;
52+
EntriesIt != DevBin->EntriesEnd; ++EntriesIt) {
53+
54+
std::shared_ptr<detail::kernel_id_impl> KernleIDImpl =
55+
std::make_shared<detail::kernel_id_impl>(EntriesIt->name);
56+
57+
sycl::kernel_id KernelID =
58+
detail::createSyclObjFromImpl<sycl::kernel_id>(KernleIDImpl);
59+
60+
// Insert new element keeping MKernelIDs sorted.
61+
auto It = std::lower_bound(MKernelIDs.begin(), MKernelIDs.end(), KernelID,
62+
LessByNameComp{});
63+
MKernelIDs.insert(It, std::move(KernelID));
64+
}
65+
}
66+
67+
bool has_kernel(const kernel_id &KernelIDCand) const noexcept {
68+
return std::binary_search(MKernelIDs.begin(), MKernelIDs.end(),
69+
KernelIDCand, LessByNameComp{});
70+
}
71+
72+
bool has_kernel(const kernel_id &KernelIDCand,
73+
const device &DeviceCand) const noexcept {
74+
for (const device &Device : MDevices)
75+
if (Device == DeviceCand)
76+
return has_kernel(KernelIDCand);
77+
78+
return false;
79+
}
80+
81+
const std::vector<kernel_id> &get_kernel_ids() const noexcept {
82+
return MKernelIDs;
83+
}
84+
85+
bool has_specialization_constants() const noexcept {
86+
return !MSpecConstsBlob.empty();
87+
}
88+
89+
bool all_specialization_constant_native() const noexcept {
90+
assert(false && "Not implemented");
91+
return false;
92+
}
93+
94+
// The struct maps specialization ID to offset in the binary blob where value
95+
// for this spec const should be.
96+
struct SpecConstIDOffset {
97+
unsigned int ID = 0;
98+
unsigned int Offset = 0;
99+
};
100+
101+
bool has_specialization_constant(unsigned int SpecID) const noexcept {
102+
return std::any_of(
103+
MSpecConstOffsets.begin(), MSpecConstOffsets.end(),
104+
[SpecID](const SpecConstIDOffset &Pair) { return Pair.ID == SpecID; });
105+
}
106+
107+
void set_specialization_constant_raw_value(unsigned int SpecID,
108+
const void *Value,
109+
size_t ValueSize) noexcept {
110+
for (const SpecConstIDOffset &Pair : MSpecConstOffsets)
111+
if (Pair.ID == SpecID) {
112+
// Lock the mutex to prevent when one thread in the middle of writing a
113+
// new value while another thread is reading the value to pass it to
114+
// JIT compiler.
115+
const std::lock_guard<std::mutex> SpecConstLock(MSpecConstAccessMtx);
116+
std::memcpy(MSpecConstsBlob.data() + Pair.Offset, Value, ValueSize);
117+
return;
118+
}
119+
}
120+
121+
void get_specialization_constant_raw_value(unsigned int SpecID,
122+
void *ValueRet,
123+
size_t ValueSize) const noexcept {
124+
for (const SpecConstIDOffset &Pair : MSpecConstOffsets)
125+
if (Pair.ID == SpecID) {
126+
// Lock the mutex to prevent when one thread in the middle of writing a
127+
// new value while another thread is reading the value to pass it to
128+
// JIT compiler.
129+
const std::lock_guard<std::mutex> SpecConstLock(MSpecConstAccessMtx);
130+
std::memcpy(ValueRet, MSpecConstsBlob.data() + Pair.Offset, ValueSize);
131+
return;
132+
}
133+
}
134+
135+
bundle_state get_state() const noexcept { return MState; }
136+
137+
void set_state(bundle_state NewState) noexcept { MState = NewState; }
138+
139+
private:
140+
RTDeviceBinaryImage *MBinImage = nullptr;
141+
context MContext;
142+
std::vector<device> MDevices;
143+
bundle_state MState;
144+
// List of kernel ids available in this image, elements should be sorted
145+
// according to LessByNameComp
146+
std::vector<kernel_id> MKernelIDs;
147+
148+
// A mutex for sycnhronizing access to spec constants blob. Mutable because
149+
// needs to be locked in the const method for getting spec constant value.
150+
mutable std::mutex MSpecConstAccessMtx;
151+
// Binary blob which can have values of all specialization constants in the
152+
// image
153+
std::vector<unsigned char> MSpecConstsBlob;
154+
// Contains list of spec ID + their offsets in the MSpecConstsBlob
155+
std::vector<SpecConstIDOffset> MSpecConstOffsets;
156+
};
157+
158+
} // namespace detail
159+
} // namespace sycl
160+
} // __SYCL_INLINE_NAMESPACE(cl)

0 commit comments

Comments
 (0)