Skip to content
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

[SYCL] Add device config file consistency test #16369

Open
wants to merge 20 commits into
base: sycl
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/sycl-linux-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ jobs:
--cmake-opt="-DLLVM_INSTALL_UTILS=ON" \
--cmake-opt="-DNATIVECPU_USE_OCK=Off" \
--cmake-opt="-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=SPIRV"
--cmake-opt="-DINSTALL_DEVICE_CONFIG_FILE=ON"
jzc marked this conversation as resolved.
Show resolved Hide resolved
- name: Compile
id: build
run: cmake --build $GITHUB_WORKSPACE/build
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/SYCLLowerIR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ set(LLVM_TABLEGEN_PROJECT LLVM)
set(LLVM_TARGET_DEFINITIONS DeviceConfigFile.td)
tablegen(LLVM DeviceConfigFile.inc -gen-dynamic-tables)
add_public_tablegen_target(DeviceConfigFile)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/DeviceConfigFile.hpp"
"${CMAKE_CURRENT_BINARY_DIR}/DeviceConfigFile.inc"
DESTINATION llvm/SYCLLowerIR
COMPONENT DeviceConfigFile)
7 changes: 2 additions & 5 deletions llvm/include/llvm/SYCLLowerIR/DeviceConfigFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
#include <map>
#include <string>
#include <vector>

namespace llvm {
class StringRef;
}
#include <string_view>

