-
Notifications
You must be signed in to change notification settings - Fork 16k
[libsycl] Add lit configuration files and basic test #177407
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| cmake_minimum_required(VERSION 3.20.0) | ||
|
|
||
| message("Configuring libsycl End-to-End Tests") | ||
|
|
||
| set(LIBSYCL_CXX_COMPILER "${LLVM_BINARY_DIR}/bin/clang++") | ||
| set(LIBSYCL_E2E_CXX_FLAGS "" CACHE STRING | ||
| "Flags passed to clang++ when building SYCL end-to-end tests") | ||
|
|
||
| configure_lit_site_cfg( | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in | ||
| ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py | ||
| MAIN_CONFIG | ||
| ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py | ||
| ) | ||
|
|
||
| list(APPEND LIBSYCL_E2E_TEST_DEPS | ||
| libsycl-toolchain | ||
| FileCheck | ||
| not | ||
| ) | ||
|
|
||
| add_lit_testsuite(check-sycl-e2e | ||
| "Running libsycl End-to-End tests" | ||
| ${CMAKE_CURRENT_BINARY_DIR} | ||
| EXCLUDE_FROM_CHECK_ALL | ||
| DEPENDS ${LIBSYCL_E2E_TEST_DEPS}) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| ## Getting Started | ||
|
|
||
| This directory contains `libsycl` tests distributed in subdirectories based on | ||
| testing scope. `libsycl` uses LIT to configure and run its tests. | ||
|
|
||
| Please see the [Lit Command Guide](https://llvm.org/docs/CommandGuide/lit.html) | ||
| for more information about LIT. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| * Target runtime(s) to execute tests on devices. | ||
| TODO: add link to liboffload instruction once they add it. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't liboffload just be there if you build clang/llvm with sycl support? I was expecting that here will be a list of runtimes such as L0 which must be available for the test to run. Should we list here these runtimes one by one?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. your understanding is correct and the idea is to have an instruction about L0/CUDA/HIP runtimes setup here. And I believe this instruction must be provided on liboffload level since it is the runtime that directly works with them. This instruction is absent since liboffload has poor (and/or absent) documentation now. Intel liboffload team has docs in TODO list and will add it once it will be ready. |
||
| * Compiler & libsycl. Can be built following these | ||
| [instructions](/libsycl/docs/index.rst). | ||
|
|
||
| ## Run the tests | ||
|
|
||
| `libsycl` is integrated via LLVM_ENABLE_RUNTIMES and is not visible as top | ||
| level target. Same is applicable for tests. To run `check-sycl-e2e` tests you | ||
| need to prefix `<build>/runtimes/runtimes-bins/` to the paths of all tests. | ||
| For example, to run all the libsycl end-to-end tests you can do: | ||
| ```bash | ||
| <build>/bin/llvm-lit <build>/runtimes/runtimes-bins/libsycl/test_e2e | ||
| ``` | ||
|
|
||
| To run individual test, use the path to it instead. | ||
|
|
||
| If you are using `ninja` as your build system, you can run all the tests in the | ||
| libsycl testsuite as: | ||
|
|
||
| ```bash | ||
| ninja -C <build>/runtimes/runtimes-bins check-sycl-e2e | ||
| ``` | ||
|
|
||
|
|
||
| ## CMake parameters | ||
|
|
||
| These parameters can be used to configure tests: | ||
|
|
||
| `LIBSYCL_CXX_COMPILER` - path to compiler to use it for building tests. | ||
|
|
||
| `LIBSYCL_E2E_CXX_FLAGS` - flags to be passed to `LIBSYCL_CXX_COMPILER` when | ||
| building libsycl end-to-end tests. | ||
|
|
||
| `LLVM_LIT` - path to llvm-lit tool. | ||
|
|
||
| ## Creating or modifying tests | ||
|
|
||
| ### LIT feature checks | ||
|
|
||
| Following features can be passed to LIT via `REQUIRES`, `UNSUPPORTED`, etc. | ||
| filters to limit test execution to the specific environment. | ||
|
|
||
| #### Auto-detected features | ||
|
|
||
| The following features are automatically detected by `llvm-lit` by scanning the | ||
| environment: | ||
|
|
||
| * `linux` - host OS; | ||
| * `any-device-is-gpu` - device type to be available; | ||
| * `any-device-is-level_zero` - backend to be available; | ||
|
|
||
| Note: `sycl-ls` tool doesn't have assigned feature since it is essential for | ||
| tests configuration and is always available if test is executed. | ||
|
|
||
| ### llvm-lit parameters | ||
|
|
||
| Following options can be passed to `llvm-lit` tool with `--param` option to | ||
| configure test execution: | ||
|
|
||
| * `libsycl_compiler` - full path to compiler to use; | ||
| * `extra_environment` - comma-separated list of variables with values to be | ||
| added to test environment. Can be also set by `LIT_EXTRA_ENVIRONMENT` | ||
| variable in CMake. | ||
| * `extra_system_environment` - comma-separated list of variables to be | ||
| propagated from the host environment to test environment. Can be also set by | ||
| `LIT_EXTRA_SYSTEM_ENVIRONMENT` variable in CMake. | ||
|
|
||
| Example: | ||
|
|
||
| ```bash | ||
| <build>/bin/llvm-lit --param libsycl_compiler=path/to/clang++ \ | ||
| <build>/runtimes/runtimes-bins/libsycl/test_e2e | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| // RUN: %clangxx %sycl_options %s -o %t.out | ||
| // RUN: %t.out | ||
| // | ||
| // Tests platform::get_devices for each device type. | ||
|
|
||
| #include <sycl.hpp> | ||
|
|
||
| #include <algorithm> | ||
| #include <iostream> | ||
|
|
||
| std::string BackendToString(sycl::backend Backend) { | ||
| switch (Backend) { | ||
| case sycl::backend::opencl: | ||
| return "opencl"; | ||
| case sycl::backend::level_zero: | ||
| return "level_zero"; | ||
| case sycl::backend::cuda: | ||
| return "cuda"; | ||
| case sycl::backend::hip: | ||
| return "hip"; | ||
| default: | ||
| return "unknown"; | ||
| } | ||
| } | ||
|
|
||
| std::string DeviceTypeToString(sycl::info::device_type DevType) { | ||
| switch (DevType) { | ||
| case sycl::info::device_type::all: | ||
| return "device_type::all"; | ||
| case sycl::info::device_type::cpu: | ||
| return "device_type::cpu"; | ||
| case sycl::info::device_type::gpu: | ||
| return "device_type::gpu"; | ||
| case sycl::info::device_type::accelerator: | ||
| return "device_type::accelerator"; | ||
| case sycl::info::device_type::custom: | ||
| return "device_type::custom"; | ||
| case sycl::info::device_type::automatic: | ||
| return "device_type::automatic"; | ||
| case sycl::info::device_type::host: | ||
| return "device_type::host"; | ||
| default: | ||
| return "UNKNOWN"; | ||
| } | ||
| } | ||
|
|
||
| std::string GenerateDeviceDescription(sycl::info::device_type DevType, | ||
| const sycl::platform &Platform) { | ||
| return std::string(DeviceTypeToString(DevType)) + " (" + | ||
| BackendToString(Platform.get_backend()) + ")"; | ||
| } | ||
|
|
||
| template <typename T1, typename T2> | ||
| int Check(const T1 &LHS, const T2 &RHS, std::string TestName) { | ||
| if (LHS != RHS) { | ||
| std::cerr << "Failed check " << LHS << " != " << RHS << ": " << TestName | ||
| << std::endl; | ||
| return 1; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| int CheckDeviceType(const sycl::platform &P, sycl::info::device_type DevType, | ||
| std::vector<sycl::device> &AllDevices) { | ||
| assert(DevType != sycl::info::device_type::all); | ||
| int Failures = 0; | ||
|
|
||
| std::vector<sycl::device> Devices = P.get_devices(DevType); | ||
|
|
||
| if (DevType == sycl::info::device_type::automatic) { | ||
| if (AllDevices.empty()) { | ||
| Failures += Check(Devices.size(), 0, | ||
| "No devices reported for device_type::all query, but " | ||
| "device_type::automatic returns a device."); | ||
| } else { | ||
| Failures += Check(Devices.size(), 1, | ||
| "Number of devices for device_type::automatic query."); | ||
| if (Devices.size()) | ||
| Failures += Check( | ||
| std::count(AllDevices.begin(), AllDevices.end(), Devices[0]), 1, | ||
| "Device is in the set of device_type::all devices in the " | ||
| "platform."); | ||
| } | ||
| return Failures; | ||
| } | ||
|
|
||
| // Count devices with the type; | ||
| size_t DevCount = 0; | ||
| for (sycl::device Device : Devices) | ||
| DevCount += (Device.get_info<sycl::info::device::device_type>() == DevType); | ||
|
|
||
| Failures += Check(Devices.size(), DevCount, | ||
| "Unexpected number of devices for " + | ||
| GenerateDeviceDescription(DevType, P)); | ||
|
|
||
| Failures += | ||
| Check(std::all_of(Devices.begin(), Devices.end(), | ||
| [&](const auto &Dev) { | ||
| return std::count(AllDevices.begin(), | ||
| AllDevices.end(), Dev) == 1; | ||
| }), | ||
| true, | ||
| "Not all devices for " + GenerateDeviceDescription(DevType, P) + | ||
| " appear in the list of all devices"); | ||
|
|
||
| return Failures; | ||
| } | ||
|
|
||
| int main() { | ||
| int Failures = 0; | ||
| for (sycl::platform P : sycl::platform::get_platforms()) { | ||
| std::vector<sycl::device> Devices = P.get_devices(); | ||
|
|
||
| for (sycl::info::device_type DevType : | ||
| {sycl::info::device_type::cpu, sycl::info::device_type::gpu, | ||
| sycl::info::device_type::accelerator, sycl::info::device_type::custom, | ||
| sycl::info::device_type::automatic, sycl::info::device_type::host}) | ||
| Failures += CheckDeviceType(P, DevType, Devices); | ||
| } | ||
| return Failures; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left
e2ein the name intentionally. In the end we will have same test folders as other projects:test,unittests+test_e2e. As in intel/llvmunittestsandtestwon't require backend runtimes to be present on system to do check. while e2e testing require and so can't be joined withtest.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my point of view, we have two top level test directories artificially created due to attempting to move some tests requiring third-party software/hardware to llvm-test-suite repository.
I see no reason to complicate the implementation with this separation. I don't see such complications in other runtime library projects depending on third-party software/hardware (e.g. liboffload, libc++, etc.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have different configs for them. lit config and features for e2e tests are way more complex that is needed for
test.testrequire compilation + sometimes tools like objdump to be run. That's it. I lot of stuff related to device choice, runtimes, build-only/run-only has no sense for that kind of tests.I would prefer 2 different setups doing exactly what is needed for each kind of tests than merge them and have a monstrous config that should handle everything.
plus it may be easier to avoid a mess when compile-only and e2e tests are separated. we can have ./test/compile-only and ./test/e2e if you want to keep it under 'test' top folder but I don't see why it is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it's simpler. I don't understand why we need to maintain to different LIT config files when "compile-only" tests are sub-set of regular tests. We can use single config for both types of tests.