Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion conformance_tests/sysman/test_sysman_power/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ add_lzt_test(
level_zero_tests::utils
DEFINES USE_ZESINIT
)

add_lzt_test_executable(
NAME test_sysman_power_process_helper
GROUP "/conformance_tests/tools/sysman"
PREFIX "process" # install to prefix so it's not confused for a test
SOURCES
src/test_sysman_power_process_helper.cpp
LINK_LIBRARIES
level_zero_tests::logging
level_zero_tests::utils
)
133 changes: 133 additions & 0 deletions conformance_tests/sysman/test_sysman_power/src/test_sysman_power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
*
*/

#include <boost/process.hpp>
#include <boost/filesystem.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

#include "gtest/gtest.h"
#include <thread>
#include "logging/logging.hpp"
#include "utils/utils.hpp"
#include "test_harness/test_harness.hpp"
#include <chrono>

namespace lzt = level_zero_tests;
namespace bp = boost::process;
namespace fs = boost::filesystem;
namespace bi = boost::interprocess;

#include <level_zero/zes_api.h>

Expand Down Expand Up @@ -183,6 +192,130 @@ LZT_TEST_F(
}
}
}
struct powerInfo {
Copy link

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'powerInfo' struct is duplicated between files. Consider defining it in a shared header file to avoid code duplication and ensure consistency.

Copilot uses AI. Check for mistakes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems valid comment. @Sarbojit2019 Could you please address this?

uint32_t interval;
uint32_t limit;
bool limitValueLocked;
};
struct powerDomains {
zes_uuid_t uuid;
std::vector<powerInfo> power_info_list;
};
LZT_TEST_F(
POWER_TEST,
MultiProcessTestSetValidPowerLimitInParentProcessAndReadInChildProcess) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please follow a Given..When..Then.. way of naming a test case?

// run test for all available devices
std::vector<powerDomains> pd(devices.size());
for (size_t d = 0; d < devices.size(); ++d) {
uint32_t count = 0;
auto p_power_handles = lzt::get_power_handles(devices[d], count);
if (count == 0) {
FAIL() << "No handles found: "
<< _ze_result_t(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE);
}

// loop through all power domains and set the power limit

//step 1: i) Preserve initial power limit descriptors for restoration later
// ii) Set the power limit and verify the setting
std::vector<std::vector<zes_power_limit_ext_desc_t>> power_limits_descriptors_initial(p_power_handles.size());
for (size_t p = 0; p < p_power_handles.size(); ++p) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless you're modifying the elements of the vector power_handles, I think simple for loop declaration such as follow would be more concise just to access the elements.
for (auto &power_handle: power_handles)

EXPECT_NE(nullptr, p_power_handles[p]);

uint32_t count_power = 0;
std::vector<zes_power_limit_ext_desc_t> power_limits_descriptors;
auto status = lzt::get_power_limits_ext(
p_power_handles[p], &count_power,
power_limits_descriptors);
if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) {
continue;
}
EXPECT_ZE_RESULT_SUCCESS(status);
// set power limit
zes_power_limit_ext_desc_t power_peak_set = {};
for (auto &power_limits_descriptor : power_limits_descriptors) {
power_limits_descriptors_initial[p].push_back(power_limits_descriptor);
if (power_limits_descriptor.level == ZES_POWER_LEVEL_PEAK) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you're implementing this test only for PEAK power limit?
I believe this test should be implemented for all the available power limits.

power_peak_set = power_limits_descriptor;
power_peak_set.limit = power_limits_descriptor.limit - 1000;
power_limits_descriptor.limit = power_peak_set.limit;
}
}

if (power_peak_set.limitValueLocked == false) {
// store power info into the list for sharing it with child process
powerInfo p_info;
p_info.limit = power_peak_set.limit;
p_info.interval = power_peak_set.interval;
p_info.limitValueLocked = power_peak_set.limitValueLocked;
pd[d].power_info_list.push_back(p_info);

status = lzt::set_power_limits_ext(p_power_handles[p], &count_power,
power_limits_descriptors.data());
if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) {
continue;
}
EXPECT_ZE_RESULT_SUCCESS(status);