namespace DeviceConfigFile {

Expand All @@ -22,7 +19,7 @@ namespace DeviceConfigFile {
// DeviceConfigFile.td.
struct TargetInfo {
bool maySupportOtherAspects;
std::vector<llvm::StringRef> aspects;
std::vector<std::string_view> aspects;
std::vector<unsigned> subGroupSizes;
std::string aotToolchain;
std::string aotToolchainOptions;
Expand Down
14 changes: 10 additions & 4 deletions llvm/include/llvm/SYCLLowerIR/DeviceConfigFile.td
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,18 @@ defvar IntelCpuAspects = [
AspectExt_oneapi_srgb, AspectExt_oneapi_native_assert,
AspectExt_intel_legacy_image, AspectExt_oneapi_ballot_group,
AspectExt_oneapi_fixed_size_group, AspectExt_oneapi_opportunistic_group,
AspectExt_oneapi_tangle_group, AspectExt_oneapi_private_alloca
AspectExt_oneapi_tangle_group, AspectExt_oneapi_private_alloca,
AspectOnline_compiler, AspectOnline_linker, AspectExt_intel_gpu_slices,
AspectExt_intel_gpu_subslices_per_slice, AspectExt_intel_gpu_eu_count_per_subslice,
AspectExt_intel_gpu_hw_threads_per_eu, AspectExt_intel_device_id,
AspectExt_oneapi_virtual_functions
] # AllUSMAspects;

def : TargetInfo<"spir64", [], [], "", "", 1>;
def : TargetInfo<"spir64_gen", [], [], "", "", 1>;
def : TargetInfo<"spir64_x86_64", IntelCpuAspects, [4, 8, 16, 32, 64], "", "", 1>;
def : TargetInfo<"spir64_fpga", [], [], "", "", 1>;
def : TargetInfo<"x86_64", [], [], "", "", 1>;
def : TargetInfo<"x86_64", IntelCpuAspects, [4, 8, 16, 32, 64], "", "", 1>;
// Examples of how to use a combination of explicitly specified values + predefined lists
//defvar AspectList = [AspectCpu] # AllUSMAspects;
//def : TargetInfo<"Test", AspectList, []>;
Expand All @@ -183,9 +187,11 @@ defvar Fp16Fp64Atomic64 = [AspectFp16, AspectFp64, AspectAtomic64];
defvar Fp16Atomic64 = [AspectFp16, AspectAtomic64];
defvar Sg8_16_32 = [8, 16, 32];
defvar Sg16_32 = [16, 32];
defvar IntelBaseAspects = [AspectExt_intel_esimd];
defvar IntelGPUBaseAspects = [AspectExt_intel_esimd, AspectExt_oneapi_ballot_group,
AspectExt_oneapi_fixed_size_group, AspectExt_oneapi_opportunistic_group,
AspectExt_oneapi_tangle_group];
class IntelTargetInfo<string Name, list<Aspect> Aspects, list<int> subGroupSizesList>
: TargetInfo<Name, IntelBaseAspects # Aspects, subGroupSizesList>;
: TargetInfo<Name, IntelGPUBaseAspects # Aspects, subGroupSizesList>;
// Note: only the "canonical" target names are listed here - see
// SYCL::gen::resolveGenDevice().
//
Expand Down
5 changes: 5 additions & 0 deletions sycl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,11 @@ if("hip" IN_LIST SYCL_ENABLE_BACKENDS)
list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS ur_adapter_hip)
endif()

if(INSTALL_DEVICE_CONFIG_FILE)
add_dependencies(sycl-toolchain DeviceConfigFile)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you give some background on why we need to install this? thx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still testing things, so I might change some things, but I want to support the new device_config_file_consistency test. It uses the DeviceConfigFile.hpp, and that file includes DeviceConfigFile.inc, which is generated by tablegen. On CI from what I understand the e2e tests are invoked by using the packed install files from the build step and only runs CMake on the sycl/test-e2e subfolder. So since we probably don't want to build tablegen and invoke other LLVM cmake files when running the e2e tests, I install the DeviceConfigFile.inc it in the build step to pass it to the e2e tests. Also note that this test must be an e2e test as it queries the device it is running the test on, so it can't be moved to sycl/test.

Copy link
Contributor

@sarnex sarnex Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry so what tools/files are required to generate that hpp file? Is it just llvm-tablegen and DeviceConfigFile.inc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea just tablegen and DeviceConfigFile.td are needed for the hpp file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also just for some more background I was aiming so that DeviceConfigFile.hpp is not installed by default because outside of testing, this file is not needed for a SYCL distribution, it is only used in the compiler.

list(APPEND SYCL_TOOLCHAIN_DEPLOY_COMPONENTS DeviceConfigFile)
endif()

# Use it as fake dependency in order to force another command(s) to execute.
add_custom_command(OUTPUT __force_it
COMMAND "${CMAKE_COMMAND}" -E echo
Expand Down
138 changes: 138 additions & 0 deletions sycl/test-e2e/Basic/device_config_file_consistency.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// This test checks to see if every aspect and sub-group size declared in the
// device config file is supported by the device. Note this does not mean
// check that the device config file is exhaustive, only that the device
// supports everything it declares. However, this test does print out any
// aspects that are supported by the device but not declared in the device
// config file.

// UNSUPPORTED: accelerator
// UNSUPPORTED-INTENDED: Accelerator is not supported by sycl_ext_oneapi_device_architecture
// REQURIES: device-config-file
// RUN: %{build} -o %t.out %device_config_file_include_flag
// RUN: %{run} %t.out
#include <map>

#include <sycl/detail/core.hpp>
#include <llvm/SYCLLowerIR/DeviceConfigFile.hpp>

#define __SYCL_ASPECT_DEPRECATED_ALIAS(ASPECT, ID, MESSAGE) \
__SYCL_ASPECT_DEPRECATED(ASPECT, ID, MESSAGE)

using namespace sycl;

const char *getArchName(const device &Device) {
namespace syclex = sycl::ext::oneapi::experimental;
auto arch = Device.get_info<syclex::info::device::architecture>();
switch (arch) {
#define __SYCL_ARCHITECTURE(ARCH, VAL) \
case syclex::architecture::ARCH: \
return #ARCH;
#define __SYCL_ARCHITECTURE_ALIAS(ARCH, VAL)
#include <sycl/ext/oneapi/experimental/device_architecture.def>
#undef __SYCL_ARCHITECTURE
#undef __SYCL_ARCHITECTURE_ALIAS
}
return "unknown";
}

// checks if a container contains a specific element
jzc marked this conversation as resolved.
Show resolved Hide resolved
template <typename Container, typename T>
bool contains(const Container &c, const T &elem) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
return std::find(c.begin(), c.end(), elem) != c.end();
}

std::string_view getAspectName(aspect asp) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
switch (asp) {
#define __SYCL_ASPECT(ASPECT, ID) \
case aspect::ASPECT: \
return #ASPECT;
#include <sycl/info/aspects.def>
#undef __SYCL_ASPECT
}
return "unknown";
}

aspect getAspectByName(std::string_view name) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
#define __SYCL_ASPECT(ASPECT, ID) \
if (name == #ASPECT) \
return aspect::ASPECT;
#include <sycl/info/aspects.def>
throw std::invalid_argument("Unknown aspect name");
}

int main() {
// Get the device arch
jzc marked this conversation as resolved.
Show resolved Hide resolved
queue q;
jzc marked this conversation as resolved.
Show resolved Hide resolved
auto dev = q.get_device();
jzc marked this conversation as resolved.
Show resolved Hide resolved
auto device_name = getArchName(dev);
jzc marked this conversation as resolved.
Show resolved Hide resolved

auto TargetInfo = DeviceConfigFile::TargetTable.find(device_name);
if (TargetInfo == DeviceConfigFile::TargetTable.end()) {
std::cout << "No aspects found for device " << device_name << std::endl;
return 1;
}

// Check aspects consistency
jzc marked this conversation as resolved.
Show resolved Hide resolved
int nAspectInconsistencies = 0;
jzc marked this conversation as resolved.
Show resolved Hide resolved
std::cout << "Checking consistency of aspects for device " << device_name
<< "...\n";

auto supportedAspects = dev.get_info<info::device::aspects>();
jzc marked this conversation as resolved.
Show resolved Hide resolved
auto deviceConfigAspectNames = TargetInfo->second.aspects;
jzc marked this conversation as resolved.
Show resolved Hide resolved
std::vector<aspect> deviceConfigAspects;
jzc marked this conversation as resolved.
Show resolved Hide resolved
for (auto aspectName : deviceConfigAspectNames) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
deviceConfigAspects.push_back(getAspectByName(aspectName));
}

for (auto asp : deviceConfigAspects) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
if (!contains(supportedAspects, asp)) {
std::cout << "error: " << device_name << " does not support aspect "
<< getAspectName(asp)
<< " but it is declared in the device config file\n";
++nAspectInconsistencies;
}
}
for (auto asp : supportedAspects) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
if (!contains(deviceConfigAspects, asp)) {
std::cout << "note: the device " << device_name << " supports aspect "
<< getAspectName(asp)
<< " but it is not declared in the device config file\n";
// Not necessarily an error, so we won't increment n_fail
jzc marked this conversation as resolved.
Show resolved Hide resolved
}
}

