feature(sysman): Add support of zesPowerGetEnergyCounter() API for BMG

Related-To: NEO-11296

Signed-off-by: Anvesh Bakwad <anvesh.bakwad@intel.com>
This commit is contained in:
Anvesh Bakwad
2025-04-28 15:02:18 +00:00
committed by Compute-Runtime-Automation
parent f3ad230c45
commit 615a41b9f5
14 changed files with 728 additions and 54 deletions

View File

@@ -80,18 +80,17 @@ ze_result_t LinuxPowerImp::getEnergyCounter(zes_power_energy_counter_t *pEnergy)
ze_result_t result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
if (isTelemetrySupportAvailable) {
result = pSysmanProductHelper->getPowerEnergyCounter(pEnergy, pLinuxSysmanImp, powerDomain, subdeviceId);
}
if (result != ZE_RESULT_SUCCESS) {
if ((result = pSysfsAccess->read(energyCounterNodeFile, pEnergy->energy)) != ZE_RESULT_SUCCESS) {
NEO::printDebugString(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "Error@ %s(): SysfsAccess->read() failed to read %s/%s and returning error:0x%x \n", __FUNCTION__, intelGraphicsHwmonDir.c_str(), energyCounterNodeFile.c_str(), getErrorCode(result));
if ((result = pSysmanProductHelper->getPowerEnergyCounter(pEnergy, pLinuxSysmanImp, powerDomain, subdeviceId)) == ZE_RESULT_SUCCESS) {
return result;
}
}
pEnergy->timestamp = SysmanDevice::getSysmanTimestamp();
if ((result = pSysfsAccess->read(energyCounterNodeFile, pEnergy->energy)) != ZE_RESULT_SUCCESS) {
NEO::printDebugString(NEO::debugManager.flags.PrintDebugMessages.get(), stderr, "Error@ %s(): SysfsAccess->read() failed to read %s/%s and returning error:0x%x \n", __FUNCTION__, intelGraphicsHwmonDir.c_str(), energyCounterNodeFile.c_str(), getErrorCode(result));
return result;
}
pEnergy->timestamp = SysmanDevice::getSysmanTimestamp();
return result;
}

View File

