From 80eeb7960f1e5c8f089baf21f74e787ff4410746 Mon Sep 17 00:00:00 2001 From: Chris Freehill Date: Mon, 7 Jan 2019 08:44:23 -0600 Subject: [PATCH] Add support for reading frequency-volt curva data [ROCm/rocm_smi_lib commit: 639a4e3503c0d3cd46bda146fe0b335ab5bdd8fb] --- projects/rocm-smi-lib/CMakeLists.txt | 2 +- .../rocm-smi-lib/include/rocm_smi/rocm_smi.h | 130 ++++++++- .../include/rocm_smi/rocm_smi_common.h | 4 + .../include/rocm_smi/rocm_smi_device.h | 1 + projects/rocm-smi-lib/src/rocm_smi.cc | 267 ++++++++++++++++-- projects/rocm-smi-lib/src/rocm_smi_device.cc | 12 +- projects/rocm-smi-lib/src/rocm_smi_main.cc | 4 + .../rocm_smi_test/functional/rsmi_sanity.cc | 78 +++++ 8 files changed, 468 insertions(+), 30 deletions(-) diff --git a/projects/rocm-smi-lib/CMakeLists.txt b/projects/rocm-smi-lib/CMakeLists.txt index 69fb0c4f14..01b00d62bc 100755 --- a/projects/rocm-smi-lib/CMakeLists.txt +++ b/projects/rocm-smi-lib/CMakeLists.txt @@ -44,7 +44,7 @@ set(ROCM_SMI_TARGET "${ROCM_SMI}64") # Until ABI stabilizes VERSION_MAJOR will be 0. This should be over-ridden # by git tags (through "git describe") when they are present. 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 ######################### ## Setup the package version based on git tags. diff --git a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h index 9a94263c61..9264c82e94 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h @@ -54,15 +54,28 @@ extern "C" { * Main header file for the ROCm SMI library. * All required function, structure, enum, etc. definitions should be defined * 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 #define RSMI_MAX_NUM_FREQUENCIES 32 -//! Maximum possible value for fan speed. Should be used as the denominator when -//! determining fan speed percentage. +//! Maximum possible value for fan speed. Should be used as the denominator +//! when determining fan speed percentage. #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 */ @@ -271,6 +284,57 @@ typedef struct { const char *build; //!< Build string } 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. * @@ -701,6 +765,66 @@ 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, 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 + * + * @details + * + * @param[in] dv_ind a device index + * + * + * @param[in] + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + */ +rsmi_status_t rsmi_dev_od_volt_set(uint32_t dv_ind, rsmi_clk_type clk, + rsmi_freq_ind i); + +/** + * @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 @@ -894,7 +1018,7 @@ rsmi_status_string(rsmi_status_t status, const char **status_string); * @details Get the major, minor, patch and build string for RSMI build * 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. * * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call diff --git a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_common.h b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_common.h index 95db33e8d8..4379b0b8dc 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_common.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_common.h @@ -58,6 +58,10 @@ struct RocmSMI_env_vars { // Store env. variables here 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_ diff --git a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_device.h b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_device.h index 61f7774660..c4943eb01b 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_device.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_device.h @@ -67,6 +67,7 @@ enum DevInfoTypes { kDevPCIEBW, kDevPowerProfileMode, kDevUsage, + kDevPowerODVoltage, }; class Device { diff --git a/projects/rocm-smi-lib/src/rocm_smi.cc b/projects/rocm-smi-lib/src/rocm_smi.cc index cdebed6e82..bbe6f42fce 100755 --- a/projects/rocm-smi-lib/src/rocm_smi.cc +++ b/projects/rocm-smi-lib/src/rocm_smi.cc @@ -108,18 +108,46 @@ static rsmi_status_t errno_to_rsmi_status(uint32_t err) { 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: * ": <|*>" */ static uint64_t freq_string_to_int(const std::vector &freq_lines, bool *is_curr, uint32_t lanes[], int i) { - assert(is_curr != nullptr); - std::istringstream fs(freq_lines[i]); uint32_t ind; - float freq; + uint64_t freq; std::string junk; std::string units_str; std::string star_str; @@ -137,28 +165,7 @@ static uint64_t freq_string_to_int(const std::vector &freq_lines, *is_curr = false; } } - uint32_t multiplier = 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"); - } + uint32_t multiplier = get_multiplier_from_str(units_str[0]); if (star_str[0] == 'x') { assert(lanes != nullptr && "Lanes are provided but null lanes pointer"); @@ -169,6 +176,63 @@ static uint64_t freq_string_to_int(const std::vector &freq_lines, 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; + float freq; + float 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 " <|*>" @@ -540,6 +604,139 @@ static rsmi_status_t get_power_profiles(uint32_t dv_ind, 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 rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind, + rsmi_od_volt_freq_data *p) { + TRY + std::vector 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; + } + + 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 *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 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; + } + + 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) { return n && !(n & (n - 1)); } @@ -921,6 +1118,26 @@ rsmi_dev_fan_speed_max_get(uint32_t dv_ind, uint32_t sensor_ind, return ret; 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_dev_power_max_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *power) { diff --git a/projects/rocm-smi-lib/src/rocm_smi_device.cc b/projects/rocm-smi-lib/src/rocm_smi_device.cc index 98cbb48422..c4823fe0aa 100755 --- a/projects/rocm-smi-lib/src/rocm_smi_device.cc +++ b/projects/rocm-smi-lib/src/rocm_smi_device.cc @@ -66,6 +66,7 @@ static const char *kDevGPUSClkFName = "pp_dpm_sclk"; static const char *kDevGPUMClkFName = "pp_dpm_mclk"; static const char *kDevGPUPCIEClkFname = "pp_dpm_pcie"; 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 *kDevPerfLevelAutoStr = "auto"; @@ -87,6 +88,7 @@ static const std::map kDevAttribNameMap = { {kDevPCIEBW, kDevGPUPCIEClkFname}, {kDevPowerProfileMode, kDevPowerProfileModeFName}, {kDevUsage, kDevUsageFName}, + {kDevPowerODVoltage, kDevPowerODVoltageFName}, }; static const std::map kDevPerfLvlMap = { @@ -230,13 +232,15 @@ int Device::readDevInfoMultiLineStr(DevInfoTypes type, assert(retVec != nullptr); + if (env_->path_DRM_root_override && type == env_->enum_override) { + tempPath = env_->path_DRM_root_override; + } tempPath += "/device/"; tempPath += kDevAttribNameMap.at(type); std::ifstream fs(tempPath); std::stringstream buffer; - DBG_FILE_ERROR(tempPath); if (!isRegularFile(tempPath)) { return EISDIR; @@ -245,6 +249,11 @@ int Device::readDevInfoMultiLineStr(DevInfoTypes type, while (std::getline(fs, line)) { retVec->push_back(line); } + + // 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; } @@ -282,6 +291,7 @@ int Device::readDevInfo(DevInfoTypes type, std::vector *val) { case kDevGPUSClk: case kDevPCIEBW: case kDevPowerProfileMode: + case kDevPowerODVoltage: return readDevInfoMultiLineStr(type, val); break; diff --git a/projects/rocm-smi-lib/src/rocm_smi_main.cc b/projects/rocm-smi-lib/src/rocm_smi_main.cc index 96a71bda09..fc78e77d40 100755 --- a/projects/rocm-smi-lib/src/rocm_smi_main.cc +++ b/projects/rocm-smi-lib/src/rocm_smi_main.cc @@ -286,6 +286,10 @@ static int GetEnvVarInteger(const char *ev_str) { // Get and store env. variables in this method void RocmSMI::GetEnvVariables(void) { 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 diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/rsmi_sanity.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/rsmi_sanity.cc index 6ee8bbc666..c9dba5ed78 100755 --- a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/rsmi_sanity.cc +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/rsmi_sanity.cc @@ -518,6 +518,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) : TestBase() { set_num_iteration(10); // Number of iterations to execute of the main test; @@ -559,6 +612,7 @@ void TestSanity::Run(void) { rsmi_pcie_bandwidth b; rsmi_version ver = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, nullptr}; uint32_t num_monitor_devs = 0; + rsmi_od_volt_freq_data odv; err = rsmi_version_get(&ver); CHK_ERR_ASRT(err) @@ -592,6 +646,29 @@ void TestSanity::Run(void) { IF_VERB(STANDARD) { std::cout << "\t**Device ID: 0x" << std::hex << val_ui64 << std::endl; } + + err = rsmi_dev_od_volt_info_get(i, &odv); + CHK_ERR_ASRT(err) + + 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); CHK_ERR_ASRT(err) IF_VERB(STANDARD) { @@ -756,6 +833,7 @@ void TestSanity::Run(void) { std::cout << "\t=======" << std::endl; } } + IF_VERB(STANDARD) { std::cout << "***** Testing write api's" << std::endl; }