diff --git a/sycl/source/detail/config.def b/sycl/source/detail/config.def index 95750092bfb2e..d0ac3d1c34766 100644 --- a/sycl/source/detail/config.def +++ b/sycl/source/detail/config.def @@ -37,3 +37,4 @@ CONFIG(SYCL_CACHE_MAX_DEVICE_IMAGE_SIZE, 16, __SYCL_CACHE_MAX_DEVICE_IMAGE_SIZE) CONFIG(INTEL_ENABLE_OFFLOAD_ANNOTATIONS, 1, __SYCL_INTEL_ENABLE_OFFLOAD_ANNOTATIONS) CONFIG(SYCL_ENABLE_DEFAULT_CONTEXTS, 1, __SYCL_ENABLE_DEFAULT_CONTEXTS) CONFIG(SYCL_QUEUE_THREAD_POOL_SIZE, 4, __SYCL_QUEUE_THREAD_POOL_SIZE) +CONFIG(SYCL_RT_WARNING_LEVEL, 4, __SYCL_RT_WARNING_LEVEL) diff --git a/sycl/source/detail/config.hpp b/sycl/source/detail/config.hpp index fa93535db2cc1..dd2f767ae098f 100644 --- a/sycl/source/detail/config.hpp +++ b/sycl/source/detail/config.hpp @@ -183,6 +183,30 @@ template <> class SYCLConfig { } }; +template <> class SYCLConfig { + using BaseT = SYCLConfigBase; + +public: + static unsigned int get() { return getCachedValue(); } + + static void reset() { (void)getCachedValue(true); } + +private: + static unsigned int getCachedValue(bool ResetCache = false) { + const auto Parser = []() { + const char *ValStr = BaseT::getRawValue(); + int SignedLevel = ValStr ? std::atoi(ValStr) : 0; + return SignedLevel >= 0 ? SignedLevel : 0; + }; + + static unsigned int Level = Parser(); + if (ResetCache) + Level = Parser(); + + return Level; + } +}; + template <> class SYCLConfig { using BaseT = SYCLConfigBase; diff --git a/sycl/source/detail/kernel_program_cache.hpp b/sycl/source/detail/kernel_program_cache.hpp index 356c0a1288429..1dded43d9b6f2 100644 --- a/sycl/source/detail/kernel_program_cache.hpp +++ b/sycl/source/detail/kernel_program_cache.hpp @@ -130,6 +130,15 @@ class KernelProgramCache { MKernelFastCache.emplace(CacheKey, CacheVal); } + /// Clears cache state. + /// + /// This member function should only be used in unit tests. + void reset() { + MCachedPrograms = ProgramCacheT{}; + MKernelsPerProgramCache = KernelCacheT{}; + MKernelFastCache = KernelFastCacheT{}; + } + private: std::mutex MProgramCacheMutex; std::mutex MKernelsPerProgramCacheMutex; diff --git a/sycl/source/detail/program_manager/program_manager.cpp b/sycl/source/detail/program_manager/program_manager.cpp index 9d57215443e4a..72c3b317b7271 100644 --- a/sycl/source/detail/program_manager/program_manager.cpp +++ b/sycl/source/detail/program_manager/program_manager.cpp @@ -438,6 +438,17 @@ std::pair ProgramManager::getOrCreatePIProgram( return {NativePrg, BinProg.size()}; } +/// Emits information about built programs if the appropriate contitions are +/// met, namely when SYCL_RT_WARNING_LEVEL is greater than or equal to 2. +static void emitBuiltProgramInfo(const pi_program &Prog, + const ContextImplPtr &Context) { + if (SYCLConfig::get() >= 2) { + std::string ProgramBuildLog = + ProgramManager::getProgramBuildLog(Prog, Context); + std::clog << ProgramBuildLog << std::endl; + } +} + RT::PiProgram ProgramManager::getBuiltPIProgram( OSModuleHandle M, const ContextImplPtr &ContextImpl, const DeviceImplPtr &DeviceImpl, const std::string &KernelName, @@ -511,6 +522,8 @@ RT::PiProgram ProgramManager::getBuiltPIProgram( getRawSyclObjImpl(Device)->getHandleRef(), ContextImpl->getCachedLibPrograms(), DeviceLibReqMask); + emitBuiltProgramInfo(BuiltProgram.get(), ContextImpl); + { std::lock_guard Lock(MNativeProgramsMutex); NativePrograms[BuiltProgram.get()] = &Img; @@ -1785,6 +1798,8 @@ device_image_plain ProgramManager::build(const device_image_plain &DeviceImage, getRawSyclObjImpl(Devs[0])->getHandleRef(), ContextImpl->getCachedLibPrograms(), DeviceLibReqMask); + emitBuiltProgramInfo(BuiltProgram.get(), ContextImpl); + { std::lock_guard Lock(MNativeProgramsMutex); NativePrograms[BuiltProgram.get()] = &Img; diff --git a/sycl/unittests/helpers/CommonRedefinitions.hpp b/sycl/unittests/helpers/CommonRedefinitions.hpp index 8bed27d438bf9..dc57785fa3ac1 100644 --- a/sycl/unittests/helpers/CommonRedefinitions.hpp +++ b/sycl/unittests/helpers/CommonRedefinitions.hpp @@ -53,19 +53,31 @@ inline pi_result redefinedProgramGetInfoCommon(pi_program program, size_t param_value_size, void *param_value, size_t *param_value_size_ret) { + if (param_value_size_ret) { + *param_value_size_ret = sizeof(size_t); + } if (param_name == PI_PROGRAM_INFO_NUM_DEVICES) { - auto value = reinterpret_cast(param_value); - *value = 1; + if (param_value) { + auto value = reinterpret_cast(param_value); + *value = 1; + } } if (param_name == PI_PROGRAM_INFO_BINARY_SIZES) { - auto value = reinterpret_cast(param_value); - value[0] = 1; + if (param_value) { + auto value = reinterpret_cast(param_value); + value[0] = 1; + } } if (param_name == PI_PROGRAM_INFO_BINARIES) { - auto value = reinterpret_cast(param_value); - value[0] = 1; + if (param_value_size_ret) { + *param_value_size_ret = sizeof(unsigned char); + } + if (param_value) { + auto value = reinterpret_cast(param_value); + value[0] = 1; + } } return PI_SUCCESS; diff --git a/sycl/unittests/helpers/ScopedEnvVar.hpp b/sycl/unittests/helpers/ScopedEnvVar.hpp index a078eeab2f537..6e02b631a1f2a 100644 --- a/sycl/unittests/helpers/ScopedEnvVar.hpp +++ b/sycl/unittests/helpers/ScopedEnvVar.hpp @@ -8,6 +8,9 @@ #pragma once +#include + +#include #include #include diff --git a/sycl/unittests/program_manager/BuildLog.cpp b/sycl/unittests/program_manager/BuildLog.cpp new file mode 100644 index 0000000000000..97307de7fc315 --- /dev/null +++ b/sycl/unittests/program_manager/BuildLog.cpp @@ -0,0 +1,150 @@ +//==----------------- BuildLog.cpp --- Build log 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 "gtest/internal/gtest-internal.h" +#define SYCL2020_DISABLE_DEPRECATION_WARNINGS + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +// Same as defined in config.def +static constexpr auto WarningLevelEnvVar = "SYCL_RT_WARNING_LEVEL"; + +static bool LogRequested = false; + +static pi_result redefinedProgramGetBuildInfo( + pi_program program, pi_device device, cl_program_build_info param_name, + size_t param_value_size, void *param_value, size_t *param_value_size_ret) { + + if (param_value_size_ret) { + *param_value_size_ret = 1; + } + if (param_value) { + *static_cast(param_value) = '1'; + } + + if (param_name == PI_PROGRAM_BUILD_INFO_LOG) { + LogRequested = true; + } + + return PI_SUCCESS; +} + +static pi_result redefinedDeviceGetInfo(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_NAME) { + const std::string name = "Test Device"; + if (param_value_size_ret) { + *param_value_size_ret = name.size(); + } + if (param_value) { + auto *val = static_cast(param_value); + strcpy(val, name.data()); + } + } + if (param_name == PI_DEVICE_INFO_COMPILER_AVAILABLE) { + if (param_value_size_ret) { + *param_value_size_ret = sizeof(cl_bool); + } + if (param_value) { + auto *val = static_cast(param_value); + *val = 1; + } + } + return PI_SUCCESS; +} + +static void setupCommonTestAPIs(sycl::unittest::PiMock &Mock) { + using namespace sycl::detail; + Mock.redefine(redefinedProgramGetBuildInfo); + Mock.redefine(redefinedDeviceGetInfo); +} + +TEST(BuildLog, OutputNothingOnLevel1) { + using namespace sycl::detail; + using namespace sycl::unittest; + ScopedEnvVar var(WarningLevelEnvVar, "1", + SYCLConfig::reset); + + sycl::platform Plt{sycl::default_selector()}; + // TODO make sure unsupported platform is never selected + if (Plt.is_host() || Plt.get_backend() == sycl::backend::ext_oneapi_cuda || + Plt.get_backend() == sycl::backend::ext_oneapi_hip) { + GTEST_SKIP_("Test is not supported on this platform"); + } + + sycl::unittest::PiMock Mock{Plt}; + setupDefaultMockAPIs(Mock); + setupCommonTestAPIs(Mock); + + const sycl::device Dev = Plt.get_devices()[0]; + + sycl::queue Queue{Dev}; + + sycl::context Ctx = Queue.get_context(); + auto ContextImpl = getSyclObjImpl(Ctx); + // Make sure no kernels are cached + ContextImpl->getKernelProgramCache().reset(); + + LogRequested = false; + sycl::kernel_bundle KernelBundle = + sycl::get_kernel_bundle(Ctx, {Dev}); + (void)sycl::build(KernelBundle); + + EXPECT_EQ(LogRequested, false); +} + +TEST(BuildLog, OutputLogOnLevel2) { + using namespace sycl::detail; + using namespace sycl::unittest; + ScopedEnvVar var(WarningLevelEnvVar, "2", + SYCLConfig::reset); + + sycl::platform Plt{sycl::default_selector()}; + // TODO make sure unsupported platform is never selected + if (Plt.is_host() || Plt.get_backend() == sycl::backend::ext_oneapi_cuda || + Plt.get_backend() == sycl::backend::ext_oneapi_hip) { + GTEST_SKIP_("Test is not supported on this platform"); + } + + sycl::unittest::PiMock Mock{Plt}; + setupDefaultMockAPIs(Mock); + setupCommonTestAPIs(Mock); + + const sycl::device Dev = Plt.get_devices()[0]; + + sycl::queue Queue{Dev}; + + const sycl::context Ctx = Queue.get_context(); + auto ContextImpl = getSyclObjImpl(Ctx); + // Make sure no kernels are cached + ContextImpl->getKernelProgramCache().reset(); + + LogRequested = false; + sycl::kernel_bundle KernelBundle = + sycl::get_kernel_bundle(Ctx, {Dev}); + (void)sycl::build(KernelBundle); + + EXPECT_EQ(LogRequested, true); +} diff --git a/sycl/unittests/program_manager/CMakeLists.txt b/sycl/unittests/program_manager/CMakeLists.txt index b8a836e81c7d6..7ee79016233f9 100644 --- a/sycl/unittests/program_manager/CMakeLists.txt +++ b/sycl/unittests/program_manager/CMakeLists.txt @@ -1,6 +1,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) add_sycl_unittest(ProgramManagerTests OBJECT + BuildLog.cpp EliminatedArgMask.cpp itt_annotations.cpp )