[SWDEV-498711] RDC Partition Implementation (#119)

* [SWDEV-498711] RDC Partition Implementation

Change-Id: Ibfc3709793770537e4c9d36458f34c6b4f461724
Signed-off-by: adapryor <Adam.pryor@amd.com>
This commit is contained in:
Pryor, Adam
2025-03-27 14:10:11 -05:00
committed by GitHub
parent 929041b556
commit 47692d3ed5
29 changed files with 1503 additions and 358 deletions
+18 -2
View File
@@ -36,6 +36,7 @@ THE SOFTWARE.
#include "rdc_lib/impl/RdcMetricsUpdaterImpl.h"
#include "rdc_lib/impl/RdcModuleMgrImpl.h"
#include "rdc_lib/impl/RdcNotificationImpl.h"
#include "rdc_lib/impl/RdcPartitionImpl.h"
#include "rdc_lib/impl/RdcPolicyImpl.h"
#include "rdc_lib/impl/RdcTopologyLinkImpl.h"
#include "rdc_lib/impl/RdcWatchTableImpl.h"
@@ -76,7 +77,8 @@ namespace rdc {
const uint32_t METIC_UPDATE_FREQUENCY = 1000; // 1000 microseconds by default
RdcEmbeddedHandler::RdcEmbeddedHandler(rdc_operation_mode_t mode)
: group_settings_(new RdcGroupSettingsImpl()),
: partition_(new RdcPartitionImpl()),
group_settings_(new RdcGroupSettingsImpl(partition_)),
cache_mgr_(new RdcCacheManagerImpl()),
metric_fetcher_(new RdcMetricFetcherImpl()),
rdc_module_mgr_(new RdcModuleMgrImpl(metric_fetcher_)),
@@ -261,9 +263,14 @@ rdc_status_t RdcEmbeddedHandler::rdc_group_gpu_add(rdc_gpu_group_t group_id, uin
if (status != RDC_ST_OK) {
return status;
}
rdc_entity_info_t info = rdc_get_info_from_entity_index(gpu_index);
uint32_t physical_gpu = info.device_index;
bool is_gpu_exist = false;
for (uint32_t i = 0; i < count; i++) {
if (gpu_index_list[i] == gpu_index) {
if (gpu_index_list[i] == physical_gpu) {
is_gpu_exist = true;
break;
}
@@ -527,5 +534,14 @@ rdc_status_t RdcEmbeddedHandler::rdc_config_clear(rdc_gpu_group_t group_id) {
return config_handler_->rdc_config_clear(group_id);
}
rdc_status_t RdcEmbeddedHandler::rdc_get_num_partition(uint32_t index, uint16_t* num_partition) {
return partition_->rdc_get_num_partition_impl(index, num_partition);
}
rdc_status_t RdcEmbeddedHandler::rdc_instance_profile_get(
uint32_t entity_index, rdc_instance_resource_type_t resource_type,
rdc_resource_profile_t* profile) {
return partition_->rdc_instance_profile_get_impl(entity_index, resource_type, profile);
}
} // namespace rdc
} // namespace amd
+45 -14
View File
@@ -23,13 +23,17 @@ THE SOFTWARE.
#include <ctime>
#include "amd_smi/amdsmi.h"
#include "rdc_lib/RdcLogger.h"
#include "rdc_lib/impl/RdcPartitionImpl.h"
#include "rdc_lib/impl/SmiUtils.h"
#include "rdc_lib/rdc_common.h"
namespace amd {
namespace rdc {
RdcGroupSettingsImpl::RdcGroupSettingsImpl() {
RdcGroupSettingsImpl::RdcGroupSettingsImpl(const RdcPartitionPtr& partition)
: partition_(partition) {
// Add the default job stats fields
rdc_field_t job_fields[] = {RDC_FI_GPU_MEMORY_USAGE, RDC_FI_POWER_USAGE, RDC_FI_GPU_CLOCK,
RDC_FI_GPU_UTIL, RDC_FI_PCIE_TX, RDC_FI_PCIE_RX,
@@ -67,23 +71,50 @@ rdc_status_t RdcGroupSettingsImpl::rdc_group_gpu_destroy(rdc_gpu_group_t p_rdc_g
rdc_status_t RdcGroupSettingsImpl::rdc_group_gpu_add(rdc_gpu_group_t groupId, uint32_t gpu_index) {
std::lock_guard<std::mutex> guard(group_mutex_);
auto ite = gpu_group_.find(groupId);
if (ite != gpu_group_.end()) {
// Check whether the index already exists
for (uint32_t i = 0; i < ite->second.count; i++) {
if (ite->second.entity_ids[i] == gpu_index) {
RDC_LOG(RDC_INFO, "Fail to add " << gpu_index << " to GPU group " << groupId
<< " as it is already exists");
if (ite == gpu_group_.end()) {
return RDC_ST_NOT_FOUND;
}
rdc_entity_info_t entity_info = rdc_get_info_from_entity_index(gpu_index);
uint16_t num_partitions = 0;
rdc_status_t status =
partition_->rdc_get_num_partition_impl(entity_info.device_index, &num_partitions);
if (status != RDC_ST_OK) {
return status;
}
if (num_partitions != UINT16_MAX && num_partitions > 1) {
if (entity_info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
if (entity_info.instance_index >= num_partitions) {
RDC_LOG(RDC_INFO, "Invalid partition instance: GPU "
<< entity_info.device_index << " supports " << num_partitions
<< " partitions, but instance index is "
<< entity_info.instance_index);
return RDC_ST_BAD_PARAMETER;
}
}
if (ite->second.count < RDC_GROUP_MAX_ENTITIES) {
ite->second.entity_ids[ite->second.count] = gpu_index;
ite->second.count++;
} else {
return RDC_ST_MAX_LIMIT;
}
} else {
return RDC_ST_NOT_FOUND;
if (entity_info.entity_role != RDC_DEVICE_ROLE_PHYSICAL) {
RDC_LOG(RDC_INFO, "GPU " << entity_info.device_index
<< " is not partitionable, but a partition instance was provided.");
return RDC_ST_BAD_PARAMETER;
}
}
// Check whether the index already exists
for (uint32_t i = 0; i < ite->second.count; i++) {
if (ite->second.entity_ids[i] == gpu_index) {
RDC_LOG(RDC_INFO, "Fail to add " << gpu_index << " to GPU group " << groupId
<< " as it is already exists");
return RDC_ST_BAD_PARAMETER;
}
}
if (ite->second.count < RDC_GROUP_MAX_ENTITIES) {
ite->second.entity_ids[ite->second.count] = gpu_index;
ite->second.count++;
} else {
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
+148 -7
View File
@@ -471,9 +471,18 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
amdsmi_processor_handle processor_handle = {};
amdsmi_status_t ret = get_processor_handle_from_id(gpu_index, &processor_handle);
rdc_entity_info_t info = rdc_get_info_from_entity_index(gpu_index);
amdsmi_status_t ret = get_processor_handle_from_id(info.device_index, &processor_handle);
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Failed to get processor handle for GPU " << gpu_index << " error: " << ret);
std::string info_str;
if (info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
info_str =
"g" + std::to_string(info.device_index) + "." + std::to_string(info.instance_index);
} else {
info_str = std::to_string(info.device_index);
}
RDC_LOG(RDC_ERROR, "Failed to get processor handle for GPU " << info_str << " error: " << ret);
return Smi2RdcError(ret);
}
@@ -486,6 +495,138 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
value->field_id = field_id;
value->status = AMDSMI_STATUS_NOT_SUPPORTED;
if (info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
uint16_t num_partitions = 0;
amdsmi_status_t st = get_num_partition(info.device_index, &num_partitions);
if (st != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Failed to get partition info for GPU " << info.device_index);
return RDC_ST_UNKNOWN_ERROR;
}
amdsmi_processor_handle processor_handle = {};
amdsmi_status_t ret = get_processor_handle_from_id(gpu_index, &processor_handle);
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Cannot get processor handle for partition " << info.instance_index);
return Smi2RdcError(ret);
}
amdsmi_gpu_metrics_t gpu_metrics = {};
ret = amdsmi_get_gpu_metrics_info(processor_handle, &gpu_metrics);
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Failed to get GPU metrics info for partition " << info.instance_index);
return Smi2RdcError(ret);
}
switch (field_id) {
case RDC_FI_GPU_CLOCK: {
const uint16_t* clock_array = gpu_metrics.current_gfxclks;
std::vector<uint16_t> valid_clocks;
valid_clocks.reserve(8);
for (uint32_t i = 0; i < 8; i++) {
uint16_t clk = clock_array[i];
if (clk != 0 && clk != 0xFFFF) {
valid_clocks.push_back(clk);
}
}
uint32_t vc = static_cast<uint32_t>(valid_clocks.size());
uint32_t pCount = static_cast<uint32_t>(num_partitions);
uint32_t partIdx = info.instance_index;
if (valid_clocks.empty() || vc < num_partitions) {
RDC_LOG(RDC_ERROR, "No valid clocks, or less than total partitions");
return RDC_ST_NO_DATA;
}
if (vc == num_partitions) {
value->value.l_int = clock_array[info.instance_index] * 1000000;
value->type = INTEGER;
value->status = RDC_ST_OK;
return RDC_ST_OK;
}
uint32_t chunk_size = vc / pCount;
uint32_t start_idx = partIdx * chunk_size;
uint32_t end_idx = start_idx + chunk_size;
// Average partition clocks
uint64_t sum = 0;
for (uint32_t i = start_idx; i < end_idx; i++) {
sum += valid_clocks[i];
}
uint32_t count = end_idx - start_idx;
if (count == 0) {
return RDC_ST_NO_DATA;
}
uint64_t avg_clock = sum / count;
value->value.l_int = avg_clock * 1000000;
value->type = INTEGER;
value->status = RDC_ST_OK;
return RDC_ST_OK;
}
case RDC_FI_GPU_UTIL: {
uint32_t p = info.instance_index;
if (p >= AMDSMI_MAX_NUM_XCP) {
return RDC_ST_NO_DATA;
}
const amdsmi_gpu_xcp_metrics_t& xcp = gpu_metrics.xcp_stats[p];
uint64_t sum = 0;
uint32_t count = 0;
for (uint32_t i = 0; i < AMDSMI_MAX_NUM_XCC; i++) {
uint32_t busy = xcp.gfx_busy_inst[i];
if (busy != UINT32_MAX) {
sum += busy;
count++;
}
}
if (count == 0) {
return RDC_ST_NO_DATA;
}
uint64_t avg_busy = sum / count;
value->value.l_int = avg_busy;
value->type = INTEGER;
value->status = RDC_ST_OK;
return RDC_ST_OK;
}
case RDC_FI_GPU_MM_DEC_UTIL: {
uint32_t p = info.instance_index;
if (p >= AMDSMI_MAX_NUM_XCP) {
return RDC_ST_NO_DATA;
}
const amdsmi_gpu_xcp_metrics_t& xcp = gpu_metrics.xcp_stats[p];
uint64_t sum = 0;
uint32_t count = 0;
for (uint32_t i = 0; i < AMDSMI_MAX_NUM_VCN; i++) {
uint16_t vcn = xcp.vcn_busy[i];
if (vcn != UINT16_MAX) {
sum += vcn;
count++;
}
}
if (count == 0) {
return RDC_ST_NO_DATA;
}
uint64_t avg_decode = sum / count;
value->value.l_int = avg_decode;
value->type = INTEGER;
value->status = RDC_ST_OK;
return RDC_ST_OK;
}
default:
// All other fields => N/A for partition
RDC_LOG(RDC_DEBUG, "Partition " << gpu_index << ": Field " << field_id_string(field_id)
<< " not supported => NO_DATA.");
return RDC_ST_NO_DATA;
}
} // end if partition
auto read_smi_counter = [&](void) {
RdcFieldKey f_key(gpu_index, field_id);
smi_data = get_smi_data(f_key);
@@ -600,12 +741,11 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
break;
}
case RDC_FI_GPU_COUNT: {
uint32_t processor_count = 0;
// amdsmi is initialized in AMDSMI_INIT_AMD_GPUS mode -> returned sockets are GPUs
value->status = get_processor_count(processor_count);
uint32_t socket_count = 0;
value->status = amdsmi_get_socket_handles(&socket_count, nullptr);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(processor_count);
value->value.l_int = static_cast<int64_t>(socket_count);
}
} break;
case RDC_FI_POWER_USAGE: {
@@ -913,8 +1053,9 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
value->value.l_int = static_cast<int64_t>(pending_page_num);
}
}
} else
} else {
value->status = Smi2RdcError(ret);
}
break;
}
+117
View File
@@ -0,0 +1,117 @@
/*
Copyright (c) 2025 - present 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 "rdc_lib/impl/RdcPartitionImpl.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
#include "amd_smi/amdsmi.h"
#include "rdc/rdc.h"
#include "rdc_lib/impl/SmiUtils.h"
namespace amd {
namespace rdc {
rdc_status_t RdcPartitionImpl::rdc_instance_profile_get_impl(
uint32_t entity_index, rdc_instance_resource_type_t resource_type,
rdc_resource_profile_t* profile) {
if (profile == nullptr) {
return RDC_ST_BAD_PARAMETER;
}
profile->partition_resource = 0;
profile->num_partitions_share_resource = 0;
rdc_entity_info_t info = rdc_get_info_from_entity_index(entity_index);
amdsmi_processor_handle proc_handle;
// Get processor handle of socket
amdsmi_status_t ret = get_processor_handle_from_id(info.device_index, &proc_handle);
if (ret != AMDSMI_STATUS_SUCCESS) {
return RDC_ST_UNKNOWN_ERROR;
}
amdsmi_accelerator_partition_profile_config_t config;
memset(&config, 0, sizeof(config));
ret = amdsmi_get_gpu_accelerator_partition_profile_config(proc_handle, &config);
if (ret == AMDSMI_STATUS_NOT_SUPPORTED) {
return RDC_ST_OK;
} else if (ret != AMDSMI_STATUS_SUCCESS) {
return RDC_ST_UNKNOWN_ERROR;
}
amdsmi_accelerator_partition_profile_t active_profile;
memset(&active_profile, 0, sizeof(active_profile));
uint32_t num = 0; // This is unused
ret = amdsmi_get_gpu_accelerator_partition_profile(proc_handle, &active_profile, &num);
if (ret != AMDSMI_STATUS_SUCCESS) {
return RDC_ST_UNKNOWN_ERROR;
}
// If physical device, use profile 0 to get all XCC's/Decoders
uint32_t lookup_id =
(info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) ? active_profile.profile_index : 0;
// Map rdc resource type to smi
amdsmi_accelerator_partition_resource_type_t smi_resource;
switch (resource_type) {
case RDC_ACCELERATOR_XCC:
smi_resource = AMDSMI_ACCELERATOR_XCC;
break;
case RDC_ACCELERATOR_DECODER:
smi_resource = AMDSMI_ACCELERATOR_DECODER;
break;
default:
return RDC_ST_NOT_SUPPORTED;
}
bool found = false;
uint32_t total_resource = 0;
uint32_t resource_share = 0;
for (uint32_t i = 0; i < AMDSMI_MAX_CP_PROFILE_RESOURCES; i++) {
const auto& res = config.resource_profiles[i];
if (res.profile_index == lookup_id && res.resource_type == smi_resource) {
total_resource = res.partition_resource;
resource_share = res.num_partitions_share_resource;
found = true;
break;
}
}
if (!found) {
return RDC_ST_UNKNOWN_ERROR;
}
profile->partition_resource = total_resource;
profile->num_partitions_share_resource = resource_share;
return RDC_ST_OK;
}
rdc_status_t RdcPartitionImpl::rdc_get_num_partition_impl(uint32_t index, uint16_t* num_partition) {
if (get_num_partition(index, num_partition) != AMDSMI_STATUS_SUCCESS) {
return RDC_ST_UNKNOWN_ERROR;
}
return RDC_ST_OK;
}
} // namespace rdc
} // namespace amd
+175 -264
View File
@@ -34,8 +34,8 @@ THE SOFTWARE.
#include "rdc/rdc.h"
#include "rdc_lib/RdcLogger.h"
#include "rdc_lib/impl/RdcMetricFetcherImpl.h"
#include "rdc_lib/rdc_common.h"
#include "rdc_lib/impl/SmiUtils.h"
#include "rdc_lib/rdc_common.h"
namespace amd {
namespace rdc {
@@ -209,6 +209,42 @@ rdc_status_t RdcWatchTableImpl::rdc_field_watch(rdc_gpu_group_t group_id,
return result;
}
// Check for rocprof fields in partitions
rdc_group_info_t ginfo;
result = group_settings_->rdc_group_gpu_get_info(group_id, &ginfo);
if (result != RDC_ST_OK) {
return result;
}
bool groupHasPartition = false;
for (unsigned int i = 0; i < ginfo.count; i++) {
uint32_t entityId = ginfo.entity_ids[i];
rdc_entity_info_t info = rdc_get_info_from_entity_index(entityId);
if (info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
groupHasPartition = true;
break;
}
}
rdc_field_group_info_t field_info;
result = group_settings_->rdc_group_field_get_info(field_group_id, &field_info);
if (result != RDC_ST_OK) {
return result;
}
bool groupHasRocprof = false;
if (result == RDC_ST_OK) {
for (unsigned int i = 0; i < field_info.count; i++) {
rdc_field_t fid = field_info.field_ids[i];
if (fid >= 800 && fid < 900) { // Rocprof fields in the 800's
groupHasRocprof = true;
break;
}
}
}
if (groupHasPartition && groupHasRocprof) {
return RDC_ST_NOT_SUPPORTED;
}
// See if any of the fields are notification fields, and
// set them up, if so.
result = notifications_->set_listen_events(fields_in_watch);
@@ -381,30 +417,30 @@ rdc_status_t RdcWatchTableImpl::create_health_field_group(unsigned int component
// set filed ids
std::vector<rdc_field_t> field_ids{};
if (components & RDC_HEALTH_WATCH_PCIE) {
field_ids.push_back(RDC_HEALTH_PCIE_REPLAY_COUNT);
field_ids.push_back(RDC_HEALTH_PCIE_REPLAY_COUNT);
}
if (components & RDC_HEALTH_WATCH_XGMI) {
field_ids.push_back(RDC_HEALTH_XGMI_ERROR);
field_ids.push_back(RDC_HEALTH_XGMI_ERROR);
}
if (components & RDC_HEALTH_WATCH_MEM) {
field_ids.push_back(RDC_FI_ECC_UNCORRECT_TOTAL);
field_ids.push_back(RDC_HEALTH_RETIRED_PAGE_NUM);
field_ids.push_back(RDC_HEALTH_PENDING_PAGE_NUM);
field_ids.push_back(RDC_HEALTH_RETIRED_PAGE_LIMIT);
field_ids.push_back(RDC_FI_ECC_UNCORRECT_TOTAL);
field_ids.push_back(RDC_HEALTH_RETIRED_PAGE_NUM);
field_ids.push_back(RDC_HEALTH_PENDING_PAGE_NUM);
field_ids.push_back(RDC_HEALTH_RETIRED_PAGE_LIMIT);
}
if (components & RDC_HEALTH_WATCH_EEPROM) {
field_ids.push_back(RDC_HEALTH_EEPROM_CONFIG_VALID);
field_ids.push_back(RDC_HEALTH_EEPROM_CONFIG_VALID);
}
if (components & RDC_HEALTH_WATCH_THERMAL) {
field_ids.push_back(RDC_HEALTH_THERMAL_THROTTLE_TIME);
field_ids.push_back(RDC_HEALTH_THERMAL_THROTTLE_TIME);
}
if (components & RDC_HEALTH_WATCH_POWER) {
field_ids.push_back(RDC_HEALTH_POWER_THROTTLE_TIME);
field_ids.push_back(RDC_HEALTH_POWER_THROTTLE_TIME);
}
if (0 == field_ids.size()) {
@@ -417,8 +453,7 @@ rdc_status_t RdcWatchTableImpl::create_health_field_group(unsigned int component
field_group_name.c_str(), field_group_id);
}
rdc_status_t RdcWatchTableImpl::rdc_health_set(rdc_gpu_group_t group_id,
unsigned int components) {
rdc_status_t RdcWatchTableImpl::rdc_health_set(rdc_gpu_group_t group_id, unsigned int components) {
// remove old health for same group_id
rdc_health_clear(group_id);
@@ -447,13 +482,11 @@ rdc_status_t RdcWatchTableImpl::rdc_health_set(rdc_gpu_group_t group_id,
// get initial values
rdc_field_value value;
result = metric_fetcher_->fetch_smi_field(fields->first, fields->second, &value);
if (result != RDC_ST_OK)
break;
if (result != RDC_ST_OK) break;
// set initial values to cache
result = cache_mgr_->rdc_health_set(group_id, fields->first, value);
if (result != RDC_ST_OK)
break;
if (result != RDC_ST_OK) break;
}
// Start to watch the fields and update fields per 1 second.
@@ -461,10 +494,8 @@ rdc_status_t RdcWatchTableImpl::rdc_health_set(rdc_gpu_group_t group_id,
return result;
}
rdc_status_t RdcWatchTableImpl::rdc_health_get(rdc_gpu_group_t group_id,
unsigned int *components) {
if (nullptr == components)
return RDC_ST_BAD_PARAMETER;
rdc_status_t RdcWatchTableImpl::rdc_health_get(rdc_gpu_group_t group_id, unsigned int* components) {
if (nullptr == components) return RDC_ST_BAD_PARAMETER;
std::lock_guard<std::mutex> guard(watch_mutex_);
auto table_iter = health_watch_table_.find(group_id);
@@ -478,23 +509,19 @@ rdc_status_t RdcWatchTableImpl::rdc_health_get(rdc_gpu_group_t group_id,
return RDC_ST_OK;
}
bool RdcWatchTableImpl::add_health_incident(uint32_t gpu_index,
rdc_health_system_t component,
rdc_health_result_t health,
uint32_t err_code,
std::string err_msg,
rdc_health_incidents_t* incident,
bool RdcWatchTableImpl::add_health_incident(uint32_t gpu_index, rdc_health_system_t component,
rdc_health_result_t health, uint32_t err_code,
std::string err_msg, rdc_health_incidents_t* incident,
rdc_health_response_t* response) {
bool result = false;
incident->gpu_index = gpu_index;
incident->component = component;
incident->health = health;
incident->gpu_index = gpu_index;
incident->component = component;
incident->health = health;
incident->error.code = err_code;
strncpy_with_null(incident->error.msg, err_msg.c_str(), MAX_HEALTH_MSG_LENGTH);
if (incident->health > response->overall_health)
response->overall_health = incident->health;
if (incident->health > response->overall_health) response->overall_health = incident->health;
response->incidents_count++;
if (response->incidents_count >= HEALTH_MAX_ERROR_ITEMS) {
RDC_LOG(RDC_INFO, "Health incidents are full!");
@@ -504,24 +531,20 @@ bool RdcWatchTableImpl::add_health_incident(uint32_t gpu_index,
return (result);
}
rdc_status_t RdcWatchTableImpl::get_start_end_values(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_field_t field,
uint64_t start_timestamp,
rdc_field_value *start_value,
rdc_field_value *end_value) {
if ((nullptr == start_value) && (nullptr == end_value))
return RDC_ST_BAD_PARAMETER;
rdc_status_t RdcWatchTableImpl::get_start_end_values(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_field_t field, uint64_t start_timestamp,
rdc_field_value* start_value,
rdc_field_value* end_value) {
if ((nullptr == start_value) && (nullptr == end_value)) return RDC_ST_BAD_PARAMETER;
rdc_status_t result = RDC_ST_OK;
if (nullptr != start_value) {
//get the values of the field at the start_timestamp/end_timestampe
result = cache_mgr_->rdc_health_get_values(group_id,
gpu_index, field,
start_timestamp, 0,
start_value, nullptr);
// get the values of the field at the start_timestamp/end_timestampe
result = cache_mgr_->rdc_health_get_values(group_id, gpu_index, field, start_timestamp, 0,
start_value, nullptr);
if (result != RDC_ST_OK) {
RDC_LOG(RDC_ERROR, "Error get gpu: " << gpu_index << " field: " << field << " history data. Return: " << result);
RDC_LOG(RDC_ERROR, "Error get gpu: " << gpu_index << " field: " << field
<< " history data. Return: " << result);
return result;
}
}
@@ -529,30 +552,25 @@ rdc_status_t RdcWatchTableImpl::get_start_end_values(rdc_gpu_group_t group_id,
// get end values
result = metric_fetcher_->fetch_smi_field(gpu_index, field, end_value);
if (result != RDC_ST_OK)
RDC_LOG(RDC_ERROR, "Error get gpu: " << gpu_index << " field: " << field << " current data. Return: " << result);
RDC_LOG(RDC_ERROR, "Error get gpu: " << gpu_index << " field: " << field
<< " current data. Return: " << result);
return result;
}
rdc_status_t RdcWatchTableImpl::pcie_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::pcie_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
//get field start/end values
// get field start/end values
rdc_field_value start = {}, end = {};
uint64_t start_timestamp = static_cast<uint64_t>(time(nullptr) - 60) * 1000;
//get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_PCIE_REPLAY_COUNT,
start_timestamp,
&start,
&end);
if (result != RDC_ST_OK)
return result;
// get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_PCIE_REPLAY_COUNT,
start_timestamp, &start, &end);
if (result != RDC_ST_OK) return result;
uint64_t pcie_replay_count = end.value.l_int - start.value.l_int;
if (pcie_replay_count > PCIE_MAX_REPLAYS_PERMIN) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(pcie_replay_count);
@@ -560,37 +578,26 @@ rdc_status_t RdcWatchTableImpl::pcie_check(rdc_gpu_group_t group_id,
err_msg += std::to_string(PCIE_MAX_REPLAYS_PERMIN);
err_msg += ".";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_PCIE,
RDC_HEALTH_RESULT_WARN,
RDC_FR_PCI_REPLAY_RATE,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_PCIE, RDC_HEALTH_RESULT_WARN,
RDC_FR_PCI_REPLAY_RATE, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::xgmi_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::xgmi_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
//get field start/end values
// get field start/end values
rdc_field_value end = {};
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_XGMI_ERROR,
0,
nullptr,
&end);
if (result != RDC_ST_OK)
return result;
rdc_status_t result =
get_start_end_values(group_id, gpu_index, RDC_HEALTH_XGMI_ERROR, 0, nullptr, &end);
if (result != RDC_ST_OK) return result;
amdsmi_xgmi_status_t status = static_cast<amdsmi_xgmi_status_t>(end.value.l_int);
if (AMDSMI_XGMI_STATUS_NO_ERRORS != status) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
uint32_t err_code;
std::string err_msg = "Detected ";
@@ -603,106 +610,68 @@ rdc_status_t RdcWatchTableImpl::xgmi_check(rdc_gpu_group_t group_id,
}
err_msg += ".";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_XGMI,
RDC_HEALTH_RESULT_FAIL,
err_code,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_XGMI, RDC_HEALTH_RESULT_FAIL, err_code,
err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::memory_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::memory_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
//get field start/end values
rdc_field_value start= {}, end = {};
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_FI_ECC_UNCORRECT_TOTAL,
0,
nullptr,
&end);
if (result != RDC_ST_OK)
return result;
// get field start/end values
rdc_field_value start = {}, end = {};
rdc_status_t result =
get_start_end_values(group_id, gpu_index, RDC_FI_ECC_UNCORRECT_TOTAL, 0, nullptr, &end);
if (result != RDC_ST_OK) return result;
uint64_t ecc_uncorrectable_count = 0;
ecc_uncorrectable_count = end.value.l_int;
if (ecc_uncorrectable_count > 0) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(ecc_uncorrectable_count);
err_msg += " uncorrectable ECC error(s) since last GPU reset.";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_MEM,
RDC_HEALTH_RESULT_FAIL,
RDC_FR_ECC_UNCORRECTABLE_DETECTED,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_MEM, RDC_HEALTH_RESULT_FAIL,
RDC_FR_ECC_UNCORRECTABLE_DETECTED, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_PENDING_PAGE_NUM,
0,
nullptr,
&end);
if (result != RDC_ST_OK)
return result;
result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_PENDING_PAGE_NUM, 0, nullptr, &end);
if (result != RDC_ST_OK) return result;
uint64_t num_pages = end.value.l_int;
if (num_pages > 0) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(num_pages);
err_msg += " pending retired page(s).";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_MEM,
RDC_HEALTH_RESULT_WARN,
RDC_FR_PENDING_PAGE_RETIREMENTS,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_MEM, RDC_HEALTH_RESULT_WARN,
RDC_FR_PENDING_PAGE_RETIREMENTS, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
//get retired page number
result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_RETIRED_PAGE_NUM,
0,
nullptr,
&end);
if (result != RDC_ST_OK)
return result;
// get retired page number
result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_RETIRED_PAGE_NUM, 0, nullptr, &end);
if (result != RDC_ST_OK) return result;
uint64_t retired_page = end.value.l_int;
//get retired page threshold
result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_RETIRED_PAGE_LIMIT,
0,
nullptr,
&end);
if (result != RDC_ST_OK)
return result;
// get retired page threshold
result =
get_start_end_values(group_id, gpu_index, RDC_HEALTH_RETIRED_PAGE_LIMIT, 0, nullptr, &end);
if (result != RDC_ST_OK) return result;
uint32_t retired_page_threshold = end.value.l_int;
if (retired_page > retired_page_threshold) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(retired_page);
@@ -710,14 +679,9 @@ rdc_status_t RdcWatchTableImpl::memory_check(rdc_gpu_group_t group_id,
err_msg += std::to_string(retired_page_threshold);
err_msg += ".";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_MEM,
RDC_HEALTH_RESULT_FAIL,
RDC_FR_RETIRED_PAGES_LIMIT,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_MEM, RDC_HEALTH_RESULT_FAIL,
RDC_FR_RETIRED_PAGES_LIMIT, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
return RDC_ST_OK;
@@ -725,31 +689,22 @@ rdc_status_t RdcWatchTableImpl::memory_check(rdc_gpu_group_t group_id,
if (retired_page > 0) {
uint64_t start_timestamp = static_cast<uint64_t>(time(nullptr) - 604800) * 1000;
//get retired page number last 1 week
result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_RETIRED_PAGE_NUM,
start_timestamp,
&start,
&end);
if (result != RDC_ST_OK)
return result;
// get retired page number last 1 week
result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_RETIRED_PAGE_NUM, start_timestamp,
&start, &end);
if (result != RDC_ST_OK) return result;
retired_page = end.value.l_int - start.value.l_int;
if (retired_page > 1) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(retired_page);
err_msg += " retired pages more than one in the last week.";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_MEM,
RDC_HEALTH_RESULT_FAIL,
RDC_FR_RETIRED_PAGES_UNCORRECTABLE_LIMIT,
err_msg,
incident,
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_MEM, RDC_HEALTH_RESULT_FAIL,
RDC_FR_RETIRED_PAGES_UNCORRECTABLE_LIMIT, err_msg, incident,
response))
return RDC_ST_MAX_LIMIT;
}
@@ -758,194 +713,150 @@ rdc_status_t RdcWatchTableImpl::memory_check(rdc_gpu_group_t group_id,
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::eeprom_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::eeprom_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
rdc_field_value end = {};
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_FI_ECC_UNCORRECT_TOTAL,
0,
nullptr,
&end);
if (result != RDC_ST_OK && result != RDC_ST_CORRUPTED_EEPROM)
return result;
rdc_status_t result =
get_start_end_values(group_id, gpu_index, RDC_FI_ECC_UNCORRECT_TOTAL, 0, nullptr, &end);
if (result != RDC_ST_OK && result != RDC_ST_CORRUPTED_EEPROM) return result;
if (result == RDC_ST_CORRUPTED_EEPROM) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected a corrupt EEPROM since last GPU reset.";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_EEPROM,
RDC_HEALTH_RESULT_WARN,
RDC_FR_CORRUPT_EEPROM,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_EEPROM, RDC_HEALTH_RESULT_WARN,
RDC_FR_CORRUPT_EEPROM, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::thermal_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::thermal_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
//get field start/end values
// get field start/end values
rdc_field_value start = {}, end = {};
uint64_t start_timestamp = static_cast<uint64_t>(time(nullptr) - 60) * 1000;
//get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_THERMAL_THROTTLE_TIME,
start_timestamp,
&start,
&end);
if (result != RDC_ST_OK)
return result;
// get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_THERMAL_THROTTLE_TIME,
start_timestamp, &start, &end);
if (result != RDC_ST_OK) return result;
uint64_t acc_socket_thrm = end.value.l_int - start.value.l_int;
if (0 < acc_socket_thrm) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(acc_socket_thrm);
err_msg += " clock throttling due to thermal violation in the last minute.";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_THERMAL,
RDC_HEALTH_RESULT_WARN,
RDC_FR_CLOCKS_THROTTLE_THERMAL,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_THERMAL, RDC_HEALTH_RESULT_WARN,
RDC_FR_CLOCKS_THROTTLE_THERMAL, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::power_check(rdc_gpu_group_t group_id,
uint32_t gpu_index,
rdc_status_t RdcWatchTableImpl::power_check(rdc_gpu_group_t group_id, uint32_t gpu_index,
rdc_health_response_t* response) {
//get field start/end values
// get field start/end values
rdc_field_value start = {}, end = {};
uint64_t start_timestamp = static_cast<uint64_t>(time(nullptr) - 60) * 1000;
//get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id,
gpu_index,
RDC_HEALTH_POWER_THROTTLE_TIME,
start_timestamp,
&start,
&end);
if (result != RDC_ST_OK)
return result;
// get the history data last 1 minute
rdc_status_t result = get_start_end_values(group_id, gpu_index, RDC_HEALTH_POWER_THROTTLE_TIME,
start_timestamp, &start, &end);
if (result != RDC_ST_OK) return result;
uint64_t acc_ppt_pwr = end.value.l_int - start.value.l_int;
if (0 < acc_ppt_pwr) {
rdc_health_incidents_t *incident = &response->incidents[response->incidents_count];
rdc_health_incidents_t* incident = &response->incidents[response->incidents_count];
std::string err_msg = "Detected ";
err_msg += std::to_string(acc_ppt_pwr);
err_msg += " Detected clock throttling due to power violation in the last minute.";
//add incident
if (add_health_incident(gpu_index,
RDC_HEALTH_WATCH_POWER,
RDC_HEALTH_RESULT_WARN,
RDC_FR_CLOCKS_THROTTLE_POWER,
err_msg,
incident,
response))
// add incident
if (add_health_incident(gpu_index, RDC_HEALTH_WATCH_POWER, RDC_HEALTH_RESULT_WARN,
RDC_FR_CLOCKS_THROTTLE_POWER, err_msg, incident, response))
return RDC_ST_MAX_LIMIT;
}
return RDC_ST_OK;
}
rdc_status_t RdcWatchTableImpl::rdc_health_check(rdc_gpu_group_t group_id,
rdc_health_response_t *response) {
if (nullptr == response)
return RDC_ST_BAD_PARAMETER;
rdc_health_response_t* response) {
if (nullptr == response) return RDC_ST_BAD_PARAMETER;
unsigned int components = 0;
std::vector<RdcFieldKey> fields_in_watch;
do { //< lock guard for thread safe
std::lock_guard<std::mutex> guard(watch_mutex_);
auto health = health_watch_table_.find(group_id);
if (health == health_watch_table_.end())
return RDC_ST_NOT_FOUND;
if (health == health_watch_table_.end()) return RDC_ST_NOT_FOUND;
components = health->second.components;
fields_in_watch = health->second.fields;
} while (0);
rdc_group_info_t ginfo;
rdc_status_t result = group_settings_->rdc_group_gpu_get_info(group_id, &ginfo);
if (result != RDC_ST_OK)
return result;
if (result != RDC_ST_OK) return result;
for (auto fields = fields_in_watch.begin(); fields != fields_in_watch.end(); fields++) {
// get current values
rdc_field_value value;
result = metric_fetcher_->fetch_smi_field(fields->first, fields->second, &value);
if (result != RDC_ST_OK)
break;
if (result != RDC_ST_OK) break;
// set current values to cache
result = cache_mgr_->rdc_update_health_stats(group_id, fields->first, value);
if (result != RDC_ST_OK)
break;
if (result != RDC_ST_OK) break;
}
//init response
// init response
response->overall_health = RDC_HEALTH_RESULT_PASS;
response->incidents_count = 0;
for (uint32_t gindex = 0; gindex < ginfo.count; gindex++) {
//PCIe
// PCIe
if (components & RDC_HEALTH_WATCH_PCIE) {
result = pcie_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
//XGMI
// XGMI
if (components & RDC_HEALTH_WATCH_XGMI) {
result = xgmi_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
//Memory
// Memory
if (components & RDC_HEALTH_WATCH_MEM) {
result = memory_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
//EEPROM
// EEPROM
if (components & RDC_HEALTH_WATCH_EEPROM) {
result = eeprom_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
//Thermal
// Thermal
if (components & RDC_HEALTH_WATCH_THERMAL) {
result = thermal_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
//Power
// Power
if (components & RDC_HEALTH_WATCH_POWER) {
result = power_check(group_id, ginfo.entity_ids[gindex], response);
if (result == RDC_ST_MAX_LIMIT)
return result;
if (result == RDC_ST_MAX_LIMIT) return result;
}
} //end of for gindex
} // end of for gindex
return RDC_ST_OK;
}
@@ -953,7 +864,7 @@ rdc_status_t RdcWatchTableImpl::rdc_health_check(rdc_gpu_group_t group_id,
rdc_status_t RdcWatchTableImpl::rdc_health_clear(rdc_gpu_group_t group_id) {
rdc_field_grp_t field_group_id;
do { //< lock guard for thread safe
do { //< lock guard for thread safe
std::lock_guard<std::mutex> guard(watch_mutex_);
auto health = health_watch_table_.find(group_id);
if (health == health_watch_table_.end()) {
@@ -1219,8 +1130,8 @@ void RdcWatchTableImpl::debug_status() {
for (const auto& p : hite->second.fields) {
strstream << "<" << p.first << "," << p.second << "> ";
}
RDC_LOG(RDC_DEBUG,
"group id : " << hite->first << " components : " << hite->second.components << " fields : " << strstream.str());
RDC_LOG(RDC_DEBUG, "group id : " << hite->first << " components : " << hite->second.components
<< " fields : " << strstream.str());
}
if (fields_to_watch_.size() > 0) {
+108 -28
View File
@@ -23,6 +23,7 @@ THE SOFTWARE.
#include "rdc_lib/impl/SmiUtils.h"
#include <cstdint>
#include <cstring>
#include <vector>
#include "amd_smi/amdsmi.h"
@@ -79,44 +80,59 @@ rdc_status_t Smi2RdcError(amdsmi_status_t rsmi) {
amdsmi_status_t get_processor_handle_from_id(uint32_t gpu_id,
amdsmi_processor_handle* processor_handle) {
uint32_t socket_count;
uint32_t processor_count;
auto ret = amdsmi_get_socket_handles(&socket_count, nullptr);
uint32_t socket_count = 0;
amdsmi_status_t ret = amdsmi_get_socket_handles(&socket_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
std::vector<amdsmi_socket_handle> sockets(socket_count);
std::vector<amdsmi_processor_handle> all_processors{};
ret = amdsmi_get_socket_handles(&socket_count, sockets.data());
for (auto& socket : sockets) {
ret = amdsmi_get_processor_handles(socket, &processor_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
std::vector<amdsmi_processor_handle> processors(processor_count);
ret = amdsmi_get_processor_handles(socket, &processor_count, processors.data());
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
for (auto& processor : processors) {
processor_type_t processor_type = {};
ret = amdsmi_get_processor_type(processor, &processor_type);
if (processor_type != AMDSMI_PROCESSOR_TYPE_AMD_GPU) {
RDC_LOG(RDC_ERROR, "Expect AMD_GPU device type!");
return AMDSMI_STATUS_NOT_SUPPORTED;
}
all_processors.push_back(processor);
}
std::vector<amdsmi_socket_handle> sockets(socket_count);
ret = amdsmi_get_socket_handles(&socket_count, sockets.data());
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
if (gpu_id >= all_processors.size()) {
std::vector<std::vector<amdsmi_processor_handle>> procs_by_socket;
procs_by_socket.resize(socket_count);
for (size_t s = 0; s < sockets.size(); s++) {
uint32_t proc_count = 0;
ret = amdsmi_get_processor_handles(sockets[s], &proc_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
std::vector<amdsmi_processor_handle> procs(proc_count);
ret = amdsmi_get_processor_handles(sockets[s], &proc_count, procs.data());
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
for (auto& proc : procs) {
processor_type_t proc_type = {};
ret = amdsmi_get_processor_type(proc, &proc_type);
if (proc_type != AMDSMI_PROCESSOR_TYPE_AMD_GPU) {
return AMDSMI_STATUS_NOT_SUPPORTED;
}
}
procs_by_socket[s] = procs;
}
rdc_entity_info_t info = rdc_get_info_from_entity_index(gpu_id);
uint32_t socket_index = info.device_index;
uint32_t instance_index = info.instance_index;
if (socket_index >= procs_by_socket.size()) {
return AMDSMI_STATUS_INPUT_OUT_OF_BOUNDS;
}
// Get processor handle from GPU id
*processor_handle = all_processors[gpu_id];
const auto& handles = procs_by_socket[socket_index];
if (instance_index >= handles.size()) {
return AMDSMI_STATUS_INPUT_OUT_OF_BOUNDS;
}
*processor_handle = handles[instance_index];
return AMDSMI_STATUS_SUCCESS;
}
@@ -141,5 +157,69 @@ amdsmi_status_t get_processor_count(uint32_t& all_processor_count) {
return AMDSMI_STATUS_SUCCESS;
}
amdsmi_status_t get_socket_handles(std::vector<amdsmi_socket_handle>& sockets) {
uint32_t socket_count = 0;
amdsmi_status_t ret = amdsmi_get_socket_handles(&socket_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
sockets.resize(socket_count);
ret = amdsmi_get_socket_handles(&socket_count, sockets.data());
return ret;
}
amdsmi_status_t get_processor_handles(amdsmi_socket_handle socket,
std::vector<amdsmi_processor_handle>& processors) {
uint32_t processor_count = 0;
amdsmi_status_t ret = amdsmi_get_processor_handles(socket, &processor_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
processors.resize(processor_count);
ret = amdsmi_get_processor_handles(socket, &processor_count, processors.data());
return ret;
}
amdsmi_status_t get_kfd_partition_id(amdsmi_processor_handle proc, uint32_t* partition_id) {
amdsmi_kfd_info_t kfd_info = {};
amdsmi_status_t ret = amdsmi_get_gpu_kfd_info(proc, &kfd_info);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
*partition_id = kfd_info.current_partition_id;
return ret;
}
amdsmi_status_t get_metrics_info(amdsmi_processor_handle proc, amdsmi_gpu_metrics_t* metrics) {
amdsmi_status_t ret = amdsmi_get_gpu_metrics_info(proc, metrics);
return ret;
}
amdsmi_status_t get_num_partition(uint32_t index, uint16_t* num_partition) {
// Get the processor handle for the physical device.
amdsmi_processor_handle proc_handle;
amdsmi_status_t ret = get_processor_handle_from_id(index, &proc_handle);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
amdsmi_gpu_metrics_t metrics;
memset(&metrics, 0, sizeof(metrics));
ret = get_metrics_info(proc_handle, &metrics);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
}
*num_partition = metrics.num_partition;
return ret;
}
} // namespace rdc
} // namespace amd