if (nAspectInconsistencies == 0)
std::cout << "All aspects are consistent\n";

// Check sub-group sizes consistency
jzc marked this conversation as resolved.
Show resolved Hide resolved
int nSubGroupSizeInconsistencies = 0;
jzc marked this conversation as resolved.
Show resolved Hide resolved
std::cout << "Checking consistency of sub-group sizes for device "
<< device_name << "...\n";

auto supportedSubGroupSizes = dev.get_info<info::device::sub_group_sizes>();
jzc marked this conversation as resolved.
Show resolved Hide resolved
auto deviceConfigSubGroupSizes = TargetInfo->second.subGroupSizes;
jzc marked this conversation as resolved.
Show resolved Hide resolved

for (auto size : deviceConfigSubGroupSizes) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
if (!contains(supportedSubGroupSizes, size)) {
std::cout << "error: " << device_name
<< " does not support sub-group size " << size
<< " but it is declared in the device config file\n";
++nSubGroupSizeInconsistencies;
}
}
for (auto size : supportedSubGroupSizes) {
jzc marked this conversation as resolved.
Show resolved Hide resolved
if (!contains(deviceConfigSubGroupSizes, size)) {
std::cout << "note: the device " << device_name
<< " supports sub-group size " << size
<< " but it is not declared in the device config file\n";
// Not necessarily an error, so we won't increment n_fail
jzc marked this conversation as resolved.
Show resolved Hide resolved
}
}

if (nSubGroupSizeInconsistencies == 0)
std::cout << "All sub-group sizes are consistent\n";

return nAspectInconsistencies + nSubGroupSizeInconsistencies;
}

#undef __SYCL_ASPECT_DEPRECATED_ALIAS
12 changes: 12 additions & 0 deletions sycl/test-e2e/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,18 @@ def open_check_file(file_name):
("%clang", " " + config.dpcpp_compiler + " " + config.c_flags)
)

if config.llvm_main_include_dir:
config.available_features.add("device-config-file")
config.substitutions.append(
("%device_config_file_include_flag",
f"-I {config.llvm_main_include_dir}")
)
elif os.path.exists(f"{config.sycl_include}/llvm/SYCLLowerIR/DeviceConfigFile.hpp"):
config.available_features.add("device-config-file")
config.substitutions.append(
("%device_config_file_include_flag", "")
)

# Set timeout for a single test
try:
import psutil
Expand Down
1 change: 1 addition & 0 deletions sycl/test-e2e/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ site.addsitedir("@CMAKE_CURRENT_SOURCE_DIR@")
config.dpcpp_compiler = lit_config.params.get("dpcpp_compiler", "@SYCL_CXX_COMPILER@")
config.dpcpp_root_dir= os.path.dirname(os.path.dirname(config.dpcpp_compiler))

config.llvm_main_include_dir = "@LLVM_MAIN_INCLUDE_DIR@"
config.llvm_tools_dir = os.path.join(config.dpcpp_root_dir, 'bin')
config.lit_tools_dir = os.path.dirname("@TEST_SUITE_LIT@")
config.dump_ir_supported = lit_config.params.get("dump_ir", ("@DUMP_IR_SUPPORTED@" if "@DUMP_IR_SUPPORTED@" else False))
Expand Down
5 changes: 2 additions & 3 deletions sycl/test/basic_tests/device_config_file_aspects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//
#include <map>

#include <llvm/ADT/StringRef.h>
#include <llvm/SYCLLowerIR/DeviceConfigFile.hpp>
#include <sycl/sycl.hpp>

Expand All @@ -16,7 +15,7 @@ int main() {
auto aspectsList = testAspects->second.aspects;

#define __SYCL_ASPECT(ASPECT, ASPECT_VAL) \
llvm::StringRef s##ASPECT(#ASPECT); \
std::string_view s##ASPECT(#ASPECT); \
assert(std::find(aspectsList.begin(), aspectsList.end(), s##ASPECT) != \
aspectsList.end());

Expand All @@ -29,7 +28,7 @@ int main() {
assert(testDeprecatedAspects != DeviceConfigFile::TargetTable.end());
auto deprecatedAspectsList = testDeprecatedAspects->second.aspects;
#define __SYCL_ASPECT_DEPRECATED(ASPECT, ASPECT_VAL, MSG) \
llvm::StringRef s##ASPECT(#ASPECT); \
std::string_view s##ASPECT(#ASPECT); \
assert(std::find(deprecatedAspectsList.begin(), deprecatedAspectsList.end(), \
s##ASPECT) != deprecatedAspectsList.end());

Expand Down
Loading