// Read power limits to confirm power limit is set
zes_power_limit_ext_desc_t power_peak_get = {};
std::vector<zes_power_limit_ext_desc_t> power_limits_descriptors_get;
status = lzt::get_power_limits_ext(p_power_handles[p], &count_power,
power_limits_descriptors_get);
if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) {
continue;
}
EXPECT_ZE_RESULT_SUCCESS(status);
for (const auto &p_power_limits_descriptor_get :
power_limits_descriptors_get) {
if (p_power_limits_descriptor_get.level == ZES_POWER_LEVEL_PEAK) {
power_peak_get = p_power_limits_descriptor_get;
}
}
EXPECT_EQ(power_peak_get.limitValueLocked, power_peak_set.limitValueLocked);
EXPECT_EQ(power_peak_get.interval, power_peak_set.interval);
EXPECT_EQ(power_peak_get.limit, power_peak_set.limit);
}
}

// step 2: Launch child process and share power limits set
// create named shared object and copy all power settings
zes_uuid_t uuid = lzt::get_sysman_device_uuid(devices[d]);

bi::shared_memory_object::remove("MultiProcPowerLimitSharedMemory");
bi::shared_memory_object power_limit_shm(bi::create_only, "MultiProcPowerLimitSharedMemory", bi::read_write);
Copy link

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared memory object name 'MultiProcPowerLimitSharedMemory' is hardcoded in multiple places. Consider defining it as a constant to improve maintainability.

Suggested change
bi::shared_memory_object power_limit_shm(bi::create_only, "MultiProcPowerLimitSharedMemory", bi::read_write);
bi::shared_memory_object::remove(MULTI_PROC_POWER_LIMIT_SHARED_MEMORY_NAME);
bi::shared_memory_object power_limit_shm(bi::create_only, MULTI_PROC_POWER_LIMIT_SHARED_MEMORY_NAME, bi::read_write);

Copilot uses AI. Check for mistakes.

power_limit_shm.truncate(ZES_MAX_UUID_SIZE+pd[d].power_info_list.size()*sizeof(powerInfo));
bi::mapped_region mapped_region(power_limit_shm, bi::read_write);
std::memcpy(mapped_region.get_address(), uuid.id, ZES_MAX_UUID_SIZE);
std::memcpy(((char*)mapped_region.get_address())+ZES_MAX_UUID_SIZE, pd[d].power_info_list.data(), pd[d].power_info_list.size()*sizeof(powerInfo));
Copy link

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The pointer arithmetic and casting make this line complex and hard to read. Consider using a more explicit approach with offset variables or helper functions.

Suggested change
std::memcpy(((char*)mapped_region.get_address())+ZES_MAX_UUID_SIZE, pd[d].power_info_list.data(), pd[d].power_info_list.size()*sizeof(powerInfo));
size_t power_info_offset = ZES_MAX_UUID_SIZE;
std::memcpy(static_cast<char*>(mapped_region.get_address()) + power_info_offset,
pd[d].power_info_list.data(),
pd[d].power_info_list.size() * sizeof(powerInfo));

Copilot uses AI. Check for mistakes.


// launch child process with power_handle_count
auto env = boost::this_process::environment();
fs::path helper_path(fs::current_path() / "process");
bp::environment child_env = env;
std::vector<fs::path> paths;
paths.push_back(helper_path);
fs::path helper = bp::search_path("test_sysman_power_process_helper", paths);
bp::child get_power_limit_in_child_proc(helper,bp::args({std::to_string(p_power_handles.size())}), child_env);
get_power_limit_in_child_proc.wait();

// check child process return status to decide test pass/fail.
EXPECT_EQ(get_power_limit_in_child_proc.exit_code(), 0);

// Step 3 : Restore power limits back to original
for (size_t p = 0; p < p_power_handles.size(); ++p) {
EXPECT_NE(nullptr, p_power_handles[p]);
uint32_t count_power = 0;
auto status = lzt::set_power_limits_ext(
p_power_handles[p], &count_power,
power_limits_descriptors_initial[p].data()); // restore initial limits
if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) {
continue;
}
EXPECT_ZE_RESULT_SUCCESS(status);
}
}
}
LZT_TEST_F(
POWER_TEST,
GivenValidPowerHandleWhenRequestingPowerLimitsThenExpectzesSysmanPowerGetLimitsToReturnSameValuesTwice) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
*
* Copyright (C) 2020-2025 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