@@ -83,6 +83,7 @@ enum class SysfsName {
sysfsNamePackageEnergyCounterNode,
sysfsNamePackageDefaultPowerLimit,
sysfsNamePackageCriticalPowerLimit,
sysfsNameCardEnergyCounterNode,
sysfsNameStandbyModeControl,
sysfsNameMemoryAddressRange,
sysfsNameMaxMemoryFrequency,
@@ -331,7 +332,7 @@ class SysmanKmdInterfaceXe : public SysmanKmdInterface {
bool isBoostFrequencyAvailable() const override { return false; }
bool isTdpFrequencyAvailable() const override { return false; }
bool isPhysicalMemorySizeSupported() const override { return true; }
std::vector<zes_power_domain_t> getPowerDomains() const override { return {ZES_POWER_DOMAIN_PACKAGE}; }
std::vector<zes_power_domain_t> getPowerDomains() const override;
// Wedged state is not supported in XE.
void getWedgedStatus(LinuxSysmanImp *pLinuxSysmanImp, zes_device_state_t *pState) override{};

View File

@@ -50,9 +50,10 @@ void SysmanKmdInterfaceXe::initSysfsNameToFileMap(SysmanProductHelper *pSysmanPr
sysfsNameToFileMap[SysfsName::sysfsNameThrottleReasonThermal] = std::make_pair("freq0/throttle/reason_thermal", "");
sysfsNameToFileMap[SysfsName::sysfsNamePackageSustainedPowerLimit] = std::make_pair("", "power1_max");
sysfsNameToFileMap[SysfsName::sysfsNamePackageSustainedPowerLimitInterval] = std::make_pair("", "power1_max_interval");
sysfsNameToFileMap[SysfsName::sysfsNamePackageEnergyCounterNode] = std::make_pair("", "energy1_input");
sysfsNameToFileMap[SysfsName::sysfsNamePackageEnergyCounterNode] = std::make_pair("", "energy2_input");
sysfsNameToFileMap[SysfsName::sysfsNamePackageDefaultPowerLimit] = std::make_pair("", "power1_rated_max");
sysfsNameToFileMap[SysfsName::sysfsNamePackageCriticalPowerLimit] = std::make_pair("", pSysmanProductHelper->getPackageCriticalPowerLimitFile());
sysfsNameToFileMap[SysfsName::sysfsNameCardEnergyCounterNode] = std::make_pair("", "energy1_input");
sysfsNameToFileMap[SysfsName::sysfsNameMemoryAddressRange] = std::make_pair("physical_vram_size_bytes", "");
sysfsNameToFileMap[SysfsName::sysfsNameMaxMemoryFrequency] = std::make_pair("freq_vram_rp0", "");
sysfsNameToFileMap[SysfsName::sysfsNameMinMemoryFrequency] = std::make_pair("freq_vram_rpn", "");
@@ -97,6 +98,8 @@ std::string SysmanKmdInterfaceXe::getEnergyCounterNodeFile(zes_power_domain_t po
std::string filePath = {};
if (powerDomain == ZES_POWER_DOMAIN_PACKAGE) {
filePath = sysfsNameToFileMap[SysfsName::sysfsNamePackageEnergyCounterNode].second;
} else if (powerDomain == ZES_POWER_DOMAIN_CARD) {
filePath = sysfsNameToFileMap[SysfsName::sysfsNameCardEnergyCounterNode].second;
}
return filePath;
}
@@ -171,6 +174,10 @@ std::string SysmanKmdInterfaceXe::getHwmonName(uint32_t subDeviceId, bool isSubd
return "xe";
}
std::vector<zes_power_domain_t> SysmanKmdInterfaceXe::getPowerDomains() const {
return {ZES_POWER_DOMAIN_CARD, ZES_POWER_DOMAIN_PACKAGE, ZES_POWER_DOMAIN_MEMORY, ZES_POWER_DOMAIN_GPU};
}
std::optional<std::string> SysmanKmdInterfaceXe::getEngineClassString(uint16_t engineClass) {
auto sysfEngineString = xeEngineClassToSysfsEngineMap.find(engineClass);
if (sysfEngineString == xeEngineClassToSysfsEngineMap.end()) {

View File

@@ -17,11 +17,29 @@ constexpr static auto gfxProduct = IGFX_BMG;
#include "level_zero/sysman/source/shared/linux/product_helper/sysman_product_helper_xe_hp_and_later.inl"
// XTAL clock frequency is denoted as an integer between [0-3] with a predefined value for each number.
// This vector defines the predefined value for each integer represented by the index of the vector.
static const std::vector<double> indexToXtalClockFrequecyMap = {24, 19.2, 38.4, 25};
static std::map<std::string, std::map<std::string, uint64_t>> guidToKeyOffsetMap = {
{"0x1e2f8200", // BMG PUNIT rev 1
{{"VRAM_BANDWIDTH", 56}}},
{{"XTAL_CLK_FREQUENCY", 4},
{"VRAM_BANDWIDTH", 56},
{"XTAL_COUNT", 1024},
{"VCCGT_ENERGY_ACCUMULATOR", 1628},
{"VCCDDR_ENERGY_ACCUMULATOR", 1640}}},
{"0x1e2f8201", // BMG PUNIT rev 2
{{"XTAL_CLK_FREQUENCY", 4},
{"ACCUM_PACKAGE_ENERGY", 48},
{"ACCUM_PSYS_ENERGY", 52},
{"VRAM_BANDWIDTH", 56},
{"XTAL_COUNT", 1024},
{"VCCGT_ENERGY_ACCUMULATOR", 1628},
{"VCCDDR_ENERGY_ACCUMULATOR", 1640}}},
{"0x5e2f8210", // BMG OOBMSM Rev 15
{{"SOC_THERMAL_SENSORS_TEMPERATURE_0_2_0_GTTMMADR[1]", 164},
{{"PACKAGE_ENERGY_STATUS_SKU_0_0_0_PCU", 136},
{"PLATFORM_ENERGY_STATUS", 140},
{"SOC_THERMAL_SENSORS_TEMPERATURE_0_2_0_GTTMMADR[1]", 164},
{"VRAM_TEMPERATURE_0_2_0_GTTMMADR", 168},
{"reg_PCIESS_rx_bytecount_lsb", 280},
{"reg_PCIESS_rx_bytecount_msb", 276},
@@ -275,7 +293,9 @@ static std::map<std::string, std::map<std::string, uint64_t>> guidToKeyOffsetMap
{"GDDR5_CH1_GT_64B_WR_REQ_UPPER", 1280},
{"GDDR5_CH1_GT_64B_WR_REQ_LOWER", 1284}}},
{"0x5e2f8211", // BMG OOBMSM Rev 16
{{"SOC_THERMAL_SENSORS_TEMPERATURE_0_2_0_GTTMMADR[1]", 164},
{{"PACKAGE_ENERGY_STATUS_SKU_0_0_0_PCU", 136},
{"PLATFORM_ENERGY_STATUS", 140},
{"SOC_THERMAL_SENSORS_TEMPERATURE_0_2_0_GTTMMADR[1]", 164},
{"VRAM_TEMPERATURE_0_2_0_GTTMMADR", 168},
{"reg_PCIESS_rx_bytecount_lsb", 280},
{"reg_PCIESS_rx_bytecount_msb", 284},
@@ -966,6 +986,95 @@ ze_result_t SysmanProductHelperHw<gfxProduct>::getGroupEngineBusynessFromSingleE
return ZE_RESULT_SUCCESS;
}
template <>
ze_result_t SysmanProductHelperHw<gfxProduct>::getPowerEnergyCounter(zes_power_energy_counter_t *pEnergy, LinuxSysmanImp *pLinuxSysmanImp, zes_power_domain_t powerDomain, uint32_t subdeviceId) {
const std::unordered_map<zes_power_domain_t, std::vector<std::string>> powerDomainToKeyMap = {
{ZES_POWER_DOMAIN_PACKAGE, {"ACCUM_PACKAGE_ENERGY", "PACKAGE_ENERGY_STATUS_SKU_0_0_0_PCU"}},
{ZES_POWER_DOMAIN_CARD, {"ACCUM_PSYS_ENERGY", "PLATFORM_ENERGY_STATUS"}},
{ZES_POWER_DOMAIN_MEMORY, {"VCCDDR_ENERGY_ACCUMULATOR"}},
{ZES_POWER_DOMAIN_GPU, {"VCCGT_ENERGY_ACCUMULATOR"}}};
auto powerDomainToKeyMapIter = powerDomainToKeyMap.find(powerDomain);
if (powerDomainToKeyMapIter == powerDomainToKeyMap.end()) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
std::string &rootPath = pLinuxSysmanImp->getPciRootPath();
std::map<uint32_t, std::string> telemNodes = {};
NEO::PmtUtil::getTelemNodesInPciPath(std::string_view(rootPath), telemNodes);
if (telemNodes.empty()) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
std::map<std::string, uint64_t> keyOffsetMap = {};
std::unordered_map<std::string, std::string> keyTelemInfoMap = {};
// Iterate through all the TelemNodes to find both OOBMSM and PUNIT guids along with their keyOffsetMap
for (const auto &telemNode : telemNodes) {
std::string telemNodeDir = telemNode.second;
std::array<char, NEO::PmtUtil::guidStringSize> guidString = {};
if (!NEO::PmtUtil::readGuid(telemNodeDir, guidString)) {
continue;
}
auto keyOffsetMapIterator = guidToKeyOffsetMap.find(guidString.data());
if (keyOffsetMapIterator == guidToKeyOffsetMap.end()) {
continue;
}
const auto &tempKeyOffsetMap = keyOffsetMapIterator->second;
for (auto it = tempKeyOffsetMap.begin(); it != tempKeyOffsetMap.end(); it++) {
keyOffsetMap[it->first] = it->second;
keyTelemInfoMap[it->first] = telemNodeDir;
}
}
if (keyOffsetMap.empty()) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
// Energy Counter calculation
uint32_t energyCounter = 0;
bool isReadValueSuccess = false;
for (const auto &key : powerDomainToKeyMapIter->second) {
if (PlatformMonitoringTech::readValue(keyOffsetMap, keyTelemInfoMap[key], key, 0, energyCounter)) {
isReadValueSuccess = true;
break;
}
}
if (!isReadValueSuccess) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;
}
// Energy counter is in U(18.14) format. Need to convert it into uint64_t and then in MicroJoule
const uint32_t energyIntegerPart = static_cast<uint32_t>(energyCounter >> 14);
const uint32_t energyDecimalBits = static_cast<uint32_t>((energyCounter & 0x3FFF));
const double energyDecimalPart = static_cast<double>(energyDecimalBits) / (1 << 14);
const double energyInJoules = static_cast<double>(energyIntegerPart + energyDecimalPart);
pEnergy->energy = static_cast<uint64_t>((energyInJoules * convertJouleToMicroJoule));
// Timestamp calcuation
uint64_t timestamp64 = 0;
std::string key = "XTAL_COUNT";
if (!PlatformMonitoringTech::readValue(keyOffsetMap, keyTelemInfoMap[key], key, 0, timestamp64)) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;
}
uint32_t frequency = 0;
key = "XTAL_CLK_FREQUENCY";
if (!PlatformMonitoringTech::readValue(keyOffsetMap, keyTelemInfoMap[key], key, 0, frequency)) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;
}
double timestamp = timestamp64 / indexToXtalClockFrequecyMap[frequency & 0x2];
pEnergy->timestamp = static_cast<uint64_t>(timestamp);
return ZE_RESULT_SUCCESS;
}
template class SysmanProductHelperHw<gfxProduct>;
} // namespace Sysman

View File

@@ -228,6 +228,7 @@ ze_result_t SysmanProductHelperHw<gfxProduct>::getPowerEnergyCounter(zes_power_e
// PMT will return energy counter in Q20 format(fixed point representation) where first 20 bits(from LSB) represent decimal part
// and remaining integral part which is converted into joule by division with 1048576(2^20) and then converted into microjoules
pEnergy->energy = (energyCounter / fixedPointToJoule) * convertJouleToMicroJoule;
pEnergy->timestamp = SysmanDevice::getSysmanTimestamp();
return ZE_RESULT_SUCCESS;
}

View File

@@ -7,6 +7,7 @@
set(L0_TESTS_SYSMAN_POWER_LINUX
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/test_zes_power.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_zes_power_xe.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test_zes_power_helper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mock_sysfs_power.h
)

View File

@@ -33,7 +33,7 @@ const std::string sustainedPowerLimit("power1_max");
const std::string sustainedPowerLimitInterval("power1_max_interval");
const std::string criticalPowerLimit1("curr1_crit");
const std::string criticalPowerLimit2("power1_crit");
const std::string energyCounterNode("energy1_input");
const std::string packageEnergyCounterNode("energy1_input");
const std::string defaultPowerLimit("power1_rated_max");
constexpr uint64_t expectedEnergyCounter = 123456785u;
constexpr uint64_t expectedEnergyCounterTile0 = 123456785u;
@@ -106,11 +106,11 @@ struct MockPowerSysfsAccessInterface : public L0::Sysman::SysFsAccessInterface {
return mockReadPeakResult;
}
val = criticalPowerLimitVal;
} else if (file.compare(i915HwmonDirTile0 + "/" + energyCounterNode) == 0) {
} else if (file.compare(i915HwmonDirTile0 + "/" + packageEnergyCounterNode) == 0) {
val = expectedEnergyCounterTile0;
} else if (file.compare(i915HwmonDirTile1 + "/" + energyCounterNode) == 0) {
} else if (file.compare(i915HwmonDirTile1 + "/" + packageEnergyCounterNode) == 0) {
val = expectedEnergyCounterTile1;
} else if (file.compare(i915HwmonDir + "/" + energyCounterNode) == 0) {
} else if (file.compare(i915HwmonDir + "/" + packageEnergyCounterNode) == 0) {
val = expectedEnergyCounter;
} else if (file.compare(i915HwmonDir + "/" + defaultPowerLimit) == 0) {
val = mockDefaultPowerLimitVal;
@@ -248,7 +248,7 @@ struct MockPowerSysfsAccessInterface : public L0::Sysman::SysFsAccessInterface {
}
bool fileExists(const std::string file) override {
if (file.find(energyCounterNode) != std::string::npos) {
if (file.find(packageEnergyCounterNode) != std::string::npos) {
return isEnergyCounterFilePresent;
} else if (file.find(sustainedPowerLimit) != std::string::npos) {
return isSustainedPowerLimitFilePresent;
@@ -304,19 +304,6 @@ class SysmanDevicePowerFixtureI915 : public SysmanDeviceFixture {
}
};
class SysmanDevicePowerFixtureXe : public SysmanDeviceFixture {
protected:
L0::Sysman::SysmanDevice *device = nullptr;
void SetUp() override {
SysmanDeviceFixture::SetUp();
device = pSysmanDevice;
pSysmanDeviceImp->pPowerHandleContext->handleList.clear();
}
void TearDown() override {
SysmanDeviceFixture::TearDown();
}
};
class SysmanDevicePowerMultiDeviceFixture : public SysmanMultiDeviceFixture {
protected:
L0::Sysman::SysmanDevice *device = nullptr;

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/helpers/string.h"
#include "level_zero/sysman/source/api/power/linux/sysman_os_power_imp.h"
#include "level_zero/sysman/source/device/sysman_device_imp.h"
#include "level_zero/sysman/source/shared/linux/sysman_fs_access_interface.h"
#include "level_zero/sysman/test/unit_tests/sources/linux/mock_sysman_fixture.h"
#include "level_zero/sysman/test/unit_tests/sources/shared/linux/kmd_interface/mock_sysman_kmd_interface_xe.h"
namespace L0 {
namespace Sysman {
namespace ult {
constexpr uint64_t expectedEnergyCounter = 123456785u;
const std::string xeHwmonDir("device/hwmon/hwmon1");
const std::string cardEnergyCounterNode("energy1_input");
const std::string packageEnergyCounterNode("energy2_input");
class MockXePowerSysfsAccess : public L0::Sysman::SysFsAccessInterface {
public:
ze_result_t mockScanDirEntriesResult = ZE_RESULT_SUCCESS;
ze_result_t mockReadResult = ZE_RESULT_SUCCESS;
std::vector<ze_result_t> mockReadValUnsignedLongResult{};
bool isCardEnergyCounterFilePresent = true;
bool isPackageEnergyCounterFilePresent = true;
ze_result_t read(const std::string file, std::string &val) override {
if (mockReadResult != ZE_RESULT_SUCCESS) {
return mockReadResult;
}
ze_result_t result = ZE_RESULT_ERROR_UNKNOWN;
if (file.compare(xeHwmonDir + "/" + "name") == 0) {
val = "xe";
result = ZE_RESULT_SUCCESS;
} else {
val = "";
result = ZE_RESULT_ERROR_NOT_AVAILABLE;
}
return result;
}
ze_result_t read(const std::string file, uint64_t &val) override {
ze_result_t result = ZE_RESULT_SUCCESS;
if (!mockReadValUnsignedLongResult.empty()) {
result = mockReadValUnsignedLongResult.front();
mockReadValUnsignedLongResult.erase(mockReadValUnsignedLongResult.begin());
if (result != ZE_RESULT_SUCCESS) {
return result;
}
}
if ((file.compare(xeHwmonDir + "/" + cardEnergyCounterNode) == 0) || (file.compare(xeHwmonDir + "/" + packageEnergyCounterNode) == 0)) {
val = expectedEnergyCounter;
} else {
result = ZE_RESULT_ERROR_NOT_AVAILABLE;
}
return result;
}
ze_result_t scanDirEntries(const std::string path, std::vector<std::string> &listOfEntries) override {
const std::string hwmonDir("device/hwmon");
if (mockScanDirEntriesResult != ZE_RESULT_SUCCESS) {
return mockScanDirEntriesResult;
}
if (path.compare(hwmonDir) == 0) {
listOfEntries.push_back("hwmon1");
return ZE_RESULT_SUCCESS;
}
return ZE_RESULT_ERROR_NOT_AVAILABLE;
}
bool fileExists(const std::string file) override {
if (file.find(cardEnergyCounterNode) != std::string::npos) {
return isCardEnergyCounterFilePresent;
} else if (file.find(packageEnergyCounterNode) != std::string::npos) {
return isPackageEnergyCounterFilePresent;
}
return false;
}
MockXePowerSysfsAccess() = default;
};
struct MockXePowerFsAccess : public L0::Sysman::FsAccessInterface {
MockXePowerFsAccess() = default;
};
class PublicLinuxPowerImp : public L0::Sysman::LinuxPowerImp {
public:
PublicLinuxPowerImp(L0::Sysman::OsSysman *pOsSysman, ze_bool_t onSubdevice, uint32_t subdeviceId, zes_power_domain_t powerDomain) : L0::Sysman::LinuxPowerImp(pOsSysman, onSubdevice, subdeviceId, powerDomain) {}
using L0::Sysman::LinuxPowerImp::isTelemetrySupportAvailable;
using L0::Sysman::LinuxPowerImp::pSysfsAccess;
};
class SysmanDevicePowerFixtureXe : public SysmanDeviceFixture {
protected:
L0::Sysman::SysmanDevice *device = nullptr;
MockXePowerFsAccess *pFsAccess = nullptr;
MockXePowerSysfsAccess *pSysfsAccess = nullptr;
MockSysmanKmdInterfaceXe *pSysmanKmdInterface = nullptr;
void SetUp() override {
SysmanDeviceFixture::SetUp();
device = pSysmanDevice;
pFsAccess = new MockXePowerFsAccess();
pSysfsAccess = new MockXePowerSysfsAccess();
pSysmanKmdInterface = new MockSysmanKmdInterfaceXe(pLinuxSysmanImp->getSysmanProductHelper());
pSysmanKmdInterface->pFsAccess.reset(pFsAccess);
pSysmanKmdInterface->pSysfsAccess.reset(pSysfsAccess);
pLinuxSysmanImp->pSysmanKmdInterface.reset(pSysmanKmdInterface);
pLinuxSysmanImp->pFsAccess = pFsAccess;
pSysfsAccess->mockScanDirEntriesResult = ZE_RESULT_SUCCESS;
}
void TearDown() override {
SysmanDeviceFixture::TearDown();
}
std::vector<zes_pwr_handle_t> getPowerHandles(uint32_t count) {
std::vector<zes_pwr_handle_t> handles(count, nullptr);
EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, handles.data()), ZE_RESULT_SUCCESS);
return handles;
}
};
} // namespace ult
} // namespace Sysman
} // namespace L0

View File

@@ -564,7 +564,7 @@ TEST_F(SysmanDevicePowerFixtureI915, GivenHwMonDoesNotExistAndTelemDataNotAvaila
TEST_F(SysmanDevicePowerFixtureI915, GivenValidPowerHandlesWithTelemetrySupportNotAvailableButSysfsReadSucceedsWhenGettingPowerEnergyCounterThenValidPowerReadingsRetrievedFromSysfsNode) {
zes_power_energy_counter_t energyCounter = {};
std::unique_ptr<PublicLinuxPowerImp> pLinuxPowerImp(new PublicLinuxPowerImp(pOsSysman, false, 0, ZES_POWER_DOMAIN_PACKAGE));
pLinuxPowerImp->isTelemetrySupportAvailable = true;
pLinuxPowerImp->isTelemetrySupportAvailable = false;
EXPECT_EQ(ZE_RESULT_SUCCESS, pLinuxPowerImp->getEnergyCounter(&energyCounter));
EXPECT_EQ(energyCounter.energy, expectedEnergyCounter);
}
@@ -588,14 +588,6 @@ TEST_F(SysmanDevicePowerFixtureI915, GivenValidPowerHandleWhenSettingPowerEnergy
}
}
TEST_F(SysmanDevicePowerFixtureXe, GivenKmdInterfaceWhenGettingSysFsFilenamesForPowerForXeVersionThenProperPathsAreReturned) {
auto pSysmanKmdInterface = std::make_unique<SysmanKmdInterfaceXe>(pLinuxSysmanImp->getSysmanProductHelper());
EXPECT_STREQ("energy1_input", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageEnergyCounterNode, 0, false).c_str());
EXPECT_STREQ("power1_rated_max", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageDefaultPowerLimit, 0, false).c_str());
EXPECT_STREQ("power1_max", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageSustainedPowerLimit, 0, false).c_str());
EXPECT_STREQ("power1_max_interval", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageSustainedPowerLimitInterval, 0, false).c_str());
}
} // namespace ult
} // namespace Sysman
} // namespace L0

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "level_zero/sysman/test/unit_tests/sources/power/linux/mock_sysfs_power_xe.h"
namespace L0 {
namespace Sysman {
namespace ult {
TEST_F(SysmanDevicePowerFixtureXe, GivenKmdInterfaceWhenGettingSysFsFilenamesForPowerForXeVersionThenProperPathsAreReturned) {
auto pSysmanKmdInterface = std::make_unique<SysmanKmdInterfaceXe>(pLinuxSysmanImp->getSysmanProductHelper());
EXPECT_STREQ("energy1_input", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNameCardEnergyCounterNode, 0, false).c_str());
EXPECT_STREQ("energy2_input", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageEnergyCounterNode, 0, false).c_str());
EXPECT_STREQ("power1_rated_max", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageDefaultPowerLimit, 0, false).c_str());
EXPECT_STREQ("power1_max", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageSustainedPowerLimit, 0, false).c_str());
EXPECT_STREQ("power1_max_interval", pSysmanKmdInterface->getSysfsFilePath(SysfsName::sysfsNamePackageSustainedPowerLimitInterval, 0, false).c_str());
}
TEST_F(SysmanDevicePowerFixtureXe, GivenComponentCountZeroWhenEnumeratingPowerDomainsWhenOnlySysfsNodesExistThenValidCountIsReturned) {
uint32_t count = 0;
EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS);
EXPECT_EQ(count, 2u);
}
} // namespace ult
} // namespace Sysman
} // namespace L0

