rdc: Add CPU support and CPU metrics infrastructure (#770)
This commit is contained in:
@@ -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})
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
set noparent
|
||||
linelength=100
|
||||
filter=-build/include_subdir,-legal/copyright,-runtime/printf,-build/c++11,-runtime/int,-build/header_guard
|
||||
@@ -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)
|
||||
|
||||
@@ -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, ×tamp);
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user