Skip to content

Commit 30033c1

Browse files
Merge pull request #331 from diptorupd/feature/context_ctor
Add SYCL context constructor and test cases.
2 parents 1a7075f + 554a90e commit 30033c1

File tree

3 files changed

+324
-1
lines changed

3 files changed

+324
-1
lines changed

dpctl-capi/include/dpctl_sycl_context_interface.h

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,53 @@
2929
#include "Support/ExternC.h"
3030
#include "Support/MemOwnershipAttrs.h"
3131
#include "dpctl_data_types.h"
32-
#include "dpctl_sycl_platform_interface.h"
32+
#include "dpctl_error_handler_type.h"
33+
#include "dpctl_sycl_device_manager.h"
34+
#include "dpctl_sycl_enum_types.h"
3335
#include "dpctl_sycl_types.h"
3436
#include <stdbool.h>
3537

3638
DPCTL_C_EXTERN_C_BEGIN
3739

40+
/*!
41+
* @brief Constructs a new SYCL context for the given SYCL device using the
42+
* optional async error handler and properties bit flags.
43+
*
44+
* @param DRef Opaque pointer to a SYCL device.
45+
* @param error_handler A callback function that will be invoked by the
46+
* async_handler used during context creation. Can be
47+
* NULL if no async_handler is needed.
48+
* @param properties An optional combination of bit flags to define
49+
* context properties. Currently, dpctl does not use
50+
* this argument.
51+
* @return A new opaque pointer wrapping a SYCL context.
52+
*/
53+
DPCTL_API
54+
__dpctl_give DPCTLSyclContextRef
55+
DPCTLContext_Create(__dpctl_keep const DPCTLSyclDeviceRef DRef,
56+
error_handler_callback *error_handler,
57+
int properties);
58+
59+
/*!
60+
* @brief Constructs a new SYCL context for the given vector of SYCL devices
61+
* using the optional async error handler and properties bit flags.
62+
*
63+
* @param DVRef An opaque pointer to a std::vector of
64+
* DPCTLSyclDeviceRef opaque pointers.
65+
* @param error_handler A callback function that will be invoked by the
66+
* async_handler used during context creation. Can be
67+
* NULL if no async_handler is needed.
68+
* @param properties An optional combination of bit flags to define
69+
* context properties. Currently, dpctl does not use
70+
* this argument.
71+
* @return A new opaque pointer wrapping a SYCL context.
72+
*/
73+
DPCTL_API
74+
__dpctl_give DPCTLSyclContextRef
75+
DPCTLContext_CreateFromDevices(__dpctl_keep const DPCTLDeviceVectorRef DVRef,
76+
error_handler_callback *error_handler,
77+
int properties);
78+
3879
/*!
3980
* @brief Checks if two DPCTLSyclContextRef objects point to the same
4081
* sycl::context.
@@ -47,6 +88,17 @@ DPCTL_API
4788
bool DPCTLContext_AreEq(__dpctl_keep const DPCTLSyclContextRef CtxRef1,
4889
__dpctl_keep const DPCTLSyclContextRef CtxRef2);
4990

91+
/*!
92+
* @brief Returns a copy of the DPCTLSyclContextRef object.
93+
*
94+
* @param CRef DPCTLSyclContextRef object to be copied.
95+
* @return A new DPCTLSyclContextRef created by copying the passed in
96+
* DPCTLSyclContextRef object.
97+
*/
98+
DPCTL_API
99+
__dpctl_give DPCTLSyclContextRef
100+
DPCTLContext_Copy(__dpctl_keep const DPCTLSyclContextRef CRef);
101+
50102
/*!
51103
* @brief Returns true if this SYCL context is a host context.
52104
*

dpctl-capi/source/dpctl_sycl_context_interface.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
//===----------------------------------------------------------------------===//
2626

2727
#include "dpctl_sycl_context_interface.h"
28+
#include "../helper/include/dpctl_async_error_handler.h"
2829
#include "Support/CBindingWrapping.h"
2930
#include <CL/sycl.hpp>
3031

@@ -34,8 +35,60 @@ namespace
3435
{
3536
// Create wrappers for C Binding types (see CBindingWrapping.h).
3637
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(context, DPCTLSyclContextRef)
38+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(device, DPCTLSyclDeviceRef)
39+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(vector_class<DPCTLSyclDeviceRef>,
40+
DPCTLDeviceVectorRef)
3741
} /* end of anonymous namespace */
3842

