[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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user