rdc: Add CPU support and CPU metrics infrastructure (#770)

This commit is contained in:
Dmitrii
2025-09-12 16:14:38 -05:00
committed by GitHub
orang tua eb46160a8f
melakukan 8abe24d3b0
22 mengubah file dengan 885 tambahan dan 387 penghapusan
+5
Melihat File
@@ -115,6 +115,11 @@ option(BUILD_EXAMPLES "Build examples" OFF)
# Enable shared libraries for gtest
option(BUILD_SHARED_LIBS "Build shared library (.so) or not." ON)
option(BUILD_ESMI "Enable AMDSMI ESMI Library" ON)
if(BUILD_ESMI)
add_definitions("-DENABLE_ESMI_LIB=1")
endif()
# Enable address sanitizer
set(ADDRESS_SANITIZER_DEFAULT OFF)
if(DEFINED ENV{ADDRESS_SANITIZER})
-3
Melihat File
@@ -1,3 +0,0 @@
set noparent
linelength=100
filter=-build/include_subdir,-legal/copyright,-runtime/printf,-build/c++11,-runtime/int,-build/header_guard
+33 -13
Melihat File
@@ -215,19 +215,19 @@ FLD_DESC_ENT(RDC_EVNT_XGMI_4_THRPUT, "Tx throughput to XGMI neighbor 4 in b/
FLD_DESC_ENT(RDC_EVNT_XGMI_5_THRPUT, "Tx throughput to XGMI neighbor 5 in b/s", "XGMI_5_T", true)
// Asynchronous event notifications
FLD_DESC_ENT(RDC_EVNT_NOTIF_VMFAULT, "VM page fault", "VM_PAGE_FAULT", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_THERMAL_THROTTLE, "Clk freq decrease due to temp", "THERMAL_THROT", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PRE_RESET, "GPU reset is about to occur", "GPU_PRE_RESET", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_POST_RESET, "GPU reset just occurred", "GPU_POST_RESET", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_MIGRATE_START, "GPU migrate has started", "MIGRATE_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_MIGRATE_END, "GPU migrate has ended", "MIGRATE_END", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PAGE_FAULT_START, "GPU page fault started", "PAGE_FAULT_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PAGE_FAULT_END, "GPU page fault ended", "PAGE_FAULT_END", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_QUEUE_EVICTION, "GPU queue eviction occured", "QUEUE_EVICITION", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_QUEUE_RESTORE, "GPU queue restore occured", "QUEUE_RESTORE", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_UNMAP_FROM_GPU, "GPU unmap occured", "UNMAP_FROM_GPU", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PROCESS_START, "GPU process started", "PROCESS_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PROCESS_END, "GPU process ended", "PROCESS_END", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_VMFAULT, "VM page fault", "VM_PAGE_FAULT", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_THERMAL_THROTTLE, "Clk freq decrease due to temp", "THERMAL_THROT", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PRE_RESET, "GPU reset is about to occur", "GPU_PRE_RESET", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_POST_RESET, "GPU reset just occurred", "GPU_POST_RESET", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_MIGRATE_START, "GPU migrate has started", "MIGRATE_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_MIGRATE_END, "GPU migrate has ended", "MIGRATE_END", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PAGE_FAULT_START, "GPU page fault started", "PAGE_FAULT_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PAGE_FAULT_END, "GPU page fault ended", "PAGE_FAULT_END", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_QUEUE_EVICTION, "GPU queue eviction occured", "QUEUE_EVICITION", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_QUEUE_RESTORE, "GPU queue restore occured", "QUEUE_RESTORE", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_UNMAP_FROM_GPU, "GPU unmap occured", "UNMAP_FROM_GPU", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PROCESS_START, "GPU process started", "PROCESS_START", false)
FLD_DESC_ENT(RDC_EVNT_NOTIF_PROCESS_END, "GPU process ended", "PROCESS_END", false)
// RDC health related fields
FLD_DESC_ENT(RDC_HEALTH_XGMI_ERROR, "XGMI one or more errors detected", "XGMI_ERROR", true)
@@ -238,3 +238,23 @@ FLD_DESC_ENT(RDC_HEALTH_RETIRED_PAGE_LIMIT, "Retired page limit",
FLD_DESC_ENT(RDC_HEALTH_EEPROM_CONFIG_VALID, "Verify checksum of EEPROM", "EEPROM_CONFIG_VALID", true)
FLD_DESC_ENT(RDC_HEALTH_POWER_THROTTLE_TIME, "Power throttle status counter", "POWER_THROTTLE_TIME", true)
FLD_DESC_ENT(RDC_HEALTH_THERMAL_THROTTLE_TIME, "Total time(ms) in thermal throttle status", "THERMAL_THROTTLE_TIME", true)
// CPU-related fields description
FLD_DESC_ENT(RDC_FI_CPU_SKT_COUNT, "Number of CPU sockets", "CPU_SKT_COUNT", false)
FLD_DESC_ENT(RDC_FI_CPU_MODEL, "Name of the CPU model", "CPU_MODEL", false)
FLD_DESC_ENT(RDC_FI_CPU_MODEL_ID, "CPU model identifier", "CPU_MODEL_ID", false)
FLD_DESC_ENT(RDC_FI_CPU_FAMILY, "CPU family identifier", "CPU_FAMILY", false)
FLD_DESC_ENT(RDC_FI_CPU_CORES_PER_SKT, "CPU cores per socket identifier", "CPU_CORES_PER_SKT", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_ENERGY, "CPU socket energy consumption (microjoules)", "CPU_SKT_ENERGY", false)
FLD_DESC_ENT(RDC_FI_CPU_HSMP_DRIVER_VERSION, "HSMP driver version", "CPU_HSMP_DRIVER_VERSION", false)
FLD_DESC_ENT(RDC_FI_CPU_SMU_FW_VERSION, "SMU firmware version", "CPU_SMU_FW_VERSION", false)
FLD_DESC_ENT(RDC_FI_CPU_HSMP_PROTO_VERSION, "HSMP protocol version", "CPU_HSMP_PROTO_VERSION", false)
FLD_DESC_ENT(RDC_FI_CPU_FCLK_FREQUENCY, "CPU fabric clock frequency (MHz)", "CPU_FCLK_FREQUENCY", false)
FLD_DESC_ENT(RDC_FI_CPU_MCLK_FREQUENCY, "CPU memory clock frequency (MHz)", "CPU_MCLK_FREQUENCY", false)
FLD_DESC_ENT(RDC_FI_CPU_CCLK_LIMIT, "CPU core clock limit (MHz)", "CPU_CCLK_LIMIT", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_ACTIVE_FREQ_LIMIT, "CPU socket active frequency limit (MHz)", "CPU_SKT_ACTIVE_FREQ_LIMIT", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_FREQ_LIMIT_SRC, "CPU socket frequency limit source type", "CPU_SKT_FREQ_LIMIT_SRC", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_FREQ_RANGE_MAX, "CPU socket maximum frequency range (MHz)", "CPU_SKT_FREQ_RANGE_MAX", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_FREQ_RANGE_MIN, "CPU socket minimum frequency range (MHz)", "CPU_SKT_FREQ_RANGE_MIN", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_C0_RESIDENCY, "CPU socket C0 residency percentage", "CPU_SKT_C0_RESIDENCY", false)
FLD_DESC_ENT(RDC_FI_CPU_SKT_LCLK_DPM_LEVEL, "CPU socket LCLK DPM level", "CPU_SKT_LCLK_DPM_LEVEL", false)
+27 -7
Melihat File
@@ -25,10 +25,6 @@ THE SOFTWARE.
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#ifdef __cplusplus
// cstddef include causes issues on older GCC
// use stddef.h instead
#if __GNUC__ < 9
@@ -424,6 +420,30 @@ typedef enum {
RDC_HEALTH_EEPROM_CONFIG_VALID, //!< Reads the EEPROM and verifies the checksums
RDC_HEALTH_POWER_THROTTLE_TIME, //!< Power throttle status counter
RDC_HEALTH_THERMAL_THROTTLE_TIME, //!< Total time in thermal throttle status (microseconds)
/**
* @brief RDC CPU related fields
*/
RDC_FI_CPU_SKT_COUNT = 10000, //!< CPU socket count
RDC_FI_CPU_FIRST = RDC_FI_CPU_SKT_COUNT,
RDC_FI_CPU_MODEL, //!< Name of the model
RDC_FI_CPU_MODEL_ID, //!< CPU model identifier
RDC_FI_CPU_FAMILY, //!< CPU family identifier
RDC_FI_CPU_CORES_PER_SKT, //!< CPU cores per socket
RDC_FI_CPU_SKT_ENERGY, //!< CPU socket energy consumption (microjoules)
RDC_FI_CPU_HSMP_DRIVER_VERSION, //!< HSMP driver version
RDC_FI_CPU_SMU_FW_VERSION, //!< SMU firmware version
RDC_FI_CPU_HSMP_PROTO_VERSION, //!< HSMP protocol version
RDC_FI_CPU_FCLK_FREQUENCY, //!< CPU fabric clock frequency (MHz)
RDC_FI_CPU_MCLK_FREQUENCY, //!< CPU memory clock frequency (MHz)
RDC_FI_CPU_CCLK_LIMIT, //!< CPU core clock limit (MHz)
RDC_FI_CPU_SKT_ACTIVE_FREQ_LIMIT, //!< CPU socket active frequency limit (MHz)
RDC_FI_CPU_SKT_FREQ_LIMIT_SRC, //!< CPU socket frequency limit source type
RDC_FI_CPU_SKT_FREQ_RANGE_MAX, //!< CPU socket maximum frequency range (MHz)
RDC_FI_CPU_SKT_FREQ_RANGE_MIN, //!< CPU socket minimum frequency range (MHz)
RDC_FI_CPU_SKT_C0_RESIDENCY, //!< CPU socket C0 residency percentage
RDC_FI_CPU_SKT_LCLK_DPM_LEVEL, //!< CPU socket LCLK DPM level
RDC_FI_CPU_LAST = RDC_FI_CPU_SKT_LCLK_DPM_LEVEL,
} rdc_field_t;
// even and odd numbers are used for correctable and uncorrectable errors
@@ -1812,15 +1832,15 @@ rdc_status_t rdc_get_num_partition(rdc_handle_t p_rdc_handle, uint32_t index,
bool rdc_is_partition_string(const char* s);
/**
* @brief Parse partition id into physical gpu and partition
* @brief Parse partition id into socket and partition
*
* @param[in] s - singular partition string
* @param[out] physicalGpu - socket id
* @param[out] socket - socket id
* @param[out] partition - partition id
*
* @retval bool - success
*/
bool rdc_parse_partition_string(const char* s, uint32_t* physicalGpu, uint32_t* partition);
bool rdc_parse_partition_string(const char* s, uint32_t* socket, uint32_t* partition);
#ifdef __cplusplus
}
@@ -22,8 +22,6 @@ THE SOFTWARE.
#ifndef INCLUDE_RDC_LIB_RDCENTITYCODEC_H_
#define INCLUDE_RDC_LIB_RDCENTITYCODEC_H_
#include "rdc/rdc.h"
/*
*
* See rdc.h for description of entity_index
@@ -36,6 +34,7 @@ THE SOFTWARE.
*
*
*/
#include <cstdint>
static constexpr uint32_t RDC_ENTITY_TYPE_SHIFT = 29;
static constexpr uint32_t RDC_ENTITY_ROLE_SHIFT = 27;
static constexpr uint32_t RDC_ENTITY_INSTANCE_SHIFT = 11;
@@ -46,9 +45,5 @@ static constexpr uint32_t RDC_ENTITY_ROLE_MASK = 0x3; // 2 bits for role.
static constexpr uint32_t RDC_ENTITY_INSTANCE_MASK = 0x3FF; // 10 bits for instance.
static constexpr uint32_t RDC_ENTITY_DEVICE_MASK = 0x3FF; // 10 bits for device.
rdc_entity_info_t rdc_get_info_from_entity_index(uint32_t entity_index);
uint32_t rdc_get_entity_index_from_info(rdc_entity_info_t info);
bool rdc_is_partition_string(const char* s);
bool rdc_parse_partition_string(const char* s, uint32_t* physicalGpu, uint32_t* partition);
// entity functions are declared in rdc.h
#endif // INCLUDE_RDC_LIB_RDCENTITYCODEC_H_
@@ -91,6 +91,14 @@ class RdcMetricFetcherImpl final : public RdcMetricFetcher {
bool async_get_pcie_throughput(uint32_t gpu_index, rdc_field_t field_id, rdc_field_value* value);
void get_pcie_throughput(const RdcFieldKey& key);
rdc_status_t fetch_gpu_field_(uint32_t gpu_index, rdc_field_t field_id, rdc_field_value* value,
amdsmi_processor_handle& processor_handle);
rdc_status_t fetch_gpu_partition_field_(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value);
rdc_status_t fetch_cpu_field_(uint32_t gpu_index, rdc_field_t field_id, rdc_field_value* value);
bool async_fetching = false;
//!< Async metric retreive
std::map<RdcFieldKey, MetricValue> async_metrics_;
std::map<RdcFieldKey, std::shared_ptr<FieldSMIData>> smi_data_;
@@ -250,6 +250,30 @@ class rdc_field_t(c_int):
RDC_HEALTH_POWER_THROTTLE_TIME = 3006
RDC_HEALTH_THERMAL_THROTTLE_TIME = 3007
RDC_FI_CPU_COUNT = 10000
RDC_FI_CPU_MODEL = 10001
RDC_FI_CPU_CORE_ENERGY = 10002
RDC_FI_CPU_SOCKET_ENERGY = 10003
RDC_FI_CPU_THREADS_PER_CORE = 10004
RDC_FI_CPU_HSMP_DRIVER_VERSION = 10005
RDC_FI_CPU_SMU_FW_VERSION = 10006
RDC_FI_CPU_HSMP_PROTO_VERSION = 10007
RDC_FI_CPU_FCLK_FREQUENCY = 10008
RDC_FI_CPU_MCLK_FREQUENCY = 10009
RDC_FI_CPU_CCLK_LIMIT = 10010
RDC_FI_CPU_SOCKET_ACTIVE_FREQ_LIMIT = 10011
RDC_FI_CPU_SOCKET_FREQ_LIMIT_SRC = 10012
RDC_FI_CPU_SOCKET_FREQ_RANGE_MAX = 10013
RDC_FI_CPU_SOCKET_FREQ_RANGE_MIN = 10014
RDC_FI_CPU_CORE_FREQ_LIMIT = 10015
RDC_FI_CPU_CORE_BOOST_LIMIT = 10016
RDC_FI_CPU_SOCKET_C0_RESIDENCY = 10017
RDC_FI_CPU_SOCKET_LCLK_DPM_LEVEL = 10018
RDC_FI_CPU_FAMILY = 10019
RDC_FI_CPU_MODEL_ID = 10020
RDC_FI_CPU_CORES_PER_SOCKET = 10021
RDC_FI_CPU_SOCKET_COUNT = 10022
_rdc_metric_type_lookup = {
RDC_FI_INVALID: rdc_metric_type_t.INVALID,
RDC_FI_GPU_COUNT: rdc_metric_type_t.LABEL,
@@ -277,7 +301,7 @@ class rdc_field_t(c_int):
def get_rdc_metric_type(cls, rdc_metric_t):
if isinstance(rdc_metric_t, str):
rdc_metric_t = getattr(cls, rdc_metric_t, None)
# If the metric was found, do the lookup, otherwise default GAUGE
if rdc_metric_t is not None:
return cls._rdc_metric_type_lookup.get(rdc_metric_t, rdc_metric_type_t.GAUGE)
@@ -288,7 +312,7 @@ class rdc_field_t(c_int):
for attr_name, attr_value in cls.__dict__.items():
if isinstance(attr_value, int) and attr_value == value:
return attr_name
return "Unknown field value"
return "Unknown field value"
rdc_handle_t = c_void_p
rdc_gpu_group_t = c_uint32
@@ -164,6 +164,7 @@ rdc_status_t rdc_group_gpu_add(rdc_handle_t p_rdc_handle, rdc_gpu_group_t groupI
return static_cast<amd::rdc::RdcHandler*>(p_rdc_handle)->rdc_group_gpu_add(groupId, gpuIndex);
}
// TODO: rewrite get_all to allow different types
rdc_status_t rdc_device_get_all(rdc_handle_t p_rdc_handle,
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES], uint32_t* count) {
if (!p_rdc_handle || !count) {
@@ -24,11 +24,8 @@ THE SOFTWARE.
#include <rdc_lib/RdcEntityCodec.h>
#include <algorithm>
#include <iostream>
#include <string>
#include "common/rdc_utils.h"
rdc_entity_info_t rdc_get_info_from_entity_index(uint32_t entity_index) {
rdc_entity_info_t info;
info.device_type =
@@ -54,33 +51,34 @@ bool rdc_is_partition_string(const char* s) {
return false;
}
if (s[0] != 'g') {
// Support both GPU ('g') and CPU ('c') partition strings
if (s[0] != 'g' && s[0] != 'c') {
return false;
}
std::string str(s);
size_t dotPos = str.find('.');
if (dotPos == std::string::npos) return false;
size_t dot_pos = str.find('.');
if (dot_pos == std::string::npos) return false;
if (dotPos <= 1 || dotPos >= str.size() - 1) return false;
if (dot_pos <= 1 || dot_pos >= str.size() - 1) return false;
std::string gpuPart = str.substr(1, dotPos - 1);
std::string partitionPart = str.substr(dotPos + 1);
std::string socket_part = str.substr(1, dot_pos - 1);
std::string partition_part = str.substr(dot_pos + 1);
if (!std::all_of(gpuPart.begin(), gpuPart.end(), ::isdigit) ||
!std::all_of(partitionPart.begin(), partitionPart.end(), ::isdigit))
if (!std::all_of(socket_part.begin(), socket_part.end(), ::isdigit) ||
!std::all_of(partition_part.begin(), partition_part.end(), ::isdigit))
return false;
int gpuIndex = std::stoi(gpuPart);
int partitionIndex = std::stoi(partitionPart);
int socket_index = std::stoi(socket_part);
int partition_index = std::stoi(partition_part);
if (gpuIndex < 0 || gpuIndex >= RDC_MAX_NUM_DEVICES) return false;
if (partitionIndex < 0 || partitionIndex >= RDC_MAX_NUM_PARTITIONS) return false;
if (socket_index < 0 || socket_index >= RDC_MAX_NUM_DEVICES) return false;
if (partition_index < 0 || partition_index >= RDC_MAX_NUM_PARTITIONS) return false;
return true;
}
bool rdc_parse_partition_string(const char* s, uint32_t* physicalGpu, uint32_t* partition) {
bool rdc_parse_partition_string(const char* s, uint32_t* socket, uint32_t* partition) {
if (!s) {
return false;
}
@@ -96,16 +94,17 @@ bool rdc_parse_partition_string(const char* s, uint32_t* physicalGpu, uint32_t*
if (pos == std::string::npos) return false;
std::string gpuStr = rest.substr(0, pos);
std::string partStr = rest.substr(pos + 1);
std::string socket_str = rest.substr(0, pos);
std::string partition_str = rest.substr(pos + 1);
// Ensure both parts are a number
if (!(!gpuStr.empty() && std::all_of(gpuStr.begin(), gpuStr.end(), ::isdigit)) ||
!(!partStr.empty() && std::all_of(partStr.begin(), partStr.end(), ::isdigit))) {
if (!(!socket_str.empty() && std::all_of(socket_str.begin(), socket_str.end(), ::isdigit)) ||
!(!partition_str.empty() &&
std::all_of(partition_str.begin(), partition_str.end(), ::isdigit))) {
return false;
}
*physicalGpu = std::stoi(gpuStr);
*partition = std::stoi(partStr);
*socket = std::stoi(socket_str);
*partition = std::stoi(partition_str);
return true;
}
@@ -49,8 +49,21 @@ class smi_initializer {
smi_initializer() {
// Make sure smi will not be initialized multiple times
amdsmi_shut_down();
amdsmi_status_t ret = amdsmi_init(AMDSMI_INIT_AMD_GPUS);
amdsmi_status_t ret = AMDSMI_STATUS_UNKNOWN_ERROR;
uint64_t init_flag = AMDSMI_INIT_AMD_GPUS;
#ifdef ENABLE_ESMI_LIB
init_flag |= AMDSMI_INIT_AMD_CPUS;
#endif
ret = amdsmi_init(init_flag);
#ifdef ENABLE_ESMI_LIB
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Failed to initalize amdsmi with CPUs enabled.. Disabling CPUs.");
init_flag &= ~AMDSMI_INIT_AMD_CPUS;
ret = amdsmi_init(init_flag);
}
#endif
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "SMI FAILED with" << ret);
throw amd::rdc::RdcException(RDC_ST_FAIL_LOAD_MODULE, "SMI initialize fail");
}
}
@@ -95,8 +95,9 @@ rdc_status_t RdcGroupSettingsImpl::rdc_group_gpu_add(rdc_gpu_group_t groupId, ui
}
}
} else {
if (entity_info.entity_role != RDC_DEVICE_ROLE_PHYSICAL) {
RDC_LOG(RDC_INFO, "GPU " << entity_info.device_index
if ((entity_info.entity_role != RDC_DEVICE_ROLE_PHYSICAL) &&
(entity_info.device_type == RDC_DEVICE_TYPE_GPU)) {
RDC_LOG(RDC_INFO, "GPU " << entity_info.device_index << "." << entity_info.device_type
<< " is not partitionable, but a partition instance was provided.");
return RDC_ST_BAD_PARAMETER;
}
@@ -25,9 +25,8 @@ THE SOFTWARE.
#include <string.h>
#include <sys/time.h>
#include <chrono> //NOLINT
#include <cstddef>
#include <cstdint>
#include <memory>
#include <set>
#include <vector>
@@ -89,16 +88,16 @@ RdcMetricFetcherImpl::~RdcMetricFetcherImpl() {
uint64_t RdcMetricFetcherImpl::now() {
struct timeval tv {};
gettimeofday(&tv, NULL);
gettimeofday(&tv, nullptr);
return static_cast<uint64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
}
void RdcMetricFetcherImpl::get_ecc(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value) {
amdsmi_status_t err = AMDSMI_STATUS_SUCCESS;
amdsmi_ras_err_state_t err_state;
amdsmi_ras_err_state_t err_state = AMDSMI_RAS_ERR_STATE_INVALID;
amdsmi_processor_handle processor_handle;
amdsmi_processor_handle processor_handle = nullptr;
err = get_processor_handle_from_id(gpu_index, &processor_handle);
assert(err == AMDSMI_STATUS_SUCCESS);
@@ -208,9 +207,9 @@ void RdcMetricFetcherImpl::get_ecc_total(uint32_t gpu_index, rdc_field_t field_i
amdsmi_status_t err = AMDSMI_STATUS_SUCCESS;
uint64_t correctable_count = 0;
uint64_t uncorrectable_count = 0;
amdsmi_ras_err_state_t err_state;
amdsmi_ras_err_state_t err_state = AMDSMI_RAS_ERR_STATE_INVALID;
amdsmi_processor_handle processor_handle;
amdsmi_processor_handle processor_handle = nullptr;
err = get_processor_handle_from_id(gpu_index, &processor_handle);
if (!value) {
@@ -279,10 +278,10 @@ bool RdcMetricFetcherImpl::async_get_pcie_throughput(uint32_t gpu_index, rdc_fie
void RdcMetricFetcherImpl::get_pcie_throughput(const RdcFieldKey& key) {
uint32_t gpu_index = key.first;
uint64_t sent, received, max_pkt_sz;
amdsmi_status_t ret;
uint64_t sent = 0, received = 0, max_pkt_sz = 0;
amdsmi_status_t ret = AMDSMI_STATUS_INVAL;
amdsmi_processor_handle processor_handle;
amdsmi_processor_handle processor_handle = nullptr;
ret = get_processor_handle_from_id(gpu_index, &processor_handle);
// Return if the cache does not expire yet
@@ -298,8 +297,8 @@ void RdcMetricFetcherImpl::get_pcie_throughput(const RdcFieldKey& key) {
ret = amdsmi_get_gpu_pci_throughput(processor_handle, &sent, &received, &max_pkt_sz);
uint64_t curTime = now();
MetricValue value;
value.cache_ttl = 30 * 1000; // cache 30 seconds
MetricValue value{};
value.cache_ttl = static_cast<long>(30) * 1000; // cache 30 seconds
value.value.type = INTEGER;
do {
std::lock_guard<std::mutex> guard(task_mutex_);
@@ -370,7 +369,7 @@ rdc_status_t RdcMetricFetcherImpl::bulk_fetch_smi_fields(
auto ite = bulk_fields.begin();
for (; ite != bulk_fields.end(); ite++) {
amdsmi_gpu_metrics_t gpu_metrics;
amdsmi_processor_handle processor_handle;
amdsmi_processor_handle processor_handle = nullptr;
rs = get_processor_handle_from_id(ite->first, &processor_handle);
rs = amdsmi_get_gpu_metrics_info(processor_handle, &gpu_metrics);
@@ -437,11 +436,11 @@ constexpr double kGig = 1000000000.0;
static uint64_t sum_xgmi_read(const amdsmi_gpu_metrics_t& gpu_metrics) {
uint64_t total = 0;
const auto not_supported_metrics_data = std::numeric_limits<uint64_t>::max();
for (int i = 0; i < AMDSMI_MAX_NUM_XGMI_LINKS; ++i) {
if (gpu_metrics.xgmi_read_data_acc[i] == not_supported_metrics_data) {
for (unsigned long i : gpu_metrics.xgmi_read_data_acc) {
if (i == not_supported_metrics_data) {
continue;
}
total += gpu_metrics.xgmi_read_data_acc[i];
total += i;
}
if (total == 0) {
return not_supported_metrics_data;
@@ -452,11 +451,11 @@ static uint64_t sum_xgmi_read(const amdsmi_gpu_metrics_t& gpu_metrics) {
static uint64_t sum_xgmi_write(const amdsmi_gpu_metrics_t& gpu_metrics) {
uint64_t total = 0;
const auto not_supported_metrics_data = std::numeric_limits<uint64_t>::max();
for (int i = 0; i < AMDSMI_MAX_NUM_XGMI_LINKS; ++i) {
if (gpu_metrics.xgmi_write_data_acc[i] == not_supported_metrics_data) {
for (unsigned long i : gpu_metrics.xgmi_write_data_acc) {
if (i == not_supported_metrics_data) {
continue;
}
total += gpu_metrics.xgmi_write_data_acc[i];
total += i;
}
if (total == 0) {
return not_supported_metrics_data;
@@ -464,173 +463,20 @@ static uint64_t sum_xgmi_write(const amdsmi_gpu_metrics_t& gpu_metrics) {
return total;
}
rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value) {
if (!value) {
return RDC_ST_BAD_PARAMETER;
std::shared_ptr<FieldSMIData> RdcMetricFetcherImpl::get_smi_data(RdcFieldKey key) {
auto r_info = smi_data_.find(key);
if (r_info != smi_data_.end()) {
return r_info->second;
}
bool async_fetching = false;
return nullptr;
}
rdc_status_t RdcMetricFetcherImpl::fetch_gpu_field_(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value,
amdsmi_processor_handle& processor_handle) {
std::shared_ptr<FieldSMIData> smi_data;
amdsmi_processor_handle 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) {
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);
}
if (!is_field_valid(field_id)) {
RDC_LOG(RDC_ERROR, "Fail to fetch field " << field_id << " which is not supported");
return RDC_ST_NOT_SUPPORTED;
}
value->ts = now();
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(AMDSMI_MAX_NUM_GFX_CLKS);
for (uint32_t i = 0; i < AMDSMI_MAX_NUM_GFX_CLKS; 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 = static_cast<int64_t>(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:
// for now we must let other plugins return valid data for partition metrics
// TODO: All other fields => N/A for partition IN AMDSMI
// RDC_LOG(RDC_DEBUG, "Partition " << gpu_index << ": Field " << field_id_string(field_id)
// << " not supported => NO_DATA.");
break;
}
} // end if partition
amdsmi_status_t ret = AMDSMI_STATUS_INVAL;
auto read_smi_counter = [&](void) {
RdcFieldKey f_key(gpu_index, field_id);
@@ -645,7 +491,7 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
value->type = INTEGER;
};
auto read_gpu_metrics_uint64_t = [&](void) {
auto read_gpu_metrics_uint64_t = [&]() {
amdsmi_gpu_metrics_t gpu_metrics;
value->status = amdsmi_get_gpu_metrics_info(processor_handle, &gpu_metrics);
RDC_LOG(RDC_DEBUG, "Read the gpu metrics:" << value->status);
@@ -766,14 +612,7 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
} break;
case RDC_FI_POWER_USAGE: {
amdsmi_power_info_t power_info = {};
// Handle API breaking change in amdsmi commit dc4a16da6fb45d581a6e23c78d340172989418a0
// Breaking change is only in rocm 6.4.0 (amdsmi 25.2)
// It is reverted to old signature in 6.4.1 (amdsmi 25.3)
#if (((AMDSMI_LIB_VERSION_MAJOR) == 25) && ((AMDSMI_LIB_VERSION_MINOR) == 2))
value->status = amdsmi_get_power_info(processor_handle, 0, &power_info);
#else
value->status = amdsmi_get_power_info(processor_handle, &power_info);
#endif
value->type = INTEGER;
if (value->status != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "amdsmi_get_power_info failed!");
@@ -854,15 +693,16 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
}
break;
}
case RDC_FI_GPU_PAGE_RETRIED:
uint32_t num_pages;
amdsmi_retired_page_record_t info;
value->status = amdsmi_get_gpu_bad_page_info(processor_handle, &num_pages, &info);
case RDC_FI_GPU_PAGE_RETRIED: {
uint32_t num_pages = 0;
amdsmi_retired_page_record_t page_record;
value->status = amdsmi_get_gpu_bad_page_info(processor_handle, &num_pages, &page_record);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = num_pages;
}
break;
}
case RDC_FI_OAM_ID:
case RDC_FI_DEV_ID:
case RDC_FI_REV_ID:
@@ -917,7 +757,7 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
constexpr uint32_t kUTILIZATION_COUNTERS(1);
amdsmi_utilization_counter_t utilization_counters[kUTILIZATION_COUNTERS];
utilization_counters[0].type = AMDSMI_COARSE_DECODER_ACTIVITY;
uint64_t timestamp;
uint64_t timestamp = 0;
value->status = amdsmi_get_utilization_count(processor_handle, utilization_counters,
kUTILIZATION_COUNTERS, &timestamp);
@@ -1024,18 +864,16 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
case RDC_FI_PCIE_BANDWIDTH:
read_gpu_metrics_uint64_t();
break;
case RDC_HEALTH_XGMI_ERROR: {
amdsmi_xgmi_status_t status;
ret = amdsmi_gpu_xgmi_error_status(processor_handle, &status);
amdsmi_xgmi_status_t xgmi_status = AMDSMI_XGMI_STATUS_NO_ERRORS;
ret = amdsmi_gpu_xgmi_error_status(processor_handle, &xgmi_status);
value->status = Smi2RdcError(ret);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(status);
value->value.l_int = static_cast<int64_t>(xgmi_status);
}
break;
}
case RDC_HEALTH_PCIE_REPLAY_COUNT: {
amdsmi_pcie_info_t pcie_info;
ret = amdsmi_get_pcie_info(processor_handle, &pcie_info);
@@ -1046,7 +884,6 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
}
break;
}
case RDC_HEALTH_RETIRED_PAGE_NUM:
case RDC_HEALTH_PENDING_PAGE_NUM: {
uint32_t num_pages = 0;
@@ -1078,7 +915,6 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
}
break;
}
case RDC_HEALTH_RETIRED_PAGE_LIMIT: {
uint32_t retired_page_threshold = 0;
ret = amdsmi_get_gpu_bad_page_threshold(processor_handle, &retired_page_threshold);
@@ -1089,13 +925,11 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
}
break;
}
case RDC_HEALTH_EEPROM_CONFIG_VALID: {
ret = amdsmi_gpu_validate_ras_eeprom(processor_handle);
value->status = Smi2RdcError(ret);
break;
}
case RDC_HEALTH_POWER_THROTTLE_TIME:
case RDC_HEALTH_THERMAL_THROTTLE_TIME: {
amdsmi_violation_status_t violation_status;
@@ -1110,7 +944,6 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
}
break;
}
case RDC_FI_GPU_BUSY_PERCENT: {
uint32_t gpu_busy_percent = 0;
ret = amdsmi_get_gpu_busy_percent(processor_handle, &gpu_busy_percent);
@@ -1119,12 +952,415 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(gpu_busy_percent);
}
break;
}
default:
break;
}
return Smi2RdcError(static_cast<amdsmi_status_t>(value->status));
}
rdc_status_t RdcMetricFetcherImpl::fetch_gpu_partition_field_(uint32_t gpu_index,
rdc_field_t field_id,
rdc_field_value* value) {
rdc_entity_info_t info = rdc_get_info_from_entity_index(gpu_index);
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 device " << 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;
// TODO: extract mapping to separate function
valid_clocks.reserve(AMDSMI_MAX_NUM_GFX_CLKS);
for (uint32_t i = 0; i < AMDSMI_MAX_NUM_GFX_CLKS; 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 = static_cast<int64_t>(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 (unsigned int busy : xcp.gfx_busy_inst) {
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 (unsigned short vcn : xcp.vcn_busy) {
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 IN AMDSMI
return RDC_ST_NOT_SUPPORTED;
break;
}
}
rdc_status_t RdcMetricFetcherImpl::fetch_cpu_field_(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value) {
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 CPU " << gpu_index);
return Smi2RdcError(ret);
}
processor_type_t processor_type = AMDSMI_PROCESSOR_TYPE_UNKNOWN;
ret = amdsmi_get_processor_type(processor_handle, &processor_type);
if (ret != AMDSMI_STATUS_SUCCESS) {
RDC_LOG(RDC_ERROR, "Cannot get processor type for CPU " << gpu_index);
return Smi2RdcError(ret);
}
RDC_LOG(RDC_DEBUG, "Processor type for CPU " << gpu_index << ": " << processor_type);
// Initialize common values
value->field_id = field_id;
value->ts = now();
switch (field_id) {
case RDC_FI_CPU_MODEL: {
amdsmi_cpu_info_t cpu_info = {};
value->status = amdsmi_get_cpu_model_name(processor_handle, &cpu_info);
value->type = STRING;
if (value->status == AMDSMI_STATUS_SUCCESS) {
// Use the actual CPU model name from AMD SMI
snprintf(value->value.str, sizeof(value->value.str), "%s", cpu_info.model_name);
}
break;
}
case RDC_FI_CPU_SKT_ENERGY: {
uint64_t energy = 0;
value->status = amdsmi_get_cpu_socket_energy(processor_handle, &energy);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(energy);
}
break;
}
case RDC_FI_CPU_HSMP_DRIVER_VERSION: {
amdsmi_hsmp_driver_version_t hsmp_driver_ver = {};
value->status = amdsmi_get_cpu_hsmp_driver_version(processor_handle, &hsmp_driver_ver);
value->type = STRING;
if (value->status == AMDSMI_STATUS_SUCCESS) {
snprintf(value->value.str, sizeof(value->value.str), "%u.%u", hsmp_driver_ver.major,
hsmp_driver_ver.minor);
}
break;
}
case RDC_FI_CPU_SMU_FW_VERSION: {
amdsmi_smu_fw_version_t smu_fw = {};
value->status = amdsmi_get_cpu_smu_fw_version(processor_handle, &smu_fw);
value->type = STRING;
if (value->status == AMDSMI_STATUS_SUCCESS) {
snprintf(value->value.str, sizeof(value->value.str), "%u.%u.%u", smu_fw.major, smu_fw.minor,
smu_fw.debug);
}
break;
}
case RDC_FI_CPU_HSMP_PROTO_VERSION: {
uint32_t proto_ver = 0;
value->status = amdsmi_get_cpu_hsmp_proto_ver(processor_handle, &proto_ver);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(proto_ver);
}
break;
}
case RDC_FI_CPU_FCLK_FREQUENCY:
case RDC_FI_CPU_MCLK_FREQUENCY: {
uint32_t fclk = 0, mclk = 0;
value->status = amdsmi_get_cpu_fclk_mclk(processor_handle, &fclk, &mclk);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
if (field_id == RDC_FI_CPU_FCLK_FREQUENCY) {
value->value.l_int = static_cast<int64_t>(fclk);
} else {
value->value.l_int = static_cast<int64_t>(mclk);
}
}
break;
}
case RDC_FI_CPU_CCLK_LIMIT: {
uint32_t cclk = 0;
value->status = amdsmi_get_cpu_cclk_limit(processor_handle, &cclk);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(cclk);
}
break;
}
case RDC_FI_CPU_SKT_ACTIVE_FREQ_LIMIT:
case RDC_FI_CPU_SKT_FREQ_LIMIT_SRC: {
uint16_t freq = 0;
char* src_type = nullptr;
value->status =
amdsmi_get_cpu_socket_current_active_freq_limit(processor_handle, &freq, &src_type);
if (field_id == RDC_FI_CPU_SKT_ACTIVE_FREQ_LIMIT) {
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(freq);
}
} else {
value->type = STRING;
if (value->status == AMDSMI_STATUS_SUCCESS && src_type != nullptr) {
strncpy(value->value.str, src_type, sizeof(value->value.str) - 1);
value->value.str[sizeof(value->value.str) - 1] = '\0';
}
}
break;
}
case RDC_FI_CPU_SKT_FREQ_RANGE_MAX:
case RDC_FI_CPU_SKT_FREQ_RANGE_MIN: {
uint16_t fmax = 0, fmin = 0;
value->status = amdsmi_get_cpu_socket_freq_range(processor_handle, &fmax, &fmin);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
if (field_id == RDC_FI_CPU_SKT_FREQ_RANGE_MAX) {
value->value.l_int = static_cast<int64_t>(fmax);
} else {
value->value.l_int = static_cast<int64_t>(fmin);
}
}
break;
}
case RDC_FI_CPU_SKT_C0_RESIDENCY: {
uint32_t c0_residency = 0;
value->status = amdsmi_get_cpu_socket_c0_residency(processor_handle, &c0_residency);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(c0_residency);
}
break;
}
case RDC_FI_CPU_SKT_LCLK_DPM_LEVEL: {
uint8_t nbio_id = 0;
amdsmi_dpm_level_t nbio = {};
value->status = amdsmi_get_cpu_socket_lclk_dpm_level(processor_handle, nbio_id, &nbio);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(nbio.max_dpm_level);
}
break;
}
case RDC_FI_CPU_FAMILY: {
uint32_t cpu_family = 0;
value->status = amdsmi_get_cpu_family(&cpu_family);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(cpu_family);
}
break;
}
case RDC_FI_CPU_MODEL_ID: {
uint32_t cpu_model = 0;
value->status = amdsmi_get_cpu_model(&cpu_model);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(cpu_model);
}
break;
}
case RDC_FI_CPU_CORES_PER_SKT: {
uint32_t sock_count = 0;
amdsmi_status_t ret_count = amdsmi_get_cpu_socket_count(&sock_count);
if (ret_count == AMDSMI_STATUS_SUCCESS && sock_count > 0) {
std::vector<amdsmi_sock_info_t> soc_info(sock_count);
value->status = amdsmi_get_cpu_cores_per_socket(sock_count, soc_info.data());
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
// Return cores for the first socket or specific socket based on processor_handle
value->value.l_int = static_cast<int64_t>(soc_info[0].cores_per_socket);
}
} else {
value->status = ret_count;
}
break;
}
case RDC_FI_CPU_SKT_COUNT: {
uint32_t sock_count = 0;
value->status = amdsmi_get_cpu_socket_count(&sock_count);
value->type = INTEGER;
if (value->status == AMDSMI_STATUS_SUCCESS) {
value->value.l_int = static_cast<int64_t>(sock_count);
}
break;
}
default:
value->status = AMDSMI_STATUS_NOT_SUPPORTED;
RDC_LOG(RDC_DEBUG, "CPU field " << field_id << " not supported");
break;
}
return Smi2RdcError(static_cast<amdsmi_status_t>(value->status));
}
rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field_t field_id,
rdc_field_value* value) {
if (!value) {
return RDC_ST_BAD_PARAMETER;
}
amdsmi_processor_handle processor_handle = {};
rdc_status_t status = RDC_ST_UNKNOWN_ERROR;
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) {
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 device " << info_str << " error: " << ret);
return Smi2RdcError(ret);
}
// Check if this is a CPU field being requested
bool is_cpu_field = ((field_id >= RDC_FI_CPU_FIRST) && (field_id <= RDC_FI_CPU_LAST));
// If it's a CPU field, validate device type or determine it automatically
if (is_cpu_field) {
// Check if device type is already set correctly
if (info.device_type != RDC_DEVICE_TYPE_CPU) {
// Try to determine if this is actually a CPU device
// In a more complete implementation, you would query the processor type here
processor_type_t processor_type = AMDSMI_PROCESSOR_TYPE_UNKNOWN;
amdsmi_status_t type_ret = amdsmi_get_processor_type(processor_handle, &processor_type);
if (type_ret == AMDSMI_STATUS_SUCCESS && processor_type == AMDSMI_PROCESSOR_TYPE_AMD_CPU) {
RDC_LOG(RDC_DEBUG, "Auto-detected CPU device for index " << gpu_index);
info.device_type = RDC_DEVICE_TYPE_CPU;
} else {
RDC_LOG(RDC_ERROR, "CPU field " << field_id_string(field_id)
<< " requested for non-CPU device " << gpu_index
<< " (type: " << info.device_type << ")");
return RDC_ST_NOT_SUPPORTED;
}
}
}
if (is_field_valid(field_id) == false) {
RDC_LOG(RDC_ERROR, "Fail to fetch field " << field_id << " which is not supported");
return RDC_ST_NOT_SUPPORTED;
}
value->ts = now();
value->field_id = field_id;
value->status = AMDSMI_STATUS_NOT_SUPPORTED;
if (info.device_type == RDC_DEVICE_TYPE_CPU) {
// don't care about partition for CPUs
status = fetch_cpu_field_(gpu_index, field_id, value);
} else if (info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
status = fetch_gpu_partition_field_(gpu_index, field_id, value);
} else if (info.device_type == RDC_DEVICE_TYPE_GPU) {
status = fetch_gpu_field_(gpu_index, field_id, value, processor_handle);
} else {
RDC_LOG(RDC_ERROR, "Unsupported device type for fetching field: " << field_id_string(field_id));
return RDC_ST_NOT_SUPPORTED;
}
if (status != RDC_ST_OK) {
RDC_LOG(RDC_ERROR, "Fetch status is not ok error: " << status);
}
int64_t latency = now() - value->ts;
if (value->status != AMDSMI_STATUS_SUCCESS) {
if (async_fetching) { //!< Async fetching is not an error
@@ -1148,25 +1384,16 @@ rdc_status_t RdcMetricFetcherImpl::fetch_smi_field(uint32_t gpu_index, rdc_field
return value->status == AMDSMI_STATUS_SUCCESS ? RDC_ST_OK : RDC_ST_SMI_ERROR;
}
std::shared_ptr<FieldSMIData> RdcMetricFetcherImpl::get_smi_data(RdcFieldKey key) {
std::map<RdcFieldKey, std::shared_ptr<FieldSMIData>>::iterator r_info = smi_data_.find(key);
if (r_info != smi_data_.end()) {
return r_info->second;
}
return nullptr;
}
static rdc_status_t init_smi_counter(RdcFieldKey fk, amdsmi_event_group_t grp,
amdsmi_event_handle_t* handle) {
amdsmi_status_t ret;
uint32_t counters_available;
amdsmi_status_t ret = AMDSMI_STATUS_INVAL;
uint32_t counters_available = 0;
uint32_t dv_ind = fk.first;
rdc_field_t f = fk.second;
assert(handle != nullptr);
amdsmi_processor_handle processor_handle;
amdsmi_processor_handle processor_handle = nullptr;
ret = get_processor_handle_from_id(dv_ind, &processor_handle);
ret = amdsmi_gpu_counter_group_supported(processor_handle, grp);
@@ -1212,7 +1439,7 @@ static rdc_status_t init_smi_counter(RdcFieldKey fk, amdsmi_event_group_t grp,
}
rdc_status_t RdcMetricFetcherImpl::delete_smi_handle(RdcFieldKey fk) {
amdsmi_status_t ret;
amdsmi_status_t ret = AMDSMI_STATUS_INVAL;
switch (fk.second) {
case RDC_EVNT_XGMI_0_NOP_TX:
@@ -1229,7 +1456,7 @@ rdc_status_t RdcMetricFetcherImpl::delete_smi_handle(RdcFieldKey fk) {
case RDC_EVNT_XGMI_3_THRPUT:
case RDC_EVNT_XGMI_4_THRPUT:
case RDC_EVNT_XGMI_5_THRPUT: {
amdsmi_event_handle_t h;
amdsmi_event_handle_t h = 0L;
if (smi_data_.find(fk) == smi_data_.end()) {
return RDC_ST_NOT_SUPPORTED;
}
@@ -1262,8 +1489,8 @@ rdc_status_t RdcMetricFetcherImpl::acquire_smi_handle(RdcFieldKey fk) {
rdc_status_t ret = RDC_ST_OK;
auto get_evnt_handle = [&](amdsmi_event_group_t grp) {
amdsmi_event_handle_t handle;
rdc_status_t result;
amdsmi_event_handle_t handle = 0L;
rdc_status_t result = RDC_ST_UNKNOWN_ERROR;
if (get_smi_data(fk) != nullptr) {
// This event has already been initialized.
@@ -1275,7 +1502,7 @@ rdc_status_t RdcMetricFetcherImpl::acquire_smi_handle(RdcFieldKey fk) {
RDC_LOG(RDC_ERROR, "Failed to init SMI counter. Return:" << result);
return result;
}
auto fsh = std::shared_ptr<FieldSMIData>(new FieldSMIData);
auto fsh = std::make_shared<FieldSMIData>();
if (fsh == nullptr) {
return RDC_ST_INSUFF_RESOURCES;
@@ -1299,7 +1526,6 @@ rdc_status_t RdcMetricFetcherImpl::acquire_smi_handle(RdcFieldKey fk) {
case RDC_EVNT_XGMI_1_BEATS_TX:
ret = get_evnt_handle(AMDSMI_EVNT_GRP_XGMI);
break;
case RDC_EVNT_XGMI_0_THRPUT:
case RDC_EVNT_XGMI_1_THRPUT:
case RDC_EVNT_XGMI_2_THRPUT:
@@ -1308,7 +1534,6 @@ rdc_status_t RdcMetricFetcherImpl::acquire_smi_handle(RdcFieldKey fk) {
case RDC_EVNT_XGMI_5_THRPUT:
ret = get_evnt_handle(AMDSMI_EVNT_GRP_XGMI_DATA_OUT);
break;
default:
break;
}
@@ -186,9 +186,17 @@ rdc_status_t RdcSmiLib::rdc_telemetry_fields_query(uint32_t field_ids[MAX_NUM_FI
RDC_FI_GPU_MEMORY_MAX_BANDWIDTH, RDC_FI_GPU_MEMORY_CUR_BANDWIDTH,
RDC_FI_GPU_BUSY_PERCENT, RDC_FI_GPU_PAGE_RETRIED,
RDC_FI_DEV_ID, RDC_FI_REV_ID, RDC_FI_TARGET_GRAPHICS_VERSION,
RDC_FI_NUM_OF_COMPUTE_UNITS, RDC_FI_UUID, RDC_FI_GPU_PARTITION_COUNT,
RDC_FI_NUM_OF_COMPUTE_UNITS, RDC_FI_UUID, RDC_FI_GPU_PARTITION_COUNT,
RDC_FI_CPU_SKT_COUNT, RDC_FI_CPU_MODEL, RDC_FI_CPU_MODEL_ID,
RDC_FI_CPU_FAMILY, RDC_FI_CPU_CORES_PER_SKT, RDC_FI_CPU_SKT_ENERGY,
RDC_FI_CPU_HSMP_DRIVER_VERSION, RDC_FI_CPU_SMU_FW_VERSION, RDC_FI_CPU_HSMP_PROTO_VERSION,
RDC_FI_CPU_FCLK_FREQUENCY, RDC_FI_CPU_MCLK_FREQUENCY, RDC_FI_CPU_CCLK_LIMIT,
RDC_FI_CPU_SKT_ACTIVE_FREQ_LIMIT,
RDC_FI_CPU_SKT_FREQ_LIMIT_SRC, RDC_FI_CPU_SKT_FREQ_RANGE_MAX, RDC_FI_CPU_SKT_FREQ_RANGE_MIN,
RDC_FI_CPU_SKT_C0_RESIDENCY, RDC_FI_CPU_SKT_LCLK_DPM_LEVEL,
};
// clang-format on
std::copy(fields.begin(), fields.end(), field_ids);
*field_count = fields.size();
+3 -12
Melihat File
@@ -28,7 +28,6 @@ THE SOFTWARE.
#include "amd_smi/amdsmi.h"
#include "rdc/rdc.h"
#include "rdc_lib/RdcLogger.h"
namespace amd {
namespace rdc {
@@ -108,14 +107,6 @@ amdsmi_status_t get_processor_handle_from_id(uint32_t gpu_id,
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;
}
@@ -169,7 +160,7 @@ amdsmi_status_t get_gpu_id_from_processor_handle(amdsmi_processor_handle process
amdsmi_status_t get_processor_count(uint32_t& all_processor_count) {
uint32_t total_processor_count = 0;
uint32_t socket_count;
uint32_t socket_count = 0;
auto ret = amdsmi_get_socket_handles(&socket_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
@@ -177,7 +168,7 @@ amdsmi_status_t get_processor_count(uint32_t& all_processor_count) {
std::vector<amdsmi_socket_handle> sockets(socket_count);
ret = amdsmi_get_socket_handles(&socket_count, sockets.data());
for (auto& socket : sockets) {
uint32_t processor_count;
uint32_t processor_count = 0;
ret = amdsmi_get_processor_handles(socket, &processor_count, nullptr);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
@@ -234,7 +225,7 @@ amdsmi_status_t get_metrics_info(amdsmi_processor_handle proc, amdsmi_gpu_metric
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_processor_handle proc_handle = nullptr;
amdsmi_status_t ret = get_processor_handle_from_id(index, &proc_handle);
if (ret != AMDSMI_STATUS_SUCCESS) {
return ret;
@@ -35,7 +35,6 @@ THE SOFTWARE.
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <stdexcept>
#include <vector>
@@ -45,7 +44,6 @@ THE SOFTWARE.
#include "rdc_lib/RdcLogger.h"
#include "rdc_lib/RdcTelemetryLibInterface.h"
#include "rdc_lib/impl/SmiUtils.h"
#include "rdc_lib/rdc_common.h"
#include "rdc_modules/rdc_rocp/RdcRocpCounterSampler.h"
namespace amd {
@@ -157,6 +155,7 @@ const char* RdcRocpBase::get_field_id_from_name(rdc_field_t field) {
const std::vector<rdc_field_t> RdcRocpBase::get_field_ids() {
std::vector<rdc_field_t> field_ids;
field_ids.reserve(field_to_metric.size());
for (auto& [k, v] : field_to_metric) {
field_ids.push_back(k);
}
@@ -297,6 +296,7 @@ void RdcRocpBase::init_rocp_if_not() {
}
// populate fields
all_fields.reserve(temp_field_map_k.size());
for (const auto& [k, v] : temp_field_map_k) {
all_fields.emplace_back(v);
}
@@ -43,8 +43,8 @@ class RdciDmonSubSystem : public RdciSubSystem {
void show_field_usage() const;
void clean_up();
// Need to resolve gpu indexes after process is called
void resolve_gpu_indexes();
// Need to resolve device indexes after process is called
void resolve_device_indexes();
void create_temp_group();
void create_temp_field_group();
@@ -67,8 +67,8 @@ class RdciDmonSubSystem : public RdciSubSystem {
std::map<OPTIONS, uint32_t> options_;
std::vector<rdc_field_t> field_ids_;
std::string raw_gpu_indexes_;
std::vector<uint32_t> gpu_indexes_;
std::string raw_device_indexes_;
std::vector<uint32_t> device_indexes_;
bool need_cleanup_;
uint64_t latest_time_stamp_;
bool show_timpstamps_;
@@ -177,7 +177,8 @@ void RdciDiagSubSystem::process() {
for (uint32_t j = 0; j < test_result.per_gpu_result_count; j++) {
const rdc_diag_per_gpu_result_t& gpu_result = test_result.gpu_results[j];
if (strlen(gpu_result.gpu_result.msg) > 0) {
std::cout << " GPU " << gpu_result.gpu_index << " " << gpu_result.gpu_result.msg << "\n";
// Support both GPU and CPU device result reporting
std::cout << " Device " << gpu_result.gpu_index << " " << gpu_result.gpu_result.msg << "\n";
}
}
}
@@ -19,8 +19,6 @@ 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 "RdciDiscoverySubSystem.h"
#include <getopt.h>
#include <unistd.h>
@@ -28,6 +26,7 @@ THE SOFTWARE.
#include <iomanip>
#include <set>
#include "RdciDiscoverySubSystem.h"
#include "rdc/rdc.h"
#include "rdc/rdc_private.h"
#include "rdc_lib/RdcException.h"
@@ -111,6 +110,7 @@ void RdciDiscoverySubSystem::show_help() const {
void RdciDiscoverySubSystem::show_attributes() {
uint32_t gpu_index_list[RDC_MAX_NUM_DEVICES];
uint32_t count = 0;
rdc_status_t result = rdc_device_get_all(rdc_handle_, gpu_index_list, &count);
if (result != RDC_ST_OK) {
throw RdcException(result, "Fail to get device information");
@@ -234,14 +234,14 @@ void RdciDiscoverySubSystem::show_attributes_with_partitions() {
std::cout << ", \"partitions\": [";
}
for (uint32_t pid = 0; pid < num_partition; pid++) {
std::string instance_str = "g" + std::to_string(i) + "." + std::to_string(pid);
std::string instance_str;
rdc_entity_info_t part_info;
part_info.device_index = i;
part_info.instance_index = pid;
part_info.entity_role = RDC_DEVICE_ROLE_PARTITION_INSTANCE;
part_info.device_type = RDC_DEVICE_TYPE_GPU;
uint32_t part_entity_index = rdc_get_entity_index_from_info(part_info);
instance_str = "g" + std::to_string(i) + "." + std::to_string(pid);
rdc_resource_profile_t part_xcc = {};
rdc_resource_profile_t part_decoder = {};
+109 -77
Melihat File
@@ -26,7 +26,6 @@ THE SOFTWARE.
#include <signal.h>
#include <unistd.h>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <ctime>
@@ -35,14 +34,12 @@ THE SOFTWARE.
#include <queue>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/rdc_fields_supported.h"
#include "common/rdc_utils.h"
#include "rdc/rdc.h"
#include "rdc_lib/RdcException.h"
#include "rdc_lib/rdc_common.h"
namespace amd {
namespace rdc {
@@ -68,7 +65,11 @@ std::string entity_to_string(uint32_t entity_index) {
rdc_entity_info_t info = rdc_get_info_from_entity_index(entity_index);
if (info.entity_role == RDC_DEVICE_ROLE_PARTITION_INSTANCE) {
return "g" + std::to_string(info.device_index) + "." + std::to_string(info.instance_index);
if (info.device_type == RDC_DEVICE_TYPE_CPU) {
return "c" + std::to_string(info.device_index) + "." + std::to_string(info.instance_index);
} else {
return "g" + std::to_string(info.device_index) + "." + std::to_string(info.instance_index);
}
}
return std::to_string(info.device_index);
}
@@ -166,16 +167,15 @@ void RdciDmonSubSystem::parse_cmd_opts(int argc, char** argv) {
throw RdcException(RDC_ST_BAD_PARAMETER, "Need to specify the fields or field group id");
} else {
std::vector<std::string> vec_ids = split_string(field_ids, ',');
for (uint32_t i = 0; i < vec_ids.size(); i++) {
if (!IsNumber(vec_ids[i])) {
for (const auto& vec_id : vec_ids) {
if (!IsNumber(vec_id)) {
rdc_field_t field_id = RDC_FI_INVALID;
if (!amd::rdc::get_field_id_from_name(vec_ids[i], &field_id)) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"The field name " + vec_ids[i] + " is not valid");
if (!amd::rdc::get_field_id_from_name(vec_id, &field_id)) {
throw RdcException(RDC_ST_BAD_PARAMETER, "The field name " + vec_id + " is not valid");
}
field_ids_.push_back(field_id);
} else {
field_ids_.push_back(static_cast<rdc_field_t>(std::stoi(vec_ids[i])));
field_ids_.push_back(static_cast<rdc_field_t>(std::stoi(vec_id)));
}
}
}
@@ -204,7 +204,7 @@ void RdciDmonSubSystem::parse_cmd_opts(int argc, char** argv) {
}
// Store gpu indexes to parse later
raw_gpu_indexes_ = gpu_indexes;
raw_device_indexes_ = gpu_indexes;
}
void RdciDmonSubSystem::show_help() const {
@@ -254,12 +254,12 @@ void RdciDmonSubSystem::show_help() const {
}
void RdciDmonSubSystem::create_temp_group() {
if (gpu_indexes_.size() == 0) {
if (device_indexes_.size() == 0) {
return;
}
const std::string group_name("rdci-dmon-group");
rdc_gpu_group_t group_id;
rdc_gpu_group_t group_id = 0;
rdc_status_t result =
rdc_group_gpu_create(rdc_handle_, RDC_GROUP_EMPTY, group_name.c_str(), &group_id);
if (result != RDC_ST_OK) {
@@ -267,17 +267,10 @@ void RdciDmonSubSystem::create_temp_group() {
}
need_cleanup_ = true;
for (uint32_t i = 0; i < gpu_indexes_.size(); i++) {
result = rdc_group_gpu_add(rdc_handle_, group_id, gpu_indexes_[i]);
for (unsigned int device_index : device_indexes_) {
result = rdc_group_gpu_add(rdc_handle_, group_id, device_index);
if (result != RDC_ST_OK) {
rdc_entity_info_t info = rdc_get_info_from_entity_index(gpu_indexes_[i]);
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);
}
std::string info_str = entity_to_string(device_index);
throw RdcException(result, "Fail to add " + info_str + " to the dmon group.");
}
}
@@ -290,7 +283,7 @@ void RdciDmonSubSystem::create_temp_field_group() {
}
const std::string field_group_name("rdci-dmon-field-group");
rdc_field_grp_t group_id;
rdc_field_grp_t group_id = 0;
rdc_field_t field_ids[RDC_MAX_FIELD_IDS_PER_FIELD_GROUP];
for (uint32_t i = 0; i < field_ids_.size(); i++) {
field_ids[i] = field_ids_[i];
@@ -306,7 +299,7 @@ void RdciDmonSubSystem::create_temp_field_group() {
options_.insert({OPTIONS_FIELD_GROUP_ID, group_id});
}
void RdciDmonSubSystem::resolve_gpu_indexes() {
void RdciDmonSubSystem::resolve_device_indexes() {
uint32_t device_list[RDC_MAX_NUM_DEVICES];
uint32_t count = 0;
rdc_status_t res = rdc_device_get_all(rdc_handle_, device_list, &count);
@@ -314,66 +307,105 @@ void RdciDmonSubSystem::resolve_gpu_indexes() {
throw RdcException(res, "Failed to get all devices");
}
// If neither group or gpu_index was specified, default to all
if (raw_gpu_indexes_.empty()) {
gpu_indexes_.assign(device_list, device_list + count);
// If neither group or device_index was specified, default to all
if (raw_device_indexes_.empty()) {
device_indexes_.assign(device_list, device_list + count);
return;
}
std::vector<std::string> vec_ids = split_string(raw_gpu_indexes_, ',');
for (uint32_t i = 0; i < vec_ids.size(); i++) {
if (rdc_is_partition_string(vec_ids[i].c_str())) {
uint32_t logicalPhysicalGpu;
uint32_t partition;
if (!rdc_parse_partition_string(vec_ids[i].c_str(), &logicalPhysicalGpu, &partition)) {
throw RdcException(RDC_ST_BAD_PARAMETER, "Invalid partition format: " + vec_ids[i]);
std::vector<std::string> vec_ids = split_string(raw_device_indexes_, ',');
for (const auto& vec_id : vec_ids) {
if (rdc_is_partition_string(vec_id.c_str())) {
uint32_t logicalPhysicalDevice = 0;
uint32_t partition = 0;
if (!rdc_parse_partition_string(vec_id.c_str(), &logicalPhysicalDevice, &partition)) {
throw RdcException(RDC_ST_BAD_PARAMETER, "Invalid partition format: " + vec_id);
}
if (logicalPhysicalGpu >= count) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"GPU " + std::to_string(logicalPhysicalGpu) + " is out of range");
// Detect device type from partition string prefix
bool is_cpu_device = (vec_id[0] == 'c');
std::string device_type_str = is_cpu_device ? "CPU" : "GPU";
if (logicalPhysicalDevice >= count) {
throw RdcException(
RDC_ST_BAD_PARAMETER,
device_type_str + " " + std::to_string(logicalPhysicalDevice) + " is out of range");
}
uint32_t physicalGpu = device_list[logicalPhysicalGpu];
uint32_t physicalDevice = device_list[logicalPhysicalDevice];
uint16_t num_partitions = 0;
rdc_status_t st = rdc_get_num_partition(rdc_handle_, physicalGpu, &num_partitions);
if (st != RDC_ST_OK) {
throw RdcException(st,
"Failed to get partition info for GPU " + std::to_string(physicalGpu));
}
if (num_partitions == UINT16_MAX || num_partitions <= 1) {
if (is_cpu_device) {
// CPU-specific validation: CPUs don't have GPU-style partitioning
if (partition != 0) {
throw RdcException(RDC_ST_BAD_PARAMETER, "GPU " + std::to_string(physicalGpu) +
" is not partitioned, so partition " +
std::to_string(partition) + " is invalid");
throw RdcException(RDC_ST_BAD_PARAMETER,
"CPU " + std::to_string(physicalDevice) +
" does not support partitioning, partition " +
std::to_string(partition) + " is invalid");
}
} else {
if (partition >= num_partitions) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"GPU " + std::to_string(physicalGpu) + " supports only " +
std::to_string(num_partitions) + " partitions, partition " +
std::to_string(partition) + " is invalid");
// GPU-specific validation: Check GPU partitioning
uint16_t num_partitions = 0;
rdc_status_t st = rdc_get_num_partition(rdc_handle_, physicalDevice, &num_partitions);
if (st != RDC_ST_OK) {
throw RdcException(
st, "Failed to get partition info for GPU " + std::to_string(physicalDevice));
}
if (num_partitions == UINT16_MAX || num_partitions <= 1) {
if (partition != 0) {
throw RdcException(RDC_ST_BAD_PARAMETER, "GPU " + std::to_string(physicalDevice) +
" is not partitioned, so partition " +
std::to_string(partition) + " is invalid");
}
} else {
if (partition >= num_partitions) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"GPU " + std::to_string(physicalDevice) + " supports only " +
std::to_string(num_partitions) + " partitions, partition " +
std::to_string(partition) + " is invalid");
}
}
}
rdc_entity_info_t phys_info;
phys_info.device_index = physicalGpu;
phys_info.device_index = physicalDevice;
phys_info.instance_index = partition;
phys_info.entity_role = RDC_DEVICE_ROLE_PARTITION_INSTANCE;
phys_info.device_type = RDC_DEVICE_TYPE_GPU;
phys_info.device_type = is_cpu_device ? RDC_DEVICE_TYPE_CPU : RDC_DEVICE_TYPE_GPU;
uint32_t phys_entity_index = rdc_get_entity_index_from_info(phys_info);
gpu_indexes_.push_back(phys_entity_index);
} else if (IsNumber(vec_ids[i])) {
uint32_t logicalIndex = std::stoi(vec_ids[i]);
device_indexes_.push_back(phys_entity_index);
} else if (IsNumber(vec_id)) {
uint32_t logicalIndex = std::stoi(vec_id);
if (logicalIndex >= count) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"GPU " + std::to_string(logicalIndex) + " is out of range");
"Device " + std::to_string(logicalIndex) + " is out of range");
}
gpu_indexes_.push_back(std::stoi(vec_ids[i]));
device_indexes_.push_back(std::stoi(vec_id));
} else if (vec_id.length() >= 2 && vec_id[0] == 'c') {
// Handle CPU device IDs like "c0", "c1", etc. (without partition)
std::string cpu_id = vec_id.substr(1);
if (!IsNumber(cpu_id)) {
throw RdcException(RDC_ST_BAD_PARAMETER, "Invalid CPU device ID: " + vec_id);
}
uint32_t logicalIndex = std::stoi(cpu_id);
if (logicalIndex >= count) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"CPU " + std::to_string(logicalIndex) + " is out of range");
}
uint32_t physicalDevice = device_list[logicalIndex];
// Create CPU entity with partition 0 (CPUs don't have partitions)
rdc_entity_info_t cpu_info;
cpu_info.device_index = physicalDevice;
cpu_info.instance_index = 0; // Always 0 for CPUs
cpu_info.entity_role = RDC_DEVICE_ROLE_PARTITION_INSTANCE;
cpu_info.device_type = RDC_DEVICE_TYPE_CPU;
uint32_t cpu_entity_index = rdc_get_entity_index_from_info(cpu_info);
device_indexes_.push_back(cpu_entity_index);
} else {
throw RdcException(RDC_ST_BAD_PARAMETER, "The GPU index " + vec_ids[i] +
throw RdcException(RDC_ST_BAD_PARAMETER, "The device index " + vec_id +
" needs to be a number or a valid partition");
}
}
@@ -383,9 +415,9 @@ void RdciDmonSubSystem::show_field_usage() const {
std::cout << "Supported fields Ids:" << std::endl;
amd::rdc::fld_id2name_map_t& field_id_to_descript = amd::rdc::get_field_id_description_from_id();
for (auto i = field_id_to_descript.begin(); i != field_id_to_descript.end(); i++) {
if (i->second.do_display || dmon_ops_ == DMON_LIST_ALL_FIELDS) {
std::cout << i->first << " " << i->second.enum_name << " : " << i->second.description << "."
for (const auto& i : field_id_to_descript) {
if (i.second.do_display || dmon_ops_ == DMON_LIST_ALL_FIELDS) {
std::cout << i.first << " " << i.second.enum_name << " : " << i.second.description << "."
<< std::endl;
}
}
@@ -428,10 +460,10 @@ typedef std::priority_queue<notif_dev_value, std::vector<notif_dev_value>, Compa
static void collect_new_notifs(rdc_handle_t h, const rdc_group_info_t& group_info,
const std::vector<rdc_field_t>& notif_fields,
std::vector<uint64_t>* notif_ts, field_pq_t* notif_pq) {
rdc_status_t ret;
rdc_status_t ret = RDC_ST_UNKNOWN_ERROR;
notif_dev_value value;
std::string error_msg;
uint64_t next_ts;
uint64_t next_ts = 0;
assert(notif_ts != nullptr);
@@ -461,7 +493,7 @@ static void collect_new_notifs(rdc_handle_t h, const rdc_group_info_t& group_inf
// ts is milliseconds
static std::string ts_string(const time_t ts) {
struct tm* timeinfo;
struct tm* timeinfo = nullptr;
time_t tmp_ts = ts / 1000;
std::string ret;
@@ -504,11 +536,11 @@ void RdciDmonSubSystem::process() {
return;
}
rdc_status_t result;
rdc_status_t result = RDC_ST_UNKNOWN_ERROR;
rdc_group_info_t group_info;
rdc_field_group_info_t field_info;
resolve_gpu_indexes();
resolve_device_indexes();
// Create a temporary group/field if pass as GPU indexes or field ids
create_temp_group();
@@ -549,9 +581,9 @@ void RdciDmonSubSystem::process() {
// keep extra 1 minute data
double max_keep_age = options_[OPTIONS_DELAY] / 1000.0 + 60;
const int max_keep_samples = 10; // keep only 10 samples
result =
rdc_field_watch(rdc_handle_, options_[OPTIONS_GROUP_ID], options_[OPTIONS_FIELD_GROUP_ID],
options_[OPTIONS_DELAY] * 1000, max_keep_age, max_keep_samples);
result = rdc_field_watch(
rdc_handle_, options_[OPTIONS_GROUP_ID], options_[OPTIONS_FIELD_GROUP_ID],
static_cast<uint64_t>(options_[OPTIONS_DELAY]) * 1000, max_keep_age, max_keep_samples);
need_cleanup_ = true;
std::stringstream ss;
@@ -570,8 +602,8 @@ void RdciDmonSubSystem::process() {
ss << std::left << std::setw(25) << "TIMESTAMP";
ss << " ";
}
for (uint32_t findex = 0; findex < reg_fields.size(); findex++) {
ss << std::left << std::setw(20) << field_id_string(reg_fields[findex]);
for (auto& reg_field : reg_fields) {
ss << std::left << std::setw(20) << field_id_string(reg_field);
}
ss << std::endl;
@@ -644,7 +676,7 @@ void RdciDmonSubSystem::clean_up() {
rdc_field_unwatch(rdc_handle_, options_[OPTIONS_GROUP_ID], options_[OPTIONS_FIELD_GROUP_ID]);
}
if (gpu_indexes_.size() != 0) {
if (device_indexes_.size() != 0) {
auto group = options_.find(OPTIONS_GROUP_ID);
if (group != options_.end()) {
rdc_group_gpu_destroy(rdc_handle_, group->second);
@@ -167,6 +167,12 @@ void RdciFieldGroupSubSystem::process() {
} else {
field_ids[i] = static_cast<rdc_field_t>(std::stoi(fields[i]));
}
// Validate field compatibility with available devices
if (!is_field_valid(field_ids[i])) {
throw RdcException(RDC_ST_BAD_PARAMETER,
"Field " + std::to_string(field_ids[i]) + " is not supported");
}
}
rdc_field_grp_t group_id;
result = rdc_group_field_create(rdc_handle_, fields.size(), &field_ids[0],
+15 -3
Melihat File
@@ -52,10 +52,22 @@ FetchContent_Declare(
FetchContent_MakeAvailable(googletest)
# Source files
aux_source_directory(${SRC_DIR} rdctstSources)
set(rdctstSources
${SRC_DIR}/main.cc
${SRC_DIR}/test_base.cc
${SRC_DIR}/test_common.cc
${SRC_DIR}/test_utils.cc
)
# Other source directories
aux_source_directory(${SRC_DIR}/functional functionalSources)
# Functional test source files
set(functionalSources
${SRC_DIR}/functional/rdci_discovery.cc
${SRC_DIR}/functional/rdci_dmon.cc
${SRC_DIR}/functional/rdci_fieldgroup.cc
${SRC_DIR}/functional/rdci_group.cc
${SRC_DIR}/functional/rdci_stats.cc
${SRC_DIR}/functional/rdci_cpu_support.cc
)
link_directories(${ROCM_INSTALL_DIR} ${AMD_SMI_LIB_DIR})
@@ -0,0 +1,140 @@
/*
Copyright (c) 2025 - 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.
*/
/**
* @brief Test CPU support infrastructure in RDC
*
* These tests validate the CPU support framework without requiring AMD CPU hardware.
* They focus on infrastructure validation, field definitions, partition string parsing,
* and entity management rather than actual CPU metric collection.
*/
#include <gtest/gtest.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include "rdc/rdc.h"
#include "rdc_lib/RdcEntityCodec.h"
class RdcCpuSupportTest : public ::testing::Test {
protected:
void SetUp() override {
rdc_status_t result = rdc_init(0x0);
ASSERT_EQ(result, RDC_ST_OK);
result = rdc_start_embedded(RDC_OPERATION_MODE_AUTO, &rdc_handle_);
ASSERT_EQ(result, RDC_ST_OK);
ASSERT_NE(rdc_handle_, nullptr);
}
void TearDown() override {
if (rdc_handle_ != nullptr) {
rdc_stop_embedded(rdc_handle_);
rdc_handle_ = nullptr;
}
rdc_shutdown();
}
rdc_handle_t rdc_handle_ = nullptr;
};
// Test CPU partition string parsing
TEST_F(RdcCpuSupportTest, CpuPartitionStringParsing) {
// generate map to test this feature
std::map<std::pair<uint32_t, uint32_t>, std::string> cpu_partition_string_map = {
{{0, 0}, "c0.0"}, {{1, 0}, "c1.0"}, {{0, 1}, "c0.1"}, {{2, 0}, "c2.0"}, {{15, 7}, "c15.7"}};
for (const auto& [indices, partition_str] : cpu_partition_string_map) {
uint32_t device_index = 255;
uint32_t instance_index = 255;
bool parsed = rdc_parse_partition_string(partition_str.c_str(), &device_index, &instance_index);
EXPECT_TRUE(parsed) << "Should successfully parse CPU partition string: " << partition_str;
EXPECT_EQ(device_index, indices.first)
<< "Device index should match for partition string: " << partition_str;
EXPECT_EQ(instance_index, indices.second)
<< "Instance index should match for partition string: " << partition_str;
}
}
// Test CPU field group creation
TEST_F(RdcCpuSupportTest, CpuFieldGroupCreation) {
// Test creating field groups with CPU fields
std::vector<rdc_field_t> cpu_fields = {RDC_FI_CPU_SKT_COUNT, RDC_FI_CPU_MODEL};
rdc_field_grp_t field_group_id = 0;
const char* group_name = "cpu_test_group";
// Create field group with CPU fields
rdc_status_t result =
rdc_group_field_create(rdc_handle_, static_cast<uint32_t>(cpu_fields.size()), &cpu_fields[0],
group_name, &field_group_id);
// Should succeed in creating CPU field group
EXPECT_EQ(result, RDC_ST_OK) << "Should be able to create CPU field group";
if (result == RDC_ST_OK) {
// Verify we can get field group info
rdc_field_group_info_t group_info;
rdc_status_t info_result = rdc_group_field_get_info(rdc_handle_, field_group_id, &group_info);
EXPECT_EQ(info_result, RDC_ST_OK) << "Should be able to get field group info";
if (info_result == RDC_ST_OK) {
EXPECT_EQ(group_info.count, cpu_fields.size()) << "Field group should have correct count";
EXPECT_STREQ(group_info.group_name, group_name) << "Field group should have correct name";
}
// Clean up
rdc_group_field_destroy(rdc_handle_, field_group_id);
}
}
// Test mixed GPU/CPU field groups
TEST_F(RdcCpuSupportTest, MixedGpuCpuFieldGroups) {
// Test creating field groups with both GPU and CPU fields
std::vector<rdc_field_t> mixed_fields = {
RDC_FI_GPU_UTIL, // GPU field
RDC_FI_CPU_CCLK_LIMIT, // CPU field
RDC_FI_GPU_TEMP, // GPU field
RDC_FI_CPU_FCLK_FREQUENCY // CPU field
};
rdc_field_grp_t field_group_id = 0;
const char* group_name = "mixed_test_group";
// Create field group with mixed GPU/CPU fields
rdc_status_t result =
rdc_group_field_create(rdc_handle_, static_cast<uint32_t>(mixed_fields.size()),
&mixed_fields[0], group_name, &field_group_id);
// Should succeed in creating mixed field group
EXPECT_EQ(result, RDC_ST_OK) << "Should be able to create mixed GPU/CPU field group";
if (result == RDC_ST_OK) {
// Clean up
rdc_group_field_destroy(rdc_handle_, field_group_id);
}
}