Skip to content

Commit b3dac2f

Browse files
author
Diptorup Deb
authored
Merge pull request #453 from IntelPython:feature/producing-filter-selector
Feature/producing filter selector
2 parents d227ab9 + c31be27 commit b3dac2f

File tree

7 files changed

+232
-7
lines changed

7 files changed

+232
-7
lines changed

dpctl-capi/include/dpctl_sycl_device_manager.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,26 @@ DPCTL_API
7676
__dpctl_give DPCTLDeviceVectorRef
7777
DPCTLDeviceMgr_GetDevices(int device_identifier);
7878

79+
/*!
80+
* @brief Returns an index on the given device in the vector returned by
81+
* #DPCTLDeviceMgr_GetDevices if found, -1 otherwise.
82+
*
83+
* The device_identifier can be a combination of #DPCTLSyclBackendType and
84+
* #DPCTLSyclDeviceType bit flags. The function returns all devices that
85+
* match the specified bit flags.
86+
*
87+
* @param DRef A #DPCTLSyclDeviceRef opaque pointer.
88+
* @param device_identifier A bitflag that can be any combination of
89+
* #DPCTLSyclBackendType and #DPCTLSyclDeviceType
90+
* enum values.
91+
* @return If found, returns the position of the given device in the
92+
* vector that would be returned by #DPCTLDeviceMgr_GetDevices if called
93+
* with the same device_identifier argument.
94+
*/
95+
DPCTL_API
96+
int DPCTLDeviceMgr_GetPositionInDevices(__dpctl_keep DPCTLSyclDeviceRef DRef,
97+
int device_identifier);
98+
7999
/*!
80100
* @brief If the DPCTLSyclDeviceRef argument is a root device, then this
81101
* function returns a cached default SYCL context for that device.

dpctl-capi/source/dpctl_sycl_device_manager.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,35 @@ DPCTLDeviceMgr_GetDevices(int device_identifier)
164164
return wrap(Devices);
165165
}
166166

167+
int DPCTLDeviceMgr_GetPositionInDevices(__dpctl_keep DPCTLSyclDeviceRef DRef,
168+
int device_identifier)
169+
{
170+
constexpr int not_found = -1;
171+
if (!DRef) {
172+
return not_found;
173+
}
174+
175+
const auto &root_devices = device::get_devices();
176+
default_selector mRanker;
177+
int index = not_found;
178+
auto reference_device = *(unwrap(DRef));
179+
180+
for (const auto &root_device : root_devices) {
181+
if (mRanker(root_device) < 0)
182+
continue;
183+
auto Bty(DPCTL_SyclBackendToDPCTLBackendType(
184+
root_device.get_platform().get_backend()));
185+
auto Dty(DPCTL_SyclDeviceTypeToDPCTLDeviceType(
186+
root_device.get_info<info::device::device_type>()));
187+
if ((device_identifier & Bty) && (device_identifier & Dty)) {
188+
++index;
189+
if (root_device == reference_device)
190+
return index;
191+
}
192+
}
193+
return not_found;
194+
}
195+
167196
/*!
168197
* Returns the number of available devices for a specific backend and device
169198
* type combination.

dpctl-capi/tests/test_sycl_device_manager.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,12 @@ struct TestDPCTLGetDevicesOrdering : public ::testing::TestWithParam<int>
146146
{
147147
DPCTLDeviceVectorRef DV = nullptr;
148148
size_t nDevices = 0;
149+
int device_type_mask;
149150

150151
TestDPCTLGetDevicesOrdering()
151152
{
152-
const int device_type_mask =
153-
(GetParam() & DPCTLSyclDeviceType::DPCTL_ALL) |
154-
DPCTLSyclBackendType::DPCTL_ALL_BACKENDS;
153+
device_type_mask = (GetParam() & DPCTLSyclDeviceType::DPCTL_ALL) |
154+
DPCTLSyclBackendType::DPCTL_ALL_BACKENDS;
155155
EXPECT_NO_FATAL_FAILURE(
156156
DV = DPCTLDeviceMgr_GetDevices(device_type_mask));
157157
EXPECT_TRUE(DV != nullptr);
@@ -179,6 +179,7 @@ TEST_P(TestDPCTLGetDevicesOrdering, ChkConsistencyWithFilterSelector)
179179
std::string fs_device_type, fs;
180180
DPCTLSyclDeviceRef DRef = nullptr, D0Ref = nullptr;
181181
DPCTLSyclDeviceSelectorRef DSRef = nullptr;
182+
int j = -1;
182183
EXPECT_NO_FATAL_FAILURE(DRef = DPCTLDeviceVector_GetAt(DV, i));
183184
EXPECT_NO_FATAL_FAILURE(Dty = DPCTLDevice_GetDeviceType(DRef));
184185
EXPECT_NO_FATAL_FAILURE(
@@ -189,6 +190,10 @@ TEST_P(TestDPCTLGetDevicesOrdering, ChkConsistencyWithFilterSelector)
189190
EXPECT_NO_FATAL_FAILURE(D0Ref = DPCTLDevice_CreateFromSelector(DSRef));
190191
EXPECT_NO_FATAL_FAILURE(DPCTLDeviceSelector_Delete(DSRef));
191192
EXPECT_TRUE(DPCTLDevice_AreEq(DRef, D0Ref));
193+
EXPECT_NO_FATAL_FAILURE(
194+
j = DPCTLDeviceMgr_GetPositionInDevices(DRef, device_type_mask));
195+
EXPECT_TRUE(j >= 0);
196+
EXPECT_TRUE(i == static_cast<decltype(i)>(j));
192197
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(D0Ref));
193198
EXPECT_NO_FATAL_FAILURE(DPCTLDevice_Delete(DRef));
194199
}

dpctl/_backend.pxd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ cdef extern from "dpctl_sycl_device_manager.h":
208208
DPCTLDeviceVectorRef DVRef,
209209
size_t index)
210210
cdef DPCTLDeviceVectorRef DPCTLDeviceMgr_GetDevices(int device_identifier)
211+
cdef int DPCTLDeviceMgr_GetPositionInDevices(
212+
const DPCTLSyclDeviceRef DRef,
213+
int device_identifier)
211214
cdef size_t DPCTLDeviceMgr_GetNumDevices(int device_identifier)
212215
cdef void DPCTLDeviceMgr_PrintDeviceInfo(const DPCTLSyclDeviceRef DRef)
213216
cdef DPCTLSyclContextRef DPCTLDeviceMgr_GetCachedContext(

dpctl/_sycl_device.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,7 @@ cdef public class SyclDevice(_SyclDevice) [object PySyclDeviceObject, type PySyc
5151
cdef list create_sub_devices_by_counts(self, object counts)
5252
cdef list create_sub_devices_by_affinity(self, _partition_affinity_domain_type domain)
5353
cdef cpp_bool equals(self, SyclDevice q)
54+
cdef int get_device_type_ordinal(self)
55+
cdef int get_overall_ordinal(self)
56+
cdef int get_backend_ordinal(self)
57+
cdef int get_backend_and_device_type_ordinal(self)

dpctl/_sycl_device.pyx

Lines changed: 150 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ from ._backend cimport ( # noqa: E211
6161
DPCTLDevice_IsCPU,
6262
DPCTLDevice_IsGPU,
6363
DPCTLDevice_IsHost,
64+
DPCTLDeviceMgr_GetDevices,
65+
DPCTLDeviceMgr_GetPositionInDevices,
6466
DPCTLDeviceMgr_GetRelativeId,
6567
DPCTLDeviceMgr_PrintDeviceInfo,
6668
DPCTLDeviceSelector_Delete,
@@ -825,8 +827,23 @@ cdef class SyclDevice(_SyclDevice):
825827

826828
@property
827829
def filter_string(self):
828-
""" For a parent device, returns a ``tuple (backend, device_kind,
829-
relative_id)``. Raises an exception for sub-devices.
830+
"""
831+
For a parent device, returns a fully specified filter selector
832+
string``backend:device_type:relative_id`` selecting the device.
833+
834+
Raises an exception for sub-devices.
835+
836+
:Example:
837+
.. code-block:: python
838+
839+
import dpctl
840+
841+
# Create a SyclDevice with an explicit filter string,
842+
# in this case the first level_zero gpu device.
843+
level_zero_gpu = dpctl.SyclDevice("level_zero:gpu:0")
844+
# filter_string property should be "level_zero:gpu:0"
845+
dev = dpctl.SyclDevice(level_zero_gpu.filter_string)
846+
assert level_zero_gpu == dev
830847
"""
831848
cdef DPCTLSyclDeviceRef pDRef = NULL
832849
cdef DPCTLSyclBackendType BTy
@@ -846,3 +863,134 @@ cdef class SyclDevice(_SyclDevice):
846863
# this a sub-device, free it, and raise an exception
847864
DPCTLDevice_Delete(pDRef)
848865
raise TypeError("This SyclDevice is not a root device")
866+
867+
cdef int get_backend_and_device_type_ordinal(self):
868+
"""
869+
If this device is a root ``sycl::device`` returns the ordinal
870+
position of this device in the vector
871+
``sycl::device::get_devices(device_type_of_this_device)``
872+
filtered to contain only devices with the same backend as this
873+
device.
874+
875+
Returns -1 if the device is a sub-device, or the device could not
876+
be found in the vector.
877+
"""
878+
cdef int64_t relId = DPCTLDeviceMgr_GetRelativeId(self._device_ref)
879+
return relId
880+
881+
cdef int get_device_type_ordinal(self):
882+
"""
883+
If this device is a root ``sycl::device`` returns the ordinal
884+
position of this device in the vector
885+
``sycl::device::get_devices(device_type_of_this_device)``
886+
887+
Returns -1 if the device is a sub-device, or the device could not
888+
be found in the vector.
889+
"""
890+
cdef DPCTLSyclDeviceType DTy
891+
cdef int64_t relId = -1
892+
893+
DTy = DPCTLDevice_GetDeviceType(self._device_ref)
894+
relId = DPCTLDeviceMgr_GetPositionInDevices(
895+
self._device_ref, _backend_type._ALL_BACKENDS | DTy)
896+
return relId
897+
898+
cdef int get_backend_ordinal(self):
899+
"""
900+
If this device is a root ``sycl::device`` returns the ordinal
901+
position of this device in the vector ``sycl::device::get_devices()``
902+
filtered to contain only devices with the same backend as this
903+
device.
904+
905+
Returns -1 if the device is a sub-device, or the device could not
906+
be found in the vector.
907+
"""
908+
cdef DPCTLSyclBackendType BTy
909+
cdef int64_t relId = -1
910+
911+
BTy = DPCTLDevice_GetBackend(self._device_ref)
912+
relId = DPCTLDeviceMgr_GetPositionInDevices(
913+
self._device_ref, BTy | _device_type._ALL_DEVICES)
914+
return relId
915+
916+
cdef int get_overall_ordinal(self):
917+
"""
918+
If this device is a root ``sycl::device`` returns the ordinal
919+
position of this device in the vector ``sycl::device::get_devices()``
920+
filtered to contain only devices with the same backend as this
921+
device.
922+
923+
Returns -1 if the device is a sub-device, or the device could not
924+
be found in the vector.
925+
"""
926+
cdef int64_t relId = -1
927+
928+
relId = DPCTLDeviceMgr_GetPositionInDevices(
929+
self._device_ref,
930+
(_backend_type._ALL_BACKENDS | _device_type._ALL_DEVICES)
931+
)
932+
return relId
933+
934+
def get_filter_string(self, include_backend=True, include_device_type=True):
935+
"""
936+
For a parent device returns a filter selector string
937+
that includes backend or device type based on the value
938+
of the given keyword arguments.
939+
940+
Raises a TypeError if this devices is a sub-device, or
941+
a ValueError if no match was found in the vector returned
942+
by ``sycl::device::get_devices()``.
943+
944+
:Example:
945+
.. code-block:: python
946+
947+
import dpctl
948+
949+
# Create a GPU SyclDevice
950+
gpu_dev = dpctl.SyclDevice("gpu:0")
951+
# filter string should be "gpu:0"
952+
fs = gpu_dev.get_filter_string(use_backend=False)
953+
dev = dpctl.SyclDevice(fs)
954+
assert gpu _dev == dev
955+
"""
956+
cdef int relId = -1
957+
cdef DPCTLSyclDeviceRef pDRef = NULL
958+
cdef DPCTLSyclDeviceType DTy
959+
cdef DPCTLSyclBackendType BTy
960+
961+
if include_backend:
962+
if include_device_type:
963+
relId = self.get_backend_and_device_type_ordinal()
964+
else:
965+
relId = self.get_backend_ordinal()
966+
else:
967+
if include_device_type:
968+
relId = self.get_device_type_ordinal()
969+
else:
970+
relId = self.get_overall_ordinal()
971+
972+
if relId < 0:
973+
pDRef = DPCTLDevice_GetParentDevice(self._device_ref)
974+
if (pDRef is NULL):
975+
raise ValueError
976+
else:
977+
# this a sub-device, free it, and raise an exception
978+
DPCTLDevice_Delete(pDRef)
979+
raise TypeError("This SyclDevice is not a root device")
980+
else:
981+
if include_backend:
982+
BTy = DPCTLDevice_GetBackend(self._device_ref)
983+
be_str = _backend_type_to_filter_string_part(BTy)
984+
if include_device_type:
985+
DTy = DPCTLDevice_GetDeviceType(self._device_ref)
986+
dt_str = _device_type_to_filter_string_part(DTy)
987+
return ":".join((be_str, dt_str, str(relId)))
988+
else:
989+
return ":".join((be_str, str(relId)))
990+
else:
991+
if include_device_type:
992+
DTy = DPCTLDevice_GetDeviceType(self._device_ref)
993+
dt_str = _device_type_to_filter_string_part(DTy)
994+
return ":".join((dt_str, str(relId)))
995+
else:
996+
return str(relId)

dpctl/tests/test_sycl_device.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,13 +591,29 @@ def test_filter_string(valid_filter):
591591
)
592592

593593

594-
def test_filter_string2():
594+
def test_filter_string_property():
595595
"""
596596
Test that filter_string reconstructs the same device.
597597
"""
598598
devices = dpctl.get_devices()
599599
for d in devices:
600-
if d.default_selector_score > 0:
600+
if d.default_selector_score >= 0:
601601
dev_id = d.filter_string
602602
d_r = dpctl.SyclDevice(dev_id)
603603
assert d == d_r
604+
605+
606+
def test_filter_string_method():
607+
"""
608+
Test that filter_string reconstructs the same device.
609+
"""
610+
devices = dpctl.get_devices()
611+
for d in devices:
612+
for be in [True, False]:
613+
for dt in [True, False]:
614+
if d.default_selector_score >= 0:
615+
dev_id = d.get_filter_string(
616+
include_backend=be, include_device_type=dt
617+
)
618+
d_r = dpctl.SyclDevice(dev_id)
619+
assert d == d_r, "Failed "

0 commit comments

Comments
 (0)