Merge pull request #9 from cfreehill/pp_od_clk_voltage
Add support for reading frequency-volt curve data
[ROCm/amdsmi commit: ef27d41628]
This commit is contained in:
@@ -44,7 +44,7 @@ set(ROCM_SMI_TARGET "${ROCM_SMI}64")
|
|||||||
# Until ABI stabilizes VERSION_MAJOR will be 0. This should be over-ridden
|
# Until ABI stabilizes VERSION_MAJOR will be 0. This should be over-ridden
|
||||||
# by git tags (through "git describe") when they are present.
|
# by git tags (through "git describe") when they are present.
|
||||||
set(ROCM_SMI_LIB_VERSION_MAJOR 0)
|
set(ROCM_SMI_LIB_VERSION_MAJOR 0)
|
||||||
set(ROCM_SMI_LIB_VERSION_MINOR 1)
|
set(ROCM_SMI_LIB_VERSION_MINOR 2)
|
||||||
|
|
||||||
################# Determine the library version #########################
|
################# Determine the library version #########################
|
||||||
## Setup the package version based on git tags.
|
## Setup the package version based on git tags.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Package: rocm_smi_lib
|
||||||
|
Architecture: amd64
|
||||||
|
Maintainer: Advanced Micro Devices Inc.
|
||||||
|
Priority: optional
|
||||||
|
Version: MODULE_VERSION
|
||||||
|
Depends:
|
||||||
|
Homepage: https://github.com/RadeonOpenCompute/rocm_smi_lib
|
||||||
|
Description: System Management Interface Library for ROCm
|
||||||
|
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
do_ldconfig() {
|
||||||
|
echo /opt/rocm/lib > /etc/ld.so.conf.d/x86_64-librocm_smi_lib.conf && ldconfig
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
configure)
|
||||||
|
do_ldconfig
|
||||||
|
;;
|
||||||
|
abort-upgrade|abort-remove|abort-deconfigure)
|
||||||
|
echo "$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
rm_ldconfig() {
|
||||||
|
rm -f /etc/ld.so.conf.d/x86_64-librocm_smi_lib.conf && ldconfig
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
remove)
|
||||||
|
rm_ldconfig
|
||||||
|
;;
|
||||||
|
purge)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/opt/rocm/lib
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
echo -e "/opt/rocm/lib\n/opt/rocm/lib64" > /etc/ld.so.conf.d/x86_64-librocm_smi_lib.conf && ldconfig
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
if [ $1 -eq 0 ]; then
|
||||||
|
rm -f /etc/ld.so.conf.d/x86_64-librocm_smi_lib.conf && ldconfig
|
||||||
|
fi
|
||||||
@@ -54,15 +54,28 @@ extern "C" {
|
|||||||
* Main header file for the ROCm SMI library.
|
* Main header file for the ROCm SMI library.
|
||||||
* All required function, structure, enum, etc. definitions should be defined
|
* All required function, structure, enum, etc. definitions should be defined
|
||||||
* in this file.
|
* in this file.
|
||||||
|
*
|
||||||
|
* @unstable The rocm_smi library api is new, and therefore subject to change
|
||||||
|
* either at the ABI or API level. Once committed, every effort will be made
|
||||||
|
* to not break backward compatibility, but it may not be achieveable in some
|
||||||
|
* cases. Instead of marking every function prototype as "unstable", we are
|
||||||
|
* instead saying the API is unstable (i.e., changes are possible) while the
|
||||||
|
* major version remains 0. This means that if the API/ABI changes, we will
|
||||||
|
* not increment the major version to 1. Once the ABI stabilizes, we will
|
||||||
|
* increment the major version to 1, and thereafter increment it on all ABI
|
||||||
|
* breaks.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//! Guaranteed maximum possible number of supported frequencies
|
//! Guaranteed maximum possible number of supported frequencies
|
||||||
#define RSMI_MAX_NUM_FREQUENCIES 32
|
#define RSMI_MAX_NUM_FREQUENCIES 32
|
||||||
|
|
||||||
//! Maximum possible value for fan speed. Should be used as the denominator when
|
//! Maximum possible value for fan speed. Should be used as the denominator
|
||||||
//! determining fan speed percentage.
|
//! when determining fan speed percentage.
|
||||||
#define RSMI_MAX_FAN_SPEED 255
|
#define RSMI_MAX_FAN_SPEED 255
|
||||||
|
|
||||||
|
//! The number of points that make up a voltage-frequency curve definition
|
||||||
|
#define RSMI_NUM_VOLTAGE_CURVE_POINTS 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Error codes retured by rocm_smi_lib functions
|
* @brief Error codes retured by rocm_smi_lib functions
|
||||||
*/
|
*/
|
||||||
@@ -271,6 +284,57 @@ typedef struct {
|
|||||||
const char *build; //!< Build string
|
const char *build; //!< Build string
|
||||||
} rsmi_version;
|
} rsmi_version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This structure represents a range (e.g., frequencies or voltages).
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t lower_bound; //!< Lower bound of range
|
||||||
|
uint64_t upper_bound; //!< Upper bound of range
|
||||||
|
} rsmi_range;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This structure represents a point on the frequency-voltage plane.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint64_t frequency; //!< Frequency coordinate (in Hz)
|
||||||
|
uint64_t voltage; //!< Voltage coordinate (in mV)
|
||||||
|
} rsmi_od_vddc_point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This structure holds 2 ::rsmi_od_vddc_point's, representing the
|
||||||
|
* diagonal corners of a rectangular region in freq-voltage space.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
rsmi_od_vddc_point min_corner; //!< The "lower-left" corner of rectangle
|
||||||
|
rsmi_od_vddc_point max_corner; //!< The "upper-right" corner of rectangle
|
||||||
|
} rsmi_freq_volt_region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This structure holds the frequency-voltage values for a device.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
rsmi_range curr_sclk_range; //!< The current SCLK frequency range
|
||||||
|
rsmi_range curr_mclk_range; //!< The current MCLK frequency range;
|
||||||
|
//!< (upper bound only)
|
||||||
|
rsmi_range sclk_freq_limits; //!< The range possible of SCLK values
|
||||||
|
rsmi_range mclk_freq_limits; //!< The range possible of MCLK values
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current voltage curve
|
||||||
|
*/
|
||||||
|
rsmi_od_vddc_point curve[RSMI_NUM_VOLTAGE_CURVE_POINTS];
|
||||||
|
uint32_t num_regions; //!< The number of voltage curve regions
|
||||||
|
} rsmi_od_volt_freq_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This values of this enum are used as frequency identifiers.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
RSMI_FREQ_IND_MIN = 0, //!< Index used for the minimum frequency value
|
||||||
|
RSMI_FREQ_IND_MAX = 1, //!< Index used for the maximum frequency value
|
||||||
|
RSMI_FREQ_IND_INVALID = 0xFFFFFFFF //!< An invalid frequency index
|
||||||
|
} rsmi_freq_ind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize Rocm SMI.
|
* @brief Initialize Rocm SMI.
|
||||||
*
|
*
|
||||||
@@ -701,6 +765,51 @@ rsmi_status_t rsmi_dev_fan_speed_max_get(uint32_t dv_ind,
|
|||||||
rsmi_status_t rsmi_dev_fan_speed_set(uint32_t dv_ind, uint32_t sensor_ind,
|
rsmi_status_t rsmi_dev_fan_speed_set(uint32_t dv_ind, uint32_t sensor_ind,
|
||||||
uint64_t speed);
|
uint64_t speed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function retrieves the voltage/frequency curve information
|
||||||
|
*
|
||||||
|
* @details Given a device index @p dv_ind and a pointer to a
|
||||||
|
* ::rsmi_od_volt_freq_data structure @p odv, this function will populate @p
|
||||||
|
* odv. See ::rsmi_od_volt_freq_data for more details.
|
||||||
|
*
|
||||||
|
* @param[in] dv_ind a device index
|
||||||
|
*
|
||||||
|
* @param[in] odv a pointer to an ::rsmi_od_volt_freq_data structure
|
||||||
|
*
|
||||||
|
* @retval ::RSMI_STATUS_SUCCESS is returned upon successful call.
|
||||||
|
*/
|
||||||
|
rsmi_status_t rsmi_dev_od_volt_info_get(uint32_t dv_ind,
|
||||||
|
rsmi_od_volt_freq_data *odv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function will retrieve the current valid regions in the
|
||||||
|
* frequency/voltage space.
|
||||||
|
*
|
||||||
|
* @details Given a device index @p dv_ind, a pointer to an unsigned integer
|
||||||
|
* @p num_regions and a buffer of ::rsmi_freq_volt_region structures, @p
|
||||||
|
* buffer, this function will populate @p buffer with the current
|
||||||
|
* frequency-volt space regions. The caller should assign @p buffer to memory
|
||||||
|
* that can be written to by this function. The caller should also
|
||||||
|
* indicate the number of ::rsmi_freq_volt_region structures that can safely
|
||||||
|
* be written to @p buffer in @p num_regions.
|
||||||
|
*
|
||||||
|
* The number of regions to expect this function provide (@p num_regions) can
|
||||||
|
* be obtained by calling ::rsmi_dev_od_volt_info_get().
|
||||||
|
*
|
||||||
|
* @param[in] dv_ind a device index
|
||||||
|
*
|
||||||
|
* @param[inout] num_regions As input, this is the number of
|
||||||
|
* ::rsmi_freq_volt_region structures that can be written to @p buffer. As
|
||||||
|
* output, this is the number of ::rsmi_freq_volt_region structures that were
|
||||||
|
* actually written.
|
||||||
|
*
|
||||||
|
* @param[inout] buffer a caller provided buffer to which
|
||||||
|
* ::rsmi_freq_volt_region structures will be written
|
||||||
|
*
|
||||||
|
* @retval ::RSMI_STATUS_SUCCESS is returned upon successful call.
|
||||||
|
*/
|
||||||
|
rsmi_status_t rsmi_dev_od_volt_curve_regions_get(uint32_t dv_ind,
|
||||||
|
uint32_t *num_regions, rsmi_freq_volt_region *buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the average power consumption of the device with provided
|
* @brief Get the average power consumption of the device with provided
|
||||||
@@ -894,7 +1003,7 @@ rsmi_status_string(rsmi_status_t status, const char **status_string);
|
|||||||
* @details Get the major, minor, patch and build string for RSMI build
|
* @details Get the major, minor, patch and build string for RSMI build
|
||||||
* currently in use through @p version
|
* currently in use through @p version
|
||||||
*
|
*
|
||||||
* @paramp[inout] version A pointer to an ::rsmi_version structure that will
|
* @param[inout] version A pointer to an ::rsmi_version structure that will
|
||||||
* be updated with the version information upon return.
|
* be updated with the version information upon return.
|
||||||
*
|
*
|
||||||
* @retval ::RSMI_STATUS_SUCCESS is returned upon successful call
|
* @retval ::RSMI_STATUS_SUCCESS is returned upon successful call
|
||||||
|
|||||||
@@ -58,6 +58,10 @@
|
|||||||
struct RocmSMI_env_vars {
|
struct RocmSMI_env_vars {
|
||||||
// Store env. variables here
|
// Store env. variables here
|
||||||
uint32_t debug_output_bitfield;
|
uint32_t debug_output_bitfield;
|
||||||
|
uint32_t enum_override;
|
||||||
|
const char *path_DRM_root_override;
|
||||||
|
const char *path_HWMon_root_override;
|
||||||
|
const char *path_power_root_override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_ROCM_SMI_ROCM_SMI_COMMON_H_
|
#endif // INCLUDE_ROCM_SMI_ROCM_SMI_COMMON_H_
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ enum DevInfoTypes {
|
|||||||
kDevPCIEBW,
|
kDevPCIEBW,
|
||||||
kDevPowerProfileMode,
|
kDevPowerProfileMode,
|
||||||
kDevUsage,
|
kDevUsage,
|
||||||
|
kDevPowerODVoltage,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Device {
|
class Device {
|
||||||
|
|||||||
+256
-25
@@ -108,18 +108,46 @@ static rsmi_status_t errno_to_rsmi_status(uint32_t err) {
|
|||||||
default: return RSMI_STATUS_UNKNOWN_ERROR;
|
default: return RSMI_STATUS_UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t get_multiplier_from_str(char units_char) {
|
||||||
|
uint32_t multiplier = 0;
|
||||||
|
|
||||||
|
switch (units_char) {
|
||||||
|
case 'G': // GT or GHz
|
||||||
|
multiplier = 1000000000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'M': // MT or MHz
|
||||||
|
multiplier = 1000000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'K': // KT or KHz
|
||||||
|
case 'V': // default unit for voltage is mV
|
||||||
|
multiplier = 1000;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'T': // Transactions
|
||||||
|
case 'H': // Hertz
|
||||||
|
case 'm': // mV (we will make mV the default unit for voltage)
|
||||||
|
multiplier = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(!"Unexpected units for frequency");
|
||||||
|
}
|
||||||
|
return multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string of the form:
|
* Parse a string of the form:
|
||||||
* "<int index>: <int freq><freq. unit string> <|*>"
|
* "<int index>: <int freq><freq. unit string> <|*>"
|
||||||
*/
|
*/
|
||||||
static uint64_t freq_string_to_int(const std::vector<std::string> &freq_lines,
|
static uint64_t freq_string_to_int(const std::vector<std::string> &freq_lines,
|
||||||
bool *is_curr, uint32_t lanes[], int i) {
|
bool *is_curr, uint32_t lanes[], int i) {
|
||||||
assert(is_curr != nullptr);
|
|
||||||
|
|
||||||
std::istringstream fs(freq_lines[i]);
|
std::istringstream fs(freq_lines[i]);
|
||||||
|
|
||||||
uint32_t ind;
|
uint32_t ind;
|
||||||
float freq;
|
long double freq;
|
||||||
std::string junk;
|
std::string junk;
|
||||||
std::string units_str;
|
std::string units_str;
|
||||||
std::string star_str;
|
std::string star_str;
|
||||||
@@ -137,28 +165,7 @@ static uint64_t freq_string_to_int(const std::vector<std::string> &freq_lines,
|
|||||||
*is_curr = false;
|
*is_curr = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t multiplier = 0;
|
uint32_t multiplier = get_multiplier_from_str(units_str[0]);
|
||||||
|
|
||||||
switch (units_str[0]) {
|
|
||||||
case 'G': // GT or GHz
|
|
||||||
multiplier = 1000000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'M': // MT or MHz
|
|
||||||
multiplier = 1000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'K': // KT or KHz
|
|
||||||
multiplier = 1000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'T': // Transactions
|
|
||||||
case 'H': // Hertz
|
|
||||||
multiplier = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(!"Unexpected units for frequency");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (star_str[0] == 'x') {
|
if (star_str[0] == 'x') {
|
||||||
assert(lanes != nullptr && "Lanes are provided but null lanes pointer");
|
assert(lanes != nullptr && "Lanes are provided but null lanes pointer");
|
||||||
@@ -169,6 +176,63 @@ static uint64_t freq_string_to_int(const std::vector<std::string> &freq_lines,
|
|||||||
return freq*multiplier;
|
return freq*multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void freq_volt_string_to_point(std::string in_line,
|
||||||
|
rsmi_od_vddc_point *pt) {
|
||||||
|
std::istringstream fs_vlt(in_line);
|
||||||
|
|
||||||
|
assert(pt != nullptr);
|
||||||
|
|
||||||
|
uint32_t ind;
|
||||||
|
long double freq;
|
||||||
|
long double volts;
|
||||||
|
std::string junk;
|
||||||
|
std::string freq_units_str;
|
||||||
|
std::string volts_units_str;
|
||||||
|
|
||||||
|
fs_vlt >> ind;
|
||||||
|
fs_vlt >> junk; // colon
|
||||||
|
fs_vlt >> freq;
|
||||||
|
fs_vlt >> freq_units_str;
|
||||||
|
fs_vlt >> volts;
|
||||||
|
fs_vlt >> volts_units_str;
|
||||||
|
|
||||||
|
uint32_t multiplier = get_multiplier_from_str(freq_units_str[0]);
|
||||||
|
|
||||||
|
pt->frequency = freq*multiplier;
|
||||||
|
|
||||||
|
multiplier = get_multiplier_from_str(volts_units_str[0]);
|
||||||
|
pt->voltage = volts*multiplier;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void od_value_pair_str_to_range(std::string in_line, rsmi_range *rg) {
|
||||||
|
std::istringstream fs_rng(in_line);
|
||||||
|
|
||||||
|
assert(rg != nullptr);
|
||||||
|
|
||||||
|
std::string clk;
|
||||||
|
uint64_t lo;
|
||||||
|
uint64_t hi;
|
||||||
|
std::string lo_units_str;
|
||||||
|
std::string hi_units_str;
|
||||||
|
|
||||||
|
fs_rng >> clk; // This is clk + colon; e.g., "SCLK:"
|
||||||
|
fs_rng >> lo;
|
||||||
|
fs_rng >> lo_units_str;
|
||||||
|
fs_rng >> hi;
|
||||||
|
fs_rng >> hi_units_str;
|
||||||
|
|
||||||
|
uint32_t multiplier = get_multiplier_from_str(lo_units_str[0]);
|
||||||
|
|
||||||
|
rg->lower_bound = lo*multiplier;
|
||||||
|
|
||||||
|
multiplier = get_multiplier_from_str(hi_units_str[0]);
|
||||||
|
rg->upper_bound = hi*multiplier;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string of the form "<int index> <mode name string> <|*>"
|
* Parse a string of the form "<int index> <mode name string> <|*>"
|
||||||
@@ -540,6 +604,153 @@ static rsmi_status_t get_power_profiles(uint32_t dv_ind,
|
|||||||
CATCH
|
CATCH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We expect the format of the the pp_od_clk_voltage file to look like this:
|
||||||
|
OD_SCLK:
|
||||||
|
0: 872Mhz
|
||||||
|
1: 1837Mhz
|
||||||
|
OD_MCLK:
|
||||||
|
1: 1000Mhz
|
||||||
|
OD_VDDC_CURVE:
|
||||||
|
0: 872Mhz 736mV
|
||||||
|
1: 1354Mhz 860mV
|
||||||
|
2: 1837Mhz 1186mV
|
||||||
|
OD_RANGE:
|
||||||
|
SCLK: 872Mhz 1900Mhz
|
||||||
|
MCLK: 168Mhz 1200Mhz
|
||||||
|
VDDC_CURVE_SCLK[0]: 872Mhz 1900Mhz
|
||||||
|
VDDC_CURVE_VOLT[0]: 737mV 1137mV
|
||||||
|
VDDC_CURVE_SCLK[1]: 872Mhz 1900Mhz
|
||||||
|
VDDC_CURVE_VOLT[1]: 737mV 1137mV
|
||||||
|
VDDC_CURVE_SCLK[2]: 872Mhz 1900Mhz
|
||||||
|
VDDC_CURVE_VOLT[2]: 737mV 1137mV
|
||||||
|
*/
|
||||||
|
static const uint32_t kOD_SCLK_label_array_index = 0;
|
||||||
|
static const uint32_t kOD_MCLK_label_array_index =
|
||||||
|
kOD_SCLK_label_array_index + 3;
|
||||||
|
static const uint32_t kOD_VDDC_CURVE_label_array_index =
|
||||||
|
kOD_MCLK_label_array_index + 2;
|
||||||
|
static const uint32_t kOD_OD_RANGE_label_array_index =
|
||||||
|
kOD_VDDC_CURVE_label_array_index + 4;
|
||||||
|
static const uint32_t kOD_VDDC_CURVE_start_index =
|
||||||
|
kOD_OD_RANGE_label_array_index + 3;
|
||||||
|
static const uint32_t kOD_VDDC_CURVE_num_lines =
|
||||||
|
kOD_VDDC_CURVE_start_index + 4;
|
||||||
|
|
||||||
|
static rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind,
|
||||||
|
rsmi_od_volt_freq_data *p) {
|
||||||
|
TRY
|
||||||
|
std::vector<std::string> val_vec;
|
||||||
|
rsmi_status_t ret;
|
||||||
|
|
||||||
|
assert(p != nullptr);
|
||||||
|
|
||||||
|
ret = get_dev_value_vec(amd::smi::kDevPowerODVoltage, dv_ind, &val_vec);
|
||||||
|
if (ret != RSMI_STATUS_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a work-around to handle systems where kDevPowerODVoltage is not
|
||||||
|
// fully supported yet.
|
||||||
|
if (val_vec.size() < 2) {
|
||||||
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(val_vec[kOD_SCLK_label_array_index] == "OD_SCLK:");
|
||||||
|
|
||||||
|
p->curr_sclk_range.lower_bound = freq_string_to_int(val_vec, nullptr,
|
||||||
|
nullptr, kOD_SCLK_label_array_index + 1);
|
||||||
|
p->curr_sclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
|
||||||
|
nullptr, kOD_SCLK_label_array_index + 2);
|
||||||
|
|
||||||
|
assert(val_vec[kOD_MCLK_label_array_index] == "OD_MCLK:");
|
||||||
|
p->curr_mclk_range.lower_bound = 0;
|
||||||
|
|
||||||
|
p->curr_mclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
|
||||||
|
nullptr, kOD_MCLK_label_array_index + 1);
|
||||||
|
|
||||||
|
assert(val_vec[kOD_VDDC_CURVE_label_array_index] == "OD_VDDC_CURVE:");
|
||||||
|
freq_volt_string_to_point(val_vec[kOD_VDDC_CURVE_label_array_index + 1],
|
||||||
|
&(p->curve[0]));
|
||||||
|
freq_volt_string_to_point(val_vec[kOD_VDDC_CURVE_label_array_index + 2],
|
||||||
|
&(p->curve[1]));
|
||||||
|
freq_volt_string_to_point(val_vec[kOD_VDDC_CURVE_label_array_index + 3],
|
||||||
|
&(p->curve[2]));
|
||||||
|
|
||||||
|
assert(val_vec[kOD_OD_RANGE_label_array_index] == "OD_RANGE:");
|
||||||
|
od_value_pair_str_to_range(val_vec[kOD_OD_RANGE_label_array_index + 1],
|
||||||
|
&(p->sclk_freq_limits));
|
||||||
|
od_value_pair_str_to_range(val_vec[kOD_OD_RANGE_label_array_index + 2],
|
||||||
|
&(p->mclk_freq_limits));
|
||||||
|
|
||||||
|
assert((val_vec.size() - kOD_VDDC_CURVE_start_index)%2 == 0);
|
||||||
|
p->num_regions = (val_vec.size() - kOD_VDDC_CURVE_start_index) / 2;
|
||||||
|
|
||||||
|
return RSMI_STATUS_SUCCESS;
|
||||||
|
CATCH
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_vc_region(uint32_t start_ind,
|
||||||
|
std::vector<std::string> *val_vec, rsmi_freq_volt_region *p) {
|
||||||
|
assert(p != nullptr);
|
||||||
|
assert(val_vec != nullptr);
|
||||||
|
// There must be at least 1 region to read in
|
||||||
|
assert(val_vec->size() >= kOD_OD_RANGE_label_array_index + 2);
|
||||||
|
assert((*val_vec)[kOD_OD_RANGE_label_array_index] == "OD_RANGE:");
|
||||||
|
|
||||||
|
rsmi_range rg;
|
||||||
|
od_value_pair_str_to_range((*val_vec)[start_ind], &rg);
|
||||||
|
p->min_corner.frequency = rg.lower_bound;
|
||||||
|
p->max_corner.frequency = rg.upper_bound;
|
||||||
|
|
||||||
|
od_value_pair_str_to_range((*val_vec)[start_ind + 1], &rg);
|
||||||
|
p->min_corner.voltage = rg.lower_bound;
|
||||||
|
p->max_corner.voltage = rg.upper_bound;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* num_regions [inout] on calling, the number of regions requested to be read
|
||||||
|
* in. At completion, the number of regions actually read in
|
||||||
|
*
|
||||||
|
* p [inout] point to pre-allocated memory where function will write region
|
||||||
|
* values. Caller must make sure there is enough space for at least
|
||||||
|
* *num_regions regions. On
|
||||||
|
*/
|
||||||
|
static rsmi_status_t get_od_clk_volt_curve_regions(uint32_t dv_ind,
|
||||||
|
uint32_t *num_regions, rsmi_freq_volt_region *p) {
|
||||||
|
TRY
|
||||||
|
std::vector<std::string> val_vec;
|
||||||
|
rsmi_status_t ret;
|
||||||
|
|
||||||
|
assert(num_regions != nullptr);
|
||||||
|
assert(*num_regions > 0);
|
||||||
|
assert(p != nullptr);
|
||||||
|
|
||||||
|
ret = get_dev_value_vec(amd::smi::kDevPowerODVoltage, dv_ind, &val_vec);
|
||||||
|
if (ret != RSMI_STATUS_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a work-around to handle systems where kDevPowerODVoltage is not
|
||||||
|
// fully supported yet.
|
||||||
|
if (val_vec.size() < 2) {
|
||||||
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t val_vec_size = val_vec.size();
|
||||||
|
assert((val_vec_size - kOD_VDDC_CURVE_start_index) > 0);
|
||||||
|
assert((val_vec_size - kOD_VDDC_CURVE_start_index)%2 == 0);
|
||||||
|
*num_regions = std::min((val_vec_size - kOD_VDDC_CURVE_start_index) / 2,
|
||||||
|
*num_regions);
|
||||||
|
|
||||||
|
for (uint32_t i=0; i < *num_regions; ++i) {
|
||||||
|
get_vc_region(kOD_VDDC_CURVE_start_index + i, &val_vec, p + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSMI_STATUS_SUCCESS;
|
||||||
|
CATCH
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_power_of_2(uint64_t n) {
|
static bool is_power_of_2(uint64_t n) {
|
||||||
return n && !(n & (n - 1));
|
return n && !(n & (n - 1));
|
||||||
}
|
}
|
||||||
@@ -921,6 +1132,26 @@ rsmi_dev_fan_speed_max_get(uint32_t dv_ind, uint32_t sensor_ind,
|
|||||||
return ret;
|
return ret;
|
||||||
CATCH
|
CATCH
|
||||||
}
|
}
|
||||||
|
rsmi_status_t
|
||||||
|
rsmi_dev_od_volt_info_get(uint32_t dv_ind, rsmi_od_volt_freq_data *odv) {
|
||||||
|
TRY
|
||||||
|
rsmi_status_t ret = get_od_clk_volt_info(dv_ind, odv);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
CATCH
|
||||||
|
}
|
||||||
|
rsmi_status_t rsmi_dev_od_volt_curve_regions_get(uint32_t dv_ind,
|
||||||
|
uint32_t *num_regions, rsmi_freq_volt_region *buffer) {
|
||||||
|
TRY
|
||||||
|
|
||||||
|
if (buffer == nullptr || num_regions == nullptr || *num_regions == 0) {
|
||||||
|
return RSMI_STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
rsmi_status_t ret = get_od_clk_volt_curve_regions(dv_ind, num_regions,
|
||||||
|
buffer);
|
||||||
|
return ret;
|
||||||
|
CATCH
|
||||||
|
}
|
||||||
|
|
||||||
rsmi_status_t
|
rsmi_status_t
|
||||||
rsmi_dev_power_max_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *power) {
|
rsmi_dev_power_max_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *power) {
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ static const char *kDevGPUSClkFName = "pp_dpm_sclk";
|
|||||||
static const char *kDevGPUMClkFName = "pp_dpm_mclk";
|
static const char *kDevGPUMClkFName = "pp_dpm_mclk";
|
||||||
static const char *kDevGPUPCIEClkFname = "pp_dpm_pcie";
|
static const char *kDevGPUPCIEClkFname = "pp_dpm_pcie";
|
||||||
static const char *kDevPowerProfileModeFName = "pp_power_profile_mode";
|
static const char *kDevPowerProfileModeFName = "pp_power_profile_mode";
|
||||||
|
static const char *kDevPowerODVoltageFName = "pp_od_clk_voltage";
|
||||||
static const char *kDevUsageFName = "gpu_busy_percent";
|
static const char *kDevUsageFName = "gpu_busy_percent";
|
||||||
|
|
||||||
static const char *kDevPerfLevelAutoStr = "auto";
|
static const char *kDevPerfLevelAutoStr = "auto";
|
||||||
@@ -87,6 +88,7 @@ static const std::map<DevInfoTypes, const char *> kDevAttribNameMap = {
|
|||||||
{kDevPCIEBW, kDevGPUPCIEClkFname},
|
{kDevPCIEBW, kDevGPUPCIEClkFname},
|
||||||
{kDevPowerProfileMode, kDevPowerProfileModeFName},
|
{kDevPowerProfileMode, kDevPowerProfileModeFName},
|
||||||
{kDevUsage, kDevUsageFName},
|
{kDevUsage, kDevUsageFName},
|
||||||
|
{kDevPowerODVoltage, kDevPowerODVoltageFName},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<rsmi_dev_perf_level, const char *> kDevPerfLvlMap = {
|
static const std::map<rsmi_dev_perf_level, const char *> kDevPerfLvlMap = {
|
||||||
@@ -230,13 +232,15 @@ int Device::readDevInfoMultiLineStr(DevInfoTypes type,
|
|||||||
|
|
||||||
assert(retVec != nullptr);
|
assert(retVec != nullptr);
|
||||||
|
|
||||||
|
if (env_->path_DRM_root_override && type == env_->enum_override) {
|
||||||
|
tempPath = env_->path_DRM_root_override;
|
||||||
|
}
|
||||||
tempPath += "/device/";
|
tempPath += "/device/";
|
||||||
tempPath += kDevAttribNameMap.at(type);
|
tempPath += kDevAttribNameMap.at(type);
|
||||||
|
|
||||||
std::ifstream fs(tempPath);
|
std::ifstream fs(tempPath);
|
||||||
std::stringstream buffer;
|
std::stringstream buffer;
|
||||||
|
|
||||||
|
|
||||||
DBG_FILE_ERROR(tempPath);
|
DBG_FILE_ERROR(tempPath);
|
||||||
if (!isRegularFile(tempPath)) {
|
if (!isRegularFile(tempPath)) {
|
||||||
return EISDIR;
|
return EISDIR;
|
||||||
@@ -245,6 +249,14 @@ int Device::readDevInfoMultiLineStr(DevInfoTypes type,
|
|||||||
while (std::getline(fs, line)) {
|
while (std::getline(fs, line)) {
|
||||||
retVec->push_back(line);
|
retVec->push_back(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (retVec->size() == 0) {
|
||||||
|
return EPERM;
|
||||||
|
}
|
||||||
|
// Remove any *trailing* empty (whitespace) lines
|
||||||
|
while (retVec->back().find_first_not_of(" \t\n\v\f\r") == std::string::npos) {
|
||||||
|
retVec->pop_back();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +294,7 @@ int Device::readDevInfo(DevInfoTypes type, std::vector<std::string> *val) {
|
|||||||
case kDevGPUSClk:
|
case kDevGPUSClk:
|
||||||
case kDevPCIEBW:
|
case kDevPCIEBW:
|
||||||
case kDevPowerProfileMode:
|
case kDevPowerProfileMode:
|
||||||
|
case kDevPowerODVoltage:
|
||||||
return readDevInfoMultiLineStr(type, val);
|
return readDevInfoMultiLineStr(type, val);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -286,6 +286,10 @@ static int GetEnvVarInteger(const char *ev_str) {
|
|||||||
// Get and store env. variables in this method
|
// Get and store env. variables in this method
|
||||||
void RocmSMI::GetEnvVariables(void) {
|
void RocmSMI::GetEnvVariables(void) {
|
||||||
env_vars_.debug_output_bitfield = GetEnvVarInteger("RSMI_DEBUG_BITFIELD");
|
env_vars_.debug_output_bitfield = GetEnvVarInteger("RSMI_DEBUG_BITFIELD");
|
||||||
|
env_vars_.path_DRM_root_override = getenv("RSMI_DEBUG_DRM_ROOT_OVERRIDE");
|
||||||
|
env_vars_.path_HWMon_root_override = getenv("RSMI_DEBUG_HWMON_ROOT_OVERRIDE");
|
||||||
|
env_vars_.path_power_root_override = getenv("RSMI_DEBUG_PP_ROOT_OVERRIDE");
|
||||||
|
env_vars_.enum_override = GetEnvVarInteger("RSMI_DEBUG_ENUM_OVERRIDE");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ static uint32_t gVerbosity = 3;
|
|||||||
std::cout << "RSMI call returned " << (RET); \
|
std::cout << "RSMI call returned " << (RET); \
|
||||||
rsmi_status_string((RET), &err_str); \
|
rsmi_status_string((RET), &err_str); \
|
||||||
std::cout << " (" << err_str << ")" << std::endl; \
|
std::cout << " (" << err_str << ")" << std::endl; \
|
||||||
std::cout << " at " << __FILE__ << ":" << __LINE__ << std::endl; \
|
std::cout << " at " << __FILE__ << ":" << std::dec << __LINE__ << \
|
||||||
|
std::endl; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,8 @@ static uint32_t gVerbosity = 3;
|
|||||||
std::cout << "ASSERT failure: Expected " << #A << " == " << #B << \
|
std::cout << "ASSERT failure: Expected " << #A << " == " << #B << \
|
||||||
", but got " << #A << " = " << (A) << ", and " << #B << " = " << \
|
", but got " << #A << " = " << (A) << ", and " << #B << " = " << \
|
||||||
(B) << std::endl; \
|
(B) << std::endl; \
|
||||||
std::cout << " at " << __FILE__ << ":" << __LINE__ << std::endl; \
|
std::cout << " at " << __FILE__ << ":" << std::dec << \
|
||||||
|
__LINE__ << std::endl; \
|
||||||
return RSMI_STATUS_UNKNOWN_ERROR; \
|
return RSMI_STATUS_UNKNOWN_ERROR; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
@@ -518,6 +520,59 @@ static void print_frequencies(rsmi_frequencies *f, uint32_t *l = nullptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pt_rng_mhz(std::string title, rsmi_range *r) {
|
||||||
|
assert(r != nullptr);
|
||||||
|
|
||||||
|
std::cout << title << std::endl;
|
||||||
|
std::cout << "\t\t** " << r->lower_bound/1000000 << " to " <<
|
||||||
|
r->upper_bound/1000000 << " MHz" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_pnt(rsmi_od_vddc_point *pt) {
|
||||||
|
std::cout << "\t\t** Frequency: " << pt->frequency/1000000 << "MHz" <<
|
||||||
|
std::endl;
|
||||||
|
std::cout << "\t\t** Voltage: " << pt->voltage << "mV" << std::endl;
|
||||||
|
}
|
||||||
|
static void pt_vddc_curve(rsmi_od_vddc_point *c) {
|
||||||
|
assert(c != nullptr);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < RSMI_NUM_VOLTAGE_CURVE_POINTS; ++i) {
|
||||||
|
print_pnt(&c[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_rsmi_od_volt_freq_data(rsmi_od_volt_freq_data *odv) {
|
||||||
|
assert(odv != nullptr);
|
||||||
|
|
||||||
|
std::cout.setf(std::ios::dec, std::ios::basefield);
|
||||||
|
pt_rng_mhz("\t\tCurrent SCLK frequency range:", &odv->curr_sclk_range);
|
||||||
|
pt_rng_mhz("\t\tCurrent MCLK frequency range:", &odv->curr_mclk_range);
|
||||||
|
pt_rng_mhz("\t\tMin/Max Possible SCLK frequency range:",
|
||||||
|
&odv->sclk_freq_limits);
|
||||||
|
pt_rng_mhz("\t\tMin/Max Possible MCLK frequency range:",
|
||||||
|
&odv->mclk_freq_limits);
|
||||||
|
|
||||||
|
std::cout << "\t\tCurrent Freq/Volt. curve:" << std::endl;
|
||||||
|
pt_vddc_curve(odv->curve);
|
||||||
|
|
||||||
|
std::cout << "\tNumber of Freq./Volt. regions: " <<
|
||||||
|
odv->num_regions << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_odv_region(rsmi_freq_volt_region *region) {
|
||||||
|
std::cout << "\t\t\"lower-left\" corner:" << std::endl;
|
||||||
|
print_pnt(®ion->min_corner);
|
||||||
|
std::cout << "\t\t\"upper-right\" corner:" << std::endl;
|
||||||
|
print_pnt(®ion->max_corner);
|
||||||
|
}
|
||||||
|
static void print_rsmi_od_volt_freq_regions(uint32_t num_regions,
|
||||||
|
rsmi_freq_volt_region *regions) {
|
||||||
|
for (uint32_t i = 0; i < num_regions; ++i) {
|
||||||
|
std::cout << "\tRegion " << i << ":" << std::endl;
|
||||||
|
print_odv_region(®ions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TestSanity::TestSanity(void) :
|
TestSanity::TestSanity(void) :
|
||||||
TestBase() {
|
TestBase() {
|
||||||
set_num_iteration(10); // Number of iterations to execute of the main test;
|
set_num_iteration(10); // Number of iterations to execute of the main test;
|
||||||
@@ -559,6 +614,7 @@ void TestSanity::Run(void) {
|
|||||||
rsmi_pcie_bandwidth b;
|
rsmi_pcie_bandwidth b;
|
||||||
rsmi_version ver = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, nullptr};
|
rsmi_version ver = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, nullptr};
|
||||||
uint32_t num_monitor_devs = 0;
|
uint32_t num_monitor_devs = 0;
|
||||||
|
rsmi_od_volt_freq_data odv;
|
||||||
|
|
||||||
err = rsmi_version_get(&ver);
|
err = rsmi_version_get(&ver);
|
||||||
CHK_ERR_ASRT(err)
|
CHK_ERR_ASRT(err)
|
||||||
@@ -592,6 +648,30 @@ void TestSanity::Run(void) {
|
|||||||
IF_VERB(STANDARD) {
|
IF_VERB(STANDARD) {
|
||||||
std::cout << "\t**Device ID: 0x" << std::hex << val_ui64 << std::endl;
|
std::cout << "\t**Device ID: 0x" << std::hex << val_ui64 << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = rsmi_dev_od_volt_info_get(i, &odv);
|
||||||
|
DISPLAY_RSMI_ERR(err)
|
||||||
|
|
||||||
|
if (err == RSMI_STATUS_SUCCESS) {
|
||||||
|
std::cout << "\t**Frequency-voltage curve data:" << std::endl;
|
||||||
|
print_rsmi_od_volt_freq_data(&odv);
|
||||||
|
|
||||||
|
rsmi_freq_volt_region *regions;
|
||||||
|
uint32_t num_regions;
|
||||||
|
regions = new rsmi_freq_volt_region[odv.num_regions];
|
||||||
|
ASSERT_TRUE(regions != nullptr);
|
||||||
|
|
||||||
|
num_regions = odv.num_regions;
|
||||||
|
err = rsmi_dev_od_volt_curve_regions_get(i, &num_regions, regions);
|
||||||
|
CHK_ERR_ASRT(err)
|
||||||
|
ASSERT_TRUE(num_regions == odv.num_regions);
|
||||||
|
|
||||||
|
std::cout << "\t**Frequency-voltage curve regions:" << std::endl;
|
||||||
|
print_rsmi_od_volt_freq_regions(num_regions, regions);
|
||||||
|
|
||||||
|
delete []regions;
|
||||||
|
}
|
||||||
|
|
||||||
err = rsmi_dev_perf_level_get(i, &pfl);
|
err = rsmi_dev_perf_level_get(i, &pfl);
|
||||||
CHK_ERR_ASRT(err)
|
CHK_ERR_ASRT(err)
|
||||||
IF_VERB(STANDARD) {
|
IF_VERB(STANDARD) {
|
||||||
@@ -756,6 +836,7 @@ void TestSanity::Run(void) {
|
|||||||
std::cout << "\t=======" << std::endl;
|
std::cout << "\t=======" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IF_VERB(STANDARD) {
|
IF_VERB(STANDARD) {
|
||||||
std::cout << "***** Testing write api's" << std::endl;
|
std::cout << "***** Testing write api's" << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user