diff --git a/level_zero/tools/source/sysman/power/windows/os_power_imp.cpp b/level_zero/tools/source/sysman/power/windows/os_power_imp.cpp index 84a30ff509..9eba3643e7 100644 --- a/level_zero/tools/source/sysman/power/windows/os_power_imp.cpp +++ b/level_zero/tools/source/sysman/power/windows/os_power_imp.cpp @@ -10,6 +10,8 @@ #include "level_zero/tools/source/sysman/sysman_const.h" #include "level_zero/tools/source/sysman/windows/kmd_sys_manager.h" +#include + namespace L0 { ze_result_t WddmPowerImp::getProperties(zes_power_properties_t *pProperties) { @@ -297,18 +299,222 @@ bool WddmPowerImp::isPowerModuleSupported() { ze_result_t status = pKmdSysManager->requestSingle(request, response); - uint32_t enabled = 0; - memcpy_s(&enabled, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + ze_bool_t enabled = false; + memcpy_s(&enabled, sizeof(ze_bool_t), response.dataBuffer, sizeof(ze_bool_t)); + powerLimitCount = 0; - return ((status == ZE_RESULT_SUCCESS) && (enabled)); + if ((status == ZE_RESULT_SUCCESS) && enabled) { + powerLimitCount++; + } + + request.requestId = KmdSysman::Requests::Power::PowerLimit2Enabled; + status = pKmdSysManager->requestSingle(request, response); + enabled = false; + memcpy_s(&enabled, sizeof(ze_bool_t), response.dataBuffer, sizeof(ze_bool_t)); + + if ((status == ZE_RESULT_SUCCESS) && enabled) { + powerLimitCount++; + } + + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit4Ac; + status = pKmdSysManager->requestSingle(request, response); + + if (status == ZE_RESULT_SUCCESS) { + powerLimitCount++; + } + + if (powerLimitCount > 0) { + return true; + } else { + return false; + } } ze_result_t WddmPowerImp::getLimitsExt(uint32_t *pCount, zes_power_limit_ext_desc_t *pSustained) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + ze_result_t result = ZE_RESULT_SUCCESS; + uint8_t count = 0; + + if (*pCount == 0) { + *pCount = powerLimitCount; + return result; + } + + *pCount = std::min(*pCount, powerLimitCount); + + KmdSysman::RequestProperty request; + KmdSysman::ResponseProperty response; + + request.commandId = KmdSysman::Command::Get; + request.componentId = KmdSysman::Component::PowerComponent; + + if (pSustained) { + // sustained + request.requestId = KmdSysman::Requests::Power::PowerLimit1Enabled; + result = pKmdSysManager->requestSingle(request, response); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + ze_bool_t enabled = false; + memcpy_s(&enabled, sizeof(ze_bool_t), response.dataBuffer, sizeof(ze_bool_t)); + + if (enabled) { + memset(&pSustained[count], 0, sizeof(zes_power_limit_ext_desc_t)); + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit1; + + result = pKmdSysManager->requestSingle(request, response); + if (result != ZE_RESULT_SUCCESS) { + return result; + } + + uint32_t limit = 0; + memcpy_s(&limit, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit1Tau; + + result = pKmdSysManager->requestSingle(request, response); + if (result != ZE_RESULT_SUCCESS) { + return result; + } + + uint32_t interval = 0; + memcpy_s(&interval, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + pSustained[count].enabled = enabled; + pSustained[count].limit = limit; + pSustained[count].enabledStateLocked = true; + pSustained[count].intervalValueLocked = false; + pSustained[count].limitValueLocked = false; + pSustained[count].source = ZES_POWER_SOURCE_ANY; + pSustained[count].level = ZES_POWER_LEVEL_SUSTAINED; + pSustained[count].limitUnit = ZES_LIMIT_UNIT_POWER; + pSustained[count].interval = interval; + count++; + } + + // Burst + request.requestId = KmdSysman::Requests::Power::PowerLimit2Enabled; + result = pKmdSysManager->requestSingle(request, response); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + enabled = false; + memcpy_s(&enabled, sizeof(ze_bool_t), response.dataBuffer, sizeof(ze_bool_t)); + + if (count < *pCount && enabled) { + memset(&pSustained[count], 0, sizeof(zes_power_limit_ext_desc_t)); + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit2; + result = pKmdSysManager->requestSingle(request, response); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + + uint32_t limit = 0; + memcpy_s(&limit, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + pSustained[count].enabled = enabled; + pSustained[count].limit = limit; + pSustained[count].enabledStateLocked = true; + pSustained[count].intervalValueLocked = false; + pSustained[count].limitValueLocked = false; + pSustained[count].source = ZES_POWER_SOURCE_ANY; + pSustained[count].level = ZES_POWER_LEVEL_BURST; + pSustained[count].limitUnit = ZES_LIMIT_UNIT_POWER; + pSustained[count].interval = 0; + count++; + } + // Peak + if (count < *pCount) { + + memset(&pSustained[count], 0, sizeof(zes_power_limit_ext_desc_t)); + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit4Ac; + result = pKmdSysManager->requestSingle(request, response); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + + uint32_t powerAC = 0; + memcpy_s(&powerAC, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit4Dc; + + result = pKmdSysManager->requestSingle(request, response); + + if (result != ZE_RESULT_SUCCESS) { + return result; + } + uint32_t powerDC = 0; + memcpy_s(&powerDC, sizeof(uint32_t), response.dataBuffer, sizeof(uint32_t)); + + pSustained[count].enabled = true; + pSustained[count].limit = powerAC; + pSustained[count].enabledStateLocked = true; + pSustained[count].intervalValueLocked = false; + pSustained[count].limitValueLocked = false; + pSustained[count].source = ZES_POWER_SOURCE_ANY; + pSustained[count].level = ZES_POWER_LEVEL_PEAK; + pSustained[count].limitUnit = ZES_LIMIT_UNIT_POWER; + pSustained[count].interval = 0; + count++; + } + } + return result; } ze_result_t WddmPowerImp::setLimitsExt(uint32_t *pCount, zes_power_limit_ext_desc_t *pSustained) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + ze_result_t status = ZE_RESULT_SUCCESS; + KmdSysman::RequestProperty request; + KmdSysman::ResponseProperty response; + + request.commandId = KmdSysman::Command::Set; + request.componentId = KmdSysman::Component::PowerComponent; + request.dataSize = sizeof(uint32_t); + + for (uint32_t i = 0; i < *pCount; i++) { + if (pSustained[i].level == ZES_POWER_LEVEL_SUSTAINED) { + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit1; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &pSustained[i].limit, sizeof(uint32_t)); + status = pKmdSysManager->requestSingle(request, response); + if (status != ZE_RESULT_SUCCESS) { + return status; + } + + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit1Tau; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &pSustained[i].interval, sizeof(uint32_t)); + status = pKmdSysManager->requestSingle(request, response); + if (status != ZE_RESULT_SUCCESS) { + return status; + } + } else if (pSustained[i].level == ZES_POWER_LEVEL_BURST) { + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit2; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &pSustained[i].limit, sizeof(uint32_t)); + status = pKmdSysManager->requestSingle(request, response); + if (status != ZE_RESULT_SUCCESS) { + return status; + } + } else if (pSustained[i].level == ZES_POWER_LEVEL_PEAK) { + if (pSustained[i].source != ZES_POWER_SOURCE_BATTERY) { + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit4Ac; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &pSustained[i].limit, sizeof(uint32_t)); + status = pKmdSysManager->requestSingle(request, response); + if (status != ZE_RESULT_SUCCESS) { + return status; + } + } else { + request.requestId = KmdSysman::Requests::Power::CurrentPowerLimit4Dc; + memcpy_s(request.dataBuffer, sizeof(uint32_t), &pSustained[i].limit, sizeof(uint32_t)); + status = pKmdSysManager->requestSingle(request, response); + if (status != ZE_RESULT_SUCCESS) { + return status; + } + } + } else { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + } + return status; } WddmPowerImp::WddmPowerImp(OsSysman *pOsSysman, ze_bool_t onSubdevice, uint32_t subdeviceId) { diff --git a/level_zero/tools/source/sysman/power/windows/os_power_imp.h b/level_zero/tools/source/sysman/power/windows/os_power_imp.h index b80b5514b2..4dd39a2c3b 100644 --- a/level_zero/tools/source/sysman/power/windows/os_power_imp.h +++ b/level_zero/tools/source/sysman/power/windows/os_power_imp.h @@ -32,6 +32,7 @@ class WddmPowerImp : public OsPower, NEO::NonCopyableOrMovableClass { protected: KmdSysManager *pKmdSysManager = nullptr; + uint32_t powerLimitCount = 0; }; } // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/sysman/power/windows/mock_power.h b/level_zero/tools/test/unit_tests/sources/sysman/power/windows/mock_power.h index ad1e0a3c79..3dff60b56f 100644 --- a/level_zero/tools/test/unit_tests/sources/sysman/power/windows/mock_power.h +++ b/level_zero/tools/test/unit_tests/sources/sysman/power/windows/mock_power.h @@ -12,6 +12,7 @@ namespace L0 { namespace ult { +constexpr uint32_t mockLimitCount = 3u; class PowerKmdSysManager : public Mock {}; diff --git a/level_zero/tools/test/unit_tests/sources/sysman/power/windows/test_zes_sysman_power.cpp b/level_zero/tools/test/unit_tests/sources/sysman/power/windows/test_zes_sysman_power.cpp index 4f087fe4dc..fd03f8ab5c 100644 --- a/level_zero/tools/test/unit_tests/sources/sysman/power/windows/test_zes_sysman_power.cpp +++ b/level_zero/tools/test/unit_tests/sources/sysman/power/windows/test_zes_sysman_power.cpp @@ -289,16 +289,84 @@ TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenSettingPowerLimitsAllo } } -TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandlesWhenCallingSetAndGetPowerLimitExtWhenHwmonInterfaceExistThenUnsupportedFeatureIsReturned) { +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandlesWhenCallingSetAndGetPowerLimitExtThenLimitsSetEarlierAreRetrieved) { // Setting allow set calls or not init(true); - auto handles = get_power_handles(powerHandleComponentCount); for (auto handle : handles) { - uint32_t limitCount = 0; - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerGetLimitsExt(handle, &limitCount, nullptr)); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, zesPowerSetLimitsExt(handle, &limitCount, nullptr)); + uint32_t limitCount = 0; + const int32_t testLimit = 3000000; + const int32_t testInterval = 10; + + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &limitCount, nullptr)); + EXPECT_EQ(limitCount, mockLimitCount); + + limitCount++; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &limitCount, nullptr)); + EXPECT_EQ(limitCount, mockLimitCount); + + std::vector allLimits(limitCount); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &limitCount, allLimits.data())); + for (uint32_t i = 0; i < limitCount; i++) { + if (allLimits[i].level == ZES_POWER_LEVEL_SUSTAINED) { + EXPECT_FALSE(allLimits[i].limitValueLocked); + EXPECT_TRUE(allLimits[i].enabledStateLocked); + EXPECT_FALSE(allLimits[i].intervalValueLocked); + EXPECT_EQ(ZES_POWER_SOURCE_ANY, allLimits[i].source); + EXPECT_EQ(ZES_LIMIT_UNIT_POWER, allLimits[i].limitUnit); + allLimits[i].limit = testLimit; + allLimits[i].interval = testInterval; + } else if (allLimits[i].level == ZES_POWER_LEVEL_PEAK) { + EXPECT_FALSE(allLimits[i].limitValueLocked); + EXPECT_TRUE(allLimits[i].enabledStateLocked); + EXPECT_FALSE(allLimits[i].intervalValueLocked); + EXPECT_EQ(ZES_POWER_SOURCE_ANY, allLimits[i].source); + EXPECT_EQ(ZES_LIMIT_UNIT_POWER, allLimits[i].limitUnit); + allLimits[i].limit = testLimit; + } else if (allLimits[i].level == ZES_POWER_LEVEL_BURST) { + EXPECT_FALSE(allLimits[i].limitValueLocked); + EXPECT_TRUE(allLimits[i].enabledStateLocked); + EXPECT_FALSE(allLimits[i].intervalValueLocked); + EXPECT_EQ(ZES_POWER_SOURCE_ANY, allLimits[i].source); + EXPECT_EQ(ZES_LIMIT_UNIT_POWER, allLimits[i].limitUnit); + allLimits[i].limit = testLimit; + } + } + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerSetLimitsExt(handle, &limitCount, allLimits.data())); + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &limitCount, allLimits.data())); + for (uint32_t i = 0; i < limitCount; i++) { + if (allLimits[i].level == ZES_POWER_LEVEL_SUSTAINED) { + EXPECT_EQ(testInterval, allLimits[i].interval); + } else if (allLimits[i].level == ZES_POWER_LEVEL_PEAK) { + EXPECT_EQ(0, allLimits[i].interval); + } + EXPECT_EQ(testLimit, allLimits[i].limit); + } + } +} + +TEST_F(SysmanDevicePowerFixture, GivenValidPowerHandleWhenCallingGetPowerLimitsExtThenProperValuesAreReturned) { + // Setting allow set calls or not + init(false); + auto handles = get_power_handles(powerHandleComponentCount); + + for (auto handle : handles) { + zes_power_limit_ext_desc_t allLimits{}; + uint32_t count = 0; + + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &count, nullptr)); + EXPECT_EQ(count, mockLimitCount); + + count = 1; + EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetLimitsExt(handle, &count, &allLimits)); + EXPECT_EQ(count, 1u); + EXPECT_EQ(false, allLimits.limitValueLocked); + EXPECT_EQ(true, allLimits.enabledStateLocked); + EXPECT_EQ(false, allLimits.intervalValueLocked); + EXPECT_EQ(ZES_POWER_SOURCE_ANY, allLimits.source); + EXPECT_EQ(ZES_LIMIT_UNIT_POWER, allLimits.limitUnit); + EXPECT_EQ(ZES_POWER_LEVEL_SUSTAINED, allLimits.level); } }