#include "utils/utils.hpp"
#include "test_harness/test_harness.hpp"
#include "logging/logging.hpp"

namespace lzt = level_zero_tests;
namespace bp = boost::process;
namespace bi = boost::interprocess;

struct powerInfo {
Copy link

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'powerInfo' struct is duplicated between this file and test_sysman_power.cpp. Consider moving this shared structure to a common header file to avoid code duplication and ensure consistency.

Copilot uses AI. Check for mistakes.

uint32_t interval;
uint32_t limit;
bool limitValueLocked;
};

void GetPowerLimitsSetByParentProcess(uint32_t power_handle_size, bool &test_result) {
//1. read shared object
bi::shared_memory_object power_limit_shm(bi::open_only, "MultiProcPowerLimitSharedMemory", bi::read_only);
bi::mapped_region region(power_limit_shm, bi::read_only);
char* data = static_cast<char*>(region.get_address());
std::vector<powerInfo> power_limits_set;
power_limits_set.resize(power_handle_size);
zes_uuid_t uuid;
memcpy(uuid.id, data, ZES_MAX_UUID_SIZE);
memcpy(power_limits_set.data(), data+ZES_MAX_UUID_SIZE, power_handle_size*sizeof(powerInfo));

//2. read power limits set for the device
auto driver = lzt::get_default_zes_driver();
auto dev_count = lzt::get_zes_device_count(driver);
auto devices = lzt::get_zes_devices(dev_count, driver);
for (auto device : devices) {
zes_uuid_t id = lzt::get_sysman_device_uuid(device);
if (lzt::is_uuid_pair_equal(id.id, uuid.id)) {
uint32_t count = 0;
auto p_power_handles = lzt::get_power_handles(device, count);
if (count == 0) {
FAIL() << "No handles found: "
<< _ze_result_t(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE);
test_result = false;
}

for (size_t p = 0; p < p_power_handles.size(); ++p) {
EXPECT_NE(nullptr, p_power_handles[p]);
uint32_t count_power = 0;
zes_power_limit_ext_desc_t power_peak_get = {};
std::vector<zes_power_limit_ext_desc_t> power_limits_descriptors;
auto status = lzt::get_power_limits_ext(
p_power_handles[p], &count_power,
power_limits_descriptors); // get power limits for all descriptors
if (status == ZE_RESULT_ERROR_UNSUPPORTED_FEATURE) {
continue;
}
EXPECT_ZE_RESULT_SUCCESS(status);
for (const auto &p_power_limits_descriptor : power_limits_descriptors) {
if (p_power_limits_descriptor.level == ZES_POWER_LEVEL_PEAK) {
power_peak_get = p_power_limits_descriptor;
}
}

EXPECT_EQ(power_peak_get.limitValueLocked,
power_limits_set[p].limitValueLocked);
EXPECT_EQ(power_peak_get.interval,
power_limits_set[p].interval);
EXPECT_EQ(power_peak_get.limit, power_limits_set[p].limit);

// Need to notify parent process about failure
if (power_peak_get.limitValueLocked != power_limits_set[p].limitValueLocked ||
power_peak_get.interval != power_limits_set[p].interval ||
power_peak_get.limit != (power_limits_set[p].limit)) {
test_result = false;
return;
}
}
}
}
}

int main(int argc, char **argv) {
if (argc != 2) {
LOG_INFO << "Insufficient argument count " <<argc;
Copy link

Copilot AI Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space before '<<argc' in the log message. Should be 'LOG_INFO << "Insufficient argument count " << argc;'

Suggested change
LOG_INFO << "Insufficient argument count " <<argc;
LOG_INFO << "Insufficient argument count " << argc;

Copilot uses AI. Check for mistakes.

return 1;
}

// Parent thread should pass number of power handles as argument
uint32_t power_handle_size = std::stoi(argv[1]);

ze_result_t result = zesInit(0);
if (result != ZE_RESULT_SUCCESS) {
exit(1);
}

bool test_result = true;
GetPowerLimitsSetByParentProcess(power_handle_size, test_result);
if (test_result == false) {
return 1; // test failed, report the same to parent process
}
return 0;
}
Loading