View File

@@ -143,7 +143,7 @@ TEST_F(SysmanFixtureDeviceXe, GivenSysmanKmdInterfaceInstanceWhenCallingGetNativ
TEST_F(SysmanFixtureDeviceXe, GivenSysmanKmdInterfaceInstanceWhenCallingGetPowerDomainsThenValidPowerDomainsAreReturned) {
auto pSysmanKmdInterface = pLinuxSysmanImp->getSysmanKmdInterface();
std::vector<zes_power_domain_t> validPowerDomains = {ZES_POWER_DOMAIN_PACKAGE};
std::vector<zes_power_domain_t> validPowerDomains = {ZES_POWER_DOMAIN_PACKAGE, ZES_POWER_DOMAIN_CARD, ZES_POWER_DOMAIN_MEMORY, ZES_POWER_DOMAIN_GPU};
auto powerDomains = pSysmanKmdInterface->getPowerDomains();
std::unordered_set<zes_power_domain_t> outputPowerDomainList(powerDomains.begin(), powerDomains.end());
@@ -188,12 +188,13 @@ TEST_F(SysmanFixtureDeviceXe, GivenSysmanKmdInterfaceInstanceWhenCallingGpuBindA
EXPECT_STREQ("/sys/bus/pci/drivers/xe/unbind", pSysmanKmdInterface->getGpuUnBindEntry().c_str());
}
TEST_F(SysmanFixtureDeviceXe, GivenSysmanKmdInterfaceWhenGetEnergyCounterNodeFilePathIsCalledForDifferentPowerDomainsThenProperPathIsReturned) {
TEST_F(SysmanFixtureDeviceXe, GivenSysmanKmdInterfaceWhenGetEnergyCounterNodeFileIsCalledForDifferentPowerDomainsThenProperFileNameIsReturned) {
auto pSysmanKmdInterface = pLinuxSysmanImp->pSysmanKmdInterface.get();
std::string expectedFilePath = "energy1_input";
EXPECT_EQ(expectedFilePath, pSysmanKmdInterface->getEnergyCounterNodeFile(ZES_POWER_DOMAIN_CARD));
expectedFilePath = "energy2_input";
EXPECT_EQ(expectedFilePath, pSysmanKmdInterface->getEnergyCounterNodeFile(ZES_POWER_DOMAIN_PACKAGE));
expectedFilePath = "";
EXPECT_EQ(expectedFilePath, pSysmanKmdInterface->getEnergyCounterNodeFile(ZES_POWER_DOMAIN_CARD));
EXPECT_EQ(expectedFilePath, pSysmanKmdInterface->getEnergyCounterNodeFile(ZES_POWER_DOMAIN_UNKNOWN));
}

View File

@@ -14,6 +14,7 @@ if(UNIX)
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_frequency_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_ras_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_power_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_power_tests_xe.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_pmt_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_device_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sysman_product_helper_pci_tests.cpp

View File

@@ -19,8 +19,7 @@ constexpr uint32_t powerHandleComponentCount = 1u;
static int mockReadLinkSuccess(const char *path, char *buf, size_t bufsize) {
std::map<std::string, std::string> fileNameLinkMap = {
{sysfsPathTelem1, realPathTelem1},
};
{sysfsPathTelem1, realPathTelem1}};
auto it = fileNameLinkMap.find(std::string(path));
if (it != fileNameLinkMap.end()) {
std::memcpy(buf, it->second.c_str(), it->second.size());
@@ -43,7 +42,7 @@ static int mockOpenSuccess(const char *pathname, int flags) {
returnValue = 5;
} else if ((strPathName == telem1TelemFileName) || (strPathName == telem2TelemFileName) || (strPathName == telem3TelemFileName)) {
returnValue = 6;
} else if (strPathName.find(energyCounterNode) != std::string::npos) {
} else if (strPathName.find(packageEnergyCounterNode) != std::string::npos) {
returnValue = 7;
}
return returnValue;
@@ -160,8 +159,8 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleForPackageDomainWit
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
uint64_t telem1Offset = 0;
std::string validGuid = "0x4f9302";
constexpr uint64_t telem1Offset = 0;
constexpr std::string_view validGuid = "0x4f9302";
if (fd == 4) {
memcpy(buf, &telem1Offset, count);
} else if (fd == 5) {
@@ -178,13 +177,12 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleForPackageDomainWit
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, pLinuxPowerImp->getEnergyCounter(&energyCounter));
}
HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleForPackageDomainWithTelemetryOffsetReadFailsAndSysfsNodeReadAlsoFailsWhenGettingPowerEnergyCounterThenFailureIsReturned, IsDG2) {
HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleForPackageDomainWithTelemetrySupportAvailableAndTelemetryOffsetReadFailsWhenGettingPowerEnergyCounterThenFailureIsReturned, IsDG2) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
std::string invalidGuid = "0x4f9302";
if (fd == 4) {
count = -1;
}
@@ -204,8 +202,8 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleForPackageDomainWit
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
uint64_t telem1Offset = 0;
std::string invalidGuid = "0xABCDEFG";
constexpr uint64_t telem1Offset = 0;
constexpr std::string_view invalidGuid = "0xABCDEFG";
if (fd == 4) {
memcpy(buf, &telem1Offset, count);
} else if (fd == 5) {
@@ -228,8 +226,8 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandlesWithTelemetrySuppo
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
uint64_t telem1Offset = 0;
std::string validGuid = "0x4f9302";
constexpr uint64_t telem1Offset = 0;
constexpr std::string_view validGuid = "0x4f9302";
if (fd == 4) {
memcpy(buf, &telem1Offset, count);
@@ -256,6 +254,7 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandlesWithTelemetrySuppo
EXPECT_EQ(ZES_POWER_DOMAIN_PACKAGE, extProperties.domain);
zes_power_energy_counter_t energyCounter = {};
uint64_t timeStampInitial = SysmanDevice::getSysmanTimestamp();
EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetEnergyCounter(handle, &energyCounter));
// Calculate output energyCounter value
@@ -263,10 +262,11 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandlesWithTelemetrySuppo
uint64_t outputEnergyCounter = static_cast<uint64_t>((setEnergyCounter / fixedPointToJoule) * convertJouleToMicroJoule);
EXPECT_EQ(energyCounter.energy, outputEnergyCounter);
EXPECT_GE(energyCounter.timestamp, timeStampInitial);
}
}
HWTEST2_F(SysmanProductHelperPowerTest, GivenValidSubdevicePowerHandleForPackagePackageDomainWithTelemetrySupportNotAvailableAndSysfsNodeReadFailsWhenGettingPowerEnergyCounterThenFailureIsReturned, IsPVC) {
HWTEST2_F(SysmanProductHelperPowerTest, GivenValidSubdevicePowerHandleForPackageDomainWithTelemetrySupportNotAvailableAndSysfsNodeReadFailsWhenGettingPowerEnergyCounterThenFailureIsReturned, IsPVC) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkFailure);
pSysfsAccess->mockReadValUnsignedLongResult.push_back(ZE_RESULT_ERROR_NOT_AVAILABLE);
zes_power_energy_counter_t energyCounter = {};
@@ -496,6 +496,50 @@ HWTEST2_F(SysmanProductHelperPowerTest, GivenValidPowerHandleWhenWritingToSustai
using SysmanProductHelperPowerMultiDeviceTest = SysmanDevicePowerMultiDeviceFixture;
constexpr uint32_t powerHandleComponentCountMultiDevice = 3u;
HWTEST2_F(SysmanProductHelperPowerMultiDeviceTest, GivenValidPowerHandlesWithTelemetrySupportAvailableButNoTelemDataWhenGettingPowerEnergyCounterThenEnergyCounterIsRetrievedThroughSysfsNode, IsPVC) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
constexpr uint64_t telem1Offset = 0;
constexpr std::string_view validGuid = "0xb15a0edd";
if (fd == 4) {
memcpy(buf, &telem1Offset, count);
} else if (fd == 5) {
memcpy(buf, validGuid.data(), count);
}
return count;
});
auto handles = getPowerHandles(powerHandleComponentCountMultiDevice);
for (auto handle : handles) {
ASSERT_NE(nullptr, handle);
zes_power_properties_t properties = {};
zes_power_ext_properties_t extProperties = {};
properties.pNext = &extProperties;
extProperties.stype = ZES_STRUCTURE_TYPE_POWER_EXT_PROPERTIES;
EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetProperties(handle, &properties));
EXPECT_EQ(ZES_POWER_DOMAIN_PACKAGE, extProperties.domain);
zes_power_energy_counter_t energyCounter = {};
const uint64_t timeStampInitial = SysmanDevice::getSysmanTimestamp();
EXPECT_EQ(ZE_RESULT_SUCCESS, zesPowerGetEnergyCounter(handle, &energyCounter));
if (!properties.onSubdevice) {
EXPECT_EQ(energyCounter.energy, expectedEnergyCounter);
} else if (properties.subdeviceId == 0u) {
EXPECT_EQ(energyCounter.energy, expectedEnergyCounterTile0);
} else if (properties.subdeviceId == 1u) {
EXPECT_EQ(energyCounter.energy, expectedEnergyCounterTile1);
}
EXPECT_GE(energyCounter.timestamp, timeStampInitial);
}
}
HWTEST2_F(SysmanProductHelperPowerMultiDeviceTest, GivenSetPowerLimitsWhenGettingPowerLimitsThenLimitsSetEarlierAreRetrieved, IsXeHpOrXeHpcOrXeHpgCore) {
auto handles = getPowerHandles(powerHandleComponentCountMultiDevice);
for (auto handle : handles) {

View File

@@ -0,0 +1,360 @@
/*
* Copyright (C) 2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "level_zero/sysman/source/shared/linux/product_helper/sysman_product_helper.h"
#include "level_zero/sysman/test/unit_tests/sources/power/linux/mock_sysfs_power_xe.h"
namespace L0 {
namespace Sysman {
namespace ult {
const std::string_view telem2OffsetFileName("/sys/class/intel_pmt/telem2/offset");
const std::string_view telem2GuidFileName("/sys/class/intel_pmt/telem2/guid");
const std::string_view telem2TelemFileName("/sys/class/intel_pmt/telem2/telem");
const std::string_view telem3OffsetFileName("/sys/class/intel_pmt/telem3/offset");
const std::string_view telem3GuidFileName("/sys/class/intel_pmt/telem3/guid");
const std::string_view telem3TelemFileName("/sys/class/intel_pmt/telem3/telem");
using SysmanXeProductHelperPowerTest = SysmanDevicePowerFixtureXe;
constexpr uint32_t bmgPowerHandleComponentCount = 4u;
static int mockReadLinkSuccess(const char *path, char *buf, size_t bufsize) {
const std::string sysfsPathTelem1 = "/sys/class/intel_pmt/telem1";
const std::string sysfsPathTelem2 = "/sys/class/intel_pmt/telem2";
const std::string sysfsPathTelem3 = "/sys/class/intel_pmt/telem3";
const std::string realPathTelem1 = "/sys/devices/pci0000:00/0000:00:0a.0/intel_vsec.telemetry.0/intel_pmt/telem1";
const std::string realPathTelem2 = "/sys/devices/pci0000:00/0000:00:1c.4/0000:06:00.0/0000:07:01.0/0000:08:00.0/intel_vsec.telemetry.1/intel_pmt/telem2";
const std::string realPathTelem3 = "/sys/devices/pci0000:00/0000:00:1c.4/0000:06:00.0/0000:07:01.0/0000:08:00.0/intel_vsec.telemetry.1/intel_pmt/telem3";
std::map<std::string, std::string> fileNameLinkMap = {
{sysfsPathTelem1, realPathTelem1},
{sysfsPathTelem2, realPathTelem2},
{sysfsPathTelem3, realPathTelem3}};
auto it = fileNameLinkMap.find(std::string(path));
if (it != fileNameLinkMap.end()) {
std::memcpy(buf, it->second.c_str(), it->second.size());
return static_cast<int>(it->second.size());
}
return -1;
}
static int mockOpenSuccess(const char *pathname, int flags) {
int returnValue = -1;
std::string strPathName(pathname);
if ((strPathName == telem2OffsetFileName) || (strPathName == telem3OffsetFileName)) {
returnValue = 4;
} else if (strPathName == telem2GuidFileName) {
returnValue = 5;
} else if (strPathName == telem3GuidFileName) {
returnValue = 6;
} else if (strPathName == telem2TelemFileName) {
returnValue = 7;
} else if (strPathName == telem3TelemFileName) {
returnValue = 8;
}
return returnValue;
}
inline static int mockStatSuccess(const std::string &filePath, struct stat *statbuf) noexcept {
statbuf->st_mode = S_IWUSR | S_IRUSR | S_IFREG;
return 0;
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenComponentCountZeroWhenEnumeratingPowerDomainsWhenPmtSupportIsAvailableThenValidCountIsReturned, IsBMG) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
constexpr uint64_t telemOffset = 0;
constexpr std::string_view validOobmsmGuid = "0x5e2f8211";
constexpr std::string_view validPunitGuid = "0x1e2f8200";
if (fd == 4) {
memcpy(buf, &telemOffset, count);
} else if (fd == 5) {
memcpy(buf, validOobmsmGuid.data(), count);
} else if (fd == 6) {
memcpy(buf, validPunitGuid.data(), count);
}
return count;
});
uint32_t count = 0;
EXPECT_EQ(zesDeviceEnumPowerDomains(device->toHandle(), &count, nullptr), ZE_RESULT_SUCCESS);
EXPECT_EQ(count, bmgPowerHandleComponentCount);
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenSysmanProductHelperInstanceWhenGettingPowerEnergyCounterForUnknownPowerDomainThenFailureIsReturned, IsBMG) {
auto pSysmanProductHelper = L0::Sysman::SysmanProductHelper::create(defaultHwInfo->platform.eProductFamily);
zes_power_energy_counter_t energyCounter = {};
auto result = pSysmanProductHelper->getPowerEnergyCounter(&energyCounter, pLinuxSysmanImp, ZES_POWER_DOMAIN_UNKNOWN, 0u);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result);
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenSysmanProductHelperInstanceWhenGettingPowerEnergyCounterAndNoTelemNodesAreAvailableThenFailureIsReturned, IsBMG) {
auto pSysmanProductHelper = L0::Sysman::SysmanProductHelper::create(defaultHwInfo->platform.eProductFamily);
zes_power_energy_counter_t energyCounter = {};
auto result = pSysmanProductHelper->getPowerEnergyCounter(&energyCounter, pLinuxSysmanImp, ZES_POWER_DOMAIN_CARD, 0u);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result);
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenSysmanProductHelperInstanceWhenGettingPowerEnergyCounterAndReadGuidFailsFromPmtUtilThenFailureIsReturned, IsBMG) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
if (fd == 5 || fd == 6) {
count = -1;
}
return count;
});
auto pSysmanProductHelper = L0::Sysman::SysmanProductHelper::create(defaultHwInfo->platform.eProductFamily);
zes_power_energy_counter_t energyCounter = {};
auto result = pSysmanProductHelper->getPowerEnergyCounter(&energyCounter, pLinuxSysmanImp, ZES_POWER_DOMAIN_CARD, 0u);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result);
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenSysmanProductHelperInstanceWhenGettingPowerEnergyCounterAndKeyOffsetMapIsNotAvailableThenFailureIsReturned, IsBMG) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
constexpr uint64_t telemOffset = 0;
constexpr std::string_view dummyGuid = "0xABCDEF";
if (fd == 4) {
memcpy(buf, &telemOffset, count);
} else if (fd == 5 || fd == 6) {
memcpy(buf, dummyGuid.data(), count);
}
return count;
});
auto pSysmanProductHelper = L0::Sysman::SysmanProductHelper::create(defaultHwInfo->platform.eProductFamily);
zes_power_energy_counter_t energyCounter = {};
auto result = pSysmanProductHelper->getPowerEnergyCounter(&energyCounter, pLinuxSysmanImp, ZES_POWER_DOMAIN_CARD, 0u);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result);
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenSysmanProductHelperInstanceWhenGettingPowerEnergyCounterAndReadValueFailsForDifferentKeysThenFailureIsReturned, IsBMG) {
static int readFailCount = 1;
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
constexpr uint64_t telemOffset = 0;
constexpr std::string_view validOobmsmGuid = "0x5e2f8211";
constexpr std::string_view validPunitGuid = "0x1e2f8200";
if (fd == 4) {
memcpy(buf, &telemOffset, count);
} else if (fd == 5) {
memcpy(buf, validOobmsmGuid.data(), count);
} else if (fd == 6) {
memcpy(buf, validPunitGuid.data(), count);
} else if (fd == 7) {
switch (offset) {
case 140:
count = (readFailCount == 1) ? -1 : sizeof(uint32_t);
break;
default:
break;
}
} else if (fd == 8) {
switch (offset) {
case 4:
count = (readFailCount == 2) ? -1 : sizeof(uint32_t);
break;
case 1024:
count = (readFailCount == 3) ? -1 : sizeof(uint64_t);
break;
default:
break;
}
}
return count;
});
auto pSysmanProductHelper = L0::Sysman::SysmanProductHelper::create(defaultHwInfo->platform.eProductFamily);
zes_power_energy_counter_t energyCounter = {};
while (readFailCount <= 3) {
auto result = pSysmanProductHelper->getPowerEnergyCounter(&energyCounter, pLinuxSysmanImp, ZES_POWER_DOMAIN_CARD, 0u);
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, result);
readFailCount++;
}
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenValidPowerHandlesWhenGettingPowerEnergyCounterThenValidValuesAreReturnedFromBothOobmsmAndPunitPath, IsBMG) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
uint64_t telemOffset = 0;
constexpr std::string_view validOobmsmGuid = "0x5e2f8211";
constexpr std::string_view validPunitGuid = "0x1e2f8200";
constexpr uint32_t mockEnergyCounter = 0xabcd;
constexpr uint32_t mockXtalFrequency = 0xef;
constexpr uint64_t mockTimestamp = 0xabef;
if (fd == 4) {
memcpy(buf, &telemOffset, count);
} else if (fd == 5) {
memcpy(buf, validOobmsmGuid.data(), count);
} else if (fd == 6) {
memcpy(buf, validPunitGuid.data(), count);
} else if (fd == 7) {
switch (offset) {
case 136:
case 140:
memcpy(buf, &mockEnergyCounter, count);
break;
default:
break;
}
} else if (fd == 8) {
switch (offset) {
case 4:
memcpy(buf, &mockXtalFrequency, count);
break;
case 1024:
memcpy(buf, &mockTimestamp, count);
break;
case 1628:
case 1640:
memcpy(buf, &mockEnergyCounter, count);
break;
default:
break;
}
}
return count;
});
constexpr uint32_t mockEnergyCounter = 0xabcd;
constexpr uint32_t mockXtalFrequency = 0xef;
constexpr uint64_t mockTimestamp = 0xabef;
constexpr double indexToXtalClockFrequecyMap[4] = {24, 19.2, 38.4, 25};
auto handles = getPowerHandles(bmgPowerHandleComponentCount);
for (auto handle : handles) {
zes_power_energy_counter_t energyCounter = {};
auto result = zesPowerGetEnergyCounter(handle, &energyCounter);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
const uint32_t integerPart = static_cast<uint32_t>(mockEnergyCounter >> 14);
const uint32_t decimalBits = static_cast<uint32_t>(mockEnergyCounter & 0x3FFF);
const double decimalPart = static_cast<double>(decimalBits) / (1 << 14);
const double finalValue = static_cast<double>(integerPart + decimalPart);
const uint64_t expectedEnergyCounter = static_cast<uint64_t>((finalValue * convertJouleToMicroJoule));
EXPECT_EQ(expectedEnergyCounter, energyCounter.energy);
const double timestamp = mockTimestamp / indexToXtalClockFrequecyMap[mockXtalFrequency & 0x2];
const uint64_t expectedTimestamp = static_cast<uint64_t>(timestamp);
EXPECT_EQ(expectedTimestamp, energyCounter.timestamp);
}
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenValidPowerHandlesWhenGettingPowerEnergyCounterThenAllValidValuesAreReturnedFromPunitPath, IsBMG) {
VariableBackup<decltype(NEO::SysCalls::sysCallsReadlink)> mockReadLink(&NEO::SysCalls::sysCallsReadlink, &mockReadLinkSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsStat)> mockStat(&NEO::SysCalls::sysCallsStat, &mockStatSuccess);
VariableBackup<decltype(NEO::SysCalls::sysCallsOpen)> mockOpen(&NEO::SysCalls::sysCallsOpen, &mockOpenSuccess);
VariableBackup<bool> allowFakeDevicePathBackup(&NEO::SysCalls::allowFakeDevicePath, true);
VariableBackup<decltype(NEO::SysCalls::sysCallsPread)> mockPread(&NEO::SysCalls::sysCallsPread, [](int fd, void *buf, size_t count, off_t offset) -> ssize_t {
uint64_t telemOffset = 0;
constexpr std::string_view validOobmsmGuid = "0x5e2f8211";
constexpr std::string_view validPunitGuid = "0x1e2f8201";
constexpr uint32_t mockEnergyCounter = 0xabcd;
constexpr uint32_t mockXtalFrequency = 0xef;
constexpr uint64_t mockTimestamp = 0xabef;
if (fd == 4) {
memcpy(buf, &telemOffset, count);
} else if (fd == 5) {
memcpy(buf, validOobmsmGuid.data(), count);
} else if (fd == 6) {
memcpy(buf, validPunitGuid.data(), count);
} else if (fd == 7) {
switch (offset) {
case 136:
case 140:
memcpy(buf, &mockEnergyCounter, count);
break;
default:
break;
}
} else if (fd == 8) {
switch (offset) {
case 4:
memcpy(buf, &mockXtalFrequency, count);
break;
case 1024:
memcpy(buf, &mockTimestamp, count);
break;
case 48:
case 52:
case 1628:
case 1640:
memcpy(buf, &mockEnergyCounter, count);
break;
default:
break;
}
}
return count;
});
constexpr uint32_t mockEnergyCounter = 0xabcd;
constexpr uint32_t mockXtalFrequency = 0xef;
constexpr uint64_t mockTimestamp = 0xabef;
constexpr double indexToXtalClockFrequecyMap[4] = {24, 19.2, 38.4, 25};
auto handles = getPowerHandles(bmgPowerHandleComponentCount);
for (auto handle : handles) {
zes_power_energy_counter_t energyCounter = {};
auto result = zesPowerGetEnergyCounter(handle, &energyCounter);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
const uint32_t integerPart = static_cast<uint32_t>(mockEnergyCounter >> 14);
const uint32_t decimalBits = static_cast<uint32_t>(mockEnergyCounter & 0x3FFF);
const double decimalPart = static_cast<double>(decimalBits) / (1 << 14);
const double finalValue = static_cast<double>(integerPart + decimalPart);
const uint64_t expectedEnergyCounter = static_cast<uint64_t>((finalValue * convertJouleToMicroJoule));
EXPECT_EQ(expectedEnergyCounter, energyCounter.energy);
const double timestamp = mockTimestamp / indexToXtalClockFrequecyMap[mockXtalFrequency & 0x2];
const uint64_t expectedTimestamp = static_cast<uint64_t>(timestamp);
EXPECT_EQ(expectedTimestamp, energyCounter.timestamp);
}
}
HWTEST2_F(SysmanXeProductHelperPowerTest, GivenValidPowerHandlesWithTelemetrySupportNotAvailableButSysfsReadSucceedsWhenGettingPowerEnergyCounterThenValidPowerReadingsRetrievedFromSysfsNode, IsBMG) {
std::vector<zes_power_domain_t> powerDomains = {ZES_POWER_DOMAIN_PACKAGE, ZES_POWER_DOMAIN_CARD};
for (const auto &powerDomain : powerDomains) {
zes_power_energy_counter_t energyCounter = {};
std::unique_ptr<PublicLinuxPowerImp> pLinuxPowerImp(new PublicLinuxPowerImp(pOsSysman, false, 0, powerDomain));
pLinuxPowerImp->isTelemetrySupportAvailable = false;
const uint64_t timeStampInitial = SysmanDevice::getSysmanTimestamp();
EXPECT_EQ(ZE_RESULT_SUCCESS, pLinuxPowerImp->getEnergyCounter(&energyCounter));
EXPECT_EQ(energyCounter.energy, expectedEnergyCounter);
EXPECT_GE(energyCounter.timestamp, timeStampInitial);
}
}
} // namespace ult
} // namespace Sysman
} // namespace L0