diff --git a/conformance_tests/sysman/test_sysman_power/CMakeLists.txt b/conformance_tests/sysman/test_sysman_power/CMakeLists.txt index 4d0c3642e..772d4d966 100644 --- a/conformance_tests/sysman/test_sysman_power/CMakeLists.txt +++ b/conformance_tests/sysman/test_sysman_power/CMakeLists.txt @@ -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 +) diff --git a/conformance_tests/sysman/test_sysman_power/src/test_sysman_power.cpp b/conformance_tests/sysman/test_sysman_power/src/test_sysman_power.cpp index 0612cee09..2d13e79f7 100644 --- a/conformance_tests/sysman/test_sysman_power/src/test_sysman_power.cpp +++ b/conformance_tests/sysman/test_sysman_power/src/test_sysman_power.cpp @@ -6,13 +6,22 @@ * */ +#include +#include +#include +#include + #include "gtest/gtest.h" #include #include "logging/logging.hpp" #include "utils/utils.hpp" #include "test_harness/test_harness.hpp" #include + namespace lzt = level_zero_tests; +namespace bp = boost::process; +namespace fs = boost::filesystem; +namespace bi = boost::interprocess; #include @@ -183,6 +192,130 @@ LZT_TEST_F( } } } +struct powerInfo { + uint32_t interval; + uint32_t limit; + bool limitValueLocked; +}; +struct powerDomains { + zes_uuid_t uuid; + std::vector power_info_list; +}; +LZT_TEST_F( + POWER_TEST, + MultiProcessTestSetValidPowerLimitInParentProcessAndReadInChildProcess) { + // run test for all available devices + std::vector 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> power_limits_descriptors_initial(p_power_handles.size()); + for (size_t p = 0; p < p_power_handles.size(); ++p) { + EXPECT_NE(nullptr, p_power_handles[p]); + + uint32_t count_power = 0; + std::vector 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) { + 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 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); + 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)); + + // 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 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) { diff --git a/conformance_tests/sysman/test_sysman_power/src/test_sysman_power_process_helper.cpp b/conformance_tests/sysman/test_sysman_power/src/test_sysman_power_process_helper.cpp new file mode 100644 index 000000000..0c7759c69 --- /dev/null +++ b/conformance_tests/sysman/test_sysman_power/src/test_sysman_power_process_helper.cpp @@ -0,0 +1,108 @@ +/* + * + * Copyright (C) 2020-2025 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include +#include + +#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 { + 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(region.get_address()); + std::vector 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 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 " <