diff --git a/level_zero/tools/source/sysman/power/linux/CMakeLists.txt b/level_zero/tools/source/sysman/power/linux/CMakeLists.txt index 172d5677ec..a111e0aa59 100644 --- a/level_zero/tools/source/sysman/power/linux/CMakeLists.txt +++ b/level_zero/tools/source/sysman/power/linux/CMakeLists.txt @@ -4,10 +4,19 @@ # SPDX-License-Identifier: MIT # -set(L0_SRCS_TOOLS_SYSMAN_POWER_LINUX - ${CMAKE_CURRENT_SOURCE_DIR}/os_power_imp.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/os_power_imp.h -) +if(SUPPORT_DG1) + set(L0_SRCS_TOOLS_SYSMAN_POWER_LINUX + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/dg1/os_power_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dg1/os_power_imp.h + ) +else() + set(L0_SRCS_TOOLS_SYSMAN_POWER_LINUX + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/os_power_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/os_power_imp.h + ) +endif() if(UNIX) target_sources(${L0_STATIC_LIB_NAME} diff --git a/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.cpp b/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.cpp new file mode 100644 index 0000000000..77c8c7fbff --- /dev/null +++ b/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.h" + +#include "level_zero/tools/source/sysman/sysman_const.h" + +#include "sysman/linux/os_sysman_imp.h" + +namespace L0 { + +const std::string LinuxPowerImp::hwmonDir("device/hwmon"); +const std::string LinuxPowerImp::i915("i915"); +const std::string LinuxPowerImp::sustainedPowerLimitEnabled("power1_max_enable"); +const std::string LinuxPowerImp::sustainedPowerLimit("power1_max"); +const std::string LinuxPowerImp::sustainedPowerLimitInterval("power1_max_interval"); +const std::string LinuxPowerImp::burstPowerLimitEnabled("power1_cap_enable"); +const std::string LinuxPowerImp::burstPowerLimit("power1_cap"); +const std::string LinuxPowerImp::energyCounterNode("energy1_input"); + +void powerGetTimestamp(uint64_t ×tamp) { + std::chrono::time_point ts = std::chrono::steady_clock::now(); + timestamp = std::chrono::duration_cast(ts.time_since_epoch()).count(); +} + +ze_result_t LinuxPowerImp::getProperties(zes_power_properties_t *pProperties) { + pProperties->onSubdevice = false; + pProperties->subdeviceId = 0; + return ZE_RESULT_SUCCESS; +} + +ze_result_t LinuxPowerImp::getEnergyCounter(zes_power_energy_counter_t *pEnergy) { + auto result = pSysfsAccess->read(i915HwmonDir + "/" + energyCounterNode, pEnergy->energy); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + powerGetTimestamp(pEnergy->timestamp); + return result; +} + +ze_result_t LinuxPowerImp::getLimits(zes_power_sustained_limit_t *pSustained, zes_power_burst_limit_t *pBurst, zes_power_peak_limit_t *pPeak) { + ze_result_t result = ZE_RESULT_ERROR_UNKNOWN; + uint64_t val = 0; + if (pSustained != nullptr) { + result = pSysfsAccess->read(i915HwmonDir + "/" + sustainedPowerLimitEnabled, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + pSustained->enabled = static_cast(val); + + if (pSustained->enabled) { + val = 0; + result = pSysfsAccess->read(i915HwmonDir + "/" + sustainedPowerLimit, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + val /= milliFactor; // Convert microWatts to milliwatts + pSustained->power = static_cast(val); + + val = 0; + result = pSysfsAccess->read(i915HwmonDir + "/" + sustainedPowerLimitInterval, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + pSustained->interval = static_cast(val); + } + } + if (pBurst != nullptr) { + result = pSysfsAccess->read(i915HwmonDir + "/" + burstPowerLimitEnabled, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + pBurst->enabled = static_cast(val); + + if (pBurst->enabled) { + result = pSysfsAccess->read(i915HwmonDir + "/" + burstPowerLimit, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + val /= milliFactor; // Convert microWatts to milliwatts + pBurst->power = static_cast(val); + } + } + if (pPeak != nullptr) { + pPeak->powerAC = -1; + pPeak->powerDC = -1; + result = ZE_RESULT_SUCCESS; + } + return result; +} + +ze_result_t LinuxPowerImp::setLimits(const zes_power_sustained_limit_t *pSustained, const zes_power_burst_limit_t *pBurst, const zes_power_peak_limit_t *pPeak) { + ze_result_t result = ZE_RESULT_ERROR_UNKNOWN; + int32_t val = 0; + if (pSustained != nullptr) { + uint64_t isSustainedPowerLimitEnabled = 0; + result = pSysfsAccess->read(i915HwmonDir + "/" + sustainedPowerLimitEnabled, isSustainedPowerLimitEnabled); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + + if (isSustainedPowerLimitEnabled) { + val = static_cast(pSustained->power) * milliFactor; // Convert milliWatts to microwatts + result = pSysfsAccess->write(i915HwmonDir + "/" + sustainedPowerLimit, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + + result = pSysfsAccess->write(i915HwmonDir + "/" + sustainedPowerLimitInterval, pSustained->interval); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + } + } + if (pBurst != nullptr) { + result = pSysfsAccess->write(i915HwmonDir + "/" + burstPowerLimitEnabled, static_cast(pBurst->enabled)); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + + if (pBurst->enabled) { + val = static_cast(pBurst->power) * milliFactor; // Convert milliWatts to microwatts + result = pSysfsAccess->write(i915HwmonDir + "/" + burstPowerLimit, val); + if (ZE_RESULT_SUCCESS != result) { + return getErrorCode(result); + } + } + } + + return result; +} + +ze_result_t LinuxPowerImp::getEnergyThreshold(zes_energy_threshold_t *pThreshold) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +ze_result_t LinuxPowerImp::setEnergyThreshold(double threshold) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; +} + +bool LinuxPowerImp::isPowerModuleSupported() { + std::vector listOfAllHwmonDirs = {}; + if (ZE_RESULT_SUCCESS != pSysfsAccess->scanDirEntries(hwmonDir, listOfAllHwmonDirs)) { + return false; + } + for (const auto &tempHwmonDirEntry : listOfAllHwmonDirs) { + const std::string i915NameFile = hwmonDir + "/" + tempHwmonDirEntry + "/" + "name"; + std::string name; + if (ZE_RESULT_SUCCESS != pSysfsAccess->read(i915NameFile, name)) { + continue; + } + if (name == i915) { + i915HwmonDir = hwmonDir + "/" + tempHwmonDirEntry; + return true; + } + } + + return false; +} + +LinuxPowerImp::LinuxPowerImp(OsSysman *pOsSysman) { + LinuxSysmanImp *pLinuxSysmanImp = static_cast(pOsSysman); + pSysfsAccess = &pLinuxSysmanImp->getSysfsAccess(); +} + +OsPower *OsPower::create(OsSysman *pOsSysman) { + LinuxPowerImp *pLinuxPowerImp = new LinuxPowerImp(pOsSysman); + return static_cast(pLinuxPowerImp); +} + +} // namespace L0 \ No newline at end of file diff --git a/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.h b/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.h new file mode 100644 index 0000000000..5e01bbe62e --- /dev/null +++ b/level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "shared/source/helpers/non_copyable_or_moveable.h" + +#include "level_zero/tools/source/sysman/power/os_power.h" + +#include + +namespace L0 { + +class SysfsAccess; +class LinuxPowerImp : public OsPower, NEO::NonCopyableOrMovableClass { + public: + ze_result_t getProperties(zes_power_properties_t *pProperties) override; + ze_result_t getEnergyCounter(zes_power_energy_counter_t *pEnergy) override; + ze_result_t getLimits(zes_power_sustained_limit_t *pSustained, zes_power_burst_limit_t *pBurst, zes_power_peak_limit_t *pPeak) override; + ze_result_t setLimits(const zes_power_sustained_limit_t *pSustained, const zes_power_burst_limit_t *pBurst, const zes_power_peak_limit_t *pPeak) override; + ze_result_t getEnergyThreshold(zes_energy_threshold_t *pThreshold) override; + ze_result_t setEnergyThreshold(double threshold) override; + + bool isPowerModuleSupported() override; + LinuxPowerImp(OsSysman *pOsSysman); + LinuxPowerImp() = default; + ~LinuxPowerImp() override = default; + + protected: + SysfsAccess *pSysfsAccess = nullptr; + + private: + std::string i915HwmonDir; + static const std::string hwmonDir; + static const std::string i915; + static const std::string sustainedPowerLimitEnabled; + static const std::string sustainedPowerLimit; + static const std::string sustainedPowerLimitInterval; + static const std::string burstPowerLimitEnabled; + static const std::string burstPowerLimit; + static const std::string energyCounterNode; + + ze_result_t getErrorCode(ze_result_t result) { + if (result == ZE_RESULT_ERROR_NOT_AVAILABLE) { + result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + return result; + } +}; +} // namespace L0 \ No newline at end of file diff --git a/level_zero/tools/source/sysman/sysman_const.h b/level_zero/tools/source/sysman/sysman_const.h index 84fa3cb53d..f3ce683d00 100644 --- a/level_zero/tools/source/sysman/sysman_const.h +++ b/level_zero/tools/source/sysman/sysman_const.h @@ -41,3 +41,4 @@ constexpr uint64_t minTimeoutInMicroSeconds = 1000u; constexpr uint16_t milliSecsToMicroSecs = 1000; constexpr uint64_t numSocTemperatureEntries = 7; constexpr uint32_t numCoreTemperatureEntries = 4; +constexpr uint32_t milliFactor = 1000u; \ No newline at end of file diff --git a/level_zero/tools/test/black_box_tests/zello_sysman.cpp b/level_zero/tools/test/black_box_tests/zello_sysman.cpp index 09937dc3d7..c6c8b49876 100644 --- a/level_zero/tools/test/black_box_tests/zello_sysman.cpp +++ b/level_zero/tools/test/black_box_tests/zello_sysman.cpp @@ -132,6 +132,7 @@ void getDeviceHandles(std::vector &devices, int argc, char * void testSysmanPower(ze_device_handle_t &device) { std::cout << std::endl << " ---- Power tests ---- " << std::endl; + bool iamroot = (geteuid() == 0); uint32_t count = 0; VALIDATECALL(zesDeviceEnumPowerDomains(device, &count, nullptr)); if (count == 0) { @@ -148,6 +149,35 @@ void testSysmanPower(ze_device_handle_t &device) { std::cout << "energyCounter.energy = " << energyCounter.energy << std::endl; std::cout << "energyCounter.timestamp = " << energyCounter.timestamp << std::endl; } + zes_power_sustained_limit_t sustainedGetDefault = {}; + zes_power_burst_limit_t burstGetDefault = {}; + VALIDATECALL(zesPowerGetLimits(handle, &sustainedGetDefault, &burstGetDefault, nullptr)); + if (verbose) { + std::cout << "sustainedGetDefault.enabled = " << sustainedGetDefault.enabled << std::endl; + if (sustainedGetDefault.enabled) { + std::cout << "sustainedGetDefault.power = " << sustainedGetDefault.power << std::endl; + std::cout << "sustainedGetDefault.interval = " << sustainedGetDefault.interval << std::endl; + } + std::cout << "burstGetDefault.enabled = " << burstGetDefault.enabled << std::endl; + if (burstGetDefault.enabled) { + std::cout << "burstGetDefault.power = " << burstGetDefault.power << std::endl; + } + } + if (iamroot) { + zes_power_sustained_limit_t sustainedSet = {}; + sustainedSet.power = sustainedGetDefault.power - sustainedGetDefault.power / 10; //Randomly try to reduce power + sustainedSet.interval = sustainedGetDefault.interval - sustainedGetDefault.interval / 10; + zes_power_burst_limit_t burstSet = {}; + if (burstGetDefault.enabled) { + burstSet.enabled = 0; + } + VALIDATECALL(zesPowerSetLimits(handle, &sustainedSet, &burstSet, nullptr)); + if (verbose) { + std::cout << "zesPowerSetLimits success" << std::endl; + std::cout << "Now restore the power values to default ones" << std::endl; + } + VALIDATECALL(zesPowerSetLimits(handle, &sustainedGetDefault, &burstGetDefault, nullptr)); + } } } diff --git a/level_zero/tools/test/unit_tests/sources/sysman/power/linux/CMakeLists.txt b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/CMakeLists.txt index 0ddd4af758..83b70c2e0c 100644 --- a/level_zero/tools/test/unit_tests/sources/sysman/power/linux/CMakeLists.txt +++ b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/CMakeLists.txt @@ -4,11 +4,23 @@ # SPDX-License-Identifier: MIT # +if(SUPPORT_DG1) + set(L0_TESTS_TOOLS_SYSMAN_POWER_LINUX + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/dg1/test_zes_power.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/dg1/mock_sysfs_power.h + ) +else() + set(L0_TESTS_TOOLS_SYSMAN_POWER_LINUX + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_zes_power.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysfs_power.h + ) +endif() + if(UNIX) target_sources(${TARGET_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt - ${CMAKE_CURRENT_SOURCE_DIR}/test_zes_power.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mock_sysfs_power.h + ${L0_TESTS_TOOLS_SYSMAN_POWER_LINUX} ) endif() diff --git a/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/mock_sysfs_power.h b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/mock_sysfs_power.h new file mode 100644 index 0000000000..365876c708 --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/mock_sysfs_power.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once +#include "level_zero/tools/source/sysman/power/linux/dg1/os_power_imp.h" + +#include "sysman/linux/fs_access.h" + +#include + +namespace L0 { +namespace ult { + +const std::string hwmonDir("device/hwmon"); +const std::string i915HwmonDir("device/hwmon/hwmon4"); +const std::string nonI915HwmonDir("device/hwmon/hwmon1"); +const std::vector listOfMockedHwmonDirs = {"hwmon1", "hwmon2", "hwmon3", "hwmon4"}; +const std::string sustainedPowerLimitEnabled("power1_max_enable"); +const std::string sustainedPowerLimit("power1_max"); +const std::string sustainedPowerLimitInterval("power1_max_interval"); +const std::string burstPowerLimitEnabled("power1_cap_enable"); +const std::string burstPowerLimit("power1_cap"); +const std::string energyCounterNode("energy1_input"); +constexpr uint64_t expectedEnergyCounter = 123456785u; +class PowerSysfsAccess : public SysfsAccess {}; + +template <> +struct Mock : public PowerSysfsAccess { + + ze_result_t getValString(const std::string file, std::string &val) { + ze_result_t result = ZE_RESULT_ERROR_UNKNOWN; + if (file.compare(i915HwmonDir + "/" + "name") == 0) { + val = "i915"; + result = ZE_RESULT_SUCCESS; + } else if (file.compare(nonI915HwmonDir + "/" + "name") == 0) { + result = ZE_RESULT_ERROR_NOT_AVAILABLE; + } else { + val = "garbageI915"; + result = ZE_RESULT_SUCCESS; + } + return result; + } + + uint64_t sustainedPowerLimitEnabledVal = 1u; + uint64_t sustainedPowerLimitVal = 0; + uint64_t sustainedPowerLimitIntervalVal = 0; + uint64_t burstPowerLimitEnabledVal = 0; + uint64_t burstPowerLimitVal = 0; + uint64_t energyCounterNodeVal = expectedEnergyCounter; + + ze_result_t getValUnsignedLongReturnErrorForEnergyCounter(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + energyCounterNode) == 0) { + return ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnErrorForBurstPowerLimit(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + val = burstPowerLimitEnabledVal; + } + if (file.compare(i915HwmonDir + "/" + burstPowerLimit) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnErrorForBurstPowerLimitEnabled(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnErrorForSustainedPowerLimitEnabled(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitEnabled) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnsPowerLimitEnabledAsDisabled(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitEnabled) == 0) { + val = 0; + return ZE_RESULT_SUCCESS; + } else if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + val = 0; + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnErrorForSustainedPower(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitEnabled) == 0) { + val = 1; + } else if (file.compare(i915HwmonDir + "/" + sustainedPowerLimit) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLongReturnErrorForSustainedPowerInterval(const std::string file, uint64_t &val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitEnabled) == 0) { + val = 1; + } else if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitInterval) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t setValUnsignedLongReturnErrorForBurstPowerLimit(const std::string file, const int val) { + if (file.compare(i915HwmonDir + "/" + burstPowerLimit) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t setValUnsignedLongReturnErrorForBurstPowerLimitEnabled(const std::string file, const int val) { + if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t setValReturnErrorForSustainedPower(const std::string file, const int val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimit) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t setValReturnErrorForSustainedPowerInterval(const std::string file, const int val) { + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitInterval) == 0) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + return ZE_RESULT_SUCCESS; + } + + ze_result_t getValUnsignedLong(const std::string file, uint64_t &val) { + ze_result_t result = ZE_RESULT_SUCCESS; + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitEnabled) == 0) { + val = sustainedPowerLimitEnabledVal; + } else if (file.compare(i915HwmonDir + "/" + sustainedPowerLimit) == 0) { + val = sustainedPowerLimitVal; + } else if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitInterval) == 0) { + val = sustainedPowerLimitIntervalVal; + } else if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + val = burstPowerLimitEnabledVal; + } else if (file.compare(i915HwmonDir + "/" + burstPowerLimit) == 0) { + val = burstPowerLimitVal; + } else if (file.compare(i915HwmonDir + "/" + energyCounterNode) == 0) { + val = energyCounterNodeVal; + } else { + result = ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + return result; + } + ze_result_t setVal(const std::string file, const int val) { + ze_result_t result = ZE_RESULT_SUCCESS; + if (file.compare(i915HwmonDir + "/" + sustainedPowerLimit) == 0) { + sustainedPowerLimitVal = static_cast(val); + } else if (file.compare(i915HwmonDir + "/" + sustainedPowerLimitInterval) == 0) { + sustainedPowerLimitIntervalVal = static_cast(val); + } else if (file.compare(i915HwmonDir + "/" + burstPowerLimitEnabled) == 0) { + burstPowerLimitEnabledVal = static_cast(val); + } else if (file.compare(i915HwmonDir + "/" + burstPowerLimit) == 0) { + burstPowerLimitVal = static_cast(val); + } else { + result = ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + return result; + } + ze_result_t getscanDirEntries(const std::string file, std::vector &listOfEntries) { + if (file.compare(hwmonDir) == 0) { + listOfEntries = listOfMockedHwmonDirs; + return ZE_RESULT_SUCCESS; + } + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + ze_result_t getscanDirEntriesStatusReturnError(const std::string file, std::vector &listOfEntries) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + Mock() = default; + + MOCK_METHOD(ze_result_t, read, (const std::string file, uint64_t &val), (override)); + MOCK_METHOD(ze_result_t, read, (const std::string file, std::string &val), (override)); + MOCK_METHOD(ze_result_t, write, (const std::string file, const int val), (override)); + MOCK_METHOD(ze_result_t, scanDirEntries, (const std::string file, std::vector &listOfEntries), (override)); +}; + +class PublicLinuxPowerImp : public L0::LinuxPowerImp { + public: + using LinuxPowerImp::pSysfsAccess; +}; + +} // namespace ult +} // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/test_zes_power.cpp b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/test_zes_power.cpp new file mode 100644 index 0000000000..ef2f8d5067 --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/sysman/power/linux/dg1/test_zes_power.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2020 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/tools/test/unit_tests/sources/sysman/linux/mock_sysman_fixture.h" + +#include "mock_sysfs_power.h" + +using ::testing::DoDefault; +using ::testing::Matcher; +using ::testing::Return; + +namespace L0 { +namespace ult { +constexpr uint32_t powerHandleComponentCount = 1u; +class SysmanDevicePowerFixture : public SysmanDeviceFixture { + + protected: + std::unique_ptr> pSysfsAccess; + SysfsAccess *pSysfsAccessOld = nullptr; + std::vector deviceHandles; + + void SetUp() override { + SysmanDeviceFixture::SetUp(); + pSysfsAccessOld = pLinuxSysmanImp->pSysfsAccess; + pSysfsAccess = std::make_unique>>(); + pLinuxSysmanImp->pSysfsAccess = pSysfsAccess.get(); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValString)); + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLong)); + ON_CALL(*pSysfsAccess.get(), write(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::setVal)); + ON_CALL(*pSysfsAccess.get(), scanDirEntries(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getscanDirEntries)); + + pSysmanDeviceImp->pPowerHandleContext->init(); + } + + void TearDown() override { + SysmanDeviceFixture::TearDown(); + pLinuxSysmanImp->pSysfsAccess = pSysfsAccessOld; + } + + std::vector get_power_handles(uint32_t count) { + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + return handles; + } +}; + +TEST_F(SysmanDevicePowerFixture, GivenComponentCountZeroWhenEnumeratingPowerDomainsThenValidCountIsReturnedAndVerifySysmanPowerGetCallSucceeds) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, powerHandleComponentCount); +} + +TEST_F(SysmanDevicePowerFixture, GivenInvalidComponentCountWhenEnumeratingPowerDomainsThenValidCountIsReturnedAndVerifySysmanPowerGetCallSucceeds) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, powerHandleComponentCount); + + count = count + 1; + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, powerHandleComponentCount); +} + +TEST_F(SysmanDevicePowerFixture, GivenComponentCountZeroWhenEnumeratingPowerDomainsThenValidPowerHandlesIsReturned) { + uint32_t count = 0; + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS); + EXPECT_EQ(count, powerHandleComponentCount); + + std::vector handles(count, nullptr); + EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS); + for (auto handle : handles) { + EXPECT_NE(handle, nullptr); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenGettingPowerPropertiesThenCallSucceeds) { + auto handles = get_power_handles(powerHandleComponentCount); + + for (auto handle : handles) { + zes_power_properties_t properties; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetProperties(handle, &properties)); + EXPECT_FALSE(properties.onSubdevice); + EXPECT_EQ(properties.subdeviceId, 0u); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenGettingPowerEnergyCounterThenValidPowerReadingsRetrieved) { + auto handles = get_power_handles(powerHandleComponentCount); + + for (auto handle : handles) { + zes_power_energy_counter_t energyCounter = {}; + ASSERT_EQ(ZE_RESULT_SUCCESS, zesPowerGetEnergyCounter(handle, &energyCounter)); + EXPECT_EQ(energyCounter.energy, expectedEnergyCounter); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenGettingPowerEnergyCounterFailedThenValidErrorCodeReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForEnergyCounter)); + for (auto handle : handles) { + zes_power_energy_counter_t energyCounter = {}; + ASSERT_EQ(ZE_RESULT_ERROR_INSUFFICIENT_PERMISSIONS, zesPowerGetEnergyCounter(handle, &energyCounter)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenGettingPowerEnergyThresholdThenUnsupportedFeatureErrorIsReturned) { + zes_energy_threshold_t threshold; + auto handles = get_power_handles(powerHandleComponentCount); + for (auto handle : handles) { + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetEnergyThreshold(handle, &threshold)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenSettingPowerEnergyThresholdThenUnsupportedFeatureErrorIsReturned) { + double threshold = 0; + auto handles = get_power_handles(powerHandleComponentCount); + for (auto handle : handles) { + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetEnergyThreshold(handle, threshold)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenSetPowerLimitsWhenGettingPowerLimitsThenLimitsSetEarlierAreRetrieved) { + auto handles = get_power_handles(powerHandleComponentCount); + for (auto handle : handles) { + zes_power_sustained_limit_t sustainedSet = {}; + zes_power_sustained_limit_t sustainedGet = {}; + sustainedSet.interval = 10; + sustainedSet.power = 300000; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handle, &sustainedSet, nullptr, nullptr)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handle, &sustainedGet, nullptr, nullptr)); + EXPECT_EQ(sustainedGet.power, sustainedSet.power); + EXPECT_EQ(sustainedGet.interval, sustainedSet.interval); + + zes_power_burst_limit_t burstSet = {}; + zes_power_burst_limit_t burstGet = {}; + burstSet.enabled = 1; + burstSet.power = 375000; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handle, nullptr, &burstSet, nullptr)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handle, nullptr, &burstGet, nullptr)); + EXPECT_EQ(burstSet.enabled, burstGet.enabled); + EXPECT_EQ(burstSet.power, burstGet.power); + + burstSet.enabled = 0; + burstGet.enabled = 0; + burstGet.power = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handle, nullptr, &burstSet, nullptr)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handle, nullptr, &burstGet, nullptr)); + EXPECT_EQ(burstSet.enabled, burstGet.enabled); + EXPECT_EQ(burstGet.power, 0); + + zes_power_peak_limit_t peakGet = {}; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handle, nullptr, nullptr, &peakGet)); + EXPECT_EQ(peakGet.powerAC, -1); + EXPECT_EQ(peakGet.powerDC, -1); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenGetPowerLimitsReturnErrorWhenGettingPowerLimitsForBurstPowerLimitThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForBurstPowerLimit)); + + for (auto handle : handles) { + zes_power_burst_limit_t burstSet = {}; + zes_power_burst_limit_t burstGet = {}; + burstSet.enabled = 1; + burstSet.power = 375000; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handle, nullptr, &burstSet, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimits(handle, nullptr, &burstGet, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenSetPowerLimitsReturnErrorWhenSettingPowerLimitsForBurstPowerLimitThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), write(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::setValUnsignedLongReturnErrorForBurstPowerLimit)); + + for (auto handle : handles) { + zes_power_burst_limit_t burstSet = {}; + burstSet.enabled = 1; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimits(handle, nullptr, &burstSet, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenSetPowerLimitsReturnErrorWhenSettingPowerLimitsForBurstPowerLimitEnabledThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), write(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::setValUnsignedLongReturnErrorForBurstPowerLimitEnabled)); + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForBurstPowerLimitEnabled)); + + for (auto handle : handles) { + zes_power_burst_limit_t burstSet = {}; + zes_power_burst_limit_t burstGet = {}; + burstSet.enabled = 1; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimits(handle, nullptr, &burstSet, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimits(handle, nullptr, &burstGet, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenReadingSustainedPowerLimitNodeReturnErrorWhenSetOrGetPowerLimitsForSustainedPowerLimitEnabledThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForSustainedPowerLimitEnabled)); + + for (auto handle : handles) { + zes_power_sustained_limit_t sustainedSet = {}; + zes_power_sustained_limit_t sustainedGet = {}; + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimits(handle, &sustainedSet, nullptr, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimits(handle, &sustainedGet, nullptr, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenReadingSustainedPowerNodeReturnErrorWhenGetPowerLimitsForSustainedPowerThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForSustainedPower)); + + for (auto handle : handles) { + zes_power_sustained_limit_t sustainedGet = {}; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimits(handle, &sustainedGet, nullptr, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenReadingSustainedPowerIntervalNodeReturnErrorWhenGetPowerLimitsForSustainedPowerThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnErrorForSustainedPowerInterval)); + + for (auto handle : handles) { + zes_power_sustained_limit_t sustainedGet = {}; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimits(handle, &sustainedGet, nullptr, nullptr)); + } +} + +TEST_F(SysmanDevicePowerFixture, GivenwritingSustainedPowerNodeReturnErrorWhenSetPowerLimitsForSustainedPowerThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), write(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::setValReturnErrorForSustainedPower)); + + zes_power_sustained_limit_t sustainedSet = {}; + sustainedSet.interval = 10; + sustainedSet.power = 300000; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimits(handles[0], &sustainedSet, nullptr, nullptr)); +} + +TEST_F(SysmanDevicePowerFixture, GivenwritingSustainedPowerIntervalNodeReturnErrorWhenSetPowerLimitsForSustainedPowerIntervalThenProperErrorCodesReturned) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), write(_, _)) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::setValReturnErrorForSustainedPowerInterval)); + + zes_power_sustained_limit_t sustainedSet = {}; + sustainedSet.interval = 10; + sustainedSet.power = 300000; + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimits(handles[0], &sustainedSet, nullptr, nullptr)); +} + +TEST_F(SysmanDevicePowerFixture, GivenGetPowerLimitsWhenPowerLimitsAreDisabledThenAllPowerValuesAreIgnored) { + auto handles = get_power_handles(powerHandleComponentCount); + + ON_CALL(*pSysfsAccess.get(), read(_, Matcher(_))) + .WillByDefault(::testing::Invoke(pSysfsAccess.get(), &Mock::getValUnsignedLongReturnsPowerLimitEnabledAsDisabled)); + + zes_power_sustained_limit_t sustainedGet = {}; + zes_power_burst_limit_t burstGet = {}; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handles[0], &sustainedGet, nullptr, nullptr)); + EXPECT_EQ(sustainedGet.interval, 0); + EXPECT_EQ(sustainedGet.power, 0); + EXPECT_EQ(sustainedGet.enabled, 0); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimits(handles[0], nullptr, &burstGet, nullptr)); + EXPECT_EQ(burstGet.enabled, 0); + EXPECT_EQ(burstGet.power, 0); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handles[0], &sustainedGet, nullptr, nullptr)); + zes_power_burst_limit_t burstSet = {}; + burstSet.enabled = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimits(handles[0], nullptr, &burstSet, nullptr)); +} + +} // namespace ult +} // namespace L0 \ No newline at end of file