Skip to content

Commit 70ee3d5

Browse files
[SYCL] Implement subset of sycl_ext_oneapi_kernel_properties (#7018)
This commit implements the following parts of the sycl_ext_oneapi_kernel_properties extension: * The work_group_size, work_group_size_hint, and sub_group_size properties. * The new overloads for single_task, parallel_for, and parallel_for_work_group in handler. * The new shortcuts for single_task and parallel_for in queue. * Support for merging property lists which is used when kernel functors have a get member for properties. The changes do not include any changes related to the device_has property and corresponding interfaces. This is split from #6941. Signed-off-by: Larsen, Steffen <steffen.larsen@intel.com>
1 parent adcaed5 commit 70ee3d5

16 files changed

+2373
-289
lines changed

sycl/doc/extensions/proposed/sycl_ext_oneapi_kernel_properties.asciidoc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,13 @@ struct device_has_key {
146146
template <size_t... Dims>
147147
struct property_value<work_group_size_key, std::integral_constant<size_t, Dims>...> {
148148
using key_t = work_group_size_key;
149-
constexpr size_t operator[](int dim);
149+
constexpr size_t operator[](int dim) const;
150150
};
151151

152152
template <size_t... Dims>
153153
struct property_value<work_group_size_hint_key, std::integral_constant<size_t, Dims>...> {
154154
using key_t = work_group_size_hint_key;
155-
constexpr size_t operator[](int dim);
155+
constexpr size_t operator[](int dim) const;
156156
};
157157

158158
template <sycl::aspect... Aspects>
@@ -342,6 +342,19 @@ q.parallel_for(range<2>{16, 16}, properties, [=](id<2> i) {
342342
}).wait();
343343
```
344344

345+
NOTE: It is currently not possible to use the same kernel function in two
346+
commands with different properties. For example, the following will result in an
347+
error at compile-time:
348+
349+
```c++
350+
auto kernelFunc = [=](){};
351+
q.single_task(kernelFunc);
352+
q.single_task(
353+
sycl::ext::oneapi::experimental::properties{
354+
sycl::ext::oneapi::experimental::sub_group_size<8>},
355+
kernelFunc);
356+
```
357+
345358
== Embedding Properties into a Kernel
346359

347360
In other situations it may be useful to embed a kernel's properties directly
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
//==------- properties.hpp - SYCL properties associated with kernels -------==//
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 <sycl/ext/oneapi/properties/property.hpp>
12+
#include <sycl/ext/oneapi/properties/property_value.hpp>
13+
14+
#include <array>
15+
16+
namespace sycl {
17+
__SYCL_INLINE_VER_NAMESPACE(_V1) {
18+
namespace ext {
19+
namespace oneapi {
20+
namespace experimental {
21+
namespace detail {
22+
// Trait for checking that all size_t values are non-zero.
23+
template <size_t... Xs> struct AllNonZero {
24+
static inline constexpr bool value = true;
25+
};
26+
template <size_t X, size_t... Xs> struct AllNonZero<X, Xs...> {
27+
static inline constexpr bool value = X > 0 && AllNonZero<Xs...>::value;
28+
};
29+
30+
// Simple helpers for containing primitive types as template arguments.
31+
template <size_t... Sizes> struct SizeList {};
32+
template <char... Sizes> struct CharList {};
33+
34+
// Helper for converting characters to a constexpr string.
35+
template <char... Chars> struct CharsToStr {
36+
static inline constexpr const char value[] = {Chars..., '\0'};
37+
};
38+
39+
// Helper for converting a list of size_t values to a comma-separated string
40+
// representation. This is done by extracting the digit one-by-one and when
41+
// finishing a value, the parsed result is added to a separate list of
42+
// "parsed" characters with the delimiter.
43+
template <typename List, typename ParsedList, char... Chars>
44+
struct SizeListToStrHelper;
45+
template <size_t Value, size_t... Values, char... ParsedChars, char... Chars>
46+
struct SizeListToStrHelper<SizeList<Value, Values...>, CharList<ParsedChars...>,
47+
Chars...>
48+
: SizeListToStrHelper<SizeList<Value / 10, Values...>,
49+
CharList<ParsedChars...>, '0' + (Value % 10),
50+
Chars...> {};
51+
template <size_t... Values, char... ParsedChars, char... Chars>
52+
struct SizeListToStrHelper<SizeList<0, Values...>, CharList<ParsedChars...>,
53+
Chars...>
54+
: SizeListToStrHelper<SizeList<Values...>,
55+
CharList<ParsedChars..., Chars..., ','>> {};
56+
template <char... ParsedChars, char... Chars>
57+
struct SizeListToStrHelper<SizeList<0>, CharList<ParsedChars...>, Chars...>
58+
: CharsToStr<ParsedChars..., Chars...> {};
59+
60+
// Converts size_t values to a comma-separated string representation.
61+
template <size_t... Sizes>
62+
struct SizeListToStr : SizeListToStrHelper<SizeList<Sizes...>, CharList<>> {};
63+
} // namespace detail
64+
65+
struct properties_tag {};
66+
67+
struct work_group_size_key {
68+
template <size_t... Dims>
69+
using value_t = property_value<work_group_size_key,
70+
std::integral_constant<size_t, Dims>...>;
71+
};
72+
73+
struct work_group_size_hint_key {
74+
template <size_t... Dims>
75+
using value_t = property_value<work_group_size_hint_key,
76+
std::integral_constant<size_t, Dims>...>;
77+
};
78+
79+
struct sub_group_size_key {
80+
template <uint32_t Size>
81+
using value_t = property_value<sub_group_size_key,
82+
std::integral_constant<uint32_t, Size>>;
83+
};
84+
85+
template <size_t Dim0, size_t... Dims>
86+
struct property_value<work_group_size_key, std::integral_constant<size_t, Dim0>,
87+
std::integral_constant<size_t, Dims>...> {
88+
static_assert(
89+
sizeof...(Dims) + 1 <= 3,
90+
"work_group_size property currently only supports up to three values.");
91+
static_assert(detail::AllNonZero<Dim0, Dims...>::value,
92+
"work_group_size property must only contain non-zero values.");
93+
94+
using key_t = work_group_size_key;
95+
96+
constexpr size_t operator[](int Dim) const {
97+
return std::array<size_t, sizeof...(Dims) + 1>{Dim0, Dims...}[Dim];
98+
}
99+
};
100+
101+
template <size_t Dim0, size_t... Dims>
102+
struct property_value<work_group_size_hint_key,
103+
std::integral_constant<size_t, Dim0>,
104+
std::integral_constant<size_t, Dims>...> {
105+
static_assert(sizeof...(Dims) + 1 <= 3,
106+
"work_group_size_hint property currently "
107+
"only supports up to three values.");
108+
static_assert(
109+
detail::AllNonZero<Dim0, Dims...>::value,
110+
"work_group_size_hint property must only contain non-zero values.");
111+
112+
using key_t = work_group_size_hint_key;
113+
114+
constexpr size_t operator[](int Dim) const {
115+
return std::array<size_t, sizeof...(Dims) + 1>{Dim0, Dims...}[Dim];
116+
}
117+
};
118+
119+
template <uint32_t Size>
120+
struct property_value<sub_group_size_key,
121+
std::integral_constant<uint32_t, Size>> {
122+
static_assert(Size != 0,
123+
"sub_group_size_key property must contain a non-zero value.");
124+
125+
using key_t = sub_group_size_key;
126+
using value_t = std::integral_constant<uint32_t, Size>;
127+
static constexpr uint32_t value = Size;
128+
};
129+
130+
template <size_t Dim0, size_t... Dims>
131+
inline constexpr work_group_size_key::value_t<Dim0, Dims...> work_group_size;
132+
133+
template <size_t Dim0, size_t... Dims>
134+
inline constexpr work_group_size_hint_key::value_t<Dim0, Dims...>
135+
work_group_size_hint;
136+
137+
template <uint32_t Size>
138+
inline constexpr sub_group_size_key::value_t<Size> sub_group_size;
139+
140+
template <> struct is_property_key<work_group_size_key> : std::true_type {};
141+
template <>
142+
struct is_property_key<work_group_size_hint_key> : std::true_type {};
143+
template <> struct is_property_key<sub_group_size_key> : std::true_type {};
144+
145+
namespace detail {
146+
template <> struct PropertyToKind<work_group_size_key> {
147+
static constexpr PropKind Kind = PropKind::WorkGroupSize;
148+
};
149+
template <> struct PropertyToKind<work_group_size_hint_key> {
150+
static constexpr PropKind Kind = PropKind::WorkGroupSizeHint;
151+
};
152+
template <> struct PropertyToKind<sub_group_size_key> {
153+
static constexpr PropKind Kind = PropKind::SubGroupSize;
154+
};
155+
156+
template <>
157+
struct IsCompileTimeProperty<work_group_size_key> : std::true_type {};
158+
template <>
159+
struct IsCompileTimeProperty<work_group_size_hint_key> : std::true_type {};
160+
template <>
161+
struct IsCompileTimeProperty<sub_group_size_key> : std::true_type {};
162+
163+
template <size_t Dim0, size_t... Dims>
164+
struct PropertyMetaInfo<work_group_size_key::value_t<Dim0, Dims...>> {
165+
static constexpr const char *name = "sycl-work-group-size";
166+
static constexpr const char *value = SizeListToStr<Dim0, Dims...>::value;
167+
};
168+
template <size_t Dim0, size_t... Dims>
169+
struct PropertyMetaInfo<work_group_size_hint_key::value_t<Dim0, Dims...>> {
170+
static constexpr const char *name = "sycl-work-group-size-hint";
171+
static constexpr const char *value = SizeListToStr<Dim0, Dims...>::value;
172+
};
173+
template <uint32_t Size>
174+
struct PropertyMetaInfo<sub_group_size_key::value_t<Size>> {
175+
static constexpr const char *name = "sycl-sub-group-size";
176+
static constexpr uint32_t value = Size;
177+
};
178+
179+
template <typename T, typename = void>
180+
struct HasKernelPropertiesGetMethod : std::false_type {};
181+
182+
template <typename T>
183+
struct HasKernelPropertiesGetMethod<
184+
T, sycl::detail::void_t<decltype(std::declval<T>().get(
185+
std::declval<properties_tag>()))>> : std::true_type {
186+
using properties_t =
187+
decltype(std::declval<T>().get(std::declval<properties_tag>()));
188+
};
189+
190+
} // namespace detail
191+
} // namespace experimental
192+
} // namespace oneapi
193+
} // namespace ext
194+
} // __SYCL_INLINE_VER_NAMESPACE(_V1)
195+
} // namespace sycl

sycl/include/sycl/ext/oneapi/properties/properties.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,20 @@ using empty_properties_t = properties<std::tuple<>>;
209209
// PropertyValueTs is sorted and contains only valid properties.
210210
template <typename... PropertyValueTs>
211211
using properties_t = properties<std::tuple<PropertyValueTs...>>;
212+
213+
// Helper for merging two property lists;
214+
template <typename LHSPropertiesT, typename RHSPropertiesT>
215+
struct merged_properties;
216+
template <typename... LHSPropertiesTs, typename... RHSPropertiesTs>
217+
struct merged_properties<properties_t<LHSPropertiesTs...>,
218+
properties_t<RHSPropertiesTs...>> {
219+
using type = properties<typename MergeProperties<
220+
std::tuple<LHSPropertiesTs...>, std::tuple<RHSPropertiesTs...>>::type>;
221+
};
222+
template <typename LHSPropertiesT, typename RHSPropertiesT>
223+
using merged_properties_t =
224+
typename merged_properties<LHSPropertiesT, RHSPropertiesT>::type;
225+
212226
} // namespace detail
213227
} // namespace experimental
214228
} // namespace oneapi

sycl/include/sycl/ext/oneapi/properties/property.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,11 @@ enum PropKind : uint32_t {
169169
ImplementInCSR = 3,
170170
LatencyAnchorID = 4,
171171
LatencyConstraint = 5,
172-
PropKindSize = 6,
172+
WorkGroupSize = 6,
173+
WorkGroupSizeHint = 7,
174+
SubGroupSize = 8,
175+
// PropKindSize must always be the last value.
176+
PropKindSize = 9,
173177
};
174178

175179
// This trait must be specialized for all properties and must have a unique

sycl/include/sycl/ext/oneapi/properties/property_utils.hpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,59 @@ struct SortedAllUnique<std::tuple<L, R, Rest...>>
219219
SortedAllUnique<std::tuple<R, Rest...>>,
220220
std::false_type> {};
221221

222+
//******************************************************************************
223+
// Property merging
224+
//******************************************************************************
225+
226+
// Merges two sets of properties, failing if two properties are the same but
227+
// with different values.
228+
// NOTE: This assumes that the properties are in sorted order.
229+
template <typename LHSPropertyT, typename RHSPropertyT> struct MergeProperties;
230+
231+
template <> struct MergeProperties<std::tuple<>, std::tuple<>> {
232+
using type = std::tuple<>;
233+
};
234+
235+
template <typename... LHSPropertyTs>
236+
struct MergeProperties<std::tuple<LHSPropertyTs...>, std::tuple<>> {
237+
using type = std::tuple<LHSPropertyTs...>;
238+
};
239+
240+
template <typename... RHSPropertyTs>
241+
struct MergeProperties<std::tuple<>, std::tuple<RHSPropertyTs...>> {
242+
using type = std::tuple<RHSPropertyTs...>;
243+
};
244+
245+
// Identical properties are allowed, but only one will carry over.
246+
template <typename PropertyT, typename... LHSPropertyTs,
247+
typename... RHSPropertyTs>
248+
struct MergeProperties<std::tuple<PropertyT, LHSPropertyTs...>,
249+
std::tuple<PropertyT, RHSPropertyTs...>> {
250+
using merge_tails =
251+
typename MergeProperties<std::tuple<LHSPropertyTs...>,
252+
std::tuple<RHSPropertyTs...>>::type;
253+
using type = typename PrependTuple<PropertyT, merge_tails>::type;
254+
};
255+
256+
template <typename... LHSPropertyTs, typename... RHSPropertyTs>
257+
struct MergeProperties<std::tuple<LHSPropertyTs...>,
258+
std::tuple<RHSPropertyTs...>> {
259+
using l_head = GetFirstType<LHSPropertyTs...>;
260+
using r_head = GetFirstType<RHSPropertyTs...>;
261+
static_assert(
262+
PropertyID<l_head>::value != PropertyID<r_head>::value,
263+
"Failed to merge property lists due to conflicting properties.");
264+
static constexpr bool left_has_min =
265+
PropertyID<l_head>::value < PropertyID<r_head>::value;
266+
using l_split = HeadSplit<std::tuple<LHSPropertyTs...>, left_has_min>;
267+
using r_split = HeadSplit<std::tuple<RHSPropertyTs...>, !left_has_min>;
268+
using min = typename SelectNonVoid<typename l_split::htype,
269+
typename r_split::htype>::type;
270+
using merge_tails = typename MergeProperties<typename l_split::ttype,
271+
typename r_split::ttype>::type;
272+
using type = typename PrependTuple<min, merge_tails>::type;
273+
};
274+
222275
} // namespace detail
223276
} // namespace experimental
224277
} // namespace oneapi

0 commit comments

Comments
 (0)