Skip to content

Commit 5560978

Browse files
Added pybind11 example that uses dpctl.SyclQueue to indicate offload
1 parent 5e5ddb9 commit 5560978

File tree

4 files changed

+198
-0
lines changed

4 files changed

+198
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Usage of dpctl entities in Pybind11
2+
3+
This extension demonstrates how dpctl Python types,
4+
such as dpctl.SyclQueue could be used in Pybind11
5+
extensions.
6+
7+
8+
# Building extension
9+
10+
```
11+
source /opt/intel/oneapi/compiler/latest/env/vars.sh
12+
CXX=dpcpp CC=dpcpp python setup.py build_ext --inplace
13+
python example.py
14+
```
15+
16+
# Sample output
17+
18+
```
19+
(idp) [17:25:27 ansatnuc04 use_dpctl_syclqueue]$ python example.py
20+
EU count returned by Pybind11 extension 24
21+
EU count computed by dpctl 24
22+
23+
Computing modular reduction using SYCL on a NumPy array
24+
Offloaded result agrees with reference one computed by NumPy
25+
```
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Data Parallel Control (dpctl)
2+
#
3+
# Copyright 2020-2021 Intel Corporation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# coding: utf-8
18+
19+
import numpy as np
20+
import pybind11_example as eg
21+
22+
import dpctl
23+
24+
q = dpctl.SyclQueue()
25+
26+
# Pass dpctl.SyclQueue to Pybind11 extension
27+
eu_count = eg.get_max_compute_units(q)
28+
29+
print(f"EU count returned by Pybind11 extension {eu_count}")
30+
print("EU count computed by dpctl {}".format(q.sycl_device.max_compute_units))
31+
32+
print("")
33+
print("Computing modular reduction using SYCL on a NumPy array")
34+
35+
X = np.random.randint(low=1, high=2 ** 16 - 1, size=10 ** 6, dtype=np.longlong)
36+
modulus_p = 347
37+
38+
Y = eg.offloaded_array_mod(
39+
q, X, modulus_p
40+
) # Y is a regular array with host memory underneath it
41+
Ynp = X % modulus_p
42+
43+
check = np.array_equal(Y, Ynp)
44+
45+
if check:
46+
print("Offloaded result agrees with reference one computed by NumPy")
47+
else:
48+
print("Offloaded array differs from reference result computed by NumPy")
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#include <CL/sycl.hpp>
2+
#include <cstdint>
3+
#include <pybind11/numpy.h>
4+
#include <pybind11/pybind11.h>
5+
6+
#include "../_sycl_queue.h"
7+
#include "../_sycl_queue_api.h"
8+
#include "dpctl_sycl_types.h"
9+
10+
namespace py = pybind11;
11+
12+
size_t get_max_compute_units(py::object queue)
13+
{
14+
PyObject *queue_ptr = queue.ptr();
15+
if (PyObject_TypeCheck(queue_ptr, &PySyclQueueType)) {
16+
DPCTLSyclQueueRef QRef =
17+
get_queue_ref(reinterpret_cast<PySyclQueueObject *>(queue_ptr));
18+
sycl::queue *q = reinterpret_cast<sycl::queue *>(QRef);
19+
20+
return q->get_device()
21+
.get_info<sycl::info::device::max_compute_units>();
22+
}
23+
else {
24+
throw std::runtime_error("expected dpctl.SyclQueue as argument");
25+
}
26+
}
27+
28+
py::array_t<int64_t>
29+
offloaded_array_mod(py::object queue,
30+
py::array_t<int64_t, py::array::c_style> array,
31+
int64_t mod)
32+
{
33+
sycl::queue *q_ptr;
34+
35+
PyObject *queue_pycapi = queue.ptr();
36+
if (PyObject_TypeCheck(queue_pycapi, &PySyclQueueType)) {
37+
DPCTLSyclQueueRef QRef =
38+
get_queue_ref(reinterpret_cast<PySyclQueueObject *>(queue_pycapi));
39+
q_ptr = reinterpret_cast<sycl::queue *>(QRef);
40+
}
41+
else {
42+
throw std::runtime_error("expected dpctl.SyclQueue as argument");
43+
}
44+
45+
py::buffer_info arg_pybuf = array.request();
46+
if (arg_pybuf.ndim != 1) {
47+
throw std::runtime_error("Expecting a vector");
48+
}
49+
if (mod <= 0) {
50+
throw std::runtime_error("Modulus must be non-negative");
51+
}
52+
53+
size_t n = arg_pybuf.size;
54+
55+
auto res = py::array_t<int64_t>(n);
56+
py::buffer_info res_pybuf = res.request();
57+
58+
int64_t *a = static_cast<int64_t *>(arg_pybuf.ptr);
59+
int64_t *r = static_cast<int64_t *>(res_pybuf.ptr);
60+
61+
{
62+
const sycl::property_list props = {
63+
sycl::property::buffer::use_host_ptr()};
64+
sycl::buffer<int64_t, 1> a_buf(a, sycl::range<1>(n), props);
65+
sycl::buffer<int64_t, 1> r_buf(r, sycl::range<1>(n), props);
66+
67+
q_ptr
68+
->submit([&](sycl::handler &cgh) {
69+
sycl::accessor a_acc(a_buf, cgh, sycl::read_only);
70+
sycl::accessor r_acc(r_buf, cgh, sycl::write_only,
71+
sycl::noinit);
72+
73+
cgh.parallel_for(sycl::range<1>(n), [=](sycl::id<1> idx) {
74+
r_acc[idx] = a_acc[idx] % mod;
75+
});
76+
})
77+
.wait_and_throw();
78+
}
79+
80+
return res;
81+
}
82+
83+
PYBIND11_MODULE(pybind11_example, m)
84+
{
85+
// Import the dpctl._sycl_queue extension
86+
import_dpctl___sycl_queue();
87+
m.def("get_max_compute_units", &get_max_compute_units,
88+
"Computes max_compute_units property of the device underlying given "
89+
"dpctl.SyclQueue");
90+
m.def("offloaded_array_mod", &offloaded_array_mod,
91+
"Compute offloaded modular reduction of integer-valued NumPy array");
92+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Data Parallel Control (dpctl)
2+
#
3+
# Copyright 2020-2021 Intel Corporation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from pybind11.setup_helpers import Pybind11Extension
18+
from setuptools import setup
19+
20+
import dpctl
21+
22+
exts = [
23+
Pybind11Extension(
24+
"pybind11_example",
25+
["./pybind11_example.cpp"],
26+
include_dirs=[dpctl.get_include()],
27+
extra_compile_args=["-fPIC"],
28+
extra_link_args=["-fPIC"],
29+
language="c++",
30+
),
31+
]
32+
33+
setup(name="pybind11_example", ext_modules=exts)

0 commit comments

Comments
 (0)