From fcff08906f450fd5253ba934f157c12e3336c5ab Mon Sep 17 00:00:00 2001 From: Simon Kallweit <64953474+skallweitNV@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:47:45 +0100 Subject: [PATCH] enable self-hosted runners (#105) * enable self-hosted runners * enable unit tests * run unit tests using ctest * fix ctest arguments * add device availability check * fix build config * fix * fix arg * disable cpu backend support on linux (broken) * improve availability test * fix skipping cuda test * improve availability check and move it to testing * fixes * rename entrypoint --- .github/workflows/ci.yml | 30 +++++-- CMakeLists.txt | 3 + src/rhi.cpp | 1 + tests/test-shared-buffer.cpp | 4 +- tests/test-shared-texture.cpp | 4 +- tests/testing.cpp | 158 ++++++++++++++++++++++++++++------ tests/testing.h | 2 + 7 files changed, 168 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c56feb8..d1f79288 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,27 @@ jobs: matrix: os: ["windows", "linux", "macos"] platform: ["x86_64", "aarch64"] + compiler: ["msvc", "gcc", "clang"] config: ["Debug", "Release"] - include: - - {os: windows, runs-on: windows-latest} - - {os: linux, runs-on: ubuntu-latest} - - {os: macos, runs-on: macos-latest} exclude: + # Exclude x86_64 for macos - {os: macos, platform: x86_64} + # Exclude unavailable compilers + - { os: windows, compiler: gcc } + - { os: windows, compiler: clang } + - { os: linux, compiler: msvc } + - { os: macos, compiler: msvc } + - { os: macos, compiler: gcc } + include: + # Builds running on self-hosted runners (build + tests) + - {os: windows, platform: "x86_64", compiler: msvc, flags: "unit-test", runs-on: { group: nvrgfx, labels: [Windows, X64] } } + - {os: linux, platform: "x86_64", compiler: gcc, flags: "unit-test", runs-on: { group: nvrgfx, labels: [Linux, X64] } } + # Builds running on GitHub hosted runners (build + tests) + - { os: macos, platform: "aarch64", compiler: clang, flags: "unit-test", runs-on: [macos-latest] } + # Builds running on GitHub hosted runners (build only) + - { os: linux, platform: "x86_64", compiler: clang, runs-on: [ubuntu-latest] } + - { os: windows, platform: "aarch64", runs-on: [windows-latest] } + - { os: linux, platform: "aarch64", runs-on: [ubuntu-latest] } runs-on: ${{ matrix.runs-on }} @@ -30,7 +44,7 @@ jobs: submodules: true - name: Setup Linux - if: matrix.os == 'linux' + if: matrix.os == 'linux' && contains(matrix.runs-on, 'ubuntu-latest') run: sudo apt-get update && sudo apt-get install -y xorg-dev - name: Setup Linux (aarch64 cross-compilation) @@ -54,4 +68,8 @@ jobs: run: cmake --preset default -S . -B build ${{env.CMAKE_ARGS}} - name: Build - run: cmake --build build -j 2 + run: cmake --build build --config ${{matrix.config}} + + - name: Unit Tests + if: contains(matrix.flags, 'unit-test') + run: ctest --test-dir build --build-config ${{matrix.config}} --verbose diff --git a/CMakeLists.txt b/CMakeLists.txt index 49f74311..e9db8aa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ endif() # Add the cmake directory to the module path. list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +include(CTest) include(CMakeDependentOption) include(FetchPackage) include(DetermineTargetArchitecture) @@ -572,6 +573,8 @@ if(SLANG_RHI_BUILD_TESTS) target_compile_features(slang-rhi-tests PRIVATE cxx_std_17) target_include_directories(slang-rhi-tests PRIVATE tests) target_link_libraries(slang-rhi-tests PRIVATE doctest stb slang slang-rhi) + + add_test(NAME slang-rhi-tests COMMAND slang-rhi-tests WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests) endif() if(SLANG_RHI_BUILD_EXAMPLES) diff --git a/src/rhi.cpp b/src/rhi.cpp index aab78ee8..91b5ada4 100644 --- a/src/rhi.cpp +++ b/src/rhi.cpp @@ -233,6 +233,7 @@ class RHI : public IRHI virtual const FormatInfo& getFormatInfo(Format format) override { return s_formatInfoMap.get(format); } virtual const char* getDeviceTypeName(DeviceType type) override; virtual bool isDeviceTypeSupported(DeviceType type) override; + Result getAdapters(DeviceType type, ISlangBlob** outAdaptersBlob) override; Result createDevice(const DeviceDesc& desc, IDevice** outDevice) override; Result reportLiveObjects() override; diff --git a/tests/test-shared-buffer.cpp b/tests/test-shared-buffer.cpp index 67d9ffe9..386d7d70 100644 --- a/tests/test-shared-buffer.cpp +++ b/tests/test-shared-buffer.cpp @@ -77,8 +77,8 @@ void testSharedBuffer(GpuTestContext* ctx, DeviceType deviceType) #if SLANG_WIN64 TEST_CASE("shared-buffer-cuda") { - if (!getRHI()->isDeviceTypeSupported(DeviceType::CUDA)) - SKIP("CUDA not supported"); + if (!isDeviceTypeAvailable(DeviceType::CUDA)) + SKIP("CUDA not available"); runGpuTests( testSharedBuffer, diff --git a/tests/test-shared-texture.cpp b/tests/test-shared-texture.cpp index 656df3fa..76b6faf8 100644 --- a/tests/test-shared-texture.cpp +++ b/tests/test-shared-texture.cpp @@ -150,8 +150,8 @@ void testSharedTexture(GpuTestContext* ctx, DeviceType deviceType) #if SLANG_WIN64 TEST_CASE("shared-texture-cuda") { - if (!getRHI()->isDeviceTypeSupported(DeviceType::CUDA)) - SKIP("CUDA not supported"); + if (!isDeviceTypeAvailable(DeviceType::CUDA)) + SKIP("CUDA not available"); runGpuTests( testSharedTexture, diff --git a/tests/testing.cpp b/tests/testing.cpp index 38a86bfc..a61380ae 100644 --- a/tests/testing.cpp +++ b/tests/testing.cpp @@ -449,29 +449,6 @@ void renderDocBeginFrame() {} void renderDocEndFrame() {} #endif -bool isSwiftShaderDevice(IDevice* device) -{ - std::string adapterName = device->getDeviceInfo().adapterName; - std::transform( - adapterName.begin(), - adapterName.end(), - adapterName.begin(), - [](unsigned char c) { return std::tolower(c); } - ); - return adapterName.find("swiftshader") != std::string::npos; -} - -static slang::IGlobalSession* getSlangGlobalSession() -{ - static slang::IGlobalSession* slangGlobalSession = []() - { - slang::IGlobalSession* session; - REQUIRE_CALL(slang::createGlobalSession(&session)); - return session; - }(); - return slangGlobalSession; -} - inline const char* deviceTypeToString(DeviceType deviceType) { switch (deviceType) @@ -495,11 +472,144 @@ inline const char* deviceTypeToString(DeviceType deviceType) } } +inline bool checkDeviceTypeAvailable(DeviceType deviceType, bool verbose = true) +{ +#define RETURN_NOT_AVAILABLE(msg) \ + { \ + if (verbose) \ + MESSAGE( \ + doctest::String(deviceTypeToString(deviceType)), \ + " is not available (", \ + doctest::String(msg), \ + ")" \ + ); \ + return false; \ + } + + if (verbose) + MESSAGE("Checking for ", doctest::String(deviceTypeToString(deviceType))); + + + if (!rhi::getRHI()->isDeviceTypeSupported(deviceType)) + RETURN_NOT_AVAILABLE("backend not supported"); + +#if SLANG_LINUX_FAMILY + if (deviceType == DeviceType::CPU) + // Known issues with CPU backend on linux. + RETURN_NOT_AVAILABLE("CPU backend not supported on linux"); +#endif + + // Try creating a device. + ComPtr device; + DeviceDesc desc; + desc.deviceType = deviceType; + if (!SLANG_SUCCEEDED(rhi::getRHI()->createDevice(desc, device.writeRef()))) + RETURN_NOT_AVAILABLE("failed to create device"); + + // Try compiling a trivial shader. + ComPtr session = device->getSlangSession(); + if (!session) + RETURN_NOT_AVAILABLE("failed to get slang session"); + + // Load shader module. + slang::IModule* module = nullptr; + { + ComPtr diagnostics; + const char* source = "[shader(\"compute\")] [numthreads(1,1,1)] void computeMain(uint3 tid : SV_DispatchThreadID) {}"; + module = session->loadModuleFromSourceString("test", "test", source, diagnostics.writeRef()); + if (verbose && diagnostics) + MESSAGE(doctest::String((const char*)diagnostics->getBufferPointer())); + if (!module) + RETURN_NOT_AVAILABLE("failed to load module"); + } + + ComPtr entryPoint; + if (!SLANG_SUCCEEDED(module->findEntryPointByName("computeMain", entryPoint.writeRef()))) + RETURN_NOT_AVAILABLE("failed to find entry point"); + + ComPtr composedProgram; + { + ComPtr diagnostics; + std::vector componentTypes; + componentTypes.push_back(module); + componentTypes.push_back(entryPoint); + session->createCompositeComponentType( + componentTypes.data(), + componentTypes.size(), + composedProgram.writeRef(), + diagnostics.writeRef() + ); + if (verbose && diagnostics) + MESSAGE(doctest::String((const char*)diagnostics->getBufferPointer())); + if (!composedProgram) + RETURN_NOT_AVAILABLE("failed to create composite component type"); + } + + ComPtr linkedProgram; + { + ComPtr diagnostics; + composedProgram->link(linkedProgram.writeRef(), diagnostics.writeRef()); + if (verbose && diagnostics) + MESSAGE(doctest::String((const char*)diagnostics->getBufferPointer())); + if (!linkedProgram) + RETURN_NOT_AVAILABLE("failed to link program"); + } + + ComPtr code; + { + ComPtr diagnostics; + linkedProgram->getEntryPointCode(0, 0, code.writeRef(), diagnostics.writeRef()); + if (verbose && diagnostics) + MESSAGE(doctest::String((const char*)diagnostics->getBufferPointer())); + if (!code) + RETURN_NOT_AVAILABLE("failed to get entry point code"); + } + + if (verbose) + MESSAGE(doctest::String(deviceTypeToString(deviceType)), " is available."); + + return true; +} + +bool isDeviceTypeAvailable(DeviceType deviceType) +{ + static std::map available; + auto it = available.find(deviceType); + if (it == available.end()) + { + available[deviceType] = checkDeviceTypeAvailable(deviceType); + } + return available[deviceType]; +} + +bool isSwiftShaderDevice(IDevice* device) +{ + std::string adapterName = device->getDeviceInfo().adapterName; + std::transform( + adapterName.begin(), + adapterName.end(), + adapterName.begin(), + [](unsigned char c) { return std::tolower(c); } + ); + return adapterName.find("swiftshader") != std::string::npos; +} + +static slang::IGlobalSession* getSlangGlobalSession() +{ + static slang::IGlobalSession* slangGlobalSession = []() + { + slang::IGlobalSession* session; + REQUIRE_CALL(slang::createGlobalSession(&session)); + return session; + }(); + return slangGlobalSession; +} + void runGpuTests(GpuTestFunc func, std::initializer_list deviceTypes) { for (auto deviceType : deviceTypes) { - if (!getRHI()->isDeviceTypeSupported(deviceType)) + if (!isDeviceTypeAvailable(deviceType)) { continue; } diff --git a/tests/testing.h b/tests/testing.h index 9150da74..0b0b3c92 100644 --- a/tests/testing.h +++ b/tests/testing.h @@ -137,6 +137,8 @@ ComPtr createTestingSession( std::vector additionalSearchPaths = {} ); +bool isDeviceTypeAvailable(DeviceType deviceType); + bool isSwiftShaderDevice(IDevice* device); std::vector getSlangSearchPaths();