43+
__dpctl_give DPCTLSyclContextRef
44+
DPCTLContext_Create(__dpctl_keep const DPCTLSyclDeviceRef DRef,
45+
error_handler_callback *error_handler,
46+
int /**/)
47+
{
48+
DPCTLSyclContextRef CRef = nullptr;
49+
auto Device = unwrap(DRef);
50+
if (!Device)
51+
return CRef;
52+
try {
53+
CRef =
54+
wrap(new context(*Device, DPCTL_AsyncErrorHandler(error_handler)));
55+
} catch (const std::bad_alloc &ba) {
56+
std::cerr << ba.what() << '\n';
57+
} catch (const runtime_error &re) {
58+
std::cerr << re.what() << '\n';
59+
}
60+
61+
return CRef;
62+
}
63+
64+
__dpctl_give DPCTLSyclContextRef
65+
DPCTLContext_CreateFromDevices(__dpctl_keep const DPCTLDeviceVectorRef DVRef,
66+
error_handler_callback *error_handler,
67+
int /**/)
68+
{
69+
DPCTLSyclContextRef CRef = nullptr;
70+
vector_class<device> Devices;
71+
auto DeviceRefs = unwrap(DVRef);
72+
if (!DeviceRefs)
73+
return CRef;
74+
Devices.reserve(DeviceRefs->size());
75+
76+
for (auto const &DRef : *DeviceRefs) {
77+
Devices.emplace_back(*unwrap(DRef));
78+
}
79+
80+
try {
81+
CRef =
82+
wrap(new context(Devices, DPCTL_AsyncErrorHandler(error_handler)));
83+
} catch (const std::bad_alloc &ba) {
84+
std::cerr << ba.what() << '\n';
85+
} catch (const runtime_error &re) {
86+
std::cerr << re.what() << '\n';
87+
}
88+
89+
return CRef;
90+
}
91+
3992
bool DPCTLContext_AreEq(__dpctl_keep const DPCTLSyclContextRef CtxRef1,
4093
__dpctl_keep const DPCTLSyclContextRef CtxRef2)
4194
{
@@ -45,6 +98,24 @@ bool DPCTLContext_AreEq(__dpctl_keep const DPCTLSyclContextRef CtxRef1,
4598
return (*unwrap(CtxRef1) == *unwrap(CtxRef2));
4699
}
47100

101+
__dpctl_give DPCTLSyclContextRef
102+
DPCTLContext_Copy(__dpctl_keep const DPCTLSyclContextRef CRef)
103+
{
104+
auto Context = unwrap(CRef);
105+
if (!Context) {
106+
std::cerr << "Cannot copy DPCTLSyclContextRef as input is a nullptr\n";
107+
return nullptr;
108+
}
109+
try {
110+
auto CopiedContext = new context(*Context);
111+
return wrap(CopiedContext);
112+
} catch (std::bad_alloc const &ba) {
113+
// \todo log error
114+
std::cerr << ba.what() << '\n';
115+
return nullptr;
116+
}
117+
}
118+
48119
bool DPCTLContext_IsHost(__dpctl_keep const DPCTLSyclContextRef CtxRef)
49120
{
50121
auto Ctx = unwrap(CtxRef);
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
//===--- test_sycl_context_interface.cpp - Test cases for device interface ===//
2+
//
3+
// Data Parallel Control (dpCtl)
4+
//
5+
// Copyright 2020-2021 Intel Corporation
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
///
21+
/// \file
22+
/// This file has unit test cases for functions defined in
23+
/// dpctl_sycl_context_interface.h.
24+
///
25+
//===----------------------------------------------------------------------===//
26+
27+
#include "Support/CBindingWrapping.h"
28+
#include "dpctl_sycl_context_interface.h"
29+
#include "dpctl_sycl_device_interface.h"
30+
#include "dpctl_sycl_device_selector_interface.h"
31+
#include "dpctl_sycl_types.h"
32+
#include <CL/sycl.hpp>
33+
#include <gtest/gtest.h>
34+
35+
using namespace cl::sycl;
36+
37+
namespace
38+
{
39+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(sycl::device, DPCTLSyclDeviceRef);
40+
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(vector_class<DPCTLSyclDeviceRef>,
41+
DPCTLDeviceVectorRef)
42+
} // namespace
43+
44+
struct TestDPCTLContextInterface : public ::testing::TestWithParam<const char *>
45+
{
46+
DPCTLSyclDeviceSelectorRef DSRef = nullptr;
47+
48+
TestDPCTLContextInterface()
49+
{
50+
EXPECT_NO_FATAL_FAILURE(DSRef = DPCTLFilterSelector_Create(GetParam()));
51+
}
52+
53+
void SetUp()
54+
{
55+
if (!DSRef) {
56+
auto message = "Skipping as no device of type " +
57+
std::string(GetParam()) + ".";
58+
GTEST_SKIP_(message.c_str());
59+
}
60+
}
61+
62+
~TestDPCTLContextInterface()
63+
{
64+
EXPECT_NO_FATAL_FAILURE(DPCTLDeviceSelector_Delete(DSRef));
65+
}
66+
};
67+
68+
TEST_P(TestDPCTLContextInterface, Chk_Create)
69+
{
70+
DPCTLSyclContextRef CRef = nullptr;
71+
DPCTLSyclDeviceRef DRef = nullptr;
72+
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDevice_CreateFromSelector(DSRef));
73+
if (!DRef)
74+
GTEST_SKIP_("Device not found");
75+
EXPECT_NO_FATAL_FAILURE(CRef = DPCTLContext_Create(DRef, nullptr, 0));
76+
ASSERT_TRUE(CRef);
77+
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
78+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef));
79+
}
80+
81+
TEST_P(TestDPCTLContextInterface, Chk_CreateWithDevices)
82+
{
83+
size_t nCUs = 0;
84+
DPCTLSyclContextRef CRef = nullptr;
85+
DPCTLSyclDeviceRef DRef = nullptr;
86+
DPCTLDeviceVectorRef DVRef = nullptr;
87+
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDevice_CreateFromSelector(DSRef));
88+
if (!DRef)
89+
GTEST_SKIP_("Device not found");
90+
91+
/* TODO: Once we have wrappers for sub-device creation let us use those
92+
* functions.
93+
*/
94+
EXPECT_NO_FATAL_FAILURE(nCUs = DPCTLDevice_GetMaxComputeUnits(DRef));
95+
if (nCUs) {
96+
auto D = unwrap(DRef);
97+
try {
98+
auto subDevices = D->create_sub_devices<
99+
info::partition_property::partition_equally>(nCUs / 2);
100+
EXPECT_NO_FATAL_FAILURE(DVRef = DPCTLDeviceVector_Create());
101+
for (auto &sd : subDevices) {
102+
unwrap(DVRef)->emplace_back(wrap(new device(sd)));
103+
}
104+
EXPECT_NO_FATAL_FAILURE(
105+
CRef = DPCTLContext_CreateFromDevices(DVRef, nullptr, 0));
106+
ASSERT_TRUE(CRef);
107+
} catch (feature_not_supported const &fnse) {
108+
GTEST_SKIP_("Skipping creating context for sub-devices");
109+
}
110+
}
111+
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
112+
EXPECT_NO_FATAL_FAILURE(DPCTLDeviceVector_Delete(DVRef));
113+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef));
114+
}
115+
116+
TEST_P(TestDPCTLContextInterface, Chk_AreEq)
117+
{
118+
DPCTLSyclContextRef CRef1 = nullptr, CRef2 = nullptr, CRef3 = nullptr;
119+
DPCTLSyclDeviceRef DRef = nullptr;
120+
bool are_eq = true, are_not_eq = false;
121+
122+
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDevice_CreateFromSelector(DSRef));
123+
if (!DRef)
124+
GTEST_SKIP_("Device not found");
125+
EXPECT_NO_FATAL_FAILURE(CRef1 = DPCTLContext_Create(DRef, nullptr, 0));
126+
EXPECT_NO_FATAL_FAILURE(CRef2 = DPCTLContext_Copy(CRef1));
127+
// TODO: This work till DPC++ does not have a default context per device,
128+
// after that we need to change the test case some how.
129+
EXPECT_NO_FATAL_FAILURE(CRef3 = DPCTLContext_Create(DRef, nullptr, 0));
130+
ASSERT_TRUE(CRef3);
131+
ASSERT_TRUE(CRef2);
132+
ASSERT_TRUE(CRef1);
133+
134+
EXPECT_NO_FATAL_FAILURE(are_eq = DPCTLContext_AreEq(CRef1, CRef2));
135+
EXPECT_NO_FATAL_FAILURE(are_not_eq = DPCTLContext_AreEq(CRef1, CRef3));
136+
EXPECT_TRUE(are_eq);
137+
EXPECT_FALSE(are_not_eq);
138+
139+
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
140+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef1));
141+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef2));
142+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef3));
143+
}
144+
145+
TEST_P(TestDPCTLContextInterface, Chk_IsHost)
146+
{
147+
DPCTLSyclContextRef CRef = nullptr;
148+
DPCTLSyclDeviceRef DRef = nullptr;
149+
bool is_host_device = false, is_host_context = false;
150+
151+
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDevice_CreateFromSelector(DSRef));
152+
if (!DRef)
153+
GTEST_SKIP_("Device not found");
154+
EXPECT_NO_FATAL_FAILURE(CRef = DPCTLContext_Create(DRef, nullptr, 0));
155+
ASSERT_TRUE(CRef);
156+
157+
EXPECT_NO_FATAL_FAILURE(is_host_device = DPCTLDevice_IsHost(DRef));
158+
EXPECT_NO_FATAL_FAILURE(is_host_context = DPCTLContext_IsHost(CRef));
159+
EXPECT_TRUE(is_host_device == is_host_context);
160+
161+
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
162+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef));
163+
}
164+
165+
TEST_P(TestDPCTLContextInterface, Chk_GetBackend)
166+
{
167+
DPCTLSyclContextRef CRef = nullptr;
168+
DPCTLSyclDeviceRef DRef = nullptr;
169+
DPCTLSyclBackendType context_backend = DPCTL_UNKNOWN_BACKEND,
170+
device_backend = DPCTL_UNKNOWN_BACKEND;
171+
172+
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDevice_CreateFromSelector(DSRef));
173+
if (!DRef)
174+
GTEST_SKIP_("Device not found");
175+
EXPECT_NO_FATAL_FAILURE(CRef = DPCTLContext_Create(DRef, nullptr, 0));
176+
ASSERT_TRUE(CRef);
177+
178+
EXPECT_NO_FATAL_FAILURE(device_backend = DPCTLDevice_GetBackend(DRef));
179+
EXPECT_NO_FATAL_FAILURE(context_backend = DPCTLContext_GetBackend(CRef));
180+
EXPECT_TRUE(device_backend == context_backend);
181+
182+
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
183+
EXPECT_NO_FATAL_FAILURE(DPCTLContext_Delete(CRef));
184+
}
185+
186+
INSTANTIATE_TEST_SUITE_P(DPCTLContextTests,
187+
TestDPCTLContextInterface,
188+
::testing::Values("opencl",
189+
"opencl:gpu",
190+
"opencl:cpu",
191+
"opencl:gpu:0",
192+
"gpu",
193+
"cpu",
194+
"level_zero",
195+
"level_zero:gpu",
196+
"opencl:cpu:0",
197+
"level_zero:gpu:0",
198+
"gpu:0",
199+
"gpu:1",
200+
"1"));

0 commit comments

Comments
 (0)