From 6968d26f3a211a22991fef41b8f848bbb9822953 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Tue, 14 Feb 2023 15:03:52 +0000 Subject: [PATCH] Sysman: Add support for sysman APIs In level_zero/sysman directory This change: - Adds support for accessing linux based filesystem - Add support for telemetry - Add support for LinuxSysmanImp Related-To: LOCI-3889 Signed-off-by: Jitendra Sharma --- cmake/run_ult_target.cmake | 10 +- .../core/source/linux/driver_teardown.cpp | 7 +- .../core/source/windows/driver_teardown.cpp | 7 +- level_zero/sysman/source/CMakeLists.txt | 1 + level_zero/sysman/source/linux/CMakeLists.txt | 25 + level_zero/sysman/source/linux/fs_access.cpp | 590 ++++++++++++++++++ level_zero/sysman/source/linux/fs_access.h | 135 ++++ .../sysman/source/linux/os_sysman_imp.cpp | 170 +++++ .../sysman/source/linux/os_sysman_imp.h | 59 ++ .../sysman/source/linux/pmt/CMakeLists.txt | 19 + level_zero/sysman/source/linux/pmt/pmt.cpp | 214 +++++++ level_zero/sysman/source/linux/pmt/pmt.h | 58 ++ .../sysman/source/linux/pmt/pmt_helper.cpp | 27 + .../sysman/source/linux/pmt/pmt_xml_offsets.h | 247 ++++++++ .../sysman/source/sysman_device_imp.cpp | 9 +- level_zero/sysman/source/sysman_device_imp.h | 2 + level_zero/sysman/source/sysman_driver.cpp | 17 +- level_zero/sysman/source/sysman_driver.h | 2 +- .../source/sysman_driver_handle_imp.cpp | 10 +- .../sysman/source/sysman_driver_handle_imp.h | 2 +- level_zero/sysman/source/sysman_driver_imp.h | 1 - .../sysman/source/windows/CMakeLists.txt | 21 + .../sysman/source/windows/os_sysman_imp.cpp | 33 + .../sysman/source/windows/os_sysman_imp.h | 26 + .../test/unit_tests/sources/CMakeLists.txt | 2 - .../unit_tests/sources/linux/CMakeLists.txt | 18 + .../sources/{ => linux}/mock_sysman_driver.h | 0 .../sources/linux/mock_sysman_drm.h | 26 + .../sources/linux/mock_sysman_fixture.h | 150 +++++ .../sources/linux/pmt/CMakeLists.txt | 14 + .../unit_tests/sources/linux/pmt/mock_pmt.h | 159 +++++ .../unit_tests/sources/linux/pmt/test_pmt.cpp | 276 ++++++++ .../unit_tests/sources/linux/test_sysman.cpp | 227 +++++++ .../{ => linux}/test_sysman_driver.cpp | 98 ++- shared/source/os_interface/linux/drm_neo.h | 1 + .../source/os_interface/linux/hw_device_id.h | 3 +- .../os_interface/linux/hw_device_id_linux.cpp | 11 +- shared/source/os_interface/linux/sys_calls.h | 3 +- .../os_interface/linux/sys_calls_linux.cpp | 6 +- .../linux/sys_calls_linux_ult.cpp | 8 + .../os_interface/linux/sys_calls_linux_ult.h | 3 +- 41 files changed, 2652 insertions(+), 45 deletions(-) create mode 100644 level_zero/sysman/source/linux/CMakeLists.txt create mode 100644 level_zero/sysman/source/linux/fs_access.cpp create mode 100644 level_zero/sysman/source/linux/fs_access.h create mode 100644 level_zero/sysman/source/linux/os_sysman_imp.cpp create mode 100644 level_zero/sysman/source/linux/os_sysman_imp.h create mode 100644 level_zero/sysman/source/linux/pmt/CMakeLists.txt create mode 100644 level_zero/sysman/source/linux/pmt/pmt.cpp create mode 100644 level_zero/sysman/source/linux/pmt/pmt.h create mode 100644 level_zero/sysman/source/linux/pmt/pmt_helper.cpp create mode 100644 level_zero/sysman/source/linux/pmt/pmt_xml_offsets.h create mode 100644 level_zero/sysman/source/windows/CMakeLists.txt create mode 100644 level_zero/sysman/source/windows/os_sysman_imp.cpp create mode 100644 level_zero/sysman/source/windows/os_sysman_imp.h create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/CMakeLists.txt rename level_zero/sysman/test/unit_tests/sources/{ => linux}/mock_sysman_driver.h (100%) create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_drm.h create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/pmt/CMakeLists.txt create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/pmt/mock_pmt.h create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/pmt/test_pmt.cpp create mode 100644 level_zero/sysman/test/unit_tests/sources/linux/test_sysman.cpp rename level_zero/sysman/test/unit_tests/sources/{ => linux}/test_sysman_driver.cpp (60%) diff --git a/cmake/run_ult_target.cmake b/cmake/run_ult_target.cmake index 9618cecebc..bfc79d857b 100644 --- a/cmake/run_ult_target.cmake +++ b/cmake/run_ult_target.cmake @@ -1,5 +1,5 @@ # -# Copyright (C) 2020-2022 Intel Corporation +# Copyright (C) 2020-2023 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -100,6 +100,11 @@ if(NOT NEO_SKIP_L0_UNIT_TESTS AND BUILD_WITH_L0) set(GTEST_OUTPUT_EXP "--gtest_output=json:${GTEST_OUTPUT_DIR}/ze_intel_gpu_exp_${product}_${revision_id}_unit_tests_results.json") message(STATUS "GTest output exp set to ${GTEST_OUTPUT_EXP}") endif() + unset(GTEST_OUTPUT_SYSMAN) + if(DEFINED GTEST_OUTPUT_DIR) + set(GTEST_OUTPUT_SYSMAN "--gtest_output=json:${GTEST_OUTPUT_DIR}/ze_intel_gpu_sysman_${product}_${revision_id}_unit_tests_results.json") + message(STATUS "GTest output tools set to ${GTEST_OUTPUT_SYSMAN}") + endif() if(NOT TARGET run_l0_tests) add_custom_target(run_l0_tests) @@ -122,6 +127,9 @@ if(NOT NEO_SKIP_L0_UNIT_TESTS AND BUILD_WITH_L0) COMMAND echo Running ze_intel_gpu_tools_tests ${target} ${slices}x${subslices}x${eu_per_ss} in ${TargetDir} COMMAND echo Cmd line: ${NEO_RUN_INTERCEPTOR_LIST} $ --product ${product} --slices ${slices} --subslices ${subslices} --eu_per_ss ${eu_per_ss} ${GTEST_EXCEPTION_OPTIONS} --gtest_repeat=${GTEST_REPEAT} ${GTEST_SHUFFLE} ${GTEST_OUTPUT_CORE} ${NEO_TESTS_LISTENER_OPTION} ${GTEST_FILTER_OPTION} --rev_id ${revision_id} COMMAND ${NEO_RUN_INTERCEPTOR_LIST} $ --product ${product} --slices ${slices} --subslices ${subslices} --eu_per_ss ${eu_per_ss} ${GTEST_EXCEPTION_OPTIONS} --gtest_repeat=${GTEST_REPEAT} ${GTEST_SHUFFLE} ${GTEST_OUTPUT_TOOLS} ${NEO_TESTS_LISTENER_OPTION} ${GTEST_FILTER_OPTION} --rev_id ${revision_id} + COMMAND echo Running ze_intel_gpu_sysman_tests ${target} ${slices}x${subslices}x${eu_per_ss} in ${TargetDir} + COMMAND echo Cmd line: ${NEO_RUN_INTERCEPTOR_LIST} $ --product ${product} --slices ${slices} --subslices ${subslices} --eu_per_ss ${eu_per_ss} ${GTEST_EXCEPTION_OPTIONS} --gtest_repeat=${GTEST_REPEAT} ${GTEST_SHUFFLE} ${GTEST_OUTPUT_CORE} ${NEO_TESTS_LISTENER_OPTION} ${GTEST_FILTER_OPTION} --rev_id ${revision_id} + COMMAND ${NEO_RUN_INTERCEPTOR_LIST} $ --product ${product} --slices ${slices} --subslices ${subslices} --eu_per_ss ${eu_per_ss} ${GTEST_EXCEPTION_OPTIONS} --gtest_repeat=${GTEST_REPEAT} ${GTEST_SHUFFLE} ${GTEST_OUTPUT_SYSMAN} ${NEO_TESTS_LISTENER_OPTION} ${GTEST_FILTER_OPTION} --rev_id ${revision_id} ) add_dependencies(run_l0_tests run_${product}_${revision_id}_l0_tests) diff --git a/level_zero/core/source/linux/driver_teardown.cpp b/level_zero/core/source/linux/driver_teardown.cpp index 57574da852..6bd2fae3aa 100644 --- a/level_zero/core/source/linux/driver_teardown.cpp +++ b/level_zero/core/source/linux/driver_teardown.cpp @@ -1,11 +1,12 @@ /* - * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "level_zero/core/source/driver/driver_handle_imp.h" +#include "level_zero/sysman/source/sysman_driver_handle_imp.h" using namespace L0; @@ -14,4 +15,8 @@ void __attribute__((destructor)) driverHandleDestructor() { delete GlobalDriver; GlobalDriver = nullptr; } + if (Sysman::GlobalSysmanDriver != nullptr) { + delete Sysman::GlobalSysmanDriver; + Sysman::GlobalSysmanDriver = nullptr; + } } \ No newline at end of file diff --git a/level_zero/core/source/windows/driver_teardown.cpp b/level_zero/core/source/windows/driver_teardown.cpp index e9db6759d3..9b4b3850dd 100644 --- a/level_zero/core/source/windows/driver_teardown.cpp +++ b/level_zero/core/source/windows/driver_teardown.cpp @@ -1,11 +1,12 @@ /* - * Copyright (C) 2020 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * */ #include "level_zero/core/source/driver/driver_handle_imp.h" +#include "level_zero/sysman/source/sysman_driver_handle_imp.h" #include @@ -17,6 +18,10 @@ BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { delete GlobalDriver; GlobalDriver = nullptr; } + if (Sysman::GlobalSysmanDriver != nullptr) { + delete Sysman::GlobalSysmanDriver; + Sysman::GlobalSysmanDriver = nullptr; + } } return TRUE; } diff --git a/level_zero/sysman/source/CMakeLists.txt b/level_zero/sysman/source/CMakeLists.txt index d5937d8c84..241af9f760 100644 --- a/level_zero/sysman/source/CMakeLists.txt +++ b/level_zero/sysman/source/CMakeLists.txt @@ -15,6 +15,7 @@ set(L0_SRCS_SYSMAN ${CMAKE_CURRENT_SOURCE_DIR}/sysman_device.h ${CMAKE_CURRENT_SOURCE_DIR}/sysman_device_imp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sysman_device_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/os_sysman.h ) target_sources(${L0_STATIC_LIB_NAME} diff --git a/level_zero/sysman/source/linux/CMakeLists.txt b/level_zero/sysman/source/linux/CMakeLists.txt new file mode 100644 index 0000000000..cb66b97a1f --- /dev/null +++ b/level_zero/sysman/source/linux/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +set(L0_SRCS_SYSMAN_LINUX + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/os_sysman_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/os_sysman_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fs_access.h + ${CMAKE_CURRENT_SOURCE_DIR}/fs_access.cpp +) + +if(UNIX) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${L0_SRCS_SYSMAN_LINUX} + ) +endif() + +add_subdirectories() + +# Make our source files visible to parent +set_property(GLOBAL PROPERTY L0_SRCS_SYSMAN_LINUX ${L0_SRCS_SYSMAN_LINUX}) diff --git a/level_zero/sysman/source/linux/fs_access.cpp b/level_zero/sysman/source/linux/fs_access.cpp new file mode 100644 index 0000000000..f2c9d9dfdd --- /dev/null +++ b/level_zero/sysman/source/linux/fs_access.cpp @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/linux/fs_access.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace L0 { +namespace Sysman { + +static ze_result_t getResult(int err) { + if ((EPERM == err) || (EACCES == err)) { + return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; + } else if (ENOENT == err) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } else if (EBUSY == err) { + return ZE_RESULT_ERROR_HANDLE_OBJECT_IN_USE; + } else { + return ZE_RESULT_ERROR_UNKNOWN; + } +} + +// Generic Filesystem Access +FsAccess::FsAccess() { +} + +FsAccess *FsAccess::create() { + return new FsAccess(); +} + +ze_result_t FsAccess::read(const std::string file, uint64_t &val) { + // Read a single line from text file without trailing newline + std::ifstream fs; + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + fs >> val; + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + fs.close(); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::read(const std::string file, double &val) { + // Read a single line from text file without trailing newline + std::ifstream fs; + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + fs >> val; + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + fs.close(); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::read(const std::string file, int32_t &val) { + // Read a single line from text file without trailing newline + std::ifstream fs; + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + fs >> val; + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + fs.close(); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::read(const std::string file, uint32_t &val) { + // Read a single line from text file without trailing newline + std::ifstream fs; + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + fs >> val; + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + fs.close(); + return ZE_RESULT_SUCCESS; +} +ze_result_t FsAccess::read(const std::string file, std::string &val) { + // Read a single line from text file without trailing newline + std::ifstream fs; + val.clear(); + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + fs >> val; + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + fs.close(); + // Strip trailing newline + if (val.back() == '\n') { + val.pop_back(); + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::read(const std::string file, std::vector &val) { + // Read a entire text file, one line per vector entry + std::string line; + std::ifstream fs; + val.clear(); + + fs.open(file.c_str()); + if (fs.fail()) { + return getResult(errno); + } + while (std::getline(fs, line)) { + if (fs.fail()) { + fs.close(); + return getResult(errno); + } + if (line.back() == '\n') { + line.pop_back(); + } + val.push_back(line); + } + fs.close(); + + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::write(const std::string file, const std::string val) { + std::ofstream sysfs; + + sysfs.open(file.c_str()); + if (sysfs.fail()) { + return getResult(errno); + } + sysfs << val << std::endl; + if (sysfs.fail()) { + sysfs.close(); + return getResult(errno); + } + sysfs.close(); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::canRead(const std::string file) { + struct stat sb; + if (statSyscall(file.c_str(), &sb) != 0) { + return ZE_RESULT_ERROR_UNKNOWN; + } + if (sb.st_mode & S_IRUSR) { + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; +} + +ze_result_t FsAccess::canWrite(const std::string file) { + struct stat sb; + if (statSyscall(file.c_str(), &sb) != 0) { + return ZE_RESULT_ERROR_UNKNOWN; + } + if (sb.st_mode & S_IWUSR) { + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; +} + +bool FsAccess::fileExists(const std::string file) { + if (NEO::SysCalls::access(file.c_str(), F_OK)) { + return false; + } + return true; +} + +ze_result_t FsAccess::getFileMode(const std::string file, ::mode_t &mode) { + struct stat sb; + if (0 != stat(file.c_str(), &sb)) { + return getResult(errno); + } + mode = sb.st_mode; + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::readSymLink(const std::string path, std::string &val) { + // returns the value of symlink at path + char buf[PATH_MAX]; + ssize_t len = NEO::SysCalls::readlink(path.c_str(), buf, PATH_MAX - 1); + if (len < 0) { + return getResult(errno); + } + buf[len] = '\0'; + val = std::string(buf); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::getRealPath(const std::string path, std::string &val) { + // returns the real file path after resolving all symlinks in path + char buf[PATH_MAX]; + char *realPath = NEO::SysCalls::realpath(path.c_str(), buf); + if (!realPath) { + return getResult(errno); + } + val = std::string(buf); + return ZE_RESULT_SUCCESS; +} + +ze_result_t FsAccess::listDirectory(const std::string path, std::vector &list) { + list.clear(); + ::DIR *procDir = ::opendir(path.c_str()); + if (!procDir) { + return getResult(errno); + } + struct ::dirent *ent; + int err = 0; + // readdir doesn't clear errno, so make sure it is clear + errno = 0; + while (NULL != (ent = ::readdir(procDir))) { + // Ignore . and .. + std::string name = std::string(ent->d_name); + if (!name.compare(".") || !name.compare("..")) { + errno = 0; + continue; + } + list.push_back(std::string(ent->d_name)); + errno = 0; + } + err = errno; + ::closedir(procDir); + // Check if in above while loop, readdir encountered any error. + if ((err != 0) && (err != ENOENT)) { + list.clear(); + return getResult(err); + } + return ZE_RESULT_SUCCESS; +} + +std::string FsAccess::getBaseName(const std::string path) { + size_t pos = path.rfind("/"); + if (std::string::npos == pos) { + return path; + } + return path.substr(pos + 1, std::string::npos); +} + +std::string FsAccess::getDirName(const std::string path) { + size_t pos = path.rfind("/"); + if (std::string::npos == pos) { + return std::string(""); + } + // Include trailing slash + return path.substr(0, pos); +} + +bool FsAccess::isRootUser() { + return (geteuid() == 0); +} + +bool FsAccess::directoryExists(const std::string path) { + if (accessSyscall(path.c_str(), F_OK)) { + return false; + } + return true; +} + +// Procfs Access +const std::string ProcfsAccess::procDir = "/proc/"; +const std::string ProcfsAccess::fdDir = "/fd/"; + +std::string ProcfsAccess::fullPath(const ::pid_t pid) { + // Returns the full path for proc entry for process pid + return std::string(procDir + std::to_string(pid)); +} + +std::string ProcfsAccess::fdDirPath(const ::pid_t pid) { + // Returns the full path to file descritpor directory + // for process pid + return std::string(fullPath(pid) + fdDir); +} + +std::string ProcfsAccess::fullFdPath(const ::pid_t pid, const int fd) { + // Returns the full path for filedescriptor fd + // for process pid + return std::string(fdDirPath(pid) + std::to_string(fd)); +} + +ProcfsAccess *ProcfsAccess::create() { + return new ProcfsAccess(); +} + +ze_result_t ProcfsAccess::listProcesses(std::vector<::pid_t> &list) { + // Returns a vector with all the active process ids in the system + list.clear(); + std::vector dir; + ze_result_t result = FsAccess::listDirectory(procDir, dir); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + for (auto &&file : dir) { + ::pid_t pid; + std::istringstream stream(file); + stream >> pid; + if (stream.fail()) { + // Non numeric filename, not a process, skip + continue; + } + list.push_back(pid); + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t ProcfsAccess::getFileDescriptors(const ::pid_t pid, std::vector &list) { + // Returns a vector with all the filedescriptor numbers opened by a pid + list.clear(); + std::vector dir; + ze_result_t result = FsAccess::listDirectory(fdDirPath(pid), dir); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + for (auto &&file : dir) { + int fd; + std::istringstream stream(file); + stream >> fd; + if (stream.fail()) { + // Non numeric filename, not a file descriptor + continue; + } + list.push_back(fd); + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t ProcfsAccess::getFileName(const ::pid_t pid, const int fd, std::string &val) { + // Given a process id and a file descriptor number + // return full name of the open file. + // NOTE: For sockets, the name will be of the format "socket:[nnnnnnn]" + return FsAccess::readSymLink(fullFdPath(pid, fd), val); +} + +bool ProcfsAccess::isAlive(const ::pid_t pid) { + return FsAccess::fileExists(fullPath(pid)); +} + +void ProcfsAccess::kill(const ::pid_t pid) { + ::kill(pid, SIGKILL); +} + +::pid_t ProcfsAccess::myProcessId() { + return ::getpid(); +} + +// Sysfs Access +const std::string SysfsAccess::drmPath = "/sys/class/drm/"; +const std::string SysfsAccess::devicesPath = "device/drm/"; +const std::string SysfsAccess::primaryDevName = "card"; +const std::string SysfsAccess::drmDriverDevNodeDir = "/dev/dri/"; +const std::string SysfsAccess::intelGpuBindEntry = "/sys/bus/pci/drivers/i915/bind"; +const std::string SysfsAccess::intelGpuUnbindEntry = "/sys/bus/pci/drivers/i915/unbind"; + +std::string SysfsAccess::fullPath(const std::string file) { + // Prepend sysfs directory path for this device + return std::string(dirname + file); +} + +SysfsAccess::SysfsAccess(const std::string dev) { + // dev could be either /dev/dri/cardX or /dev/dri/renderDX + std::string fileName = FsAccess::getBaseName(dev); + std::string devicesDir = drmPath + fileName + std::string("/") + devicesPath; + + FsAccess::listDirectory(devicesDir, deviceNames); + for (auto &&next : deviceNames) { + if (!next.compare(0, primaryDevName.length(), primaryDevName)) { + dirname = drmPath + next + std::string("/"); + break; + } + } +} + +SysfsAccess *SysfsAccess::create(const std::string dev) { + return new SysfsAccess(dev); +} + +ze_result_t SysfsAccess::canRead(const std::string file) { + // Prepend sysfs directory path and call the base canRead + return FsAccess::canRead(fullPath(file)); +} + +ze_result_t SysfsAccess::canWrite(const std::string file) { + // Prepend sysfs directory path and call the base canWrite + return FsAccess::canWrite(fullPath(file)); +} + +ze_result_t SysfsAccess::getFileMode(const std::string file, ::mode_t &mode) { + // Prepend sysfs directory path and call the base getFileMode + return FsAccess::getFileMode(fullPath(file), mode); +} + +ze_result_t SysfsAccess::read(const std::string file, std::string &val) { + // Prepend sysfs directory path and call the base read + return FsAccess::read(fullPath(file).c_str(), val); +} + +ze_result_t SysfsAccess::read(const std::string file, int32_t &val) { + std::string str; + ze_result_t result; + + result = FsAccess::read(fullPath(file), str); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + std::istringstream stream(str); + stream >> val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t SysfsAccess::read(const std::string file, uint32_t &val) { + std::string str; + ze_result_t result; + + result = FsAccess::read(fullPath(file), str); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + std::istringstream stream(str); + stream >> val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t SysfsAccess::read(const std::string file, double &val) { + std::string str; + ze_result_t result; + + result = FsAccess::read(fullPath(file), str); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + std::istringstream stream(str); + stream >> val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t SysfsAccess::read(const std::string file, uint64_t &val) { + std::string str; + ze_result_t result; + + result = FsAccess::read(fullPath(file), str); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + std::istringstream stream(str); + stream >> val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return ZE_RESULT_SUCCESS; +} + +ze_result_t SysfsAccess::read(const std::string file, std::vector &val) { + // Prepend sysfs directory path and call the base read + return FsAccess::read(fullPath(file), val); +} + +ze_result_t SysfsAccess::write(const std::string file, const std::string val) { + // Prepend sysfs directory path and call the base write + return FsAccess::write(fullPath(file).c_str(), val); +} + +ze_result_t SysfsAccess::write(const std::string file, const int val) { + std::ostringstream stream; + stream << val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return FsAccess::write(fullPath(file), stream.str()); +} + +ze_result_t SysfsAccess::write(const std::string file, const double val) { + std::ostringstream stream; + stream << val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return FsAccess::write(fullPath(file), stream.str()); +} + +ze_result_t SysfsAccess::write(const std::string file, const uint64_t val) { + std::ostringstream stream; + stream << val; + + if (stream.fail()) { + return ZE_RESULT_ERROR_UNKNOWN; + } + return FsAccess::write(fullPath(file), stream.str()); +} + +ze_result_t SysfsAccess::scanDirEntries(const std::string path, std::vector &list) { + list.clear(); + return FsAccess::listDirectory(fullPath(path).c_str(), list); +} + +ze_result_t SysfsAccess::readSymLink(const std::string path, std::string &val) { + // Prepend sysfs directory path and call the base readSymLink + return FsAccess::readSymLink(fullPath(path).c_str(), val); +} + +ze_result_t SysfsAccess::getRealPath(const std::string path, std::string &val) { + // Prepend sysfs directory path and call the base getRealPath + return FsAccess::getRealPath(fullPath(path).c_str(), val); +} + +ze_result_t SysfsAccess::bindDevice(std::string device) { + return FsAccess::write(intelGpuBindEntry, device); +} + +ze_result_t SysfsAccess::unbindDevice(std::string device) { + return FsAccess::write(intelGpuUnbindEntry, device); +} + +bool SysfsAccess::fileExists(const std::string file) { + // Prepend sysfs directory path and call the base fileExists + return FsAccess::fileExists(fullPath(file).c_str()); +} + +bool SysfsAccess::directoryExists(const std::string path) { + return FsAccess::directoryExists(fullPath(path).c_str()); +} + +bool SysfsAccess::isMyDeviceFile(const std::string dev) { + // dev is a full pathname. + if (getDirName(dev).compare(drmDriverDevNodeDir)) { + for (auto &&next : deviceNames) { + if (!getBaseName(dev).compare(next)) { + return true; + } + } + } + return false; +} + +bool SysfsAccess::isRootUser() { + return FsAccess::isRootUser(); +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/fs_access.h b/level_zero/sysman/source/linux/fs_access.h new file mode 100644 index 0000000000..595731fb0f --- /dev/null +++ b/level_zero/sysman/source/linux/fs_access.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/os_interface/linux/sys_calls.h" + +#include "level_zero/ze_api.h" +#include "level_zero/zet_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace L0 { +namespace Sysman { + +class FsAccess { + public: + static FsAccess *create(); + virtual ~FsAccess() = default; + + virtual ze_result_t canRead(const std::string file); + virtual ze_result_t canWrite(const std::string file); + virtual ze_result_t getFileMode(const std::string file, ::mode_t &mode); + + virtual ze_result_t read(const std::string file, uint64_t &val); + virtual ze_result_t read(const std::string file, std::string &val); + virtual ze_result_t read(const std::string file, std::vector &val); + virtual ze_result_t read(const std::string file, double &val); + virtual ze_result_t read(const std::string file, uint32_t &val); + virtual ze_result_t read(const std::string file, int32_t &val); + + virtual ze_result_t write(const std::string file, const std::string val); + + virtual ze_result_t readSymLink(const std::string path, std::string &buf); + virtual ze_result_t getRealPath(const std::string path, std::string &buf); + virtual ze_result_t listDirectory(const std::string path, std::vector &list); + virtual bool isRootUser(); + std::string getBaseName(const std::string path); + std::string getDirName(const std::string path); + virtual bool fileExists(const std::string file); + virtual bool directoryExists(const std::string path); + + protected: + FsAccess(); + decltype(&NEO::SysCalls::access) accessSyscall = NEO::SysCalls::access; + decltype(&stat) statSyscall = stat; +}; + +class ProcfsAccess : private FsAccess { + public: + static ProcfsAccess *create(); + ~ProcfsAccess() override = default; + + MOCKABLE_VIRTUAL ze_result_t listProcesses(std::vector<::pid_t> &list); + MOCKABLE_VIRTUAL ::pid_t myProcessId(); + MOCKABLE_VIRTUAL ze_result_t getFileDescriptors(const ::pid_t pid, std::vector &list); + MOCKABLE_VIRTUAL ze_result_t getFileName(const ::pid_t pid, const int fd, std::string &val); + MOCKABLE_VIRTUAL bool isAlive(const ::pid_t pid); + MOCKABLE_VIRTUAL void kill(const ::pid_t pid); + + protected: + ProcfsAccess() = default; + + private: + std::string fullPath(const ::pid_t pid); + std::string fdDirPath(const ::pid_t pid); + std::string fullFdPath(const ::pid_t pid, const int fd); + static const std::string procDir; + static const std::string fdDir; +}; + +class SysfsAccess : protected FsAccess { + public: + static SysfsAccess *create(const std::string file); + SysfsAccess() = default; + ~SysfsAccess() override = default; + + ze_result_t canRead(const std::string file) override; + ze_result_t canWrite(const std::string file) override; + ze_result_t getFileMode(const std::string file, ::mode_t &mode) override; + + ze_result_t read(const std::string file, std::string &val) override; + ze_result_t read(const std::string file, int32_t &val) override; + ze_result_t read(const std::string file, uint32_t &val) override; + ze_result_t read(const std::string file, uint64_t &val) override; + ze_result_t read(const std::string file, double &val) override; + ze_result_t read(const std::string file, std::vector &val) override; + + ze_result_t write(const std::string file, const std::string val) override; + MOCKABLE_VIRTUAL ze_result_t write(const std::string file, const int val); + MOCKABLE_VIRTUAL ze_result_t write(const std::string file, const uint64_t val); + MOCKABLE_VIRTUAL ze_result_t write(const std::string file, const double val); + ze_result_t write(const std::string file, std::vector val); + + MOCKABLE_VIRTUAL ze_result_t scanDirEntries(const std::string path, std::vector &list); + ze_result_t readSymLink(const std::string path, std::string &buf) override; + ze_result_t getRealPath(const std::string path, std::string &buf) override; + MOCKABLE_VIRTUAL ze_result_t bindDevice(const std::string device); + MOCKABLE_VIRTUAL ze_result_t unbindDevice(const std::string device); + bool fileExists(const std::string file) override; + MOCKABLE_VIRTUAL bool isMyDeviceFile(const std::string dev); + bool directoryExists(const std::string path) override; + bool isRootUser() override; + + protected: + std::vector deviceNames; + + private: + SysfsAccess(const std::string file); + + std::string fullPath(const std::string file); + std::string dirname; + static const std::string drmPath; + static const std::string devicesPath; + static const std::string primaryDevName; + static const std::string drmDriverDevNodeDir; + static const std::string intelGpuBindEntry; + static const std::string intelGpuUnbindEntry; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/os_sysman_imp.cpp b/level_zero/sysman/source/linux/os_sysman_imp.cpp new file mode 100644 index 0000000000..e378dfb52d --- /dev/null +++ b/level_zero/sysman/source/linux/os_sysman_imp.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/linux/os_sysman_imp.h" + +#include "shared/source/helpers/gfx_core_helper.h" +#include "shared/source/os_interface/linux/drm_neo.h" +#include "shared/source/os_interface/os_interface.h" + +#include "level_zero/sysman/source/linux/fs_access.h" +#include "level_zero/sysman/source/linux/pmt/pmt.h" + +namespace L0 { +namespace Sysman { + +const std::string LinuxSysmanImp::deviceDir("device"); + +ze_result_t LinuxSysmanImp::init() { + pFsAccess = FsAccess::create(); + DEBUG_BREAK_IF(nullptr == pFsAccess); + + if (pProcfsAccess == nullptr) { + pProcfsAccess = ProcfsAccess::create(); + } + DEBUG_BREAK_IF(nullptr == pProcfsAccess); + + ze_result_t result; + NEO::OSInterface &osInterface = *pParentSysmanDeviceImp->getRootDeviceEnvironment().osInterface; + if (osInterface.getDriverModel()->getDriverModelType() != NEO::DriverModelType::DRM) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + auto pDrm = osInterface.getDriverModel()->as(); + int myDeviceFd = pDrm->getFileDescriptor(); + std::string myDeviceName; + result = pProcfsAccess->getFileName(pProcfsAccess->myProcessId(), myDeviceFd, myDeviceName); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + if (pSysfsAccess == nullptr) { + pSysfsAccess = SysfsAccess::create(myDeviceName); + } + DEBUG_BREAK_IF(nullptr == pSysfsAccess); + + subDeviceCount = NEO::GfxCoreHelper::getSubDevicesCount(&pParentSysmanDeviceImp->getHardwareInfo()); + if (subDeviceCount == 1) { + subDeviceCount = 0; + } + + osInterface.getDriverModel()->as()->cleanup(); + // Close Drm handles + pDrm->closeFileDescriptor(); + return createPmtHandles(); +} + +ze_result_t LinuxSysmanImp::createPmtHandles() { + std::string gtDevicePCIPath; + auto result = pSysfsAccess->getRealPath("device", gtDevicePCIPath); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + auto gpuUpstreamPortPath = getPciCardBusDirectoryPath(gtDevicePCIPath); + PlatformMonitoringTech::create(this, gpuUpstreamPortPath, mapOfSubDeviceIdToPmtObject); + return result; +} + +static std::string modifyPathOnLevel(std::string realPciPath, uint8_t nLevel) { + size_t loc; + // we need to change the absolute path to 'nLevel' levels up + while (nLevel > 0) { + loc = realPciPath.find_last_of('/'); + if (loc == std::string::npos) { + break; + } + realPciPath = realPciPath.substr(0, loc); + nLevel--; + } + return realPciPath; +} + +std::string LinuxSysmanImp::getPciCardBusDirectoryPath(std::string realPciPath) { + // the cardbus is always the second pci folder after the pcie slot. + // +-[0000:89]-+-00.0 + // | +-00.1 + // | +-00.2 + // | +-00.4 + // | \-02.0-[8a-8e]----00.0-[8b-8e]--+-01.0-[8c-8d]----00.0 + // | \-02.0-[8e]--+-00.0 + // | +-00.1 + // | \-00.2 + // /sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:01.0/0000:8c:00.0 + // '/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/' will always be the same distance. + // from 0000:8c:00.0 i.e the 2nd PCI address from the gt tile. + return modifyPathOnLevel(realPciPath, 2); +} + +PlatformMonitoringTech *LinuxSysmanImp::getPlatformMonitoringTechAccess(uint32_t subDeviceId) { + auto subDeviceIdToPmtEntry = mapOfSubDeviceIdToPmtObject.find(subDeviceId); + if (subDeviceIdToPmtEntry == mapOfSubDeviceIdToPmtObject.end()) { + return nullptr; + } + return subDeviceIdToPmtEntry->second; +} + +void LinuxSysmanImp::releasePmtObject() { + for (auto &subDeviceIdToPmtEntry : mapOfSubDeviceIdToPmtObject) { + if (subDeviceIdToPmtEntry.second) { + delete subDeviceIdToPmtEntry.second; + subDeviceIdToPmtEntry.second = nullptr; + } + } + mapOfSubDeviceIdToPmtObject.clear(); +} + +FsAccess &LinuxSysmanImp::getFsAccess() { + UNRECOVERABLE_IF(nullptr == pFsAccess); + return *pFsAccess; +} + +ProcfsAccess &LinuxSysmanImp::getProcfsAccess() { + UNRECOVERABLE_IF(nullptr == pProcfsAccess); + return *pProcfsAccess; +} + +SysfsAccess &LinuxSysmanImp::getSysfsAccess() { + UNRECOVERABLE_IF(nullptr == pSysfsAccess); + return *pSysfsAccess; +} + +SysmanDeviceImp *LinuxSysmanImp::getSysmanDeviceImp() { + return pParentSysmanDeviceImp; +} + +uint32_t LinuxSysmanImp::getSubDeviceCount() { + return subDeviceCount; +} + +LinuxSysmanImp::LinuxSysmanImp(SysmanDeviceImp *pParentSysmanDeviceImp) { + this->pParentSysmanDeviceImp = pParentSysmanDeviceImp; + executionEnvironment = pParentSysmanDeviceImp->getExecutionEnvironment(); + rootDeviceIndex = pParentSysmanDeviceImp->getRootDeviceIndex(); +} + +LinuxSysmanImp::~LinuxSysmanImp() { + if (nullptr != pSysfsAccess) { + delete pSysfsAccess; + pSysfsAccess = nullptr; + } + if (nullptr != pProcfsAccess) { + delete pProcfsAccess; + pProcfsAccess = nullptr; + } + if (nullptr != pFsAccess) { + delete pFsAccess; + pFsAccess = nullptr; + } + releasePmtObject(); +} + +OsSysman *OsSysman::create(SysmanDeviceImp *pParentSysmanDeviceImp) { + LinuxSysmanImp *pLinuxSysmanImp = new LinuxSysmanImp(pParentSysmanDeviceImp); + return static_cast(pLinuxSysmanImp); +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/os_sysman_imp.h b/level_zero/sysman/source/linux/os_sysman_imp.h new file mode 100644 index 0000000000..55617ac8ca --- /dev/null +++ b/level_zero/sysman/source/linux/os_sysman_imp.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/execution_environment/execution_environment.h" +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/sysman/source/os_sysman.h" +#include "level_zero/sysman/source/sysman_device_imp.h" + +#include + +namespace L0 { +namespace Sysman { +class PlatformMonitoringTech; +class FsAccess; +class ProcfsAccess; +class SysfsAccess; + +class LinuxSysmanImp : public OsSysman, NEO::NonCopyableOrMovableClass { + public: + LinuxSysmanImp(SysmanDeviceImp *pParentSysmanDeviceImp); + ~LinuxSysmanImp() override; + + ze_result_t init() override; + + FsAccess &getFsAccess(); + ProcfsAccess &getProcfsAccess(); + SysfsAccess &getSysfsAccess(); + SysmanDeviceImp *getSysmanDeviceImp(); + uint32_t getSubDeviceCount() override; + std::string getPciCardBusDirectoryPath(std::string realPciPath); + PlatformMonitoringTech *getPlatformMonitoringTechAccess(uint32_t subDeviceId); + PRODUCT_FAMILY getProductFamily() const { return pParentSysmanDeviceImp->getProductFamily(); } + void releasePmtObject(); + ze_result_t createPmtHandles(); + std::string devicePciBdf = ""; + NEO::ExecutionEnvironment *executionEnvironment = nullptr; + uint32_t rootDeviceIndex; + + protected: + FsAccess *pFsAccess = nullptr; + ProcfsAccess *pProcfsAccess = nullptr; + SysfsAccess *pSysfsAccess = nullptr; + std::map mapOfSubDeviceIdToPmtObject; + uint32_t subDeviceCount = 0; + + private: + LinuxSysmanImp() = delete; + SysmanDeviceImp *pParentSysmanDeviceImp = nullptr; + static const std::string deviceDir; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/pmt/CMakeLists.txt b/level_zero/sysman/source/linux/pmt/CMakeLists.txt new file mode 100644 index 0000000000..ae58487012 --- /dev/null +++ b/level_zero/sysman/source/linux/pmt/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +set(L0_SRCS_SYSMAN_LINUX_PMT + ${CMAKE_CURRENT_SOURCE_DIR}/pmt_helper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pmt.h +) +if(UNIX) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${L0_SRCS_SYSMAN_LINUX_PMT} + ) +endif() +# Make our source files visible to parent +set_property(GLOBAL PROPERTY L0_SRCS_SYSMAN_PMT_LINUX ${L0_SRCS_SYSMAN_PMT_LINUX}) diff --git a/level_zero/sysman/source/linux/pmt/pmt.cpp b/level_zero/sysman/source/linux/pmt/pmt.cpp new file mode 100644 index 0000000000..8a3ed03249 --- /dev/null +++ b/level_zero/sysman/source/linux/pmt/pmt.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/linux/pmt/pmt.h" + +#include "shared/source/debug_settings/debug_settings_manager.h" + +#include "level_zero/sysman/source/linux/os_sysman_imp.h" +#include "level_zero/sysman/source/sysman_device_imp.h" + +#include +#include +#include +#include + +namespace L0 { +namespace Sysman { +const std::string PlatformMonitoringTech::baseTelemSysFS("/sys/class/intel_pmt"); +const std::string PlatformMonitoringTech::telem("telem"); +uint32_t PlatformMonitoringTech::rootDeviceTelemNodeIndex = 0; + +ze_result_t PlatformMonitoringTech::readValue(const std::string key, uint32_t &value) { + auto offset = keyOffsetMap.find(key); + if (offset == keyOffsetMap.end()) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + int fd = this->openFunction(telemetryDeviceEntry.c_str(), O_RDONLY); + if (fd == -1) { + return ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + ze_result_t res = ZE_RESULT_SUCCESS; + if (this->preadFunction(fd, &value, sizeof(uint32_t), baseOffset + offset->second) != sizeof(uint32_t)) { + res = ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + if (this->closeFunction(fd) < 0) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + return res; +} + +ze_result_t PlatformMonitoringTech::readValue(const std::string key, uint64_t &value) { + auto offset = keyOffsetMap.find(key); + if (offset == keyOffsetMap.end()) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + int fd = this->openFunction(telemetryDeviceEntry.c_str(), O_RDONLY); + if (fd == -1) { + return ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + ze_result_t res = ZE_RESULT_SUCCESS; + if (this->preadFunction(fd, &value, sizeof(uint64_t), baseOffset + offset->second) != sizeof(uint64_t)) { + res = ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + if (this->closeFunction(fd) < 0) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + return res; +} + +bool compareTelemNodes(std::string &telemNode1, std::string &telemNode2) { + std::string telem = "telem"; + auto indexString1 = telemNode1.substr(telem.size(), telemNode1.size()); + auto indexForTelemNode1 = stoi(indexString1); + auto indexString2 = telemNode2.substr(telem.size(), telemNode2.size()); + auto indexForTelemNode2 = stoi(indexString2); + return indexForTelemNode1 < indexForTelemNode2; +} + +// Check if Telemetry node(say /sys/class/intel_pmt/telem1) and gpuUpstreamPortPath share same PCI Root port +static bool isValidTelemNode(FsAccess *pFsAccess, const std::string &gpuUpstreamPortPath, const std::string sysfsTelemNode) { + std::string realPathOfTelemNode; + auto result = pFsAccess->getRealPath(sysfsTelemNode, realPathOfTelemNode); + if (result != ZE_RESULT_SUCCESS) { + return false; + } + + // Example: If + // gpuUpstreamPortPath = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0"; + // realPathOfTelemNode = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem1"; + // As gpuUpstreamPortPath is a substring of realPathOfTelemNode , hence both sysfs telemNode and GPU device share same PCI Root. + // the PMT is part of the OOBMSM sitting on a switch port 0000:8b:02.0 attached to the upstream port/ Also known as CardBus + // Hence this telem node entry is valid for GPU device. + return (realPathOfTelemNode.compare(0, gpuUpstreamPortPath.size(), gpuUpstreamPortPath) == 0); +} + +ze_result_t PlatformMonitoringTech::enumerateRootTelemIndex(FsAccess *pFsAccess, std::string &gpuUpstreamPortPath) { + std::vector listOfTelemNodes; + auto result = pFsAccess->listDirectory(baseTelemSysFS, listOfTelemNodes); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + + // listOfTelemNodes vector could contain non "telem" entries which are not interested to us. + // Lets refactor listOfTelemNodes vector as below + for (auto iterator = listOfTelemNodes.begin(); iterator != listOfTelemNodes.end(); iterator++) { + if (iterator->compare(0, telem.size(), telem) != 0) { + listOfTelemNodes.erase(iterator--); // Remove entry if its suffix is not "telem" + } + } + + // Exmaple: For below directory + // # /sys/class/intel_pmt$ ls + // telem1 telem2 telem3 + // Then listOfTelemNodes would contain telem1, telem2, telem3 + std::sort(listOfTelemNodes.begin(), listOfTelemNodes.end(), compareTelemNodes); // sort listOfTelemNodes, to arange telem nodes in ascending order + for (const auto &telemNode : listOfTelemNodes) { + if (isValidTelemNode(pFsAccess, gpuUpstreamPortPath, baseTelemSysFS + "/" + telemNode)) { + auto indexString = telemNode.substr(telem.size(), telemNode.size()); + rootDeviceTelemNodeIndex = stoi(indexString); // if telemNode is telemN, then rootDeviceTelemNodeIndex = N + return ZE_RESULT_SUCCESS; + } + } + return ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; +} + +ze_result_t PlatformMonitoringTech::init(FsAccess *pFsAccess, const std::string &gpuUpstreamPortPath, PRODUCT_FAMILY productFamily) { + std::string telemNode = telem + std::to_string(rootDeviceTelemNodeIndex); + // For XE_HP_SDV and PVC single tile devices, telemetry info is retrieved from + // tile's telem node rather from root device telem node. + if ((isSubdevice) || ((productFamily == IGFX_PVC) || (productFamily == IGFX_XE_HP_SDV))) { + uint32_t telemNodeIndex = 0; + // If rootDeviceTelemNode is telem1, then rootDeviceTelemNodeIndex = 1 + // And thus for subdevice0 --> telem node will be telem2, + // for subdevice1 --> telem node will be telem3 etc + telemNodeIndex = rootDeviceTelemNodeIndex + subdeviceId + 1; + telemNode = telem + std::to_string(telemNodeIndex); + } + std::string baseTelemSysFSNode = baseTelemSysFS + "/" + telemNode; + if (!isValidTelemNode(pFsAccess, gpuUpstreamPortPath, baseTelemSysFSNode)) { + return ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + telemetryDeviceEntry = baseTelemSysFSNode + "/" + telem; + if (!pFsAccess->fileExists(telemetryDeviceEntry)) { + NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, + "Telemetry support not available. No file %s\n", telemetryDeviceEntry.c_str()); + return ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE; + } + + std::string guid; + std::string guidPath = baseTelemSysFSNode + std::string("/guid"); + ze_result_t result = pFsAccess->read(guidPath, guid); + if (ZE_RESULT_SUCCESS != result) { + NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, + "Telemetry sysfs entry not available %s\n", guidPath.c_str()); + return result; + } + result = PlatformMonitoringTech::getKeyOffsetMap(guid, keyOffsetMap); + if (ZE_RESULT_SUCCESS != result) { + // We didnt have any entry for this guid in guidToKeyOffsetMap + return result; + } + + std::string offsetPath = baseTelemSysFSNode + std::string("/offset"); + result = pFsAccess->read(offsetPath, baseOffset); + if (ZE_RESULT_SUCCESS != result) { + NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, + "Telemetry sysfs entry not available %s\n", offsetPath.c_str()); + return result; + } + + return ZE_RESULT_SUCCESS; +} + +PlatformMonitoringTech::PlatformMonitoringTech(FsAccess *pFsAccess, ze_bool_t onSubdevice, + uint32_t subdeviceId) : subdeviceId(subdeviceId), isSubdevice(onSubdevice) { +} + +void PlatformMonitoringTech::doInitPmtObject(FsAccess *pFsAccess, uint32_t subdeviceId, PlatformMonitoringTech *pPmt, + const std::string &gpuUpstreamPortPath, + std::map &mapOfSubDeviceIdToPmtObject, PRODUCT_FAMILY productFamily) { + if (pPmt->init(pFsAccess, gpuUpstreamPortPath, productFamily) == ZE_RESULT_SUCCESS) { + mapOfSubDeviceIdToPmtObject.emplace(subdeviceId, pPmt); + NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stdout, + "Pmt object: 0x%llX initialization for subdeviceId %d successful\n", pPmt, static_cast(subdeviceId)); + return; + } + NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, + "Pmt initialization for subdeviceId %d failed\n", static_cast(subdeviceId)); + delete pPmt; // We are here as pPmt->init failed and thus this pPmt object is not useful. Let's delete that. +} + +void PlatformMonitoringTech::create(LinuxSysmanImp *pLinuxSysmanImp, std::string &gpuUpstreamPortPath, + std::map &mapOfSubDeviceIdToPmtObject) { + if (ZE_RESULT_SUCCESS == PlatformMonitoringTech::enumerateRootTelemIndex(&pLinuxSysmanImp->getFsAccess(), gpuUpstreamPortPath)) { + auto subDeviceCount = pLinuxSysmanImp->getSubDeviceCount(); + uint32_t subdeviceId = 0; + do { + ze_bool_t onSubdevice = (subDeviceCount == 0) ? false : true; + auto productFamily = pLinuxSysmanImp->getSysmanDeviceImp()->getProductFamily(); + auto pPmt = new PlatformMonitoringTech(&pLinuxSysmanImp->getFsAccess(), onSubdevice, subdeviceId); + UNRECOVERABLE_IF(nullptr == pPmt); + PlatformMonitoringTech::doInitPmtObject(&pLinuxSysmanImp->getFsAccess(), subdeviceId, pPmt, + gpuUpstreamPortPath, mapOfSubDeviceIdToPmtObject, productFamily); + subdeviceId++; + } while (subdeviceId < subDeviceCount); + } +} + +PlatformMonitoringTech::~PlatformMonitoringTech() { +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/pmt/pmt.h b/level_zero/sysman/source/linux/pmt/pmt.h new file mode 100644 index 0000000000..c8b42e23e0 --- /dev/null +++ b/level_zero/sysman/source/linux/pmt/pmt.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/helpers/non_copyable_or_moveable.h" +#include "shared/source/os_interface/linux/sys_calls.h" + +#include "level_zero/sysman/source/linux/fs_access.h" + +#include "igfxfmid.h" + +#include +#include +#include +#include + +namespace L0 { +namespace Sysman { +class LinuxSysmanImp; + +class PlatformMonitoringTech : NEO::NonCopyableOrMovableClass { + public: + PlatformMonitoringTech() = delete; + PlatformMonitoringTech(FsAccess *pFsAccess, ze_bool_t onSubdevice, uint32_t subdeviceId); + virtual ~PlatformMonitoringTech(); + + virtual ze_result_t readValue(const std::string key, uint32_t &value); + virtual ze_result_t readValue(const std::string key, uint64_t &value); + static ze_result_t enumerateRootTelemIndex(FsAccess *pFsAccess, std::string &gpuUpstreamPortPath); + static void create(LinuxSysmanImp *pLinuxSysmanImp, std::string &gpuUpstreamPortPath, + std::map &mapOfSubDeviceIdToPmtObject); + static ze_result_t getKeyOffsetMap(std::string guid, std::map &keyOffsetMap); + + protected: + static uint32_t rootDeviceTelemNodeIndex; + std::string telemetryDeviceEntry{}; + std::map keyOffsetMap; + ze_result_t init(FsAccess *pFsAccess, const std::string &gpuUpstreamPortPath, PRODUCT_FAMILY productFamily); + static void doInitPmtObject(FsAccess *pFsAccess, uint32_t subdeviceId, PlatformMonitoringTech *pPmt, const std::string &gpuUpstreamPortPath, + std::map &mapOfSubDeviceIdToPmtObject, PRODUCT_FAMILY productFamily); + decltype(&NEO::SysCalls::open) openFunction = NEO::SysCalls::open; + decltype(&NEO::SysCalls::close) closeFunction = NEO::SysCalls::close; + decltype(&NEO::SysCalls::pread) preadFunction = NEO::SysCalls::pread; + + private: + static const std::string baseTelemSysFS; + static const std::string telem; + uint64_t baseOffset = 0; + uint32_t subdeviceId = 0; + ze_bool_t isSubdevice = 0; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/linux/pmt/pmt_helper.cpp b/level_zero/sysman/source/linux/pmt/pmt_helper.cpp new file mode 100644 index 0000000000..319c542c3a --- /dev/null +++ b/level_zero/sysman/source/linux/pmt/pmt_helper.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/linux/pmt/pmt.h" +#include "level_zero/sysman/source/linux/pmt/pmt_xml_offsets.h" + +namespace L0 { +namespace Sysman { + +ze_result_t PlatformMonitoringTech::getKeyOffsetMap(std::string guid, std::map &keyOffsetMap) { + ze_result_t retVal = ZE_RESULT_ERROR_UNKNOWN; + auto keyOffsetMapEntry = guidToKeyOffsetMap.find(guid); + if (keyOffsetMapEntry == guidToKeyOffsetMap.end()) { + // We didnt have any entry for this guid in guidToKeyOffsetMap + retVal = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return retVal; + } + keyOffsetMap = keyOffsetMapEntry->second; + return ZE_RESULT_SUCCESS; +} + +} // namespace Sysman +} // namespace L0 \ No newline at end of file diff --git a/level_zero/sysman/source/linux/pmt/pmt_xml_offsets.h b/level_zero/sysman/source/linux/pmt/pmt_xml_offsets.h new file mode 100644 index 0000000000..c7b094226d --- /dev/null +++ b/level_zero/sysman/source/linux/pmt/pmt_xml_offsets.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2020-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include +#include + +namespace L0 { +namespace Sysman { + +// Each entry of this map corresponds to one particular graphics card type for example, DG1 A or B step. +// or XeHP_SDV. GUID string will help in identify the card type +const std::map> guidToKeyOffsetMap = { + {"0x490e01", // DG1 B stepping + {{"PACKAGE_ENERGY", 0x420}, + {"COMPUTE_TEMPERATURES", 0x68}, + {"SOC_TEMPERATURES", 0x60}, + {"CORE_TEMPERATURES", 0x6c}}}, + {"0x490e", // DG1 A stepping + {{"PACKAGE_ENERGY", 0x400}, + {"COMPUTE_TEMPERATURES", 0x68}, + {"SOC_TEMPERATURES", 0x60}, + {"CORE_TEMPERATURES", 0x6c}}}, + {"0x4f95", // For DG2 device + {{"PACKAGE_ENERGY", 1032}, + {"SOC_TEMPERATURES", 56}}}, // SOC_TEMPERATURE contains GT_TEMP, DRAM_TEMP, SA_TEMP, DE_TEMP, PCIE_TEMP, TYPEC_TEMP + {"0x4f9301", // For ATSM device + {{"PACKAGE_ENERGY", 1032}, + {"SOC_TEMPERATURES", 56}}}, // SOC_TEMPERATURE contains GT_TEMP, DRAM_TEMP, SA_TEMP, DE_TEMP, PCIE_TEMP, TYPEC_TEMP + {"0x4f9302", // For DG2 512EU / ATS-M1 + {{"PACKAGE_ENERGY", 1032}, + {"SOC_TEMPERATURES", 56}, + {"MC_CAPTURE_TIMESTAMP", 1088}, + {"IDI_READS[0]", 1096}, + {"IDI_READS[1]", 1104}, + {"IDI_READS[2]", 1112}, + {"IDI_READS[3]", 1120}, + {"IDI_READS[4]", 1128}, + {"IDI_READS[5]", 1136}, + {"IDI_READS[6]", 1144}, + {"IDI_READS[7]", 1152}, + {"IDI_READS[8]", 1160}, + {"IDI_READS[9]", 1168}, + {"IDI_READS[10]", 1176}, + {"IDI_READS[11]", 1184}, + {"IDI_READS[12]", 1192}, + {"IDI_READS[13]", 1200}, + {"IDI_READS[14]", 1208}, + {"IDI_READS[15]", 1216}, + {"IDI_WRITES[0]", 1224}, + {"IDI_WRITES[1]", 1232}, + {"IDI_WRITES[2]", 1240}, + {"IDI_WRITES[3]", 1248}, + {"IDI_WRITES[4]", 1256}, + {"IDI_WRITES[5]", 1264}, + {"IDI_WRITES[6]", 1272}, + {"IDI_WRITES[7]", 1280}, + {"IDI_WRITES[8]", 1288}, + {"IDI_WRITES[9]", 1296}, + {"IDI_WRITES[10]", 1304}, + {"IDI_WRITES[11]", 1312}, + {"IDI_WRITES[12]", 1320}, + {"IDI_WRITES[13]", 1328}, + {"IDI_WRITES[14]", 1336}, + {"IDI_WRITES[15]", 1344}, + {"DISPLAY_VC1_READS[0]", 1352}, + {"DISPLAY_VC1_READS[1]", 1360}, + {"DISPLAY_VC1_READS[2]", 1368}, + {"DISPLAY_VC1_READS[3]", 1376}, + {"DISPLAY_VC1_READS[4]", 1384}, + {"DISPLAY_VC1_READS[5]", 1392}, + {"DISPLAY_VC1_READS[6]", 1400}, + {"DISPLAY_VC1_READS[7]", 1408}, + {"DISPLAY_VC1_READS[8]", 1416}, + {"DISPLAY_VC1_READS[9]", 1424}, + {"DISPLAY_VC1_READS[10]", 1432}, + {"DISPLAY_VC1_READS[11]", 1440}, + {"DISPLAY_VC1_READS[12]", 1448}, + {"DISPLAY_VC1_READS[13]", 1456}, + {"DISPLAY_VC1_READS[14]", 1464}, + {"DISPLAY_VC1_READS[15]", 1472}}}, + {"0x4f9502", // For DG2 128EU / ATS-M3 + {{"PACKAGE_ENERGY", 1032}, + {"SOC_TEMPERATURES", 56}, + {"MC_CAPTURE_TIMESTAMP", 1088}, + {"IDI_READS[0]", 1096}, + {"IDI_READS[1]", 1104}, + {"IDI_READS[2]", 1112}, + {"IDI_READS[3]", 1120}, + {"IDI_READS[4]", 1128}, + {"IDI_READS[5]", 1136}, + {"IDI_READS[6]", 1144}, + {"IDI_READS[7]", 1152}, + {"IDI_READS[8]", 1160}, + {"IDI_READS[9]", 1168}, + {"IDI_READS[10]", 1176}, + {"IDI_READS[11]", 1184}, + {"IDI_READS[12]", 1192}, + {"IDI_READS[13]", 1200}, + {"IDI_READS[14]", 1208}, + {"IDI_READS[15]", 1216}, + {"IDI_WRITES[0]", 1224}, + {"IDI_WRITES[1]", 1232}, + {"IDI_WRITES[2]", 1240}, + {"IDI_WRITES[3]", 1248}, + {"IDI_WRITES[4]", 1256}, + {"IDI_WRITES[5]", 1264}, + {"IDI_WRITES[6]", 1272}, + {"IDI_WRITES[7]", 1280}, + {"IDI_WRITES[8]", 1288}, + {"IDI_WRITES[9]", 1296}, + {"IDI_WRITES[10]", 1304}, + {"IDI_WRITES[11]", 1312}, + {"IDI_WRITES[12]", 1320}, + {"IDI_WRITES[13]", 1328}, + {"IDI_WRITES[14]", 1336}, + {"IDI_WRITES[15]", 1344}, + {"DISPLAY_VC1_READS[0]", 1352}, + {"DISPLAY_VC1_READS[1]", 1360}, + {"DISPLAY_VC1_READS[2]", 1368}, + {"DISPLAY_VC1_READS[3]", 1376}, + {"DISPLAY_VC1_READS[4]", 1384}, + {"DISPLAY_VC1_READS[5]", 1392}, + {"DISPLAY_VC1_READS[6]", 1400}, + {"DISPLAY_VC1_READS[7]", 1408}, + {"DISPLAY_VC1_READS[8]", 1416}, + {"DISPLAY_VC1_READS[9]", 1424}, + {"DISPLAY_VC1_READS[10]", 1432}, + {"DISPLAY_VC1_READS[11]", 1440}, + {"DISPLAY_VC1_READS[12]", 1448}, + {"DISPLAY_VC1_READS[13]", 1456}, + {"DISPLAY_VC1_READS[14]", 1464}, + {"DISPLAY_VC1_READS[15]", 1472}}}, + {"0xfdc76194", // For XeHP_SDV device + {{"HBM0MaxDeviceTemperature", 28}, + {"HBM1MaxDeviceTemperature", 36}, + {"TileMinTemperature", 40}, + {"TileMaxTemperature", 44}, + {"GTMinTemperature", 48}, + {"GTMaxTemperature", 52}, + {"VF0_VFID", 88}, + {"VF0_HBM0_READ", 92}, + {"VF0_HBM0_WRITE", 96}, + {"VF0_HBM1_READ", 104}, + {"VF0_HBM1_WRITE", 108}, + {"VF0_TIMESTAMP_L", 168}, + {"VF0_TIMESTAMP_H", 172}, + {"VF1_VFID", 176}, + {"VF1_HBM0_READ", 180}, + {"VF1_HBM0_WRITE", 184}, + {"VF1_HBM1_READ", 192}, + {"VF1_HBM1_WRITE", 196}, + {"VF1_TIMESTAMP_L", 256}, + {"VF1_TIMESTAMP_H", 260}}}, + {"0xfdc76196", // For XeHP_SDV B0 device + {{"HBM0MaxDeviceTemperature", 28}, + {"HBM1MaxDeviceTemperature", 36}, + {"TileMinTemperature", 40}, + {"TileMaxTemperature", 44}, + {"GTMinTemperature", 48}, + {"GTMaxTemperature", 52}, + {"VF0_VFID", 88}, + {"VF0_HBM0_READ", 92}, + {"VF0_HBM0_WRITE", 96}, + {"VF0_HBM1_READ", 104}, + {"VF0_HBM1_WRITE", 108}, + {"VF0_TIMESTAMP_L", 168}, + {"VF0_TIMESTAMP_H", 172}, + {"VF1_VFID", 176}, + {"VF1_HBM0_READ", 180}, + {"VF1_HBM0_WRITE", 184}, + {"VF1_HBM1_READ", 192}, + {"VF1_HBM1_WRITE", 196}, + {"VF1_TIMESTAMP_L", 256}, + {"VF1_TIMESTAMP_H", 260}}}, + {"0xb15a0edc", // For PVC device + {{"HBM0MaxDeviceTemperature", 28}, + {"HBM1MaxDeviceTemperature", 36}, + {"TileMinTemperature", 40}, + {"TileMaxTemperature", 44}, + {"GTMinTemperature", 48}, + {"GTMaxTemperature", 52}, + {"VF0_VFID", 88}, + {"VF0_HBM0_READ", 92}, + {"VF0_HBM0_WRITE", 96}, + {"VF0_HBM1_READ", 104}, + {"VF0_HBM1_WRITE", 108}, + {"VF0_TIMESTAMP_L", 168}, + {"VF0_TIMESTAMP_H", 172}, + {"VF1_VFID", 176}, + {"VF1_HBM0_READ", 180}, + {"VF1_HBM0_WRITE", 184}, + {"VF1_HBM1_READ", 192}, + {"VF1_HBM1_WRITE", 196}, + {"VF1_TIMESTAMP_L", 256}, + {"VF1_TIMESTAMP_H", 260}, + {"HBM2MaxDeviceTemperature", 300}, + {"HBM3MaxDeviceTemperature", 308}, + {"VF0_HBM2_READ", 312}, + {"VF0_HBM2_WRITE", 316}, + {"VF0_HBM3_READ", 328}, + {"VF0_HBM3_WRITE", 332}, + {"VF1_HBM2_READ", 344}, + {"VF1_HBM2_WRITE", 348}, + {"VF1_HBM3_READ", 360}, + {"VF1_HBM3_WRITE", 364}}}, + {"0xb15a0edd", // For PVC device + {{"HBM0MaxDeviceTemperature", 28}, + {"HBM1MaxDeviceTemperature", 36}, + {"TileMinTemperature", 40}, + {"TileMaxTemperature", 44}, + {"GTMinTemperature", 48}, + {"GTMaxTemperature", 52}, + {"VF0_VFID", 88}, + {"VF0_HBM0_READ", 92}, + {"VF0_HBM0_WRITE", 96}, + {"VF0_HBM1_READ", 104}, + {"VF0_HBM1_WRITE", 108}, + {"VF0_TIMESTAMP_L", 168}, + {"VF0_TIMESTAMP_H", 172}, + {"VF1_VFID", 176}, + {"VF1_HBM0_READ", 180}, + {"VF1_HBM0_WRITE", 184}, + {"VF1_HBM1_READ", 192}, + {"VF1_HBM1_WRITE", 196}, + {"VF1_TIMESTAMP_L", 256}, + {"VF1_TIMESTAMP_H", 260}, + {"HBM2MaxDeviceTemperature", 300}, + {"HBM3MaxDeviceTemperature", 308}, + {"VF0_HBM2_READ", 312}, + {"VF0_HBM2_WRITE", 316}, + {"VF0_HBM3_READ", 328}, + {"VF0_HBM3_WRITE", 332}, + {"VF1_HBM2_READ", 344}, + {"VF1_HBM2_WRITE", 348}, + {"VF1_HBM3_READ", 360}, + {"VF1_HBM3_WRITE", 364}}}, + {"0x41fe79a5", // For PVC root device + {{"PPIN", 152}, + {"BoardNumber", 72}}}}; +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/sysman_device_imp.cpp b/level_zero/sysman/source/sysman_device_imp.cpp index dd3fe32f2c..2588ee156d 100644 --- a/level_zero/sysman/source/sysman_device_imp.cpp +++ b/level_zero/sysman/source/sysman_device_imp.cpp @@ -19,14 +19,21 @@ namespace Sysman { SysmanDeviceImp::SysmanDeviceImp(NEO::ExecutionEnvironment *executionEnvironment, const uint32_t rootDeviceIndex) : executionEnvironment(executionEnvironment), rootDeviceIndex(rootDeviceIndex) { this->executionEnvironment->incRefInternal(); + pOsSysman = OsSysman::create(this); + UNRECOVERABLE_IF(nullptr == pOsSysman); } SysmanDeviceImp::~SysmanDeviceImp() { executionEnvironment->decRefInternal(); + freeResource(pOsSysman); } ze_result_t SysmanDeviceImp::init() { - return ZE_RESULT_SUCCESS; + auto result = pOsSysman->init(); + if (ZE_RESULT_SUCCESS != result) { + return result; + } + return result; } } // namespace Sysman diff --git a/level_zero/sysman/source/sysman_device_imp.h b/level_zero/sysman/source/sysman_device_imp.h index e7a0760c74..728fdd960f 100644 --- a/level_zero/sysman/source/sysman_device_imp.h +++ b/level_zero/sysman/source/sysman_device_imp.h @@ -32,6 +32,8 @@ struct SysmanDeviceImp : SysmanDevice, NEO::NonCopyableOrMovableClass { } const NEO::HardwareInfo &getHardwareInfo() const override { return *getRootDeviceEnvironment().getHardwareInfo(); } PRODUCT_FAMILY getProductFamily() const { return getHardwareInfo().platform.eProductFamily; } + NEO::ExecutionEnvironment *getExecutionEnvironment() const { return executionEnvironment; } + uint32_t getRootDeviceIndex() const { return rootDeviceIndex; } private: NEO::ExecutionEnvironment *executionEnvironment = nullptr; diff --git a/level_zero/sysman/source/sysman_driver.cpp b/level_zero/sysman/source/sysman_driver.cpp index 69da3c52a6..b06c0ada54 100644 --- a/level_zero/sysman/source/sysman_driver.cpp +++ b/level_zero/sysman/source/sysman_driver.cpp @@ -20,14 +20,13 @@ namespace L0 { namespace Sysman { -_ze_driver_handle_t *GlobalDriverHandle; +_ze_driver_handle_t *GlobalSysmanDriverHandle; uint32_t driverCount = 1; void SysmanDriverImp::initialize(ze_result_t *result) { *result = ZE_RESULT_ERROR_UNINITIALIZED; if (sysmanInitFromCore) { - // Sysman is already initialized while zeInit NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, "%s", "Sysman Initialization already happened via zeInit\n"); return; @@ -54,10 +53,7 @@ void SysmanDriverImp::initialize(ze_result_t *result) { rootDeviceIndex++; } - GlobalDriverHandle = SysmanDriverHandle::create(*executionEnvironment, result); - if (GlobalDriverHandle != nullptr) { - *result = ZE_RESULT_SUCCESS; - } + GlobalSysmanDriverHandle = SysmanDriverHandle::create(*executionEnvironment, result); } else { NEO::printDebugString(NEO::DebugManager.flags.PrintDebugMessages.get(), stderr, "%s\n", "No devices found"); @@ -77,13 +73,6 @@ ze_result_t SysmanDriverImp::driverInit(zes_init_flags_t flags) { return initStatus; } -SysmanDriverImp::~SysmanDriverImp() { - if (GlobalDriverHandle != nullptr) { - delete GlobalDriverHandle; - GlobalDriverHandle = nullptr; - } -} - ze_result_t driverHandleGet(uint32_t *pCount, zes_driver_handle_t *phDriverHandles) { if (*pCount == 0) { *pCount = driverCount; @@ -99,7 +88,7 @@ ze_result_t driverHandleGet(uint32_t *pCount, zes_driver_handle_t *phDriverHandl } for (uint32_t i = 0; i < *pCount; i++) { - phDriverHandles[i] = GlobalDriverHandle; + phDriverHandles[i] = GlobalSysmanDriverHandle; } return ZE_RESULT_SUCCESS; diff --git a/level_zero/sysman/source/sysman_driver.h b/level_zero/sysman/source/sysman_driver.h index 02869d36e1..e2b77d778a 100644 --- a/level_zero/sysman/source/sysman_driver.h +++ b/level_zero/sysman/source/sysman_driver.h @@ -26,7 +26,7 @@ ze_result_t init(zes_init_flags_t); ze_result_t driverHandleGet(uint32_t *pCount, ze_driver_handle_t *phDrivers); extern uint32_t driverCount; -extern _ze_driver_handle_t *GlobalDriverHandle; +extern _ze_driver_handle_t *GlobalSysmanDriverHandle; } // namespace Sysman } // namespace L0 diff --git a/level_zero/sysman/source/sysman_driver_handle_imp.cpp b/level_zero/sysman/source/sysman_driver_handle_imp.cpp index a578ff3bb7..4605331d44 100644 --- a/level_zero/sysman/source/sysman_driver_handle_imp.cpp +++ b/level_zero/sysman/source/sysman_driver_handle_imp.cpp @@ -22,7 +22,7 @@ namespace L0 { namespace Sysman { -struct SysmanDriverHandleImp *GlobalDriver; +struct SysmanDriverHandleImp *GlobalSysmanDriver; SysmanDriverHandleImp::SysmanDriverHandleImp() = default; @@ -32,7 +32,9 @@ ze_result_t SysmanDriverHandleImp::initialize(NEO::ExecutionEnvironment &executi continue; } auto pSysmanDevice = SysmanDevice::create(executionEnvironment, rootDeviceIndex); - this->sysmanDevices.push_back(pSysmanDevice); + if (pSysmanDevice != nullptr) { + this->sysmanDevices.push_back(pSysmanDevice); + } } if (this->sysmanDevices.size() == 0) { @@ -54,8 +56,8 @@ SysmanDriverHandle *SysmanDriverHandle::create(NEO::ExecutionEnvironment &execut return nullptr; } - GlobalDriver = driverHandle; - + GlobalSysmanDriver = driverHandle; + *returnValue = res; return driverHandle; } diff --git a/level_zero/sysman/source/sysman_driver_handle_imp.h b/level_zero/sysman/source/sysman_driver_handle_imp.h index 7e93d84c1f..0749c4123b 100644 --- a/level_zero/sysman/source/sysman_driver_handle_imp.h +++ b/level_zero/sysman/source/sysman_driver_handle_imp.h @@ -20,7 +20,7 @@ struct SysmanDriverHandleImp : SysmanDriverHandle { uint32_t numDevices = 0; }; -extern struct SysmanDriverHandleImp *GlobalDriver; +extern struct SysmanDriverHandleImp *GlobalSysmanDriver; } // namespace Sysman } // namespace L0 diff --git a/level_zero/sysman/source/sysman_driver_imp.h b/level_zero/sysman/source/sysman_driver_imp.h index 3fd84bd4bc..93d6c8a747 100644 --- a/level_zero/sysman/source/sysman_driver_imp.h +++ b/level_zero/sysman/source/sysman_driver_imp.h @@ -18,7 +18,6 @@ class SysmanDriverImp : public SysmanDriver { ze_result_t driverInit(zes_init_flags_t flags) override; void initialize(ze_result_t *result) override; - ~SysmanDriverImp() override; protected: std::once_flag initDriverOnce; diff --git a/level_zero/sysman/source/windows/CMakeLists.txt b/level_zero/sysman/source/windows/CMakeLists.txt new file mode 100644 index 0000000000..186082c93d --- /dev/null +++ b/level_zero/sysman/source/windows/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (C) 2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +set(L0_SRCS_SYSMAN_WINDOWS + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/os_sysman_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/os_sysman_imp.cpp +) + +if(WIN32) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${L0_SRCS_SYSMAN_WINDOWS} + ) +endif() + +# Make our source files visible to parent +set_property(GLOBAL PROPERTY L0_SRCS_SYSMAN_WINDOWS ${L0_SRCS_SYSMAN_WINDOWS}) diff --git a/level_zero/sysman/source/windows/os_sysman_imp.cpp b/level_zero/sysman/source/windows/os_sysman_imp.cpp new file mode 100644 index 0000000000..cfbad675ad --- /dev/null +++ b/level_zero/sysman/source/windows/os_sysman_imp.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/source/windows/os_sysman_imp.h" + +namespace L0 { +namespace Sysman { + +ze_result_t WddmSysmanImp::init() { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +uint32_t WddmSysmanImp::getSubDeviceCount() { + return 0; +} + +WddmSysmanImp::WddmSysmanImp(SysmanDeviceImp *pParentSysmanDeviceImp) { +} + +WddmSysmanImp::~WddmSysmanImp() { +} + +OsSysman *OsSysman::create(SysmanDeviceImp *pParentSysmanDeviceImp) { + WddmSysmanImp *pWddmSysmanImp = new WddmSysmanImp(pParentSysmanDeviceImp); + return static_cast(pWddmSysmanImp); +} + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/source/windows/os_sysman_imp.h b/level_zero/sysman/source/windows/os_sysman_imp.h new file mode 100644 index 0000000000..3273fb5420 --- /dev/null +++ b/level_zero/sysman/source/windows/os_sysman_imp.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/sysman/source/os_sysman.h" + +namespace L0 { +namespace Sysman { + +class WddmSysmanImp : public OsSysman, NEO::NonCopyableOrMovableClass { + public: + WddmSysmanImp(SysmanDeviceImp *pParentSysmanDeviceImp); + ~WddmSysmanImp() override; + + ze_result_t init() override; + uint32_t getSubDeviceCount() override; +}; + +} // namespace Sysman +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/CMakeLists.txt index 0a1eb84022..afbd6f0832 100644 --- a/level_zero/sysman/test/unit_tests/sources/CMakeLists.txt +++ b/level_zero/sysman/test/unit_tests/sources/CMakeLists.txt @@ -6,8 +6,6 @@ target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt - ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysman_driver.h - ${CMAKE_CURRENT_SOURCE_DIR}/test_sysman_driver.cpp ) add_subdirectories() diff --git a/level_zero/sysman/test/unit_tests/sources/linux/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/linux/CMakeLists.txt new file mode 100644 index 0000000000..17887e11bf --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/CMakeLists.txt @@ -0,0 +1,18 @@ +# +# Copyright (C) 2020-2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_sysman.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysman_fixture.h + ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysman_drm.h + ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysman_driver.h + ${CMAKE_CURRENT_SOURCE_DIR}/test_sysman_driver.cpp + ) +endif() + +add_subdirectories() diff --git a/level_zero/sysman/test/unit_tests/sources/mock_sysman_driver.h b/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_driver.h similarity index 100% rename from level_zero/sysman/test/unit_tests/sources/mock_sysman_driver.h rename to level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_driver.h diff --git a/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_drm.h b/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_drm.h new file mode 100644 index 0000000000..835b69c20c --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_drm.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/execution_environment/root_device_environment.h" +#include "shared/source/helpers/hw_info.h" +#include "shared/source/os_interface/linux/drm_neo.h" +#include "shared/source/os_interface/os_interface.h" + +namespace L0 { +namespace ult { +constexpr int mockFd = 0; +class SysmanMockDrm : public NEO::Drm { + public: + SysmanMockDrm(NEO::RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique(mockFd, ""), rootDeviceEnvironment) { + setupIoctlHelper(rootDeviceEnvironment.getHardwareInfo()->platform.eProductFamily); + } +}; + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h b/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h new file mode 100644 index 0000000000..4bea71a1f7 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2020-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "shared/source/execution_environment/root_device_environment.h" +#include "shared/source/os_interface/device_factory.h" +#include "shared/source/os_interface/linux/drm_neo.h" +#include "shared/source/os_interface/os_interface.h" +#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h" + +#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" +#include "level_zero/sysman/source/linux/fs_access.h" +#include "level_zero/sysman/source/linux/os_sysman_imp.h" +#include "level_zero/sysman/source/sysman_device.h" +#include "level_zero/sysman/source/sysman_driver_handle_imp.h" + +#include "gtest/gtest.h" + +using namespace NEO; + +namespace L0 { +namespace ult { +constexpr int mockFd = 0; +class SysmanMockDrm : public Drm { + public: + SysmanMockDrm(RootDeviceEnvironment &rootDeviceEnvironment) : Drm(std::make_unique(mockFd, ""), rootDeviceEnvironment) { + setupIoctlHelper(rootDeviceEnvironment.getHardwareInfo()->platform.eProductFamily); + } +}; + +class PublicLinuxSysmanImp : public L0::Sysman::LinuxSysmanImp { + public: + using LinuxSysmanImp::mapOfSubDeviceIdToPmtObject; + using LinuxSysmanImp::pFsAccess; + using LinuxSysmanImp::pProcfsAccess; + using LinuxSysmanImp::pSysfsAccess; +}; + +class SysmanDeviceFixture : public ::testing::Test { + public: + void SetUp() override { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + std::string str = "/sys/devices/pci0000:00/0000:00:02.0"; + buf = const_cast(str.c_str()); + return buf; + }); + + VariableBackup mockReadLink(&NEO::SysCalls::sysCallsReadlink, [](const char *path, char *buf, size_t bufsize) -> int { + std::string str = "../../devices/pci0000:37/0000:37:01.0/0000:38:00.0/0000:39:01.0/0000:3a:00.0/drm/renderD128"; + std::memcpy(buf, str.c_str(), str.size()); + return static_cast(str.size()); + }); + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + execEnv = new NEO::ExecutionEnvironment(); + execEnv->prepareRootDeviceEnvironments(numRootDevices); + for (auto i = 0u; i < execEnv->rootDeviceEnvironments.size(); i++) { + execEnv->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + execEnv->rootDeviceEnvironments[i]->osInterface = std::make_unique(); + execEnv->rootDeviceEnvironments[i]->osInterface->setDriverModel(std::make_unique(*execEnv->rootDeviceEnvironments[i])); + } + + driverHandle = std::make_unique(); + driverHandle->initialize(*execEnv); + pSysmanDevice = driverHandle->sysmanDevices[0]; + + pSysmanDeviceImp = static_cast(pSysmanDevice); + pOsSysman = pSysmanDeviceImp->pOsSysman; + pLinuxSysmanImp = static_cast(pOsSysman); + } + void TearDown() override { + } + + L0::Sysman::SysmanDevice *pSysmanDevice = nullptr; + L0::Sysman::SysmanDeviceImp *pSysmanDeviceImp = nullptr; + L0::Sysman::OsSysman *pOsSysman = nullptr; + PublicLinuxSysmanImp *pLinuxSysmanImp = nullptr; + NEO::ExecutionEnvironment *execEnv = nullptr; + std::unique_ptr driverHandle; + L0::Sysman::SysmanDevice *device = nullptr; + const uint32_t numRootDevices = 1u; +}; + +class SysmanMultiDeviceFixture : public ::testing::Test { + public: + void SetUp() override { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + std::string str = "/sys/devices/pci0000:00/0000:00:02.0"; + buf = const_cast(str.c_str()); + return buf; + }); + + VariableBackup mockReadLink(&NEO::SysCalls::sysCallsReadlink, [](const char *path, char *buf, size_t bufsize) -> int { + std::string str = "../../devices/pci0000:37/0000:37:01.0/0000:38:00.0/0000:39:01.0/0000:3a:00.0/drm/renderD128"; + std::memcpy(buf, str.c_str(), str.size()); + return static_cast(str.size()); + }); + + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + execEnv = new NEO::ExecutionEnvironment(); + execEnv->prepareRootDeviceEnvironments(numRootDevices); + DebugManager.flags.CreateMultipleSubDevices.set(numSubDevices); + for (auto i = 0u; i < execEnv->rootDeviceEnvironments.size(); i++) { + execEnv->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + execEnv->rootDeviceEnvironments[i]->osInterface = std::make_unique(); + execEnv->rootDeviceEnvironments[i]->osInterface->setDriverModel(std::make_unique(*execEnv->rootDeviceEnvironments[i])); + } + + driverHandle = std::make_unique(); + driverHandle->initialize(*execEnv); + pSysmanDevice = driverHandle->sysmanDevices[0]; + + pSysmanDeviceImp = static_cast(pSysmanDevice); + pOsSysman = pSysmanDeviceImp->pOsSysman; + pLinuxSysmanImp = static_cast(pOsSysman); + } + void TearDown() override { + } + + L0::Sysman::SysmanDevice *pSysmanDevice = nullptr; + L0::Sysman::SysmanDeviceImp *pSysmanDeviceImp = nullptr; + L0::Sysman::OsSysman *pOsSysman = nullptr; + PublicLinuxSysmanImp *pLinuxSysmanImp = nullptr; + NEO::ExecutionEnvironment *execEnv = nullptr; + std::unique_ptr driverHandle; + L0::Sysman::SysmanDevice *device = nullptr; + const uint32_t numRootDevices = 4u; + const uint32_t numSubDevices = 2u; + DebugManagerStateRestore restorer; +}; + +class PublicFsAccess : public L0::Sysman::FsAccess { + public: + using FsAccess::accessSyscall; + using FsAccess::statSyscall; +}; + +class PublicSysfsAccess : public L0::Sysman::SysfsAccess { + public: + using SysfsAccess::accessSyscall; +}; + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/linux/pmt/CMakeLists.txt b/level_zero/sysman/test/unit_tests/sources/linux/pmt/CMakeLists.txt new file mode 100644 index 0000000000..8a941005c8 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/pmt/CMakeLists.txt @@ -0,0 +1,14 @@ +# +# Copyright (C) 2021-2023 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${TARGET_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_pmt.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mock_pmt.h + ) +endif() diff --git a/level_zero/sysman/test/unit_tests/sources/linux/pmt/mock_pmt.h b/level_zero/sysman/test/unit_tests/sources/linux/pmt/mock_pmt.h new file mode 100644 index 0000000000..6661c2502e --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/pmt/mock_pmt.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "level_zero/sysman/source/linux/pmt/pmt.h" + +namespace L0 { +namespace ult { + +const std::string baseTelemSysFS("/sys/class/intel_pmt"); +const std::string telem("telem"); +const std::string telemNodeForSubdevice0("telem2"); +const std::string telemNodeForSubdevice1("telem3"); +std::string gpuUpstreamPortPathInPmt = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0"; +const std::string realPathTelem1 = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem1"; +const std::string realPathTelem2 = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem2"; +const std::string realPathTelem3 = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem3"; +const std::string realPathTelem4 = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem4"; +const std::string realPathTelem5 = "/sys/devices/pci0000:89/0000:89:02.0/0000:8a:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem5"; +const std::string invalidRealPath = "/sys/devices/pci0000:89/0000:89:02.0/0000:8e:00.0/0000:8b:02.0/0000:8e:00.1/pmt_telemetry.1.auto/intel_pmt/telem1"; +const std::string sysfsPahTelem1 = "/sys/class/intel_pmt/telem1"; +const std::string sysfsPahTelem2 = "/sys/class/intel_pmt/telem2"; +const std::string sysfsPahTelem3 = "/sys/class/intel_pmt/telem3"; +const std::string sysfsPahTelem4 = "/sys/class/intel_pmt/telem4"; +const std::string sysfsPahTelem5 = "/sys/class/intel_pmt/telem5"; + +struct MockPmtFsAccess : public L0::Sysman::FsAccess { + + ze_result_t listDirectoryResult = ZE_RESULT_SUCCESS; + ze_result_t getRealPathResult = ZE_RESULT_SUCCESS; + ze_result_t readUnsignedResult = ZE_RESULT_SUCCESS; + ze_result_t readStringResult = ZE_RESULT_SUCCESS; + ze_bool_t returnTelemNodes = true; + ze_bool_t returnInvalidRealPath = false; + ze_bool_t readInvalidString = false; + + MockPmtFsAccess() { + baseTelemSysFSNodeForSubdevice0 = baseTelemSysFS + "/" + telemNodeForSubdevice0; + baseTelemSysFSNodeForSubdevice1 = baseTelemSysFS + "/" + telemNodeForSubdevice1; + telemetryDeviceEntryForSubdevice0 = baseTelemSysFSNodeForSubdevice0 + "/" + telem; + telemetryDeviceEntryForSubdevice1 = baseTelemSysFSNodeForSubdevice1 + "/" + telem; + } + + ze_result_t read(const std::string file, std::string &val) override { + if (readStringResult != ZE_RESULT_SUCCESS) { + return readStringResult; + } + + if (readInvalidString) { + val = ""; + return ZE_RESULT_SUCCESS; + } + + std::string guidPathForSubdevice0 = baseTelemSysFSNodeForSubdevice0 + std::string("/guid"); + std::string guidPathForSubdevice1 = baseTelemSysFSNodeForSubdevice1 + std::string("/guid"); + if ((file.compare(guidPathForSubdevice0) == 0) || + (file.compare(guidPathForSubdevice1) == 0)) { + val = "0xfdc76194"; + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + ze_result_t read(const std::string file, uint64_t &val) override { + if (readUnsignedResult != ZE_RESULT_SUCCESS) { + return readUnsignedResult; + } + + if ((file.compare(baseTelemSysFSNodeForSubdevice0 + std::string("/size")) == 0) || + (file.compare(baseTelemSysFSNodeForSubdevice1 + std::string("/size")) == 0) || + (file.compare(baseTelemSysFSNodeForSubdevice0 + std::string("/offset")) == 0) || + (file.compare(baseTelemSysFSNodeForSubdevice1 + std::string("/offset")) == 0)) { + val = 0; + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + bool fileExists(const std::string file) override { + if ((file.compare(telemetryDeviceEntryForSubdevice0) == 0) || + (file.compare(telemetryDeviceEntryForSubdevice1) == 0)) { + return true; + } + + return false; + } + + ze_result_t getRealPath(const std::string path, std::string &buf) override { + if (getRealPathResult != ZE_RESULT_SUCCESS) { + return getRealPathResult; + } + + if (returnInvalidRealPath) { + buf = invalidRealPath; + return ZE_RESULT_SUCCESS; + } + + if (path.compare(sysfsPahTelem1) == 0) { + buf = realPathTelem1; + } else if (path.compare(sysfsPahTelem2) == 0) { + buf = realPathTelem2; + } else if (path.compare(sysfsPahTelem3) == 0) { + buf = realPathTelem3; + } else if (path.compare(sysfsPahTelem4) == 0) { + buf = realPathTelem4; + } else if (path.compare(sysfsPahTelem5) == 0) { + buf = realPathTelem5; + } else { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + return ZE_RESULT_SUCCESS; + } + + ze_result_t listDirectory(const std::string directory, std::vector &listOfTelemNodes) override { + if (listDirectoryResult != ZE_RESULT_SUCCESS) { + return listDirectoryResult; + } + if (directory.compare(baseTelemSysFS) == 0) { + listOfTelemNodes.push_back("crashlog2"); + listOfTelemNodes.push_back("crashlog1"); + if (returnTelemNodes) { + listOfTelemNodes.push_back("telem3"); + listOfTelemNodes.push_back("telem2"); + listOfTelemNodes.push_back("telem1"); + listOfTelemNodes.push_back("telem4"); + listOfTelemNodes.push_back("telem5"); + } + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + std::string telemetryDeviceEntryForSubdevice0; + std::string telemetryDeviceEntryForSubdevice1; + std::string baseTelemSysFSNodeForSubdevice0; + std::string baseTelemSysFSNodeForSubdevice1; +}; + +class PublicPlatformMonitoringTech : public L0::Sysman::PlatformMonitoringTech { + public: + PublicPlatformMonitoringTech(L0::Sysman::FsAccess *pFsAccess, ze_bool_t onSubdevice, uint32_t subdeviceId) : PlatformMonitoringTech(pFsAccess, onSubdevice, subdeviceId) {} + using PlatformMonitoringTech::closeFunction; + using PlatformMonitoringTech::doInitPmtObject; + using PlatformMonitoringTech::init; + using PlatformMonitoringTech::keyOffsetMap; + using PlatformMonitoringTech::openFunction; + using PlatformMonitoringTech::preadFunction; + using PlatformMonitoringTech::rootDeviceTelemNodeIndex; + using PlatformMonitoringTech::telemetryDeviceEntry; +}; + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/linux/pmt/test_pmt.cpp b/level_zero/sysman/test/unit_tests/sources/linux/pmt/test_pmt.cpp new file mode 100644 index 0000000000..dda8674384 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/pmt/test_pmt.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2021-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h" + +#include "mock_pmt.h" + +namespace L0 { +namespace ult { +static int fakeFileDescriptor = 123; + +const std::map dummyKeyOffsetMap = { + {"DUMMY_KEY", 0x0}}; + +class ZesPmtFixtureMultiDevice : public SysmanMultiDeviceFixture { + protected: + std::unique_ptr pTestFsAccess; + std::map mapOfSubDeviceIdToPmtObject; + void SetUp() override { + SysmanMultiDeviceFixture::SetUp(); + pTestFsAccess = std::make_unique(); + L0::Sysman::PlatformMonitoringTech::create(pLinuxSysmanImp, gpuUpstreamPortPathInPmt, mapOfSubDeviceIdToPmtObject); + } + void TearDown() override { + SysmanMultiDeviceFixture::TearDown(); + for (auto &subDeviceIdToPmtEntry : mapOfSubDeviceIdToPmtObject) { + delete subDeviceIdToPmtEntry.second; + subDeviceIdToPmtEntry.second = nullptr; + } + } +}; + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenValidPmtHandlesForAllSubdevicesWillBeCreated) {} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenenumerateRootTelemIndexThenCheckForErrorIflistDirectoryFails) { + pTestFsAccess->listDirectoryResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenenumerateRootTelemIndexThenCheckForErrorIfgetRealPathFails) { + pTestFsAccess->getRealPathResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenWhenenumerateRootTelemIndexThenCheckForErrorIfgetRealPathSuccessButNoTelemetryNodeAndGPUDeviceShareRootPciPort) { + pTestFsAccess->returnInvalidRealPath = true; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenTelemDirectoryContainNowTelemEntryWhenenumerateRootTelemIndexThenCheckForError) { + pTestFsAccess->returnTelemNodes = false; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenCheckForErrorThatCouldHappenDuringWhileValidatingTelemNode) { + pTestFsAccess->getRealPathResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt); + auto productFamily = pSysmanDeviceImp->getProductFamily(); + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + EXPECT_EQ(pPmt->init(pTestFsAccess.get(), gpuUpstreamPortPathInPmt, productFamily), ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenCheckForErrorThatCouldHappenDuringGUIDRead) { + pTestFsAccess->readStringResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt); + auto productFamily = pSysmanDeviceImp->getProductFamily(); + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + EXPECT_EQ(pPmt->init(pTestFsAccess.get(), gpuUpstreamPortPathInPmt, productFamily), ZE_RESULT_ERROR_NOT_AVAILABLE); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenCheckForErrorIfGUIDReadValueIsNotSupported) { + pTestFsAccess->readInvalidString = true; + L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt); + auto productFamily = pSysmanDeviceImp->getProductFamily(); + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + EXPECT_EQ(pPmt->init(pTestFsAccess.get(), gpuUpstreamPortPathInPmt, productFamily), ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenSomeKeyWhenCallingreadValueWithUint64TypeThenCheckForErrorBranches) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 0, 0); + uint64_t val = 0; + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, pPmt->readValue("SOMETHING", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenSomeKeyWhenCallingreadValueWithUint32TypeThenCheckForErrorBranches) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 0, 0); + uint32_t val = 0; + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, pPmt->readValue("SOMETHING", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenCheckForErrorThatCouldHappenDuringbaseOffsetRead) { + pTestFsAccess->readUnsignedResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + L0::Sysman::PlatformMonitoringTech::enumerateRootTelemIndex(pTestFsAccess.get(), gpuUpstreamPortPathInPmt); + auto productFamily = pSysmanDeviceImp->getProductFamily(); + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + EXPECT_EQ(pPmt->init(pTestFsAccess.get(), gpuUpstreamPortPathInPmt, productFamily), ZE_RESULT_ERROR_NOT_AVAILABLE); +} + +inline static int openMock(const char *pathname, int flags) { + if (strcmp(pathname, "/sys/class/intel_pmt/telem2/telem") == 0) { + return fakeFileDescriptor; + } + if (strcmp(pathname, "/sys/class/intel_pmt/telem3/telem") == 0) { + return fakeFileDescriptor; + } + return -1; +} + +inline static int openMockReturnFailure(const char *pathname, int flags) { + return -1; +} + +inline static int closeMock(int fd) { + if (fd == fakeFileDescriptor) { + return 0; + } + return -1; +} + +inline static int closeMockReturnFailure(int fd) { + return -1; +} + +ssize_t preadMockPmt(int fd, void *buf, size_t count, off_t offset) { + return count; +} + +ssize_t preadMockPmtFailure(int fd, void *buf, size_t count, off_t offset) { + return -1; +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint32TypeAndOpenSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->openFunction = openMockReturnFailure; + + uint32_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint32TypeAndCloseSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->telemetryDeviceEntry = baseTelemSysFS + "/" + telemNodeForSubdevice0 + "/" + telem; + pPmt->openFunction = openMock; + pPmt->preadFunction = preadMockPmt; + pPmt->closeFunction = closeMockReturnFailure; + + uint32_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint64TypeAndOpenSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->openFunction = openMockReturnFailure; + + uint64_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint64TypeAndCloseSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->telemetryDeviceEntry = baseTelemSysFS + "/" + telemNodeForSubdevice0 + "/" + telem; + pPmt->openFunction = openMock; + pPmt->preadFunction = preadMockPmt; + pPmt->closeFunction = closeMockReturnFailure; + + uint64_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint32TypeAndPreadSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->telemetryDeviceEntry = baseTelemSysFS + "/" + telemNodeForSubdevice0 + "/" + telem; + pPmt->openFunction = openMock; + pPmt->preadFunction = preadMockPmtFailure; + pPmt->closeFunction = closeMock; + + uint32_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenCallingreadValueWithUint64TypeAndPreadSysCallFailsThenreadValueFails) { + auto pPmt = std::make_unique(pTestFsAccess.get(), 1, 0); + pPmt->telemetryDeviceEntry = baseTelemSysFS + "/" + telemNodeForSubdevice0 + "/" + telem; + pPmt->openFunction = openMock; + pPmt->preadFunction = preadMockPmtFailure; + pPmt->closeFunction = closeMock; + + uint64_t val = 0; + pPmt->keyOffsetMap = dummyKeyOffsetMap; + EXPECT_EQ(ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE, pPmt->readValue("DUMMY_KEY", val)); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenValidSyscallsWhenDoingPMTInitThenPMTmapOfSubDeviceIdToPmtObjectWouldContainValidEntries) { + std::map mapOfSubDeviceIdToPmtObject; + auto subDeviceCount = pLinuxSysmanImp->getSubDeviceCount(); + uint32_t subdeviceId = 0; + do { + ze_bool_t onSubdevice = (subDeviceCount == 0) ? false : true; + auto pPmt = new PublicPlatformMonitoringTech(pTestFsAccess.get(), onSubdevice, subdeviceId); + PublicPlatformMonitoringTech::rootDeviceTelemNodeIndex = 1; + auto productFamily = pSysmanDeviceImp->getProductFamily(); + UNRECOVERABLE_IF(nullptr == pPmt); + PublicPlatformMonitoringTech::doInitPmtObject(pTestFsAccess.get(), subdeviceId, pPmt, + gpuUpstreamPortPathInPmt, mapOfSubDeviceIdToPmtObject, productFamily); + auto subDeviceIdToPmtEntry = mapOfSubDeviceIdToPmtObject.find(subdeviceId); + EXPECT_EQ(subDeviceIdToPmtEntry->second, pPmt); + delete pPmt; + + } while (++subdeviceId < subDeviceCount); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenBaseOffsetReadFailWhenDoingPMTInitThenPMTmapOfSubDeviceIdToPmtObjectWouldBeEmpty) { + std::map mapOfSubDeviceIdToPmtObject; + pTestFsAccess->readUnsignedResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + auto subDeviceCount = pLinuxSysmanImp->getSubDeviceCount(); + uint32_t subdeviceId = 0; + do { + ze_bool_t onSubdevice = (subDeviceCount == 0) ? false : true; + auto pPmt = new PublicPlatformMonitoringTech(pTestFsAccess.get(), onSubdevice, subdeviceId); + auto productFamily = pSysmanDeviceImp->getProductFamily(); + UNRECOVERABLE_IF(nullptr == pPmt); + PublicPlatformMonitoringTech::doInitPmtObject(pTestFsAccess.get(), subdeviceId, pPmt, + gpuUpstreamPortPathInPmt, mapOfSubDeviceIdToPmtObject, productFamily); + EXPECT_TRUE(mapOfSubDeviceIdToPmtObject.empty()); + + } while (++subdeviceId < subDeviceCount); +} + +TEST_F(ZesPmtFixtureMultiDevice, GivenNoPMTHandleInmapOfSubDeviceIdToPmtObjectWhenCallingreleasePmtObjectThenMapWouldGetEmpty) { + auto mapOriginal = pLinuxSysmanImp->mapOfSubDeviceIdToPmtObject; + pLinuxSysmanImp->mapOfSubDeviceIdToPmtObject.clear(); + + auto subDeviceCount = pLinuxSysmanImp->getSubDeviceCount(); + uint32_t subdeviceId = 0; + do { + pLinuxSysmanImp->mapOfSubDeviceIdToPmtObject.emplace(subdeviceId, nullptr); + } while (subdeviceId++ < subDeviceCount); + + pLinuxSysmanImp->releasePmtObject(); + EXPECT_TRUE(pLinuxSysmanImp->mapOfSubDeviceIdToPmtObject.empty()); + pLinuxSysmanImp->mapOfSubDeviceIdToPmtObject = mapOriginal; +} + +class ZesPmtFixtureNoSubDevice : public SysmanDeviceFixture { + protected: + std::unique_ptr pTestFsAccess; + std::map mapOfSubDeviceIdToPmtObject; + void SetUp() override { + SysmanDeviceFixture::SetUp(); + pTestFsAccess = std::make_unique(); + L0::Sysman::PlatformMonitoringTech::create(pLinuxSysmanImp, gpuUpstreamPortPathInPmt, mapOfSubDeviceIdToPmtObject); + } + void TearDown() override { + SysmanDeviceFixture::TearDown(); + for (auto &subDeviceIdToPmtEntry : mapOfSubDeviceIdToPmtObject) { + delete subDeviceIdToPmtEntry.second; + subDeviceIdToPmtEntry.second = nullptr; + } + } +}; + +TEST_F(ZesPmtFixtureNoSubDevice, GivenValidDeviceHandlesWhenCreatingPMTHandlesThenValidPmtHandlesForAllSubdevicesWillBeCreated) {} + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/linux/test_sysman.cpp b/level_zero/sysman/test/unit_tests/sources/linux/test_sysman.cpp new file mode 100644 index 0000000000..fdacd37de9 --- /dev/null +++ b/level_zero/sysman/test/unit_tests/sources/linux/test_sysman.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2020-2023 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/test/common/mocks/mock_driver_info.h" +#include "shared/test/common/test_macros/test.h" + +#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h" + +namespace NEO { +namespace SysCalls { +extern bool allowFakeDevicePath; +} // namespace SysCalls +} // namespace NEO +namespace L0 { +namespace ult { + +inline static int mockAccessFailure(const char *pathname, int mode) { + return -1; +} + +inline static int mockAccessSuccess(const char *pathname, int mode) { + return 0; +} + +inline static int mockStatFailure(const char *pathname, struct stat *sb) noexcept { + return -1; +} + +inline static int mockStatSuccess(const char *pathname, struct stat *sb) noexcept { + sb->st_mode = S_IWUSR | S_IRUSR; + return 0; +} + +inline static int mockStatNoPermissions(const char *pathname, struct stat *sb) noexcept { + sb->st_mode = 0; + return 0; +} + +TEST_F(SysmanDeviceFixture, GivenCreateFsAccessHandleWhenCallinggetFsAccessThenCreatedFsAccessHandleWillBeRetrieved) { + if (pLinuxSysmanImp->pFsAccess != nullptr) { + // delete previously allocated pFsAccess + delete pLinuxSysmanImp->pFsAccess; + pLinuxSysmanImp->pFsAccess = nullptr; + } + pLinuxSysmanImp->pFsAccess = L0::Sysman::FsAccess::create(); + EXPECT_EQ(&pLinuxSysmanImp->getFsAccess(), pLinuxSysmanImp->pFsAccess); +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingDirectoryExistsWithValidAndInvalidPathThenSuccessAndFailureAreReturnedRespectively) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->accessSyscall = mockAccessSuccess; + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_TRUE(tempFsAccess->directoryExists(path)); + tempFsAccess->accessSyscall = mockAccessFailure; + path = "invalidDiretory"; + EXPECT_FALSE(tempFsAccess->directoryExists(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicSysfsAccessClassWhenCallingDirectoryExistsWithInvalidPathThenFalseIsRetured) { + PublicFsAccess *tempSysfsAccess = new PublicFsAccess(); + tempSysfsAccess->accessSyscall = mockAccessFailure; + std::string path = "invalidDiretory"; + EXPECT_FALSE(tempSysfsAccess->directoryExists(path)); + delete tempSysfsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanWriteWithUserHavingWritePermissionsThenSuccessIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatSuccess; + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_EQ(ZE_RESULT_SUCCESS, tempFsAccess->canWrite(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanReadWithUserHavingReadPermissionsThenSuccessIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatSuccess; + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_EQ(ZE_RESULT_SUCCESS, tempFsAccess->canRead(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanWriteWithUserNotHavingWritePermissionsThenInsufficientIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatNoPermissions; + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_EQ(ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS, tempFsAccess->canWrite(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanReadWithUserNotHavingReadPermissionsThenInsufficientIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatNoPermissions; + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_EQ(ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS, tempFsAccess->canRead(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanReadWithInvalidPathThenErrorIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatFailure; + std::string path = "invalidPath"; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, tempFsAccess->canRead(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenPublicFsAccessClassWhenCallingCanWriteWithInvalidPathThenErrorIsReturned) { + PublicFsAccess *tempFsAccess = new PublicFsAccess(); + tempFsAccess->statSyscall = mockStatFailure; + std::string path = "invalidPath"; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, tempFsAccess->canRead(path)); + delete tempFsAccess; +} + +TEST_F(SysmanDeviceFixture, GivenValidPathnameWhenCallingFsAccessExistsThenSuccessIsReturned) { + VariableBackup allowFakeDevicePathBackup(&SysCalls::allowFakeDevicePath, true); + auto fsAccess = pLinuxSysmanImp->getFsAccess(); + + char cwd[PATH_MAX]; + std::string path = getcwd(cwd, PATH_MAX); + EXPECT_TRUE(fsAccess.fileExists(path)); +} + +TEST_F(SysmanDeviceFixture, GivenInvalidPathnameWhenCallingFsAccessExistsThenErrorIsReturned) { + auto fsAccess = pLinuxSysmanImp->getFsAccess(); + + std::string path = "noSuchFileOrDirectory"; + EXPECT_FALSE(fsAccess.fileExists(path)); +} + +TEST_F(SysmanDeviceFixture, GivenCreateSysfsAccessHandleWhenCallinggetSysfsAccessThenCreatedSysfsAccessHandleHandleWillBeRetrieved) { + if (pLinuxSysmanImp->pSysfsAccess != nullptr) { + // delete previously allocated pSysfsAccess + delete pLinuxSysmanImp->pSysfsAccess; + pLinuxSysmanImp->pSysfsAccess = nullptr; + } + pLinuxSysmanImp->pSysfsAccess = L0::Sysman::SysfsAccess::create(""); + EXPECT_EQ(&pLinuxSysmanImp->getSysfsAccess(), pLinuxSysmanImp->pSysfsAccess); +} + +TEST_F(SysmanDeviceFixture, GivenCreateProcfsAccessHandleWhenCallinggetProcfsAccessThenCreatedProcfsAccessHandleWillBeRetrieved) { + if (pLinuxSysmanImp->pProcfsAccess != nullptr) { + // delete previously allocated pProcfsAccess + delete pLinuxSysmanImp->pProcfsAccess; + pLinuxSysmanImp->pProcfsAccess = nullptr; + } + pLinuxSysmanImp->pProcfsAccess = L0::Sysman::ProcfsAccess::create(); + EXPECT_EQ(&pLinuxSysmanImp->getProcfsAccess(), pLinuxSysmanImp->pProcfsAccess); +} + +TEST_F(SysmanDeviceFixture, GivenValidPidWhenCallingProcfsAccessIsAliveThenSuccessIsReturned) { + VariableBackup allowFakeDevicePathBackup(&SysCalls::allowFakeDevicePath, true); + auto procfsAccess = pLinuxSysmanImp->getProcfsAccess(); + + EXPECT_TRUE(procfsAccess.isAlive(getpid())); +} + +TEST_F(SysmanDeviceFixture, GivenInvalidPidWhenCallingProcfsAccessIsAliveThenErrorIsReturned) { + auto procfsAccess = pLinuxSysmanImp->getProcfsAccess(); + + EXPECT_FALSE(procfsAccess.isAlive(reinterpret_cast<::pid_t>(-1))); +} + +TEST_F(SysmanDeviceFixture, GivenValidPciPathWhileGettingCardBusPortThenReturnedPathIs1LevelUpThenTheCurrentPath) { + const std::string mockBdf = "0000:00:02.0"; + const std::string mockRealPath = "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/" + mockBdf; + const std::string mockRealPath1LevelUp = "/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0"; + + std::string pciRootPort1 = pLinuxSysmanImp->getPciCardBusDirectoryPath(mockRealPath); + EXPECT_EQ(pciRootPort1, mockRealPath1LevelUp); + + std::string pciRootPort2 = pLinuxSysmanImp->getPciCardBusDirectoryPath("device"); + EXPECT_EQ(pciRootPort2, "device"); +} + +TEST_F(SysmanMultiDeviceFixture, GivenValidEffectiveUserIdCheckWhetherPermissionsReturnedByIsRootUserAreCorrect) { + int euid = geteuid(); + auto pFsAccess = pLinuxSysmanImp->getFsAccess(); + if (euid == 0) { + EXPECT_EQ(true, pFsAccess.isRootUser()); + } else { + EXPECT_EQ(false, pFsAccess.isRootUser()); + } +} + +class UnknownDriverModel : public DriverModel { + public: + UnknownDriverModel() : DriverModel(DriverModelType::UNKNOWN) {} + void setGmmInputArgs(void *args) override {} + uint32_t getDeviceHandle() const override { return 0u; } + PhysicalDevicePciBusInfo getPciBusInfo() const override { + PhysicalDevicePciBusInfo pciBusInfo(PhysicalDevicePciBusInfo::invalidValue, PhysicalDevicePciBusInfo::invalidValue, PhysicalDevicePciBusInfo::invalidValue, PhysicalDevicePciBusInfo::invalidValue); + return pciBusInfo; + } + PhysicalDevicePciSpeedInfo getPciSpeedInfo() const override { return {}; } + + bool isGpuHangDetected(OsContext &osContext) override { + return false; + } +}; + +TEST(SysmanUnknownDriverModelTest, GivenDriverModelTypeIsNotDrmWhenExecutingSysmanOnLinuxThenErrorIsReturned) { + NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); + hwInfo.capabilityTable.levelZeroSupported = true; + auto execEnv = new NEO::ExecutionEnvironment(); + execEnv->prepareRootDeviceEnvironments(1); + execEnv->rootDeviceEnvironments[0]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + execEnv->rootDeviceEnvironments[0]->osInterface = std::make_unique(); + execEnv->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::make_unique()); + + auto pSysmanDeviceImp = std::make_unique(execEnv, 0); + auto pLinuxSysmanImp = static_cast(pSysmanDeviceImp->pOsSysman); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, pLinuxSysmanImp->init()); +} + +} // namespace ult +} // namespace L0 diff --git a/level_zero/sysman/test/unit_tests/sources/test_sysman_driver.cpp b/level_zero/sysman/test/unit_tests/sources/linux/test_sysman_driver.cpp similarity index 60% rename from level_zero/sysman/test/unit_tests/sources/test_sysman_driver.cpp rename to level_zero/sysman/test/unit_tests/sources/linux/test_sysman_driver.cpp index c335de9eeb..cdadedb30c 100644 --- a/level_zero/sysman/test/unit_tests/sources/test_sysman_driver.cpp +++ b/level_zero/sysman/test/unit_tests/sources/linux/test_sysman_driver.cpp @@ -7,16 +7,20 @@ #include "shared/source/helpers/hw_info.h" #include "shared/test/common/helpers/default_hw_info.h" +#include "shared/test/common/helpers/variable_backup.h" #include "shared/test/common/mocks/mock_execution_environment.h" +#include "shared/test/common/os_interface/linux/sys_calls_linux_ult.h" #include "level_zero/sysman/source/sysman_device.h" #include "level_zero/sysman/source/sysman_driver_handle.h" #include "level_zero/sysman/source/sysman_driver_handle_imp.h" -#include "level_zero/sysman/test/unit_tests/sources/mock_sysman_driver.h" +#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_driver.h" +#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_drm.h" #include "gtest/gtest.h" #include +#include namespace L0 { namespace ult { @@ -52,6 +56,8 @@ struct SysmanDriverTestMultipleFamilySupport : public ::testing::Test { executionEnvironment->prepareRootDeviceEnvironments(numRootDevices); for (auto i = 0u; i < numRootDevices; i++) { executionEnvironment->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + executionEnvironment->rootDeviceEnvironments[i]->osInterface = std::make_unique(); + executionEnvironment->rootDeviceEnvironments[i]->osInterface->setDriverModel(std::make_unique(*executionEnvironment->rootDeviceEnvironments[i])); if (i < numSupportedRootDevices) { executionEnvironment->rootDeviceEnvironments[i]->getMutableHardwareInfo()->capabilityTable.levelZeroSupported = true; } else { @@ -67,6 +73,18 @@ struct SysmanDriverTestMultipleFamilySupport : public ::testing::Test { }; TEST_F(SysmanDriverTestMultipleFamilySupport, whenInitializingSysmanDriverWithArrayOfDevicesThenDriverIsInitializedOnlyWithThoseSupported) { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + std::string str = "/sys/devices/pci0000:00/0000:00:02.0"; + buf = const_cast(str.c_str()); + return buf; + }); + + VariableBackup mockReadLink(&NEO::SysCalls::sysCallsReadlink, [](const char *path, char *buf, size_t bufsize) -> int { + std::string str = "../../devices/pci0000:37/0000:37:01.0/0000:38:00.0/0000:39:01.0/0000:3a:00.0/drm/renderD128"; + std::memcpy(buf, str.c_str(), str.size()); + return static_cast(str.size()); + }); + ze_result_t returnValue; auto driverHandle = L0::Sysman::SysmanDriverHandle::create(*executionEnvironment, &returnValue); @@ -80,7 +98,7 @@ TEST_F(SysmanDriverTestMultipleFamilySupport, whenInitializingSysmanDriverWithAr } delete driverHandle; - L0::Sysman::GlobalDriver = nullptr; + L0::Sysman::GlobalSysmanDriver = nullptr; } struct SysmanDriverTestMultipleFamilyNoSupport : public ::testing::Test { @@ -89,9 +107,6 @@ struct SysmanDriverTestMultipleFamilyNoSupport : public ::testing::Test { executionEnvironment->prepareRootDeviceEnvironments(numRootDevices); for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { executionEnvironment->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); - } - - for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { executionEnvironment->rootDeviceEnvironments[i]->getMutableHardwareInfo()->capabilityTable.levelZeroSupported = false; } } @@ -109,9 +124,65 @@ TEST_F(SysmanDriverTestMultipleFamilyNoSupport, whenInitializingSysmanDriverWith this->executionEnvironment->decRefInternal(); } +struct SysmanDriverTestNoDeviceCreate : public ::testing::Test { + void SetUp() override { + executionEnvironment = new NEO::ExecutionEnvironment(); + executionEnvironment->prepareRootDeviceEnvironments(numRootDevices); + for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { + executionEnvironment->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); + executionEnvironment->rootDeviceEnvironments[i]->getMutableHardwareInfo()->capabilityTable.levelZeroSupported = true; + executionEnvironment->rootDeviceEnvironments[i]->osInterface = std::make_unique(); + executionEnvironment->rootDeviceEnvironments[i]->osInterface->setDriverModel(std::make_unique(*executionEnvironment->rootDeviceEnvironments[i])); + } + } + + NEO::ExecutionEnvironment *executionEnvironment = nullptr; + const uint32_t numRootDevices = 3u; +}; + +TEST_F(SysmanDriverTestNoDeviceCreate, GivenReadLinkSysCallFailWhenInitializingSysmanDriverWithArrayOfDevicesThenSysmanDeviceCreateFailAndDriverIsNull) { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + std::string str = "/sys/devices/pci0000:00/0000:00:02.0"; + buf = const_cast(str.c_str()); + return buf; + }); + + VariableBackup mockReadLink(&NEO::SysCalls::sysCallsReadlink, [](const char *path, char *buf, size_t bufsize) -> int { + return -1; + }); + ze_result_t returnValue; + this->executionEnvironment->incRefInternal(); + auto driverHandle = L0::Sysman::SysmanDriverHandle::create(*executionEnvironment, &returnValue); + EXPECT_EQ(nullptr, driverHandle); + EXPECT_EQ(returnValue, ZE_RESULT_ERROR_UNINITIALIZED); + this->executionEnvironment->decRefInternal(); +} + +TEST_F(SysmanDriverTestNoDeviceCreate, GivenRealpathSysCallFailWhenInitializingSysmanDriverWithArrayOfDevicesThenSysmanDeviceCreateFailAndDriverIsNull) { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + return nullptr; + }); + ze_result_t returnValue; + this->executionEnvironment->incRefInternal(); + auto driverHandle = L0::Sysman::SysmanDriverHandle::create(*executionEnvironment, &returnValue); + EXPECT_EQ(nullptr, driverHandle); + EXPECT_EQ(returnValue, ZE_RESULT_ERROR_UNINITIALIZED); + this->executionEnvironment->decRefInternal(); +} + struct SysmanDriverHandleTest : public ::testing::Test { void SetUp() override { + VariableBackup mockRealPath(&NEO::SysCalls::sysCallsRealpath, [](const char *path, char *buf) -> char * { + std::string str = "/sys/devices/pci0000:00/0000:00:02.0"; + buf = const_cast(str.c_str()); + return buf; + }); + VariableBackup mockReadLink(&NEO::SysCalls::sysCallsReadlink, [](const char *path, char *buf, size_t bufsize) -> int { + std::string str = "../../devices/pci0000:37/0000:37:01.0/0000:38:00.0/0000:39:01.0/0000:3a:00.0/drm/renderD128"; + std::memcpy(buf, str.c_str(), str.size()); + return static_cast(str.size()); + }); ze_result_t returnValue; NEO::HardwareInfo hwInfo = *NEO::defaultHwInfo.get(); hwInfo.capabilityTable.levelZeroSupported = true; @@ -120,16 +191,19 @@ struct SysmanDriverHandleTest : public ::testing::Test { executionEnvironment->prepareRootDeviceEnvironments(numRootDevices); for (auto i = 0u; i < executionEnvironment->rootDeviceEnvironments.size(); i++) { executionEnvironment->rootDeviceEnvironments[i]->setHwInfoAndInitHelpers(NEO::defaultHwInfo.get()); - // executionEnvironment->rootDeviceEnvironments[i]->initGmm(); + executionEnvironment->rootDeviceEnvironments[i]->osInterface = std::make_unique(); + executionEnvironment->rootDeviceEnvironments[i]->osInterface->setDriverModel(std::make_unique(*executionEnvironment->rootDeviceEnvironments[i])); } driverHandle = L0::Sysman::SysmanDriverHandle::create(*executionEnvironment, &returnValue); - L0::Sysman::GlobalDriverHandle = driverHandle; + L0::Sysman::GlobalSysmanDriverHandle = driverHandle; } void TearDown() override { - delete driverHandle; - L0::Sysman::GlobalDriver = nullptr; - L0::Sysman::GlobalDriverHandle = nullptr; + if (driverHandle) { + delete driverHandle; + } + L0::Sysman::GlobalSysmanDriver = nullptr; + L0::Sysman::GlobalSysmanDriverHandle = nullptr; } L0::Sysman::SysmanDriverHandle *driverHandle; NEO::ExecutionEnvironment *executionEnvironment = nullptr; @@ -184,7 +258,7 @@ TEST_F(SysmanDriverHandleTest, givenInitializedDriverWhenZesDriverGetIsCalledThe delete[] phDriverHandles; } -TEST_F(SysmanDriverHandleTest, givenInitializedDriverWhenZesDriverGetIsCalledThenGlobalDriverHandleIsObtained) { +TEST_F(SysmanDriverHandleTest, givenInitializedDriverWhenZesDriverGetIsCalledThenGlobalSysmanDriverHandleIsObtained) { ze_result_t result = ZE_RESULT_SUCCESS; uint32_t count = 1; @@ -193,7 +267,7 @@ TEST_F(SysmanDriverHandleTest, givenInitializedDriverWhenZesDriverGetIsCalledThe result = zesDriverGet(&count, &hDriverHandle); EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_NE(nullptr, hDriverHandle); - EXPECT_EQ(hDriverHandle, L0::Sysman::GlobalDriver); + EXPECT_EQ(hDriverHandle, L0::Sysman::GlobalSysmanDriver); } TEST_F(SysmanDriverHandleTest, givenInitializedDriverWhenGetDeviceIsCalledThenOneDeviceIsObtained) { diff --git a/shared/source/os_interface/linux/drm_neo.h b/shared/source/os_interface/linux/drm_neo.h index fd9a2ab726..93b4b740b9 100644 --- a/shared/source/os_interface/linux/drm_neo.h +++ b/shared/source/os_interface/linux/drm_neo.h @@ -102,6 +102,7 @@ class Drm : public DriverModel { MOCKABLE_VIRTUAL void checkPreemptionSupport(); inline int getFileDescriptor() const { return hwDeviceId->getFileDescriptor(); } + inline void closeFileDescriptor() const { return hwDeviceId->closeFileDescriptor(); } ADAPTER_BDF getAdapterBDF() const { return adapterBDF; } diff --git a/shared/source/os_interface/linux/hw_device_id.h b/shared/source/os_interface/linux/hw_device_id.h index 9d410bf034..b71616d80f 100644 --- a/shared/source/os_interface/linux/hw_device_id.h +++ b/shared/source/os_interface/linux/hw_device_id.h @@ -21,10 +21,11 @@ class HwDeviceIdDrm : public HwDeviceId { fileDescriptor(fileDescriptorIn), pciPath(pciPathIn) {} ~HwDeviceIdDrm() override; int getFileDescriptor() const { return fileDescriptor; } + void closeFileDescriptor(); const char *getPciPath() const { return pciPath.c_str(); } protected: - const int fileDescriptor; + int fileDescriptor; const std::string pciPath; }; } // namespace NEO diff --git a/shared/source/os_interface/linux/hw_device_id_linux.cpp b/shared/source/os_interface/linux/hw_device_id_linux.cpp index e338581ddd..d8823be0cf 100644 --- a/shared/source/os_interface/linux/hw_device_id_linux.cpp +++ b/shared/source/os_interface/linux/hw_device_id_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -10,8 +10,15 @@ namespace NEO { +void HwDeviceIdDrm::closeFileDescriptor() { + if (fileDescriptor > 0) { + SysCalls::close(fileDescriptor); + fileDescriptor = -1; + } +} + HwDeviceIdDrm::~HwDeviceIdDrm() { - SysCalls::close(fileDescriptor); + closeFileDescriptor(); } } // namespace NEO diff --git a/shared/source/os_interface/linux/sys_calls.h b/shared/source/os_interface/linux/sys_calls.h index 9c9f97eca3..22c221a518 100644 --- a/shared/source/os_interface/linux/sys_calls.h +++ b/shared/source/os_interface/linux/sys_calls.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2022 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -31,5 +31,6 @@ int munmap(void *addr, size_t size); ssize_t read(int fd, void *buf, size_t count); int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, int arg); +char *realpath(const char *path, char *buf); } // namespace SysCalls } // namespace NEO diff --git a/shared/source/os_interface/linux/sys_calls_linux.cpp b/shared/source/os_interface/linux/sys_calls_linux.cpp index 0376929e45..539b8a4160 100644 --- a/shared/source/os_interface/linux/sys_calls_linux.cpp +++ b/shared/source/os_interface/linux/sys_calls_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2022 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -100,5 +100,9 @@ int fcntl(int fd, int cmd, int arg) { return ::fcntl(fd, cmd, arg); } +char *realpath(const char *path, char *buf) { + return ::realpath(path, buf); +} + } // namespace SysCalls } // namespace NEO diff --git a/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp b/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp index ba6b022c45..cba37935cd 100644 --- a/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp +++ b/shared/test/common/os_interface/linux/sys_calls_linux_ult.cpp @@ -54,6 +54,7 @@ int (*sysCallsIoctl)(int fileDescriptor, unsigned long int request, void *arg) = int (*sysCallsPoll)(struct pollfd *pollFd, unsigned long int numberOfFds, int timeout) = nullptr; ssize_t (*sysCallsRead)(int fd, void *buf, size_t count) = nullptr; int (*sysCallsFstat)(int fd, struct stat *buf) = nullptr; +char *(*sysCallsRealpath)(const char *path, char *buf) = nullptr; int close(int fileDescriptor) { closeFuncCalled++; @@ -219,5 +220,12 @@ int fcntl(int fd, int cmd, int arg) { return 0; } +char *realpath(const char *path, char *buf) { + if (sysCallsRealpath != nullptr) { + return sysCallsRealpath(path, buf); + } + return nullptr; +} + } // namespace SysCalls } // namespace NEO diff --git a/shared/test/common/os_interface/linux/sys_calls_linux_ult.h b/shared/test/common/os_interface/linux/sys_calls_linux_ult.h index 2553ebbd5f..6880977665 100644 --- a/shared/test/common/os_interface/linux/sys_calls_linux_ult.h +++ b/shared/test/common/os_interface/linux/sys_calls_linux_ult.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2022 Intel Corporation + * Copyright (C) 2021-2023 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -21,6 +21,7 @@ extern int (*sysCallsIoctl)(int fileDescriptor, unsigned long int request, void extern int (*sysCallsPoll)(struct pollfd *pollFd, unsigned long int numberOfFds, int timeout); extern ssize_t (*sysCallsRead)(int fd, void *buf, size_t count); extern int (*sysCallsFstat)(int fd, struct stat *buf); +extern char *(*sysCallsRealpath)(const char *path, char *buf); extern const char *drmVersion; constexpr int fakeFileDescriptor = 123;