Skip to content

[SYCL] Implement atomic_memory_scope_capabilities device query for OpenCL and Level Zero #8595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 22, 2023
Merged
2 changes: 1 addition & 1 deletion opencl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ FetchContent_GetProperties(ocl-headers)
set(OpenCL_INCLUDE_DIR
${ocl-headers_SOURCE_DIR} CACHE PATH "Path to OpenCL Headers")

target_compile_definitions(Headers INTERFACE -DCL_TARGET_OPENCL_VERSION=220)
target_compile_definitions(Headers INTERFACE -DCL_TARGET_OPENCL_VERSION=300)
add_library(OpenCL-Headers ALIAS Headers)

# OpenCL Library (ICD Loader)
Expand Down
4 changes: 2 additions & 2 deletions sycl/include/sycl/detail/cl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
#pragma once

// Suppress a compiler message about undefined CL_TARGET_OPENCL_VERSION
// and define all symbols up to OpenCL 2.2
// and define all symbols up to OpenCL 3.0
#ifndef CL_TARGET_OPENCL_VERSION
#define CL_TARGET_OPENCL_VERSION 220
#define CL_TARGET_OPENCL_VERSION 300
#endif

#include <CL/cl.h>
Expand Down
1 change: 1 addition & 0 deletions sycl/plugins/esimd_emulator/pi_esimd_emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,7 @@ pi_result piDeviceGetInfo(pi_device Device, pi_device_info ParamName,
CASE_PI_UNSUPPORTED(PI_DEVICE_INFO_IMAGE_SRGB)
CASE_PI_UNSUPPORTED(PI_DEVICE_INFO_ATOMIC_64)
CASE_PI_UNSUPPORTED(PI_DEVICE_INFO_ATOMIC_MEMORY_ORDER_CAPABILITIES)
CASE_PI_UNSUPPORTED(PI_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES)
CASE_PI_UNSUPPORTED(PI_EXT_ONEAPI_DEVICE_INFO_MAX_GLOBAL_WORK_GROUPS)
CASE_PI_UNSUPPORTED(PI_EXT_ONEAPI_DEVICE_INFO_MAX_WORK_GROUPS_1D)
CASE_PI_UNSUPPORTED(PI_EXT_ONEAPI_DEVICE_INFO_MAX_WORK_GROUPS_2D)
Expand Down
62 changes: 61 additions & 1 deletion sycl/plugins/opencl/pi_opencl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,68 @@ pi_result piDeviceGetInfo(pi_device device, pi_device_info paramName,
// sycl/doc/extensions/supported/sycl_ext_intel_device_info.md
case PI_DEVICE_INFO_UUID:
case PI_DEVICE_INFO_ATOMIC_MEMORY_ORDER_CAPABILITIES:
case PI_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES:
return PI_ERROR_INVALID_VALUE;
case PI_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES: {
// Initialize result to minimum mandated capabilities according to
// SYCL2020 4.6.3.2
// Because scopes are hierarchical, wider scopes support all narrower
// scopes. At a minimum, each device must support WORK_ITEM, SUB_GROUP and
// WORK_GROUP. (https://github.com/KhronosGroup/SYCL-Docs/pull/382)
pi_memory_scope_capabilities result = PI_MEMORY_SCOPE_WORK_ITEM |
PI_MEMORY_SCOPE_SUB_GROUP |
PI_MEMORY_SCOPE_WORK_GROUP;

OCLV::OpenCLVersion devVer;

cl_device_id deviceID = cast<cl_device_id>(device);
cl_int ret_err = getDeviceVersion(deviceID, devVer);
if (ret_err != CL_SUCCESS)
return static_cast<pi_result>(ret_err);

cl_device_atomic_capabilities devCapabilities = 0;
if (devVer >= OCLV::V3_0) {
ret_err = clGetDeviceInfo(deviceID, CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES,
sizeof(cl_device_atomic_capabilities),
&devCapabilities, nullptr);
if (ret_err != CL_SUCCESS)
return static_cast<pi_result>(ret_err);
assert((devCapabilities & CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP) &&
"Violates minimum mandated guarantee");

// Because scopes are hierarchical, wider scopes support all narrower
// scopes. At a minimum, each device must support WORK_ITEM, SUB_GROUP and
// WORK_GROUP. (https://github.com/KhronosGroup/SYCL-Docs/pull/382)
// We already initialized to these minimum mandated capabilities. Just
// check wider scopes.
if (devCapabilities & CL_DEVICE_ATOMIC_SCOPE_DEVICE) {
result |= PI_MEMORY_SCOPE_DEVICE;
}

if (devCapabilities & CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES) {
result |= PI_MEMORY_SCOPE_SYSTEM;
}

} else {
// This info is only available in OpenCL version >= 3.0
// Just return minimum mandated capabilities for older versions.
// OpenCL 1.x minimum mandated capabilities are WORK_GROUP, we
// already initialized using it.
if (devVer >= OCLV::V2_0) {
// OpenCL 2.x minimum mandated capabilities are WORK_GROUP | DEVICE |
// ALL_DEVICES
result |= PI_MEMORY_SCOPE_DEVICE | PI_MEMORY_SCOPE_SYSTEM;
}
}
if (paramValue) {
if (paramValueSize < sizeof(cl_device_atomic_capabilities))
return PI_ERROR_INVALID_VALUE;

std::memcpy(paramValue, &result, sizeof(result));
}
if (paramValueSizeRet)
*paramValueSizeRet = sizeof(result);
return PI_SUCCESS;
}
case PI_DEVICE_INFO_ATOMIC_64: {
cl_int ret_err = CL_SUCCESS;
cl_bool result = CL_FALSE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,9 +1164,19 @@ UR_APIEXPORT ur_result_t UR_APICALL urDeviceGetInfo(
// bfloat16 math functions are not yet supported on Intel GPUs.
return ReturnValue(bool{false});
}
case UR_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES: {
// There are no explicit restrictions in L0 programming guide, so assume all
// are supported
ur_memory_scope_capability_flags_t result =
UR_MEMORY_SCOPE_CAPABILITY_FLAG_WORK_ITEM |
UR_MEMORY_SCOPE_CAPABILITY_FLAG_SUB_GROUP |
UR_MEMORY_SCOPE_CAPABILITY_FLAG_WORK_GROUP |
UR_MEMORY_SCOPE_CAPABILITY_FLAG_DEVICE |
UR_MEMORY_SCOPE_CAPABILITY_FLAG_SYSTEM;

return ReturnValue(result);
}

// TODO: Implement.
case UR_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES:
default:
zePrint("Unsupported ParamName in piGetDeviceInfo\n");
zePrint("ParamName=%d(0x%x)\n", ParamName, ParamName);
Expand Down
73 changes: 73 additions & 0 deletions sycl/unittests/SYCL2020/AtomicMemoryScopeCapabilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//==-------- AtomicMemoryScopeCapabilities.cpp --- queue unit tests --------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include <CL/sycl.hpp>
#include <gtest/gtest.h>
#include <helpers/PiMock.hpp>

using namespace sycl;

namespace {

thread_local bool deviceGetInfoCalled;

pi_platform PiPlatform = nullptr;

pi_result redefinedDeviceGetInfoAfter(pi_device device,
pi_device_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret) {
if (param_name == PI_DEVICE_INFO_ATOMIC_MEMORY_SCOPE_CAPABILITIES) {
deviceGetInfoCalled = true;
if (param_value) {
auto *Result =
reinterpret_cast<pi_memory_scope_capabilities *>(param_value);
*Result = PI_MEMORY_SCOPE_WORK_ITEM | PI_MEMORY_SCOPE_SUB_GROUP |
PI_MEMORY_SCOPE_WORK_GROUP | PI_MEMORY_SCOPE_DEVICE |
PI_MEMORY_SCOPE_SYSTEM;
}
}
return PI_SUCCESS;
}

TEST(AtomicMemoryScopeCapabilitiesCheck, CheckAtomicMemoryScopeCapabilities) {
sycl::unittest::PiMock Mock;
sycl::platform Plt = Mock.getPlatform();

PiPlatform = detail::getSyclObjImpl(Plt)->getHandleRef();
context DefaultCtx = Plt.ext_oneapi_get_default_context();
device Dev = DefaultCtx.get_devices()[0];

deviceGetInfoCalled = false;

Mock.redefineAfter<detail::PiApiKind::piDeviceGetInfo>(
redefinedDeviceGetInfoAfter);
auto scope_capabilities =
Dev.get_info<sycl::info::device::atomic_memory_scope_capabilities>();
EXPECT_TRUE(deviceGetInfoCalled);
size_t expectedSize = 5;
EXPECT_EQ(scope_capabilities.size(), expectedSize);

auto res = std::find(scope_capabilities.begin(), scope_capabilities.end(),
sycl::memory_scope::work_item);
EXPECT_FALSE(res == scope_capabilities.end());
res = std::find(scope_capabilities.begin(), scope_capabilities.end(),
sycl::memory_scope::sub_group);
EXPECT_FALSE(res == scope_capabilities.end());
res = std::find(scope_capabilities.begin(), scope_capabilities.end(),
sycl::memory_scope::work_group);
EXPECT_FALSE(res == scope_capabilities.end());
res = std::find(scope_capabilities.begin(), scope_capabilities.end(),
sycl::memory_scope::device);
EXPECT_FALSE(res == scope_capabilities.end());
res = std::find(scope_capabilities.begin(), scope_capabilities.end(),
sycl::memory_scope::system);
EXPECT_FALSE(res == scope_capabilities.end());
}
} // anonymous namespace
1 change: 1 addition & 0 deletions sycl/unittests/SYCL2020/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ add_sycl_unittest(SYCL2020Tests OBJECT
IsCompatible.cpp
DeviceGetInfoAspects.cpp
DeviceAspectTraits.cpp
AtomicMemoryScopeCapabilities.cpp
)