From 31f3b6d33d9e41b15bb02812dbe863486d8559ac Mon Sep 17 00:00:00 2001 From: Divya Shikre Date: Thu, 27 Aug 2020 15:00:53 -0400 Subject: [PATCH] Adding setsrange, setmrange, setvc, setslevel and setmlevel functionality to rocm lib and cli Signed-off-by: Divya Shikre Change-Id: I5fd65ea7bcd5403aaf2e42d2aa28d837929da253 [ROCm/rocm_smi_lib commit: 54d4b9d500dae869322714e1e3255d3f8635e7da] --- .../rocm-smi-lib/include/rocm_smi/rocm_smi.h | 50 +++++++ .../python_smi_tools/rocmSmiLib_cli.py | 134 ++++++++++++++++-- projects/rocm-smi-lib/src/rocm_smi.cc | 102 +++++++++++++ projects/rocm-smi-lib/src/rocm_smi_device.cc | 3 + 4 files changed, 278 insertions(+), 11 deletions(-) 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 39743c8f20..a9a70995da 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h @@ -2006,6 +2006,56 @@ rsmi_status_t rsmi_dev_gpu_clk_freq_get(uint32_t dv_ind, rsmi_status_t rsmi_dev_od_volt_info_get(uint32_t dv_ind, rsmi_od_volt_freq_data_t *odv); +/** + * @brief This function sets the clock frequency information + * + * @details Given a device index @p dv_ind, a frequency level @p level, + * a clock value @p clkvalue and a clock type @p clkType this function + * will set the sclk|mclk range + * + * @param[in] dv_ind a device index + * + * @param[in] level RSMI_FREQ_IND_MIN|RSMI_FREQ_IND_MAX to set the + * minimum (0) or maximum (1) speed. + * + * @param[in] clkvalue value to apply to the clock range. Frequency values + * are in MHz. + * + * @param[in] clkType RSMI_CLK_TYPE_SYS | RSMI_CLK_TYPE_MEM range type + * + * @retval ::RSMI_STATUS_SUCCESS call was successful + * @retval ::RSMI_STATUS_NOT_SUPPORTED installed software or hardware does not + * support this function with the given arguments + * @retval ::RSMI_STATUS_INVALID_ARGS the provided arguments are not valid + */ +rsmi_status_t rsmi_dev_od_clk_info_set(uint32_t dv_ind, rsmi_freq_ind_t level, + uint64_t clkvalue, + rsmi_clk_type_t clkType); + +/** + * @brief This function sets 1 of the 3 voltage curve points. + * + * @details Given a device index @p dv_ind, a voltage point @p vpoint + * and a voltage value @p voltvalue this function will set voltage curve point + * + * @param[in] dv_ind a device index + * + * @param[in] vpoint voltage point [0|1|2] on the voltage curve + * + * @param[in] clkvalue clock value component of voltage curve point. + * Frequency values are in MHz. + * + * @param[in] voltvalue voltage value component of voltage curve point. + * Voltage is in mV. + * + * @retval ::RSMI_STATUS_SUCCESS call was successful + * @retval ::RSMI_STATUS_NOT_SUPPORTED installed software or hardware does not + * support this function with the given arguments + * @retval ::RSMI_STATUS_INVALID_ARGS the provided arguments are not valid + */ +rsmi_status_t rsmi_dev_od_volt_info_set(uint32_t dv_ind, uint32_t vpoint, + uint64_t clkvalue, uint64_t voltvalue); + /** * @brief This function will retrieve the current valid regions in the * frequency/voltage space. diff --git a/projects/rocm-smi-lib/python_smi_tools/rocmSmiLib_cli.py b/projects/rocm-smi-lib/python_smi_tools/rocmSmiLib_cli.py index 8c9596872f..e8774427fa 100755 --- a/projects/rocm-smi-lib/python_smi_tools/rocmSmiLib_cli.py +++ b/projects/rocm-smi-lib/python_smi_tools/rocmSmiLib_cli.py @@ -595,6 +595,122 @@ def resetXgmiErr(deviceList): printLogSpacer() +def setClockRange(deviceList, clkType, level, value, autoRespond): + """ Set the range for the specified clktype in the PowerPlay table for a list of devices. + + Parameters: + deviceList -- List of DRM devices (can be a single-item list) + clktype -- [sclk|mclk] Which clock type to apply the range to + level -- [0|1] Whether to set the minimum (0) or maximum (1) speed + value -- Value to apply to the clock range + autoRespond -- Response to automatically provide for all prompts + """ + global RETCODE + if clkType not in {'sclk', 'mclk'}: + printLog(None, 'Invalid range identifier %s' % (clkType), None) + RETCODE = 1 + return + try: + int(value) + except ValueError: + printErrLog(device, 'Unable to set %s range' % (clkType)) + logging.error('%s is not an integer', value) + RETCODE = 1 + return + confirmOutOfSpecWarning(autoRespond) + printLogSpacer(' Set Valid %s Range ' % (clkType)) + for device in deviceList: + if clkType == 'sclk': + ret = rocmsmi.rsmi_dev_od_clk_info_set(device, rsmi_freq_ind_t(int(level)), int(value), rsmi_clk_names_dict[clkType]) + if rsmi_ret_ok(ret, device): + printLog(device, 'Successfully set %s level %s to %s(MHz)' % (clkType, level, value), None) + else: + printErrLog(device, 'Unable to set %s level %s to %s(MHz)' % (clkType, level, value)) + RETCODE = 1 + elif clkType == 'mclk': + ret = rocmsmi.rsmi_dev_od_clk_info_set(device, rsmi_freq_ind_t(int(level)), int(value), rsmi_clk_names_dict[clkType]) + if rsmi_ret_ok(ret, device): + printLog(device, 'Successfully set %s level %s to %s(MHz)' % (clkType, level, value), None) + else: + printErrLog(device, 'Unable to set %s level %s to %s(MHz)' % (clkType, level, value)) + RETCODE = 1 + else: + printErrLog(device, 'Unable to set %s range' % (clkType)) + logging.error('Unsupported range type %s', clkType) + RETCODE = 1 + + +def setVoltageCurve(deviceList, point, clk, volt, autoRespond): + """ Set voltage curve for a point in the PowerPlay table for a list of devices. + + Parameters: + deviceList -- List of DRM devices (can be a single-item list) + point -- Point on the voltage curve to modify + clk -- Clock speed specified for this curve point + volt -- Voltage specified for this curve point + autoRespond -- Response to automatically provide for all prompts + """ + global RETCODE + value = '%s %s %s' % (point, clk, volt) + try: + any(int(item) for item in value) + except ValueError: + printLogNoDev('Unable to set Voltage curve') + logging.error('Non-integer characters are present in %s', value) + RETCODE = 1 + return + confirmOutOfSpecWarning(autoRespond) + for device in deviceList: + ret = rocmsmi.rsmi_dev_od_volt_info_set(device, int(point), int(clk), int(volt)) + if rsmi_ret_ok(ret, device): + printLog(device, 'Successfully set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt), None) + else: + printErrLog(device, 'Unable to set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt)) + RETCODE = 1 + + +def setPowerPlayTableLevel(deviceList, clkType, point, clk, volt, autoRespond): + """ Set clock frequency and voltage for a level in the PowerPlay table for a list of devices. + + Parameters: + deviceList -- List of DRM devices (can be a single-item list) + clktype -- [sclk|mclk] Which clock type to apply the range to + point -- Point on the voltage curve to modify + clk -- Clock speed specified for this curve point + volt -- Voltage specified for this curve point + autoRespond -- Response to automatically provide for all prompts + """ + global RETCODE + value = '%s %s %s' % (point, clk, volt) + try: + any(int(item) for item in value.split()) + except ValueError: + printLogNoDev('Unable to set PowerPlay table level') + logging.error('Non-integer characters are present in %s', value) + RETCODE = 1 + return + confirmOutOfSpecWarning(autoRespond) + for device in deviceList: + if clkType == 'sclk': + ret = rocmsmi.rsmi_dev_od_clk_info_set(device, rsmi_freq_ind_t(int(point)), int(clk), rsmi_clk_names_dict[clkType]) + if rsmi_ret_ok(ret, device): + printLog(device, 'Successfully set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt), None) + else: + printErrLog(device, 'Unable to set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt)) + RETCODE = 1 + elif clkType == 'mclk': + ret = rocmsmi.rsmi_dev_od_clk_info_set(device, rsmi_freq_ind_t(int(point)), int(clk), rsmi_clk_names_dict[clkType]) + if rsmi_ret_ok(ret, device): + printLog(device, 'Successfully set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt), None) + else: + printErrLog(device, 'Unable to set voltage point %s to %s(MHz) %s(mV)' % (point, clk, volt)) + RETCODE = 1 + else: + printErrLog(device, 'Unable to set %s range' % (clkType)) + logging.error('Unsupported range type %s', clkType) + RETCODE = 1 + + def setClockOverDrive(deviceList, clktype, value, autoRespond): """ Set clock speed to OverDrive for a list of devices @@ -712,12 +828,14 @@ def setClocks(deviceList, clktype, clk): printLog(device, 'Successfully set %s bitmask to' % (clktype), str(bitmask)) else: printErrLog(device, 'Unable to set %s bitmask to: %s' % (clktype, str(bitmask))) + RETCODE = 1 else: ret = rocmsmi.rsmi_dev_pci_bandwidth_set(device, freq_bitmask) if rsmi_ret_ok(ret, device): printLog(device, 'Successfully set %s to level bitmask' % (clktype), str(bitmask)) else: printErrLog(device, 'Unable to set %s bitmask to: %s' % (clktype, str(bitmask))) + RETCODE = 1 printLogSpacer() @@ -2465,12 +2583,9 @@ if __name__ == '__main__': if args.setpcie: setClocks(deviceList, 'pcie', args.setpcie) if args.setslevel: - pass - # TODO: setPowerPlayTableLevel(deviceList, \'sclk\', args.setslevel, args.autorespond) + setPowerPlayTableLevel(deviceList, 'sclk', args.setslevel[0], args.setslevel[1], args.setslevel[2], args.autorespond) if args.setmlevel: - pass - # TODO: setPowerPlayTableLevel(deviceList, \'mclk\', args.setmlevel, args.autorespond) - # Don't do reset in combination with any other command + setPowerPlayTableLevel(deviceList, 'mclk', args.setmlevel[0], args.setmlevel[1], args.setmlevel[2], args.autorespond) if args.resetfans: resetFans(deviceList) if args.setfan: @@ -2488,14 +2603,11 @@ if __name__ == '__main__': if args.setprofile: setProfile(deviceList, args.setprofile) if args.setvc: - pass - # TODO: setVoltageCurve(deviceList, args.setvc[0], args.setvc[1], args.setvc[2], args.autorespond) + setVoltageCurve(deviceList, args.setvc[0], args.setvc[1], args.setvc[2], args.autorespond) if args.setsrange: - pass - # TODO: setClockRange(deviceList, \'sclk\', args.setsrange[0], args.setsrange[1], args.autorespond) + setClockRange(deviceList, 'sclk', args.setsrange[0], args.setsrange[1], args.autorespond) if args.setmrange: - pass - # TODO: setClockRange(deviceList, \'mclk\', args.setmrange[0], args.setmrange[1], args.autorespond) + setClockRange(deviceList, 'mclk', args.setmrange[0], args.setmrange[1], args.autorespond) if args.resetprofile: resetProfile(deviceList) if args.resetxgmierr: diff --git a/projects/rocm-smi-lib/src/rocm_smi.cc b/projects/rocm-smi-lib/src/rocm_smi.cc index b0361f9640..177532e250 100755 --- a/projects/rocm-smi-lib/src/rocm_smi.cc +++ b/projects/rocm-smi-lib/src/rocm_smi.cc @@ -817,6 +817,15 @@ rsmi_dev_perf_level_set(int32_t dv_ind, rsmi_dev_perf_level_t perf_level) { CATCH } +static rsmi_status_t +set_dev_range(uint32_t dv_ind, std::string range) { + + GET_DEV_FROM_INDX + + int ret = dev->writeDevInfo(amd::smi::kDevPowerODVoltage, range); + return amd::smi::ErrnoToRsmiStatus(ret); +} + static rsmi_status_t get_frequencies(amd::smi::DevInfoTypes type, uint32_t dv_ind, rsmi_frequencies_t *f, uint32_t *lanes = nullptr) { TRY @@ -1024,6 +1033,98 @@ static rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind, CATCH } + +rsmi_status_t rsmi_dev_od_clk_info_set(uint32_t dv_ind, rsmi_freq_ind_t level, + uint64_t clkvalue, + rsmi_clk_type_t clkType) { + TRY + rsmi_status_t ret; + + std::string sysvalue; + std::map ClkStateMap = { + {RSMI_CLK_TYPE_SYS, "s"}, + {RSMI_CLK_TYPE_MEM, "m"}, + }; + + // Set perf. level to manual so that we can then set the power profile + ret = rsmi_dev_perf_level_set(dv_ind, RSMI_DEV_PERF_LEVEL_MANUAL); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + // For clock frequency setting, enter a new value by writing a string that + // contains “s/m index clock” to the file. The index should be 0 if to set + // minimum clock. And 1 if to set maximum clock. E.g., “s 0 500” will update + // minimum sclk to be 500 MHz. “m 1 800” will update maximum mclk to 800Mhz. + + switch (clkType) { + case RSMI_CLK_TYPE_SYS: + sysvalue = ClkStateMap[clkType]; + sysvalue += ' ' + std::to_string(level); + sysvalue += ' ' + std::to_string(clkvalue); + sysvalue += '\n'; + break; + + case RSMI_CLK_TYPE_MEM: + sysvalue = ClkStateMap[clkType]; + sysvalue += ' ' + std::to_string(level); + sysvalue += ' ' + std::to_string(clkvalue); + sysvalue += '\n'; + break; + + default: + return RSMI_STATUS_INVALID_ARGS; + } + ret = set_dev_range(dv_ind, sysvalue); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + ret = set_dev_range(dv_ind, "c"); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + return RSMI_STATUS_SUCCESS; + CATCH +} + + +rsmi_status_t rsmi_dev_od_volt_info_set(uint32_t dv_ind, uint32_t vpoint, + uint64_t clkvalue, uint64_t voltvalue) { + TRY + rsmi_status_t ret; + + // Set perf. level to manual so that we can then set the power profile + ret = rsmi_dev_perf_level_set(dv_ind, RSMI_DEV_PERF_LEVEL_MANUAL); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + // For sclk voltage curve, enter the new values by writing a string that + // contains “vc point clock voltage” to the file. The points are indexed + // by 0, 1 and 2. E.g., “vc 0 300 600” will update point1 with clock set + // as 300Mhz and voltage as 600mV. “vc 2 1000 1000” will update point3 + // with clock set as 1000Mhz and voltage 1000mV. + + std::string sysvalue = "vc"; + sysvalue += ' ' + std::to_string(vpoint); + sysvalue += ' ' + std::to_string(clkvalue); + sysvalue += ' ' + std::to_string(voltvalue); + sysvalue += '\n'; + ret = set_dev_range(dv_ind, sysvalue); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + ret = set_dev_range(dv_ind, "c"); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + return RSMI_STATUS_SUCCESS; + CATCH +} + + static void get_vc_region(uint32_t start_ind, std::vector *val_vec, rsmi_freq_volt_region_t *p) { assert(p != nullptr); @@ -1092,6 +1193,7 @@ static rsmi_status_t get_od_clk_volt_curve_regions(uint32_t dv_ind, return RSMI_STATUS_SUCCESS; CATCH } + static rsmi_status_t set_power_profile(uint32_t dv_ind, rsmi_power_profile_preset_masks_t profile) { TRY diff --git a/projects/rocm-smi-lib/src/rocm_smi_device.cc b/projects/rocm-smi-lib/src/rocm_smi_device.cc index 7760b7330f..b0daea3edb 100755 --- a/projects/rocm-smi-lib/src/rocm_smi_device.cc +++ b/projects/rocm-smi-lib/src/rocm_smi_device.cc @@ -364,6 +364,8 @@ static const std::map kDevFuncDependsMap = { {"rsmi_dev_overdrive_level_set", {{kDevOverDriveLevelFName}, {}}}, {"rsmi_dev_vbios_version_get", {{kDevVBiosVerFName}, {}}}, {"rsmi_dev_od_volt_info_get", {{kDevPowerODVoltageFName}, {}}}, + {"rsmi_dev_od_volt_info_set", {{kDevPowerODVoltageFName, + kDevPerfLevelFName}, {}}}, {"rsmi_dev_od_volt_curve_regions_get", {{kDevPowerODVoltageFName}, {}}}, {"rsmi_dev_ecc_enabled_get", {{kDevErrCntFeaturesFName}, {}}}, {"rsmi_dev_ecc_status_get", {{kDevErrCntFeaturesFName}, {}}}, @@ -571,6 +573,7 @@ int Device::writeDevInfo(DevInfoTypes type, uint64_t val) { switch (type) { // The caller is responsible for making sure "val" is within a valid range case kDevOverDriveLevel: // integer between 0 and 20 + case kDevPowerODVoltage: case kDevPowerProfileMode: return writeDevInfoStr(type, std::to_string(val)); break;