diff --git a/CHANGELOG.md b/CHANGELOG.md index a815f2ffdd..e15d41f23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added +- Device descriptors "max_compute_units", "max_work_item_dimensions", "max_work_item_sizes", "max_work_group_size", "max_num_sub_groups" and "aspects" for int64 atomics inside dpctl C API and inside the dpctl.SyclDevice class. + ### Removed - The Legacy OpenCL interface. diff --git a/backends/include/dppl_sycl_device_interface.h b/backends/include/dppl_sycl_device_interface.h index 75ab605b93..f677c642fc 100644 --- a/backends/include/dppl_sycl_device_interface.h +++ b/backends/include/dppl_sycl_device_interface.h @@ -102,6 +102,76 @@ DPPL_API __dppl_give const char* DPPLDevice_GetDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef); +/*! + * @brief Wrapper over device.get_info(). + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns the valid result if device exists else returns 0. + */ +DPPL_API +uint32_t +DPPLDevice_GetMaxComputeUnits (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper for get_info(). + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns the valid result if device exists else returns 0. + */ +DPPL_API +uint32_t +DPPLDevice_GetMaxWorkItemDims (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper for get_info(). + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns the valid result if device exists else returns NULL. + */ +DPPL_API +__dppl_keep size_t* +DPPLDevice_GetMaxWorkItemSizes (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper for get_info(). + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns the valid result if device exists else returns 0. + */ +DPPL_API +size_t +DPPLDevice_GetMaxWorkGroupSize (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper over device.get_info. + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns the valid result if device exists else returns 0. + */ +DPPL_API +uint32_t +DPPLDevice_GetMaxNumSubGroups (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper over device.get_info. + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns true if device has int64_base_atomics else returns false. + */ +DPPL_API +bool +DPPLDevice_HasInt64BaseAtomics (__dppl_keep const DPPLSyclDeviceRef DRef); + +/*! + * @brief Wrapper over device.get_info. + * + * @param DRef Opaque pointer to a sycl::device + * @return Returns true if device has int64_extended_atomics else returns false. + */ +DPPL_API +bool +DPPLDevice_HasInt64ExtendedAtomics (__dppl_keep const DPPLSyclDeviceRef DRef); + /*! * @brief Returns a C string for the device name. * diff --git a/backends/include/dppl_utils.h b/backends/include/dppl_utils.h index 1cf0223f28..b0578173af 100644 --- a/backends/include/dppl_utils.h +++ b/backends/include/dppl_utils.h @@ -24,6 +24,7 @@ #pragma once +#include "dppl_data_types.h" #include "Support/DllExport.h" #include "Support/ExternC.h" #include "Support/MemOwnershipAttrs.h" @@ -31,11 +32,19 @@ DPPL_C_EXTERN_C_BEGIN /*! - * @brief Deletes the C String argument + * @brief Deletes the C String argument. * * @param str C string to be deleted */ DPPL_API void DPPLCString_Delete (__dppl_take const char* str); +/*! + * @brief Deletes an array of size_t elements. + * + * @param arr Array to be deleted. + */ +DPPL_API +void DPPLSize_t_Array_Delete (__dppl_take size_t* arr); + DPPL_C_EXTERN_C_END diff --git a/backends/source/dppl_sycl_device_interface.cpp b/backends/source/dppl_sycl_device_interface.cpp index 874094a4b1..0dbf2affe1 100644 --- a/backends/source/dppl_sycl_device_interface.cpp +++ b/backends/source/dppl_sycl_device_interface.cpp @@ -103,53 +103,161 @@ void DPPLDevice_Delete (__dppl_take DPPLSyclDeviceRef DRef) bool DPPLDevice_IsAccelerator (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_accelerator(); + auto D = unwrap(DRef); + if (D) { + return D->is_accelerator(); + } + return false; } bool DPPLDevice_IsCPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_cpu(); + auto D = unwrap(DRef); + if (D) { + return D->is_cpu(); + } + return false; } bool DPPLDevice_IsGPU (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_gpu(); + auto D = unwrap(DRef); + if (D) { + return D->is_gpu(); + } + return false; } bool DPPLDevice_IsHost (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->is_host(); + auto D = unwrap(DRef); + if (D) { + return D->is_host(); + } + return false; +} + + +uint32_t +DPPLDevice_GetMaxComputeUnits (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->get_info(); + } + return 0; +} + +uint32_t +DPPLDevice_GetMaxWorkItemDims (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->get_info(); + } + return 0; +} + +__dppl_keep size_t* +DPPLDevice_GetMaxWorkItemSizes (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + size_t *sizes = nullptr; + auto D = unwrap(DRef); + if (D) { + auto id_sizes = D->get_info(); + sizes = new size_t[3]; + for(auto i = 0ul; i < 3; ++i) { + sizes[i] = id_sizes[i]; + } + } + return sizes; +} + +size_t +DPPLDevice_GetMaxWorkGroupSize (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->get_info(); + } + return 0; +} + +uint32_t +DPPLDevice_GetMaxNumSubGroups (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->get_info(); + } + return 0; +} + +bool +DPPLDevice_HasInt64BaseAtomics (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->has(aspect::int64_base_atomics); + } + return false; +} + +bool +DPPLDevice_HasInt64ExtendedAtomics (__dppl_keep const DPPLSyclDeviceRef DRef) +{ + auto D = unwrap(DRef); + if (D) { + return D->has(aspect::int64_extended_atomics); + } + return false; } __dppl_give const char* DPPLDevice_GetName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto name = unwrap(DRef)->get_info(); - auto cstr_name = new char [name.length()+1]; - std::strcpy (cstr_name, name.c_str()); - return cstr_name; + auto D = unwrap(DRef); + if (D) { + auto name = D->get_info(); + auto cstr_name = new char [name.length()+1]; + std::strcpy (cstr_name, name.c_str()); + return cstr_name; + } + return nullptr; } __dppl_give const char* DPPLDevice_GetVendorName (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto vendor = unwrap(DRef)->get_info(); - auto cstr_vendor = new char [vendor.length()+1]; - std::strcpy (cstr_vendor, vendor.c_str()); - return cstr_vendor; + auto D = unwrap(DRef); + if (D) { + auto vendor = D->get_info(); + auto cstr_vendor = new char [vendor.length()+1]; + std::strcpy (cstr_vendor, vendor.c_str()); + return cstr_vendor; + } + return nullptr; } __dppl_give const char* DPPLDevice_GetDriverInfo (__dppl_keep const DPPLSyclDeviceRef DRef) { - auto driver = unwrap(DRef)->get_info(); - auto cstr_driver = new char [driver.length()+1]; - std::strcpy (cstr_driver, driver.c_str()); - return cstr_driver; + auto D = unwrap(DRef); + if (D) { + auto driver = D->get_info(); + auto cstr_driver = new char [driver.length()+1]; + std::strcpy (cstr_driver, driver.c_str()); + return cstr_driver; + } + return nullptr; } bool DPPLDevice_IsHostUnifiedMemory (__dppl_keep const DPPLSyclDeviceRef DRef) { - return unwrap(DRef)->get_info(); + auto D = unwrap(DRef); + if (D) { + return D->get_info(); + } + return false; } diff --git a/backends/source/dppl_utils.cpp b/backends/source/dppl_utils.cpp index cea4ef0f3d..6468809070 100644 --- a/backends/source/dppl_utils.cpp +++ b/backends/source/dppl_utils.cpp @@ -29,3 +29,8 @@ void DPPLCString_Delete (__dppl_take const char* str) { delete[] str; } + +void DPPLSize_t_Array_Delete (__dppl_take size_t* arr) +{ + delete[] arr; +} diff --git a/backends/tests/CMakeLists.txt b/backends/tests/CMakeLists.txt index f2bc8c6462..d0efc5ebfe 100644 --- a/backends/tests/CMakeLists.txt +++ b/backends/tests/CMakeLists.txt @@ -23,6 +23,7 @@ else() link_directories(${GTEST_LIB_DIR}) set(DPCTL_C_API_TEST_CASES + test_sycl_device_interface test_sycl_kernel_interface test_sycl_platform_interface test_sycl_program_interface diff --git a/backends/tests/test_sycl_device_interface.cpp b/backends/tests/test_sycl_device_interface.cpp new file mode 100644 index 0000000000..43da260e39 --- /dev/null +++ b/backends/tests/test_sycl_device_interface.cpp @@ -0,0 +1,404 @@ +//===----- test_sycl_device_interface.cpp - dpctl-C_API interface -*- C++ -*-===// +// +// Python Data Parallel Processing Library (PyDPPL) +// +// Copyright 2020 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file has unit test cases for functions defined in +/// dppl_sycl_device_interface.h. +/// +//===----------------------------------------------------------------------===// + +#include "dppl_sycl_device_interface.h" +#include "dppl_sycl_queue_interface.h" +#include "dppl_sycl_queue_manager.h" +#include "dppl_utils.h" + +#include +#include + +using namespace cl::sycl; + + +struct TestDPPLSyclDeviceInterface : public ::testing::Test +{ + DPPLSyclDeviceRef OpenCL_cpu = nullptr; + DPPLSyclDeviceRef OpenCL_gpu = nullptr; + DPPLSyclDeviceRef OpenCL_Level0_gpu = nullptr; + + TestDPPLSyclDeviceInterface () + { + if(DPPLQueueMgr_GetNumQueues(DPPL_OPENCL, DPPL_CPU)) { + auto Q = DPPLQueueMgr_GetQueue(DPPL_OPENCL, DPPL_CPU, 0); + OpenCL_cpu = DPPLQueue_GetDevice(Q); + DPPLQueue_Delete(Q); + } + + if(DPPLQueueMgr_GetNumQueues(DPPL_OPENCL, DPPL_GPU)) { + auto Q = DPPLQueueMgr_GetQueue(DPPL_OPENCL, DPPL_GPU, 0); + OpenCL_gpu = DPPLQueue_GetDevice(Q); + DPPLQueue_Delete(Q); + } + + if(DPPLQueueMgr_GetNumQueues(DPPL_LEVEL_ZERO, DPPL_GPU)) { + auto Q = DPPLQueueMgr_GetQueue(DPPL_LEVEL_ZERO, DPPL_GPU, 0); + OpenCL_Level0_gpu = DPPLQueue_GetDevice(Q); + DPPLQueue_Delete(Q); + } + } + + ~TestDPPLSyclDeviceInterface () + { + DPPLDevice_Delete(OpenCL_cpu); + DPPLDevice_Delete(OpenCL_gpu); + DPPLDevice_Delete(OpenCL_Level0_gpu); + } + +}; + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetDriverInfo) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto DriverInfo = DPPLDevice_GetDriverInfo(OpenCL_cpu); + EXPECT_TRUE(DriverInfo != nullptr); + DPPLCString_Delete(DriverInfo); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetDriverInfo) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto DriverInfo = DPPLDevice_GetDriverInfo(OpenCL_gpu); + EXPECT_TRUE(DriverInfo != nullptr); + DPPLCString_Delete(DriverInfo); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetDriverInfo) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto DriverInfo = DPPLDevice_GetDriverInfo(OpenCL_Level0_gpu); + EXPECT_TRUE(DriverInfo != nullptr); + DPPLCString_Delete(DriverInfo); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetMaxComputeUnits) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto n = DPPLDevice_GetMaxComputeUnits(OpenCL_cpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetMaxComputeUnits) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto n = DPPLDevice_GetMaxComputeUnits(OpenCL_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetMaxComputeUnits) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto n = DPPLDevice_GetMaxComputeUnits(OpenCL_Level0_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetMaxWorkItemDims) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto n = DPPLDevice_GetMaxWorkItemDims(OpenCL_cpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetMaxWorkItemDims) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto n = DPPLDevice_GetMaxWorkItemDims(OpenCL_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetMaxWorkItemDims) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto n = DPPLDevice_GetMaxWorkItemDims(OpenCL_Level0_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetMaxWorkItemSizes) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto item_sizes = DPPLDevice_GetMaxWorkItemSizes(OpenCL_cpu); + EXPECT_TRUE(item_sizes != nullptr); + DPPLSize_t_Array_Delete(item_sizes); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetMaxWorkItemSizes) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto item_sizes = DPPLDevice_GetMaxWorkItemSizes(OpenCL_gpu); + EXPECT_TRUE(item_sizes != nullptr); + DPPLSize_t_Array_Delete(item_sizes); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetMaxWorkItemSizes) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto item_sizes = DPPLDevice_GetMaxWorkItemSizes(OpenCL_Level0_gpu); + EXPECT_TRUE(item_sizes != nullptr); + DPPLSize_t_Array_Delete(item_sizes); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetMaxWorkGroupSize) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto n = DPPLDevice_GetMaxWorkGroupSize(OpenCL_cpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetMaxWorkGroupSize) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto n = DPPLDevice_GetMaxWorkGroupSize(OpenCL_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetMaxWorkGroupSize) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto n = DPPLDevice_GetMaxWorkGroupSize(OpenCL_Level0_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetMaxNumSubGroups) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto n = DPPLDevice_GetMaxNumSubGroups(OpenCL_cpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetMaxNumSubGroups) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto n = DPPLDevice_GetMaxNumSubGroups(OpenCL_gpu); + EXPECT_TRUE(n > 0); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetMaxNumSubGroups) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto n = DPPLDevice_GetMaxNumSubGroups(OpenCL_Level0_gpu); + EXPECT_TRUE(n > 0); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_HasInt64BaseAtomics) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto atomics = DPPLDevice_HasInt64BaseAtomics(OpenCL_cpu); + auto D = reinterpret_cast(OpenCL_cpu); + auto has_atomics= D->has(aspect::int64_base_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_HasInt64BaseAtomics) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto atomics = DPPLDevice_HasInt64BaseAtomics(OpenCL_gpu); + auto D = reinterpret_cast(OpenCL_gpu); + auto has_atomics= D->has(aspect::int64_base_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_HasInt64BaseAtomics) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto atomics = DPPLDevice_HasInt64BaseAtomics(OpenCL_Level0_gpu); + auto D = reinterpret_cast(OpenCL_Level0_gpu); + auto has_atomics= D->has(aspect::int64_base_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_HasInt64ExtendedAtomics) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto atomics = DPPLDevice_HasInt64ExtendedAtomics(OpenCL_cpu); + auto D = reinterpret_cast(OpenCL_cpu); + auto has_atomics= D->has(aspect::int64_extended_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_HasInt64ExtendedAtomics) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL GPU device found."); + + auto atomics = DPPLDevice_HasInt64ExtendedAtomics(OpenCL_gpu); + auto D = reinterpret_cast(OpenCL_gpu); + auto has_atomics= D->has(aspect::int64_extended_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +//TODO: Update when DPC++ properly supports aspects +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_HasInt64ExtendedAtomics) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto atomics = DPPLDevice_HasInt64ExtendedAtomics(OpenCL_Level0_gpu); + auto D = reinterpret_cast(OpenCL_Level0_gpu); + auto has_atomics= D->has(aspect::int64_extended_atomics); + EXPECT_TRUE(has_atomics == atomics); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetName) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto DevName = DPPLDevice_GetName(OpenCL_cpu); + EXPECT_TRUE(DevName != nullptr); + DPPLCString_Delete(DevName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetName) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto DevName = DPPLDevice_GetName(OpenCL_gpu); + EXPECT_TRUE(DevName != nullptr); + DPPLCString_Delete(DevName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetName) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto DevName = DPPLDevice_GetName(OpenCL_Level0_gpu); + EXPECT_TRUE(DevName != nullptr); + DPPLCString_Delete(DevName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_GetVendorName) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto VendorName = DPPLDevice_GetVendorName(OpenCL_cpu); + EXPECT_TRUE(VendorName != nullptr); + DPPLCString_Delete(VendorName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_GetVendorName) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + auto VendorName = DPPLDevice_GetVendorName(OpenCL_gpu); + EXPECT_TRUE(VendorName != nullptr); + DPPLCString_Delete(VendorName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_GetVendorName) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + auto VendorName = DPPLDevice_GetVendorName(OpenCL_Level0_gpu); + EXPECT_TRUE(VendorName != nullptr); + DPPLCString_Delete(VendorName); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLCPU_IsCPU) +{ + if(!OpenCL_cpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + EXPECT_TRUE(DPPLDevice_IsCPU(OpenCL_cpu)); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckOCLGPU_IsGPU) +{ + if(!OpenCL_gpu) + GTEST_SKIP_("Skipping as no OpenCL CPU device found."); + + EXPECT_TRUE(DPPLDevice_IsGPU(OpenCL_gpu)); +} + +TEST_F (TestDPPLSyclDeviceInterface, CheckLevel0GPU_IsGPU) +{ + if(!OpenCL_Level0_gpu) + GTEST_SKIP_("Skipping as no Level0 GPU device found."); + + EXPECT_TRUE(DPPLDevice_IsGPU(OpenCL_Level0_gpu)); +} + +int +main (int argc, char** argv) +{ + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; +} diff --git a/backends/tests/test_sycl_kernel_interface.cpp b/backends/tests/test_sycl_kernel_interface.cpp index 1efc84076d..8ef4d8d951 100644 --- a/backends/tests/test_sycl_kernel_interface.cpp +++ b/backends/tests/test_sycl_kernel_interface.cpp @@ -112,7 +112,7 @@ TEST_F (TestDPPLSyclKernelInterface, CheckGetNumArgs) int main (int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - int ret = RUN_ALL_TESTS(); - return ret; + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; } diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index 3fa9dff8a0..584ae79fd8 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -28,10 +28,12 @@ # cython: language_level=3 from libcpp cimport bool +from libc.stdint cimport uint32_t cdef extern from "dppl_utils.h": cdef void DPPLCString_Delete (const char *str) + cdef void DPPLSize_t_Array_Delete (size_t *arr) cdef extern from "dppl_sycl_enum_types.h": cdef enum _backend_type 'DPPLSyclBackendType': @@ -97,10 +99,17 @@ cdef extern from "dppl_sycl_device_interface.h": cdef bool DPPLDevice_IsCPU (const DPPLSyclDeviceRef DRef) cdef bool DPPLDevice_IsGPU (const DPPLSyclDeviceRef DRef) cdef bool DPPLDevice_IsHost (const DPPLSyclDeviceRef DRef) - cdef const char* DPPLDevice_GetDriverInfo (const DPPLSyclDeviceRef DRef) - cdef const char* DPPLDevice_GetName (const DPPLSyclDeviceRef DRef) - cdef const char* DPPLDevice_GetVendorName (const DPPLSyclDeviceRef DRef) + cpdef const char *DPPLDevice_GetDriverInfo (const DPPLSyclDeviceRef DRef) + cpdef const char *DPPLDevice_GetName (const DPPLSyclDeviceRef DRef) + cpdef const char *DPPLDevice_GetVendorName (const DPPLSyclDeviceRef DRef) cdef bool DPPLDevice_IsHostUnifiedMemory (const DPPLSyclDeviceRef DRef) + cpdef uint32_t DPPLDevice_GetMaxComputeUnits (const DPPLSyclDeviceRef DRef) + cpdef uint32_t DPPLDevice_GetMaxWorkItemDims (const DPPLSyclDeviceRef DRef) + cpdef size_t *DPPLDevice_GetMaxWorkItemSizes (const DPPLSyclDeviceRef DRef) + cpdef size_t DPPLDevice_GetMaxWorkGroupSize (const DPPLSyclDeviceRef DRef) + cpdef uint32_t DPPLDevice_GetMaxNumSubGroups (const DPPLSyclDeviceRef DRef) + cpdef bool DPPLDevice_HasInt64BaseAtomics (const DPPLSyclDeviceRef DRef) + cpdef bool DPPLDevice_HasInt64ExtendedAtomics (const DPPLSyclDeviceRef DRef) cdef extern from "dppl_sycl_event_interface.h": diff --git a/dpctl/_sycl_core.pxd b/dpctl/_sycl_core.pxd index 7ecf1adbb4..89a74dca57 100644 --- a/dpctl/_sycl_core.pxd +++ b/dpctl/_sycl_core.pxd @@ -28,6 +28,7 @@ # cython: language_level=3 from ._backend cimport * +from libc.stdint cimport uint32_t cdef class SyclContext: @@ -48,10 +49,28 @@ cdef class SyclDevice: cdef const char *_vendor_name cdef const char *_device_name cdef const char *_driver_version + cdef uint32_t _max_compute_units + cdef uint32_t _max_work_item_dims + cdef size_t *_max_work_item_sizes + cdef size_t _max_work_group_size + cdef uint32_t _max_num_sub_groups + cdef bool _int64_base_atomics + cdef bool _int64_extended_atomics @staticmethod cdef SyclDevice _create (DPPLSyclDeviceRef dref) cdef DPPLSyclDeviceRef get_device_ref (self) + cpdef get_device_name (self) + cpdef get_device_type (self) + cpdef get_vendor_name (self) + cpdef get_driver_version (self) + cpdef get_max_compute_units (self) + cpdef get_max_work_item_dims (self) + cpdef get_max_work_item_sizes (self) + cpdef get_max_work_group_size (self) + cpdef get_max_num_sub_groups (self) + cpdef has_int64_base_atomics (self) + cpdef has_int64_extended_atomics (self) cdef class SyclEvent: diff --git a/dpctl/_sycl_core.pyx b/dpctl/_sycl_core.pyx index cc5b928f1f..129728894a 100644 --- a/dpctl/_sycl_core.pyx +++ b/dpctl/_sycl_core.pyx @@ -126,6 +126,13 @@ cdef class SyclDevice: ret._vendor_name = DPPLDevice_GetVendorName(dref) ret._device_name = DPPLDevice_GetName(dref) ret._driver_version = DPPLDevice_GetDriverInfo(dref) + ret._max_compute_units = DPPLDevice_GetMaxComputeUnits(dref) + ret._max_work_item_dims = DPPLDevice_GetMaxWorkItemDims(dref) + ret._max_work_item_sizes = DPPLDevice_GetMaxWorkItemSizes(dref) + ret._max_work_group_size = DPPLDevice_GetMaxWorkGroupSize(dref) + ret._max_num_sub_groups = DPPLDevice_GetMaxNumSubGroups(dref) + ret._int64_base_atomics = DPPLDevice_HasInt64BaseAtomics(dref) + ret._int64_extended_atomics = DPPLDevice_HasInt64ExtendedAtomics(dref) return ret def __dealloc__ (self): @@ -133,18 +140,19 @@ cdef class SyclDevice: DPPLCString_Delete(self._device_name) DPPLCString_Delete(self._vendor_name) DPPLCString_Delete(self._driver_version) + DPPLSize_t_Array_Delete(self._max_work_item_sizes) def dump_device_info (self): ''' Print information about the SYCL device. ''' DPPLDevice_DumpInfo(self._device_ref) - def get_device_name (self): + cpdef get_device_name (self): ''' Returns the name of the device as a string ''' return self._device_name.decode() - def get_device_type (self): + cpdef get_device_type (self): ''' Returns the type of the device as a `device_type` enum ''' if DPPLDevice_IsGPU(self._device_ref): @@ -154,12 +162,12 @@ cdef class SyclDevice: else: raise ValueError("Unknown device type.") - def get_vendor_name (self): + cpdef get_vendor_name (self): ''' Returns the device vendor name as a string ''' return self._vendor_name.decode() - def get_driver_version (self): + cpdef get_driver_version (self): ''' Returns the OpenCL software driver version as a string in the form: major number.minor number, if this SYCL device is an OpenCL device. Returns a string class @@ -167,6 +175,58 @@ cdef class SyclDevice: ''' return self._driver_version.decode() + cpdef has_int64_base_atomics (self): + ''' Returns true if device has int64_base_atomics else returns false. + ''' + return self._int64_base_atomics + + cpdef has_int64_extended_atomics (self): + ''' Returns true if device has int64_extended_atomics else returns false. + ''' + return self._int64_extended_atomics + + cpdef get_max_compute_units (self): + ''' Returns the number of parallel compute units + available to the device. The minimum value is 1. + ''' + return self._max_compute_units + + cpdef get_max_work_item_dims (self): + ''' Returns the maximum dimensions that specify + the global and local work-item IDs used by the + data parallel execution model. The minimum + value is 3 if this SYCL device is not of device + type info::device_type::custom. + ''' + return self._max_work_item_dims + + cpdef get_max_work_item_sizes (self): + ''' Returns the maximum number of work-items + that are permitted in each dimension of the + work-group of the nd_range. The minimum + value is (1; 1; 1) for devices that are not of + device type info::device_type::custom. + ''' + max_work_item_sizes = [] + for n in range(3): + max_work_item_sizes.append(self._max_work_item_sizes[n]) + return tuple(max_work_item_sizes) + + cpdef get_max_work_group_size (self): + ''' Returns the maximum number of work-items + that are permitted in a work-group executing a + kernel on a single compute unit. The minimum + value is 1. + ''' + return self._max_work_group_size + + cpdef get_max_num_sub_groups (self): + ''' Returns the maximum number of sub-groups + in a work-group for any kernel executed on the + device. The minimum value is 1. + ''' + return self._max_num_sub_groups + cdef DPPLSyclDeviceRef get_device_ref (self): ''' Returns the DPPLSyclDeviceRef pointer for this class. ''' diff --git a/dpctl/tests/__init__.py b/dpctl/tests/__init__.py index f04131d53a..a53980d17a 100644 --- a/dpctl/tests/__init__.py +++ b/dpctl/tests/__init__.py @@ -23,6 +23,7 @@ ##===----------------------------------------------------------------------===## from .test_dump_functions import * +from .test_sycl_device import * from .test_sycl_kernel_submit import * from .test_sycl_program import * from .test_sycl_queue import * diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py new file mode 100644 index 0000000000..e222a55542 --- /dev/null +++ b/dpctl/tests/test_sycl_device.py @@ -0,0 +1,110 @@ +##===------------- test_sycl_device.py - dpctl -------*- Python -*---------===## +## +## Data Parallel Control (dpctl) +## +## Copyright 2020 Intel Corporation +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +##===----------------------------------------------------------------------===## +## +## \file +## Defines unit test cases for the SyclDevice classes defined in sycl_core.pyx. +##===----------------------------------------------------------------------===## + +import dpctl +import unittest + + +@unittest.skipIf(not dpctl.has_sycl_platforms(), "No SYCL platforms available") +class TestSyclDevice(unittest.TestCase): + def test_get_max_compute_units(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + max_compute_units = q.get_sycl_device().get_max_compute_units() + except Exception: + self.fail("Encountered an exception inside get_max_compute_units().") + self.assertTrue(max_compute_units > 0) + + def test_get_max_work_item_dims(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + max_work_item_dims = q.get_sycl_device().get_max_work_item_dims() + except Exception: + self.fail("Encountered an exception inside get_max_work_item_dims().") + self.assertTrue(max_work_item_dims > 0) + + def test_get_max_work_item_sizes(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + max_work_item_sizes = q.get_sycl_device().get_max_work_item_sizes() + except Exception: + self.fail("Encountered an exception inside get_max_work_item_sizes().") + self.assertNotEqual(max_work_item_sizes, (None, None, None)) + + def test_get_max_work_group_size(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + max_work_group_size = q.get_sycl_device().get_max_work_group_size() + except Exception: + self.fail("Encountered an exception inside get_max_work_group_size().") + self.assertTrue(max_work_group_size > 0) + + def test_get_max_num_sub_groups(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + max_num_sub_groups = q.get_sycl_device().get_max_num_sub_groups() + except Exception: + self.fail("Encountered an exception inside get_max_num_sub_groups().") + self.assertTrue(max_num_sub_groups > 0) + + def test_has_int64_base_atomics(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + aspects_base_atomics = q.get_sycl_device().has_int64_base_atomics() + except Exception: + self.fail("Encountered an exception inside has_int64_base_atomics().") + self.assertNotEqual(aspects_base_atomics, False) + + def test_has_int64_extended_atomics(self): + try: + q = dpctl.get_current_queue() + except Exception: + self.fail("Encountered an exception inside get_current_queue().") + try: + aspects_extended_atomics = q.get_sycl_device().has_int64_extended_atomics() + except Exception: + self.fail("Encountered an exception inside has_int64_extended_atomics().") + self.assertNotEqual(aspects_extended_atomics, False) + + +if __name__ == "__main__": + unittest.main()