/* * Copyright (c) Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include // NOLINT [build] #include #include #include #include #include #include "../test_base.h" #include "amd_smi/amdsmi.h" #include "rocm_smi/rocm_smi_utils.h" #include "amd_smi/impl/amd_smi_utils.h" #include "computepartition_read_write.h" TestComputePartitionReadWrite::TestComputePartitionReadWrite() : TestBase() { set_title("AMDSMI Compute Partition Read/Write Test"); set_description("The Compute Partition tests verifies that the compute " "partition can be read and updated properly."); } TestComputePartitionReadWrite::~TestComputePartitionReadWrite(void) { } void TestComputePartitionReadWrite::SetUp(void) { TestBase::SetUp(); return; } void TestComputePartitionReadWrite::DisplayTestInfo(void) { TestBase::DisplayTestInfo(); } void TestComputePartitionReadWrite::DisplayResults(void) const { TestBase::DisplayResults(); return; } void TestComputePartitionReadWrite::Close() { // This will close handles opened within rsmitst utility calls and call // amdsmi_shut_down(), so it should be done after other hsa cleanup TestBase::Close(); } const uint32_t MAX_UNSUPPORTED_PARTITIONS = 0; const uint32_t MAX_SPX_PARTITIONS = 1; // Single GPU node const uint32_t MAX_DPX_PARTITIONS = 2; const uint32_t MAX_TPX_PARTITIONS = 3; const uint32_t MAX_QPX_PARTITIONS = 4; // const uint32_t MAX_CPX_PARTITIONS = 8; static const std::string computePartitionString(amdsmi_compute_partition_type_t computeParitionType) { /** * typedef enum { * AMDSMI_COMPUTE_PARTITION_INVALID = 0, * AMDSMI_COMPUTE_PARTITION_SPX, //!< Single GPU mode (SPX)- All XCCs work * //!< together with shared memory * AMDSMI_COMPUTE_PARTITION_DPX, //!< Dual GPU mode (DPX)- Half XCCs work * //!< together with shared memory * AMDSMI_COMPUTE_PARTITION_TPX, //!< Triple GPU mode (TPX)- One-third XCCs * //!< work together with shared memory * AMDSMI_COMPUTE_PARTITION_QPX, //!< Quad GPU mode (QPX)- Quarter XCCs * //!< work together with shared memory * AMDSMI_COMPUTE_PARTITION_CPX, //!< Core mode (CPX)- Per-chip XCC with * //!< shared memory * } amdsmi_compute_partition_type_t; * */ switch (computeParitionType) { case AMDSMI_COMPUTE_PARTITION_SPX: return "SPX"; case AMDSMI_COMPUTE_PARTITION_DPX: return "DPX"; case AMDSMI_COMPUTE_PARTITION_TPX: return "TPX"; case AMDSMI_COMPUTE_PARTITION_QPX: return "QPX"; case AMDSMI_COMPUTE_PARTITION_CPX: return "CPX"; default: return "N/A"; } } static const std::map mapStringToSMIComputePartitionTypes { {"SPX", AMDSMI_COMPUTE_PARTITION_SPX}, {"DPX", AMDSMI_COMPUTE_PARTITION_DPX}, {"TPX", AMDSMI_COMPUTE_PARTITION_TPX}, {"QPX", AMDSMI_COMPUTE_PARTITION_QPX}, {"CPX", AMDSMI_COMPUTE_PARTITION_CPX}, {"UNKNOWN", AMDSMI_COMPUTE_PARTITION_INVALID} }; static const std::map resource_types_map = { { AMDSMI_ACCELERATOR_XCC, "XCC" }, { AMDSMI_ACCELERATOR_ENCODER, "ENCODER" }, { AMDSMI_ACCELERATOR_DECODER, "DECODER" }, { AMDSMI_ACCELERATOR_DMA, "DMA" }, { AMDSMI_ACCELERATOR_JPEG, "JPEG" }, { AMDSMI_ACCELERATOR_MAX, "MAX" }, }; static const std::map partition_types_map = { { AMDSMI_ACCELERATOR_PARTITION_INVALID, "N/A" }, { AMDSMI_ACCELERATOR_PARTITION_SPX, "SPX" }, { AMDSMI_ACCELERATOR_PARTITION_DPX, "DPX" }, { AMDSMI_ACCELERATOR_PARTITION_TPX, "TPX" }, { AMDSMI_ACCELERATOR_PARTITION_QPX, "QPX" }, { AMDSMI_ACCELERATOR_PARTITION_CPX, "CPX" }, { AMDSMI_ACCELERATOR_PARTITION_MAX, "MAX" }, }; static const std::map accelerator_types_map = { { AMDSMI_ACCELERATOR_PARTITION_INVALID, "AMDSMI_ACCELERATOR_PARTITION_INVALID" }, { AMDSMI_ACCELERATOR_PARTITION_SPX, "AMDSMI_ACCELERATOR_PARTITION_SPX" }, { AMDSMI_ACCELERATOR_PARTITION_DPX, "AMDSMI_ACCELERATOR_PARTITION_DPX" }, { AMDSMI_ACCELERATOR_PARTITION_TPX, "AMDSMI_ACCELERATOR_PARTITION_TPX" }, { AMDSMI_ACCELERATOR_PARTITION_QPX, "AMDSMI_ACCELERATOR_PARTITION_QPX" }, { AMDSMI_ACCELERATOR_PARTITION_CPX, "AMDSMI_ACCELERATOR_PARTITION_CPX" }, { AMDSMI_ACCELERATOR_PARTITION_MAX, "AMDSMI_ACCELERATOR_PARTITION_MAX" }, }; static void system_wait(int seconds) { // Adding a delay - since changing partitions depends on gpus not // being in an active state, we'll wait a few seconds before starting // full testing auto start = std::chrono::high_resolution_clock::now(); int waitTime = seconds; std::cout << "** Waiting for " << std::dec << waitTime << " seconds, for any GPU" << " activity to clear up. **" << std::endl; sleep(waitTime); auto stop = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(stop - start); std::cout << "** Waiting took " << duration.count() / 1000000 << " seconds **" << std::endl; } static void getProcessorHandles(amdsmi_processor_handle* processor_handles, uint32_t curr_num_devices) { if (processor_handles == nullptr) { // resize the processor_handles array processor_handles = new amdsmi_processor_handle[curr_num_devices]; } for (uint32_t i = 0; i < curr_num_devices; i++) { amdsmi_processor_handle p_handle = {}; smi_amdgpu_get_processor_handle_by_index(i, &p_handle); processor_handles[i] = p_handle; std::cout << "\t**getProcessorHandles() | processor_handles[" << std::setfill('0') << std::setw(2) << i << "]:\t" << processor_handles[i] << std::endl; } } static void checkPartitionIdChanges(amdsmi_processor_handle* const processor_handle, uint32_t dev_id, const std::string current_partition, bool isVerbose, bool reinitialize) { uint32_t max_loop = 0; uint32_t current_num_devices = 0; uint32_t dev = 0; uint32_t prev_num_devices = 0; smi_amdgpu_get_device_count(&prev_num_devices); // re-initialize to ensure new device ordering is followed if (reinitialize) { if (isVerbose) { std::cout << "\t**REINITIALIZING device list due to parition changes.\n"; } amdsmi_shut_down(); amdsmi_init(AMDSMI_INIT_AMD_GPUS); } smi_amdgpu_get_device_count(¤t_num_devices); // std::cout << "\t**Checking Partition ID Changes 3\n"; if (isVerbose) { std::cout << "\t**Device (dev) #: " << dev << "; Device dev_id: " << dev_id << "; max_loop: " << static_cast(max_loop) << "; current_num_devices: " << current_num_devices << "\n"; } // Allocate the memory for the device handlers on the socket std::vector curr_processor_handles(current_num_devices); getProcessorHandles(&curr_processor_handles[0], current_num_devices); if (current_partition == "SPX" || current_partition == "N/A") { max_loop = MAX_SPX_PARTITIONS; } else if (current_partition == "DPX") { max_loop = MAX_DPX_PARTITIONS; } else if (current_partition == "TPX") { max_loop = MAX_TPX_PARTITIONS; } else if (current_partition == "QPX") { max_loop = MAX_QPX_PARTITIONS; } else if (current_partition == "CPX") { uint16_t num_xcd; auto ret = amdsmi_get_gpu_xcd_counter(curr_processor_handles[dev_id], &num_xcd); if (ret == AMDSMI_STATUS_SUCCESS) { max_loop = static_cast(num_xcd); if (isVerbose) { std::cout << "\t**Expecting num_xcd = " << num_xcd << " to equal " "total CPX nodes\n"; } } } if (dev_id + max_loop > current_num_devices) { if (isVerbose) { std::cout << "\t**[WARNING] Readjusting dev_id (was " << dev_id << ")= " << current_num_devices << " - " << max_loop << ": " << (current_num_devices - max_loop) << "\n"; } dev_id = current_num_devices - max_loop; } for (uint32_t i = dev_id; i < dev_id + max_loop; i++) { if (isVerbose) { std::cout << "\t**checkPartitionIdChanges DEVICE INFO ===============\n"; std::cout << "\t**Device (i): " << static_cast(i) << std::endl; std::cout << "\t**dev_id: " << static_cast(dev_id) << std::endl; std::cout << "\t**Device Index: " << static_cast(dev) << std::endl; std::cout << "\t**Processor Handle: " << processor_handle[i] << std::endl; std::cout << "\t**Current Processor Handle: " << curr_processor_handles[i] << std::endl; std::cout << "\t**Current # of devices: " << static_cast(current_num_devices) << std::endl; std::cout << "\t**END checkPartitionIdChanges DEVICE INFO =============\n"; std::cout << "\t**Device (i) #: " << i << "; Device dev_id: " << dev_id << "\n\t\t** max_loop: " << static_cast(max_loop) << "\n\t\t** current_num_devices: " << current_num_devices << "\n"; } if (i >= current_num_devices) { if (isVerbose) { std::cout << "\t**[WARNING] Detected max DRM minor limitation " "(max of 64).\n\tPlease disable any other drivers taking up PCIe space" "\n\t(ex. ast or other drivers -> " "\"sudo rmmod amdgpu && sudo rmmod ast && sudo modprobe amdgpu\")." "\n\tCPX may not enumerate properly.\n"; } break; } amdsmi_kfd_info_t kfd_info; amdsmi_status_t ret = amdsmi_get_gpu_kfd_info(curr_processor_handles[i], &kfd_info); if (isVerbose) { std::cout << "\t**Checking Partition ID | Device: " << std::to_string(i) << "\n\t\t**Current Partition: " << current_partition << "\n\t\t**Max partition IDs to check: " << max_loop << "\n\t\t**Current Partition ID: " << std::to_string(kfd_info.current_partition_id) << "\n"; } EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "SPX") { EXPECT_TRUE(kfd_info.current_partition_id <= max_loop); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id < " << max_loop << " for SPX" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } else if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "DPX") { EXPECT_TRUE(kfd_info.current_partition_id <= max_loop); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id < " << max_loop << " for DPX" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } else if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "TPX") { EXPECT_TRUE(kfd_info.current_partition_id <= max_loop); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id < " << max_loop << " for TPX" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } else if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "QPX") { EXPECT_TRUE(kfd_info.current_partition_id <= max_loop); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id < " << max_loop << " for QPX" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } else if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "CPX") { EXPECT_TRUE(kfd_info.current_partition_id <= max_loop); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id < " << max_loop << " for CPX" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } else if (ret == AMDSMI_STATUS_SUCCESS && current_partition == "N/A") { EXPECT_EQ(kfd_info.current_partition_id, max_loop - 1); if (isVerbose) { std::cout << "\n\t**Confirmed partition_id = " << (max_loop - 1) << " for current_partition = N/A" << "\n\t**amdsmi_get_gpu_kfd_info(" + std::to_string(i) + ", &kfd_info); kfd_info.partition_id: " << static_cast(kfd_info.current_partition_id) << std::endl; } } } } std::string getResourceType(amdsmi_accelerator_partition_resource_type_t resource_type) { std::string resource_type_str = ""; switch (resource_type) { case AMDSMI_ACCELERATOR_XCC: resource_type_str = "XCC"; break; case AMDSMI_ACCELERATOR_ENCODER: resource_type_str = "ENCODER"; break; case AMDSMI_ACCELERATOR_DECODER: resource_type_str = "DECODER"; break; case AMDSMI_ACCELERATOR_DMA: resource_type_str = "DMA"; break; case AMDSMI_ACCELERATOR_JPEG: resource_type_str = "JPEG"; break; case AMDSMI_ACCELERATOR_MAX: resource_type_str = "MAX"; break; default: resource_type_str = "N/A"; break; } return resource_type_str; } void TestComputePartitionReadWrite::Run(void) { amdsmi_status_t ret; constexpr uint32_t k255Len = 255; char orig_char_computePartition[k255Len]; orig_char_computePartition[0] = '\0'; char current_char_computePartition[k255Len]; current_char_computePartition[0] = '\0'; const uint32_t kMAX_UINT32 = std::numeric_limits::max(); TestBase::Run(); if (setup_failed_) { std::cout << "** SetUp Failed for this test. Skipping.**" << std::endl; return; } bool isVerbose = (this->verbosity() && this->verbosity() >= (this->TestBase::VERBOSE_STANDARD)) ? true: false; // Confirm system supports compute partition, before executing wait ret = amdsmi_get_gpu_compute_partition(0, orig_char_computePartition, k255Len); if (ret == AMDSMI_STATUS_SUCCESS) { system_wait(15); } IF_VERB(STANDARD) { std::cout << "\t**======================================================================\n"; std::cout << "\t**Test #1: Get/Set Compute Partition (old functionality) ===============\n"; std::cout << "\t**======================================================================\n"; } // // TEST 1: Set/Get Compute Partition (old functionality) uint32_t initial_num_devices = num_monitor_devs(); for (uint32_t dv_ind = 0; dv_ind < initial_num_devices; ++dv_ind) { if (dv_ind != 0) { std::cout << "\n"; } PrintDeviceHeader(processor_handles_[dv_ind]); ret = amdsmi_get_gpu_compute_partition(processor_handles_[dv_ind], orig_char_computePartition, k255Len); EXPECT_TRUE(ret == AMDSMI_STATUS_SUCCESS || ret == AMDSMI_STATUS_NOT_SUPPORTED); if (ret == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_get_gpu_compute_partition: " << "Not supported on this machine" << std::endl; } continue; } for (int partition = static_cast(AMDSMI_COMPUTE_PARTITION_SPX); partition <= static_cast(AMDSMI_COMPUTE_PARTITION_CPX); partition++) { amdsmi_compute_partition_type_t updatePartition = static_cast(partition); IF_VERB(STANDARD) { std::cout << "\t**" << "======== TEST AMDSMI_COMPUTE_PARTITION_" << computePartitionString(updatePartition) << " ===============" << std::endl; } auto ret_set = amdsmi_set_gpu_compute_partition(processor_handles_[dv_ind], updatePartition); IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_compute_partition(processor_handles_[" << dv_ind << "], " << computePartitionString(updatePartition) << "): " << smi_amdgpu_get_status_string(ret_set, false) << "\n" << "\t**Requested Set Partition: " << computePartitionString(updatePartition) << "\n" << "\t**Original Partition: " << orig_char_computePartition << std::endl; } EXPECT_TRUE(ret_set == AMDSMI_STATUS_SETTING_UNAVAILABLE || ret_set== AMDSMI_STATUS_NO_PERM || ret_set == AMDSMI_STATUS_SUCCESS || ret_set == AMDSMI_STATUS_BUSY || ret_set == AMDSMI_STATUS_NOT_SUPPORTED || ret_set == AMDSMI_STATUS_INVAL); if (ret_set == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_compute_partition: " << "Not supported on this machine" << std::endl; } continue; } if (ret_set == AMDSMI_STATUS_INVAL) { std::cout << "\t**" << "1st Test: Due to invalid args, skipping rest of test for this device." << "\n\t Device might be in a static partition mode. " << "With inability to change partition modes." << std::endl; break; } ret = amdsmi_get_gpu_compute_partition(processor_handles_[dv_ind], current_char_computePartition, k255Len); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_get_gpu_compute_partition(processor_handles_[" << dv_ind << "], " << current_char_computePartition << "): " << smi_amdgpu_get_status_string(ret, false) << "\n\t**Current Partition (get): " << current_char_computePartition << std::endl; } if (ret_set == AMDSMI_STATUS_SUCCESS) { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); EXPECT_EQ(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(current_char_computePartition))); } else { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); EXPECT_NE(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(current_char_computePartition))); } } amdsmi_compute_partition_type_t updatePartition = static_cast( mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); auto ret_set = amdsmi_set_gpu_compute_partition(processor_handles_[dv_ind], updatePartition); EXPECT_TRUE(ret_set == AMDSMI_STATUS_SETTING_UNAVAILABLE || ret_set== AMDSMI_STATUS_NO_PERM || ret_set == AMDSMI_STATUS_SUCCESS || ret_set == AMDSMI_STATUS_BUSY || ret_set == AMDSMI_STATUS_NOT_SUPPORTED || ret_set == AMDSMI_STATUS_INVAL); } IF_VERB(STANDARD) { std::cout << "\n"; std::cout << "\t**======================================================================\n"; std::cout << "\t**Test #2: Get/Set Compute Partition (new functionality) ===============\n"; std::cout << "\t**======================================================================\n"; } // TEST 2: Set/Get Compute Partition (new functionality) initial_num_devices = num_monitor_devs(); amdsmi_accelerator_partition_type_t primary_partition_type = AMDSMI_ACCELERATOR_PARTITION_INVALID; uint32_t primary_index = 0; for (uint32_t dv_ind = 0; dv_ind < initial_num_devices; ++dv_ind) { if (dv_ind != 0) { std::cout << "\n"; } IF_VERB(STANDARD) { std::cout << "\n"; std::cout << "\t**======================================================================\n"; std::cout << "\t**Test #2: Get/Set Compute Partition (new functionality) ===============\n"; std::cout << "\t**DEVICE: #" << std::dec << std::setw(2) << std::setfill('0') << dv_ind << " ==========================================================\n"; std::cout << "\t**======================================================================\n"; } PrintDeviceHeader(processor_handles_[dv_ind]); amdsmi_accelerator_partition_profile_t profile = {}; uint32_t partition_id[8] = {0, 0, 0, 0, 0, 0, 0, 0}; ret = amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[dv_ind], &profile, &partition_id[0]); std::string nps_caps_str = ""; if ((profile.memory_caps.nps_flags.nps1_cap == 0 && profile.memory_caps.nps_flags.nps2_cap == 0 && profile.memory_caps.nps_flags.nps4_cap == 0 && profile.memory_caps.nps_flags.nps8_cap == 0)) { nps_caps_str = "N/A"; } else { nps_caps_str.clear(); if (profile.memory_caps.nps_flags.nps1_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS1" : nps_caps_str += ", NPS1"; } if (profile.memory_caps.nps_flags.nps2_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS2" : nps_caps_str += ", NPS2"; } if (profile.memory_caps.nps_flags.nps4_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS4" : nps_caps_str += ", NPS4"; } if (profile.memory_caps.nps_flags.nps8_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS8" : nps_caps_str += ", NPS8"; } } std::string profile_type_str = "N/A"; if (profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_SPX) { profile_type_str = "SPX"; } else if (profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_DPX) { profile_type_str = "DPX"; } else if (profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_TPX) { profile_type_str = "TPX"; } else if (profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_QPX) { profile_type_str = "QPX"; } else if (profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_CPX) { profile_type_str = "CPX"; } // save the primary partition type if (profile.profile_type != AMDSMI_ACCELERATOR_PARTITION_INVALID) { primary_partition_type = profile.profile_type; primary_index = dv_ind; } std::string partition_id_str = ""; for (int i = 0; i < 8; i++) { partition_id_str += std::to_string(partition_id[i]); if (i < 7) { partition_id_str += ", "; } switch (primary_partition_type) { case AMDSMI_ACCELERATOR_PARTITION_SPX: EXPECT_LT(partition_id[i], MAX_SPX_PARTITIONS); break; case AMDSMI_ACCELERATOR_PARTITION_DPX: EXPECT_LT(partition_id[i], MAX_DPX_PARTITIONS); break; case AMDSMI_ACCELERATOR_PARTITION_TPX: EXPECT_LT(partition_id[i], MAX_TPX_PARTITIONS); break; case AMDSMI_ACCELERATOR_PARTITION_QPX: EXPECT_LT(partition_id[i], MAX_QPX_PARTITIONS); break; case AMDSMI_ACCELERATOR_PARTITION_CPX: { uint16_t num_xcd; uint32_t max_xcps = 0; ret = amdsmi_get_gpu_xcd_counter(processor_handles_[primary_index], &num_xcd); if (ret == AMDSMI_STATUS_SUCCESS) { max_xcps = static_cast(num_xcd); } if (!amd::smi::is_vm_guest()) { // In BM, we can get the number of XCDs (calculated by getting # of gfx_clocks) EXPECT_LT(partition_id[i], max_xcps); } else { // In guest, we may not be able to get the number of XCDs // (calculated by getting # of gfx_clocks) EXPECT_LE(partition_id[i], max_xcps); } break; } case AMDSMI_ACCELERATOR_PARTITION_INVALID: EXPECT_EQ(partition_id[i], MAX_UNSUPPORTED_PARTITIONS); break; default: EXPECT_EQ(partition_id[i], MAX_UNSUPPORTED_PARTITIONS); break; } } IF_VERB(STANDARD) { std::cout << "\t**amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], &profile, &partition_id[0]):\n" << "\t\t" << smi_amdgpu_get_status_string(ret, false) << "\n\t**Current profile.profile_type: " << profile_type_str << "\n\t**profile.num_partitions: " << (profile.num_partitions == kMAX_UINT32 ? "N/A" : std::to_string(profile.num_partitions)) << "\n\t**profile.memory_caps: " << nps_caps_str << "\n\t**profile.profile_index: " << (profile.profile_index == kMAX_UINT32 ? "N/A" : std::to_string(profile.profile_index)) << "\n\t**profile.num_resources: " << profile.num_resources << "\n\t**partition_id: " << partition_id_str << std::endl; } EXPECT_TRUE(ret == AMDSMI_STATUS_SUCCESS || ret == AMDSMI_STATUS_NOT_SUPPORTED); amdsmi_accelerator_partition_profile_config_t profile_config = {}; ret = amdsmi_get_gpu_accelerator_partition_profile_config(processor_handles_[dv_ind], &profile_config); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_get_gpu_accelerator_partition_profile_config(processor_handles_[" << dv_ind << "], &profile_config):\n" << "\t\t" << smi_amdgpu_get_status_string(ret, false) << "\n\t**profile_config.num_profiles: " << profile_config.num_profiles << "\n\t**profile_config.num_resource_profiles: " << profile_config.num_resource_profiles << std::endl; } AcceleratorProfileConfig original_profile_config = {}; original_profile_config = getAvailableProfileConfigs(dv_ind, profile, profile_config, isVerbose); IF_VERB(STANDARD) { std::cout << "\t**=========================================================\n"; std::cout << "\t**Checking invalid profile Set ============================\n"; std::cout << "\t**=========================================================\n"; } // Test setting invalid profile index auto ret_expect_invalid = amdsmi_set_gpu_accelerator_partition_profile( processor_handles_[dv_ind], profile_config.num_profiles); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_set_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], " << profile_config.num_profiles << "):" << "\n\t\t" << smi_amdgpu_get_status_string(ret_expect_invalid, false) << std::endl; } EXPECT_TRUE(ret_expect_invalid == AMDSMI_STATUS_INVAL || ret_expect_invalid == AMDSMI_STATUS_NOT_SUPPORTED); IF_VERB(STANDARD) { std::cout << "\t**=========================================================\n"; std::cout << "\t**Checking valid profile Sets =============================\n"; std::cout << "\t**=========================================================\n"; } int resource_index = 0; for (uint32_t i = 0; i < profile_config.num_profiles; i++) { auto current_profile = profile_config.profiles[i]; std::string profile_type_str = "N/A"; if (current_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_SPX) { profile_type_str = "SPX"; } else if (current_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_DPX) { profile_type_str = "DPX"; } else if (current_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_TPX) { profile_type_str = "TPX"; } else if (current_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_QPX) { profile_type_str = "QPX"; } else if (current_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_CPX) { profile_type_str = "CPX"; } std::string nps_caps_str = ""; if ((current_profile.memory_caps.nps_flags.nps1_cap == 0 && current_profile.memory_caps.nps_flags.nps2_cap == 0 && current_profile.memory_caps.nps_flags.nps4_cap == 0 && current_profile.memory_caps.nps_flags.nps8_cap == 0)) { nps_caps_str = "N/A"; } else { nps_caps_str.clear(); if (current_profile.memory_caps.nps_flags.nps1_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS1" : nps_caps_str += ", NPS1"; } if (current_profile.memory_caps.nps_flags.nps2_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS2" : nps_caps_str += ", NPS2"; } if (current_profile.memory_caps.nps_flags.nps4_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS4" : nps_caps_str += ", NPS4"; } if (current_profile.memory_caps.nps_flags.nps8_cap) { (nps_caps_str.empty()) ? nps_caps_str += "NPS8" : nps_caps_str += ", NPS8"; } } IF_VERB(STANDARD) { std::cout << "\t**profile_config.profiles[" << i << "]:\n" << "\t\tprofile_type: " << profile_type_str << "\n\t\tnum_partitions: " << current_profile.num_partitions << "\n\t\tmemory_caps: " << nps_caps_str << "\n\t\tcurrent_profile.num_resources: " << current_profile.num_resources << std::endl; } for (uint32_t j = 0; j < current_profile.num_resources; j++) { auto rp = profile_config.resource_profiles[resource_index]; IF_VERB(STANDARD) { std::cout << "\n\t\t\tprofile_index: " << current_profile.profile_index << "\n\t\t\tresource_index: " << resource_index << "\n\t\t\tprofile_config.resource_profiles[" << resource_index << "].resource_type: " << getResourceType(rp.resource_type) << "\n\t\t\tprofile_config.resource_profiles[" << resource_index << "].partition_resource: " << rp.partition_resource << "\n\t\t\tprofile_config.resource_profiles[" << resource_index << "].num_partitions_share_resource: " << rp.num_partitions_share_resource << std::endl; } resource_index++; } } EXPECT_TRUE(ret == AMDSMI_STATUS_SUCCESS || ret == AMDSMI_STATUS_NOT_SUPPORTED); if (ret == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_get_gpu_accelerator_partition_profile_config: " << "Not supported on this machine" << std::endl; } continue; } for (uint32_t config = 0; config < profile_config.num_profiles; config++) { auto new_profile = profile_config.profiles[config]; std::string new_profile_type_str = "N/A"; if (new_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_SPX) { new_profile_type_str = "SPX"; } else if (new_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_DPX) { new_profile_type_str = "DPX"; } else if (new_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_TPX) { new_profile_type_str = "TPX"; } else if (new_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_QPX) { new_profile_type_str = "QPX"; } else if (new_profile.profile_type == AMDSMI_ACCELERATOR_PARTITION_CPX) { new_profile_type_str = "CPX"; } IF_VERB(STANDARD) { std::cout << "\t**" << "======== TEST AMDSMI_ACCELERATOR_PARTITION_" << new_profile_type_str << " (profile_index: " << profile_config.profiles[config].profile_index << ")" << " ===============" << std::endl; } auto ret_set = amdsmi_set_gpu_accelerator_partition_profile( processor_handles_[dv_ind], profile_config.profiles[config].profile_index); IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], " << profile_type_str << "): " << smi_amdgpu_get_status_string(ret_set, false) << "\n" << "\t**Requested Set Partition: " << new_profile_type_str << "\n" << "\t**Original Partition: " << original_profile_config.original_profile_type_str << std::endl; } EXPECT_TRUE(ret_set == AMDSMI_STATUS_SETTING_UNAVAILABLE || ret_set== AMDSMI_STATUS_NO_PERM || ret_set == AMDSMI_STATUS_SUCCESS || ret_set == AMDSMI_STATUS_BUSY || ret_set == AMDSMI_STATUS_NOT_SUPPORTED || ret_set == AMDSMI_STATUS_INVAL); if (ret_set == AMDSMI_STATUS_INVAL) { std::cout << "\t**" << "2nd Test: Due to invalid args, skipping rest of test for this device." << "\n\t Device might be in a static partition mode. " << "With inability to change partition modes." << std::endl; break; } if (ret_set == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_accelerator_partition_profile: " << "Not supported on this machine" << std::endl; } continue; } auto ret_get = amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[dv_ind], &profile, &partition_id[0]); if (ret_get == AMDSMI_STATUS_SUCCESS && ret_set == AMDSMI_STATUS_SUCCESS) { profile_type_str = partition_types_map.at(profile.profile_type); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_set_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "]," << "\n\t\t" << profile_config.profiles[config].profile_index << " (AMDSMI_ACCELERATOR_PARTITION_" << new_profile_type_str << "): " << "\n\t\t" << smi_amdgpu_get_status_string(ret_set, false) << "\n\t**amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], &profile, &partition_id[0]):\n" << "\t\t" << smi_amdgpu_get_status_string(ret_get, false) << "\n\t**Current profile.profile_type: " << profile_type_str << "\n\t**profile.num_partitions: " << (profile.num_partitions == kMAX_UINT32 ? "N/A" : std::to_string(profile.num_partitions)) << "\n\t**profile.profile_index: " << (profile.profile_index == kMAX_UINT32 ? "N/A" : std::to_string(profile.profile_index)) << std::endl; } EXPECT_STREQ(partition_types_map.at(profile.profile_type).c_str(), new_profile_type_str.c_str()); EXPECT_EQ(profile.profile_type, new_profile.profile_type); EXPECT_EQ(profile.profile_index, new_profile.profile_index); } } IF_VERB(STANDARD) { std::cout << "\t**Device Index: " << dv_ind << std::endl << "\t**======== Return to original AMDSMI_ACCELERATOR_PARTITION_" << original_profile_config.original_profile_type_str << " (profile_index: " << (original_profile_config.original_profile_index == kMAX_UINT32 ? "N/A" : std::to_string(original_profile_config.original_profile_index)) << ")" << " ===============" << std::endl; } auto ret_set = amdsmi_set_gpu_accelerator_partition_profile( processor_handles_[dv_ind], original_profile_config.original_profile_index); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_set_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "]," << "\n\t\t" << original_profile_config.original_profile_index << " (AMDSMI_ACCELERATOR_PARTITION_" << original_profile_config.original_profile_type_str << "): " << "\n\t\t" << smi_amdgpu_get_status_string(ret_set, false) << std::endl; } EXPECT_TRUE(ret_set == AMDSMI_STATUS_SETTING_UNAVAILABLE || ret_set== AMDSMI_STATUS_NO_PERM || ret_set == AMDSMI_STATUS_SUCCESS || ret_set == AMDSMI_STATUS_BUSY || ret_set == AMDSMI_STATUS_NOT_SUPPORTED || ret_set == AMDSMI_STATUS_INVAL); auto ret_get = amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[dv_ind], &profile, &partition_id[0]); IF_VERB(STANDARD) { std::cout << "\n\t**amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], &profile, &partition_id[0]):\n" << "\t\t" << smi_amdgpu_get_status_string(ret_get, false) << std::endl; } // older kernels do not support this feature if (original_profile_config.original_profile_index == kMAX_UINT32) { EXPECT_EQ(ret_get, AMDSMI_STATUS_NOT_SUPPORTED); IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_get_gpu_accelerator_partition_profile: " << "Not supported on this machine, skipping remaining tests." << std::endl; } break; } if (ret_get == AMDSMI_STATUS_SUCCESS && ret_set == AMDSMI_STATUS_SUCCESS) { profile_type_str = partition_types_map.at(profile.profile_type); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_set_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "]," << "\n\t\t" << original_profile_config.original_profile_index << " (AMDSMI_ACCELERATOR_PARTITION_" << original_profile_config.original_profile_type_str << "): " << "\n\t\t" << smi_amdgpu_get_status_string(ret_set, false) << "\n\t**amdsmi_get_gpu_accelerator_partition_profile(processor_handles_[" << dv_ind << "], &profile, &partition_id[0]):\n" << "\t\t" << smi_amdgpu_get_status_string(ret_get, false) << "\n\t**Current profile.profile_type: " << profile_type_str << "\n\t**profile.num_partitions: " << (profile.num_partitions == kMAX_UINT32 ? "N/A" : std::to_string(profile.num_partitions)) << "\n\t**profile.profile_index: " << (profile.profile_index == kMAX_UINT32 ? "N/A" : std::to_string(profile.profile_index)) << std::endl; } EXPECT_STREQ(partition_types_map.at(profile.profile_type).c_str(), original_profile_config.original_profile_type_str.c_str()); EXPECT_EQ(profile.profile_type, original_profile_config.original_profile_type); EXPECT_EQ(profile.profile_index, original_profile_config.original_profile_index); } } // END for (uint32_t dv_ind = 0; dv_ind < initial_num_devices; ++dv_ind) IF_VERB(STANDARD) { std::cout << "\n"; std::cout << "\t**======================================================================\n"; std::cout << "\t**Test #3: Check fluctuating # of devices & partition IDs ==============\n"; std::cout << "\t**======================================================================\n"; } // ---------------------------------------------------------// // TEST 3: Check fluctuating # of devices & partition IDs // // ---------------------------------------------------------// initial_num_devices = num_monitor_devs(); for (uint32_t dv_ind = 0; dv_ind < initial_num_devices; ++dv_ind) { if (dv_ind != 0) { std::cout << "\n"; } IF_VERB(STANDARD) { std::cout << "\n"; std::cout << "\t**======================================================================\n"; std::cout << "\t**Test #3: Check fluctuating # of devices & partition IDs ==============\n"; std::cout << "\t**DEVICE: #" << std::dec << std::setw(2) << std::setfill('0') << dv_ind << " ========================================================\n"; std::cout << "\t**======================================================================\n"; } // Leaving for debug purposes uint32_t device_index = 0; amdsmi_processor_handle p_handle = {}; uint32_t current_num_devices = 0; smi_amdgpu_get_device_count(¤t_num_devices); smi_amdgpu_get_processor_handle_by_index(dv_ind, &p_handle); smi_amdgpu_get_device_index(p_handle, &device_index); IF_VERB(STANDARD) { std::cout << "\t=========== START INDEX/p_handle DEVICE INFO 1 ===============\n"; std::cout << "\t**Dv_ind: " << dv_ind << std::endl; std::cout << "\t**Device Index: " << device_index << std::endl; std::cout << "\t**Processor Handle (processor_handles_[dv_ind]): " << processor_handles_[dv_ind] << std::endl; std::cout << "\t**Processor Handle: " << p_handle << std::endl; std::cout << "\t**Current # of devices: " << current_num_devices << std::endl; std::cout << "\t=========== END INDEX/p_handle DEVICE INFO 1 =============\n"; } PrintDeviceHeader(p_handle); ret = amdsmi_get_gpu_compute_partition(p_handle, orig_char_computePartition, k255Len); EXPECT_TRUE(ret == AMDSMI_STATUS_SUCCESS || ret == AMDSMI_STATUS_NOT_SUPPORTED); if (ret == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_get_gpu_compute_partition: " << "Not supported on this machine" << std::endl; } continue; } for (int partition = static_cast(mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); partition <= static_cast(AMDSMI_COMPUTE_PARTITION_CPX); partition++) { uint32_t device_index2 = 0; amdsmi_processor_handle p_handle2 = {}; smi_amdgpu_get_device_count(¤t_num_devices); smi_amdgpu_get_processor_handle_by_index(dv_ind, &p_handle2); smi_amdgpu_get_device_index(p_handle2, &device_index2); IF_VERB(STANDARD) { std::cout << "\t=========== INDEX/p_handle DEVICE INFO 2 ===============\n"; std::cout << "\t**Dv_ind: " << dv_ind << std::endl; std::cout << "\t**Device Index2: " << device_index2 << std::endl; std::cout << "\t**Processor Handle (processor_handles_[dv_ind]): " << processor_handles_[dv_ind] << std::endl; std::cout << "\t**Processor Handle: " << p_handle << std::endl; std::cout << "\t**Processor Handle2: " << p_handle2 << std::endl; std::cout << "\t**Current # of devices: " << current_num_devices << std::endl; std::cout << "\t=========== END INDEX/p_handle DEVICE INFO 2 =============\n"; } amdsmi_compute_partition_type_t updatePartition = static_cast(partition); auto ret_set = amdsmi_set_gpu_compute_partition(p_handle2, updatePartition); IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_compute_partition(processor_handles_[" << dv_ind << "], " << computePartitionString(updatePartition) << "): " << smi_amdgpu_get_status_string(ret_set, false) << "\n" << "\t**Requested Set Partition: " << computePartitionString(updatePartition) << "\n" << "\t**Original Partition: " << orig_char_computePartition << std::endl; } EXPECT_TRUE(ret_set == AMDSMI_STATUS_SETTING_UNAVAILABLE || ret_set== AMDSMI_STATUS_NO_PERM || ret_set == AMDSMI_STATUS_SUCCESS || ret_set == AMDSMI_STATUS_BUSY || ret_set == AMDSMI_STATUS_NOT_SUPPORTED || ret_set == AMDSMI_STATUS_INVAL); if (ret_set == AMDSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**" << "amdsmi_set_gpu_compute_partition: " << "Not supported on this machine" << std::endl; } continue; } if (ret_set == AMDSMI_STATUS_INVAL) { std::cout << "\t**" << "3rd Test: Due to invalid args, skipping rest of test for this device." << "\n\t Device might be in a static partition mode. " << "With inability to change partition modes." << std::endl; break; } ret = amdsmi_get_gpu_compute_partition(p_handle2, current_char_computePartition, k255Len); IF_VERB(STANDARD) { std::cout << "\t**amdsmi_get_gpu_compute_partition(processor_handles_[" << dv_ind << "], " << current_char_computePartition << "): " << smi_amdgpu_get_status_string(ret, false) << "\n\t**Current Partition (get): " << current_char_computePartition << std::endl; } if (ret_set == AMDSMI_STATUS_SUCCESS) { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); EXPECT_EQ(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(current_char_computePartition))); checkPartitionIdChanges(processor_handles_, dv_ind, std::string(current_char_computePartition), isVerbose, true); } else { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); EXPECT_NE(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(current_char_computePartition))); } } uint32_t device_index3 = 0; amdsmi_processor_handle p_handle3 = {}; smi_amdgpu_get_processor_handle_by_index(dv_ind, &p_handle3); smi_amdgpu_get_device_index(p_handle3, &device_index3); amdsmi_compute_partition_type_t updatePartition = static_cast( mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); IF_VERB(STANDARD) { std::cout << "\t**ABOUT TO GO BACK TO ORIGINAL PARTITION (" << orig_char_computePartition << ")\n"; } auto ret_set = amdsmi_set_gpu_compute_partition(p_handle3, updatePartition); checkPartitionIdChanges(processor_handles_, dv_ind, std::string(orig_char_computePartition), isVerbose, true); if (ret_set == AMDSMI_STATUS_SUCCESS) { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); EXPECT_EQ(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); } else { EXPECT_EQ(ret, AMDSMI_STATUS_SUCCESS); // on guest this means we can't change partitions // some partitions will match the original partition if (amd::smi::is_vm_guest()) { EXPECT_EQ(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); } else { EXPECT_EQ(updatePartition, mapStringToSMIComputePartitionTypes.at( std::string(orig_char_computePartition))); } } IF_VERB(STANDARD) { std::cout << "\t**Get/Set Test #3 (dev_ind: " << std::dec << dv_ind << "): Check fluctuating # of devices & partition IDs ===============\n"; } } IF_VERB(STANDARD) { std::cout << "\n"; std::cout << "\t**======================================================================\n"; std::cout << "\t**END Tests ============================================================\n"; std::cout << "\t**======================================================================\n"; } }