Add functions that tell what capabilities are supported

The new functions added in this commit allow a caller to tell up
front what functions, function variants and monitors are
supported.

Also,
* fixed a few documentation/formatting issues
* fixed a process_info test issue

Change-Id: I2184ab1a4a6898f847e791f273e2185d556e78e9
This commit is contained in:
Chris Freehill
2019-09-03 17:41:08 -05:00
parent 469af303d6
commit 551b15182b
14 changed files with 1337 additions and 60 deletions
+246 -4
View File
@@ -57,6 +57,7 @@
#include <fstream>
#include <iostream>
#include "rocm_smi/rocm_smi_common.h" // Should go before rocm_smi.h
#include "rocm_smi/rocm_smi.h"
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_device.h"
@@ -1976,13 +1977,12 @@ rsmi_dev_power_profile_presets_get(uint32_t dv_ind, uint32_t sensor_ind,
}
rsmi_status_t
rsmi_dev_power_profile_set(uint32_t dv_ind, uint32_t sensor_ind,
rsmi_dev_power_profile_set(uint32_t dv_ind, uint32_t dummy,
rsmi_power_profile_preset_masks_t profile) {
TRY
REQUIRE_ROOT_ACCESS
++sensor_ind; // power sysfs files have 1-based indices
(void)dummy;
DEVICE_MUTEX
rsmi_status_t ret = set_power_profile(dv_ind, profile);
return ret;
@@ -2498,7 +2498,7 @@ rsmi_compute_process_info_get(rsmi_process_info_t *procs,
uint32_t procs_found = 0;
int err = amd::smi:: GetProcessInfo(procs, *num_items, &procs_found);
int err = amd::smi::GetProcessInfo(procs, *num_items, &procs_found);
if (err) {
return errno_to_rsmi_status(err);
@@ -2666,3 +2666,245 @@ rsmi_dev_xgmi_error_reset(uint32_t dv_ind) {
CATCH
}
enum iterator_handle_type {
FUNC_ITER = 0,
VARIANT_ITER,
SUBVARIANT_ITER,
};
rsmi_status_t
rsmi_dev_supported_func_iterator_open(uint32_t dv_ind,
rsmi_func_id_iter_handle_t *handle) {
TRY
GET_DEV_FROM_INDX
if (handle == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
dev->fillSupportedFuncs();
*handle = new rsmi_func_id_iter_handle;
if (*handle == nullptr) {
return RSMI_STATUS_OUT_OF_RESOURCES;
}
(*handle)->id_type = FUNC_ITER;
if (dev->supported_funcs()->begin() == dev->supported_funcs()->end()) {
return RSMI_STATUS_NO_DATA;
} else {
SupportedFuncMapIt *supp_func_iter = new SupportedFuncMapIt;
if (supp_func_iter == nullptr) {
return RSMI_STATUS_OUT_OF_RESOURCES;
}
*supp_func_iter = dev->supported_funcs()->begin();
(*handle)->func_id_iter = reinterpret_cast<uintptr_t>(supp_func_iter);
(*handle)->container_ptr =
reinterpret_cast<uintptr_t>(dev->supported_funcs());
}
return RSMI_STATUS_SUCCESS;
CATCH
}
rsmi_status_t
rsmi_dev_supported_variant_iterator_open(
rsmi_func_id_iter_handle_t parent_iter,
rsmi_func_id_iter_handle_t *var_iter) {
TRY
if (var_iter == nullptr || parent_iter->id_type == SUBVARIANT_ITER) {
return RSMI_STATUS_INVALID_ARGS;
}
if (parent_iter->func_id_iter == 0) {
return RSMI_STATUS_NO_DATA;
}
*var_iter = new rsmi_func_id_iter_handle;
if (*var_iter == nullptr) {
return RSMI_STATUS_OUT_OF_RESOURCES;
}
VariantMapIt *variant_itr = nullptr;
SubVariantIt *sub_var_itr = nullptr;
SupportedFuncMapIt *func_iter;
std::shared_ptr<VariantMap> var_map_container;
std::shared_ptr<SubVariant> sub_var_map_container;
switch (parent_iter->id_type) {
case FUNC_ITER:
func_iter =
reinterpret_cast<SupportedFuncMapIt *>(parent_iter->func_id_iter);
var_map_container = (*func_iter)->second;
if (var_map_container == nullptr) {
return RSMI_STATUS_NO_DATA;
}
variant_itr = new VariantMapIt;
*variant_itr = var_map_container->begin();
(*var_iter)->func_id_iter = reinterpret_cast<uintptr_t>(variant_itr);
(*var_iter)->container_ptr =
reinterpret_cast<uintptr_t>(var_map_container.get());
(*var_iter)->id_type = VARIANT_ITER;
break;
case VARIANT_ITER:
variant_itr =
reinterpret_cast<VariantMapIt *>(parent_iter->func_id_iter);
sub_var_map_container = (*variant_itr)->second;
if (sub_var_map_container == nullptr) {
return RSMI_STATUS_NO_DATA;
}
sub_var_itr = new SubVariantIt;
*sub_var_itr = sub_var_map_container->begin();
(*var_iter)->func_id_iter = reinterpret_cast<uintptr_t>(sub_var_itr);
(*var_iter)->container_ptr =
reinterpret_cast<uintptr_t>(sub_var_map_container.get());
(*var_iter)->id_type = SUBVARIANT_ITER;
break;
default:
assert(!"Unexpected iterator type");
return RSMI_STATUS_INVALID_ARGS;
}
return RSMI_STATUS_SUCCESS;
CATCH
}
rsmi_status_t
rsmi_dev_supported_func_iterator_close(rsmi_func_id_iter_handle_t *handle) {
TRY
if (handle == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
if ((*handle)->id_type == FUNC_ITER) {
SupportedFuncMapIt *supp_func_iter =
reinterpret_cast<SupportedFuncMapIt *>((*handle)->func_id_iter);
delete supp_func_iter;
} else if ((*handle)->id_type == VARIANT_ITER) {
VariantMapIt *var_iter =
reinterpret_cast<VariantMapIt *>((*handle)->func_id_iter);
delete var_iter;
} else if ((*handle)->id_type == SUBVARIANT_ITER) {
SubVariant *subvar_iter =
reinterpret_cast<SubVariant *>((*handle)->func_id_iter);
delete subvar_iter;
} else {
return RSMI_STATUS_INVALID_ARGS;
}
delete *handle;
*handle = nullptr;
return RSMI_STATUS_SUCCESS;
CATCH
}
rsmi_status_t
rsmi_func_iter_value_get(rsmi_func_id_iter_handle_t handle,
rsmi_func_id_value_t *value) {
TRY
if (value == nullptr) {
return RSMI_STATUS_INVALID_ARGS;
}
if (handle->func_id_iter == 0) {
return RSMI_STATUS_NO_DATA;
}
SupportedFuncMapIt *func_itr = nullptr;
VariantMapIt *variant_itr = nullptr;
SubVariantIt *sub_var_itr = nullptr;
switch (handle->id_type) {
case FUNC_ITER:
func_itr = reinterpret_cast<SupportedFuncMapIt *>(handle->func_id_iter);
value->name = (*func_itr)->first.c_str();
break;
case VARIANT_ITER:
variant_itr = reinterpret_cast<VariantMapIt *>(handle->func_id_iter);
value->id = (*variant_itr)->first;
break;
case SUBVARIANT_ITER:
sub_var_itr = reinterpret_cast<SubVariantIt *>(handle->func_id_iter);
value->id = *(*sub_var_itr);
break;
default:
return RSMI_STATUS_INVALID_ARGS;
}
CATCH
return RSMI_STATUS_SUCCESS;
}
rsmi_status_t
rsmi_func_iter_next(rsmi_func_id_iter_handle_t handle) {
TRY
if (handle->func_id_iter == 0) {
return RSMI_STATUS_NO_DATA;
}
SupportedFuncMapIt *func_iter;
VariantMapIt *var_iter;
SubVariantIt *sub_var_iter;
switch (handle->id_type) {
case FUNC_ITER:
func_iter = reinterpret_cast<SupportedFuncMapIt *>(handle->func_id_iter);
(*func_iter)++;
if (*func_iter ==
reinterpret_cast<SupportedFuncMap *>(handle->container_ptr)->end()) {
handle->func_id_iter = 0;
return RSMI_STATUS_NO_DATA;
}
break;
case VARIANT_ITER:
var_iter = reinterpret_cast<VariantMapIt *>(handle->func_id_iter);
(*var_iter)++;
if (*var_iter ==
reinterpret_cast<VariantMap *>(handle->container_ptr)->end()) {
handle->func_id_iter = 0;
return RSMI_STATUS_NO_DATA;
}
break;
case SUBVARIANT_ITER:
sub_var_iter = reinterpret_cast<SubVariantIt *>(handle->func_id_iter);
(*sub_var_iter)++;
if (*sub_var_iter ==
reinterpret_cast<SubVariant *>(handle->container_ptr)->end()) {
handle->func_id_iter = 0;
return RSMI_STATUS_NO_DATA;
}
break;
break;
default:
return RSMI_STATUS_INVALID_ARGS;
}
return RSMI_STATUS_SUCCESS;
CATCH
}
+291 -14
View File
@@ -55,6 +55,7 @@
#include <iostream>
#include <sstream>
#include <vector>
#include <memory>
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_device.h"
@@ -70,7 +71,7 @@ extern "C" {
namespace amd {
namespace smi {
// Sysfs file names
// Device sysfs file names
static const char *kDevPerfLevelFName = "power_dpm_force_performance_level";
static const char *kDevDevIDFName = "device";
static const char *kDevVendorIDFName = "vendor";
@@ -82,7 +83,7 @@ static const char *kDevGPUMClkFName = "pp_dpm_mclk";
static const char *kDevDCEFClkFName = "pp_dpm_dcefclk";
static const char *kDevFClkFName = "pp_dpm_fclk";
static const char *kDevSOCClkFName = "pp_dpm_socclk";
static const char *kDevGPUPCIEClkFname = "pp_dpm_pcie";
static const char *kDevPCIEClkFName = "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";
@@ -106,17 +107,6 @@ static const char *kDevMemBusyPercentFName = "mem_busy_percent";
static const char *kDevXGMIErrorFName = "xgmi_error";
static const char *kDevSerialNumberFName = "serial_number";
// Strings that are found within sysfs files
static const char *kDevPerfLevelAutoStr = "auto";
static const char *kDevPerfLevelLowStr = "low";
static const char *kDevPerfLevelHighStr = "high";
static const char *kDevPerfLevelManualStr = "manual";
static const char *kDevPerfLevelStandardStr = "profile_standard";
static const char *kDevPerfLevelMinMClkStr = "profile_min_mclk";
static const char *kDevPerfLevelMinSClkStr = "profile_min_sclk";
static const char *kDevPerfLevelPeakStr = "profile_peak";
static const char *kDevPerfLevelUnknownStr = "unknown";
// Firmware version files
static const char *kDevFwVersionAsdFName = "fw_version/asd_fw_version";
static const char *kDevFwVersionCeFName = "fw_version/ce_fw_version";
@@ -205,6 +195,18 @@ static const std::map<DevKFDNodePropTypes, const char *> kDevKFDPropNameMap = {
{kDevKFDNodePropMaxEngClkCComp, kDevKFDNodePropMaxEngClkCCompSName},
{kDevKFDNodePropDomain, kDevKFDNodePropDomainSName},
};
// Strings that are found within sysfs files
static const char *kDevPerfLevelAutoStr = "auto";
static const char *kDevPerfLevelLowStr = "low";
static const char *kDevPerfLevelHighStr = "high";
static const char *kDevPerfLevelManualStr = "manual";
static const char *kDevPerfLevelStandardStr = "profile_standard";
static const char *kDevPerfLevelMinMClkStr = "profile_min_mclk";
static const char *kDevPerfLevelMinSClkStr = "profile_min_sclk";
static const char *kDevPerfLevelPeakStr = "profile_peak";
static const char *kDevPerfLevelUnknownStr = "unknown";
static const std::map<DevInfoTypes, const char *> kDevAttribNameMap = {
{kDevPerfLevel, kDevPerfLevelFName},
{kDevOverDriveLevel, kDevOverDriveLevelFName},
@@ -217,7 +219,7 @@ static const std::map<DevInfoTypes, const char *> kDevAttribNameMap = {
{kDevDCEFClk, kDevDCEFClkFName},
{kDevFClk, kDevFClkFName},
{kDevSOCClk, kDevSOCClkFName},
{kDevPCIEClk, kDevGPUPCIEClkFname},
{kDevPCIEClk, kDevPCIEClkFName},
{kDevPowerProfileMode, kDevPowerProfileModeFName},
{kDevUsage, kDevUsageFName},
{kDevPowerODVoltage, kDevPowerODVoltageFName},
@@ -276,6 +278,178 @@ static const std::map<rsmi_dev_perf_level, const char *> kDevPerfLvlMap = {
{RSMI_DEV_PERF_LEVEL_UNKNOWN, kDevPerfLevelUnknownStr},
};
static std::map<DevInfoTypes, uint8_t> kDevInfoVarTypeToRSMIVariant = {
// rsmi_memory_type_t
{kDevMemTotGTT, RSMI_MEM_TYPE_GTT},
{kDevMemTotVisVRAM, RSMI_MEM_TYPE_VIS_VRAM},
{kDevMemTotVRAM, RSMI_MEM_TYPE_VRAM},
{kDevMemUsedGTT, RSMI_MEM_TYPE_GTT},
{kDevMemUsedVisVRAM, RSMI_MEM_TYPE_VIS_VRAM},
{kDevMemUsedVRAM, RSMI_MEM_TYPE_VRAM},
// rsmi_clk_type_t
{kDevGPUSClk, RSMI_CLK_TYPE_SYS},
{kDevGPUMClk, RSMI_CLK_TYPE_MEM},
{kDevFClk, RSMI_CLK_TYPE_DF},
{kDevDCEFClk, RSMI_CLK_TYPE_DCEF},
{kDevSOCClk, RSMI_CLK_TYPE_SOC},
// rsmi_fw_block_t
{kDevFwVersionAsd, RSMI_FW_BLOCK_ASD},
{kDevFwVersionCe, RSMI_FW_BLOCK_CE},
{kDevFwVersionDmcu, RSMI_FW_BLOCK_DMCU},
{kDevFwVersionMc, RSMI_FW_BLOCK_MC},
{kDevFwVersionMe, RSMI_FW_BLOCK_ME},
{kDevFwVersionMec, RSMI_FW_BLOCK_MEC},
{kDevFwVersionMec2, RSMI_FW_BLOCK_MEC2},
{kDevFwVersionPfp, RSMI_FW_BLOCK_PFP},
{kDevFwVersionRlc, RSMI_FW_BLOCK_RLC},
{kDevFwVersionRlcSrlc, RSMI_FW_BLOCK_RLC_SRLC},
{kDevFwVersionRlcSrlg, RSMI_FW_BLOCK_RLC_SRLG},
{kDevFwVersionRlcSrls, RSMI_FW_BLOCK_RLC_SRLS},
{kDevFwVersionSdma, RSMI_FW_BLOCK_SDMA},
{kDevFwVersionSdma2, RSMI_FW_BLOCK_SDMA2},
{kDevFwVersionSmc, RSMI_FW_BLOCK_SMC},
{kDevFwVersionSos, RSMI_FW_BLOCK_SOS},
{kDevFwVersionTaRas, RSMI_FW_BLOCK_TA_RAS},
{kDevFwVersionTaXgmi, RSMI_FW_BLOCK_TA_XGMI},
{kDevFwVersionUvd, RSMI_FW_BLOCK_UVD},
{kDevFwVersionVce, RSMI_FW_BLOCK_VCE},
{kDevFwVersionVcn, RSMI_FW_BLOCK_VCN},
// rsmi_gpu_block_t
{kDevErrCntUMC, RSMI_GPU_BLOCK_UMC},
{kDevErrCntSDMA, RSMI_GPU_BLOCK_SDMA},
{kDevErrCntGFX, RSMI_GPU_BLOCK_GFX},
// rsmi_event_group_t
{kDevDFCountersAvailable, RSMI_EVNT_GRP_XGMI}
};
static const std::map<const char *, dev_depends_t> kDevFuncDependsMap = {
// Functions with only mandatory dependencies
{"rsmi_dev_id_get", {{kDevDevIDFName}, {}}},
{"rsmi_dev_vendor_id_get", {{kDevVendorIDFName}, {}}},
{"rsmi_dev_name_get", {{kDevVendorIDFName,
kDevDevIDFName}, {}}},
{"rsmi_dev_brand_get", {{kDevVendorIDFName}, {}}},
{"rsmi_dev_vendor_name_get", {{kDevVendorIDFName}, {}}},
{"rsmi_dev_serial_number_get", {{kDevSerialNumberFName}, {}}},
{"rsmi_dev_subsystem_id_get", {{kDevSubSysDevIDFName}, {}}},
{"rsmi_dev_subsystem_name_get", {{kDevSubSysVendorIDFName,
kDevVendorIDFName,
kDevDevIDFName}, {}}},
{"rsmi_dev_drm_render_minor_get", {{}, {}}},
{"rsmi_dev_subsystem_vendor_id_get", {{kDevSubSysVendorIDFName}, {}}},
{"rsmi_dev_unique_id_get", {{kDevUniqueIdFName}, {}}},
{"rsmi_dev_pci_bandwidth_get", {{kDevPCIEClkFName}, {}}},
{"rsmi_dev_pci_id_get", {{}, {}}},
{"rsmi_dev_pci_throughput_get", {{kDevPCIEThruPutFName}, {}}},
{"rsmi_dev_pci_replay_counter_get", {{kDevPCIEReplayCountFName}, {}}},
{"rsmi_dev_pci_bandwidth_set", {{kDevPerfLevelFName,
kDevPCIEClkFName}, {}}},
{"rsmi_dev_power_profile_set", {{kDevPerfLevelFName,
kDevPowerProfileModeFName}, {}}},
{"rsmi_dev_memory_busy_percent_get", {{kDevMemBusyPercentFName}, {}}},
{"rsmi_dev_busy_percent_get", {{kDevUsageFName}, {}}},
{"rsmi_dev_memory_reserved_pages_get", {{kDevMemPageBadFName}, {}}},
{"rsmi_dev_overdrive_level_get", {{kDevOverDriveLevelFName}, {}}},
{"rsmi_dev_power_profile_presets_get", {{kDevPowerProfileModeFName}, {}}},
{"rsmi_dev_perf_level_set", {{kDevPerfLevelFName}, {}}},
{"rsmi_dev_perf_level_get", {{kDevPerfLevelFName}, {}}},
{"rsmi_dev_overdrive_level_set", {{kDevOverDriveLevelFName}, {}}},
{"rsmi_dev_vbios_version_get", {{kDevVBiosVerFName}, {}}},
{"rsmi_dev_od_volt_info_get", {{kDevPowerODVoltageFName}, {}}},
{"rsmi_dev_od_volt_curve_regions_get", {{kDevPowerODVoltageFName}, {}}},
{"rsmi_dev_ecc_enabled_get", {{kDevErrCntFeaturesFName}, {}}},
{"rsmi_dev_ecc_status_get", {{kDevErrCntFeaturesFName}, {}}},
{"rsmi_dev_counter_group_supported", {{}, {}}},
{"rsmi_dev_counter_create", {{}, {}}},
{"rsmi_dev_xgmi_error_status", {{kDevXGMIErrorFName}, {}}},
{"rsmi_dev_xgmi_error_reset", {{kDevXGMIErrorFName}, {}}},
{"rsmi_dev_memory_reserved_pages_get", {{kDevMemPageBadFName}, {}}},
// These functions with variants, but no sensors/units. (May or may not
// have mandatory dependencies.)
{"rsmi_dev_memory_total_get", { .mandatory_depends = {},
.variants = {
kDevMemTotGTT, kDevMemTotVisVRAM,
kDevMemTotVRAM,
}
}
},
{"rsmi_dev_memory_usage_get", { .mandatory_depends = {},
.variants = {
kDevMemUsedGTT,
kDevMemUsedVisVRAM,
kDevMemUsedVRAM,
}
}
},
{"rsmi_dev_gpu_clk_freq_get", { .mandatory_depends = {},
.variants = {
kDevGPUSClk,
kDevGPUMClk,
kDevFClk,
kDevDCEFClk,
kDevSOCClk,
}
}
},
{"rsmi_dev_gpu_clk_freq_set", { .mandatory_depends =
{kDevPerfLevelFName},
.variants = {
kDevGPUSClk,
kDevGPUMClk,
kDevFClk,
kDevDCEFClk,
kDevSOCClk,
}
}
},
{"rsmi_dev_firmware_version_get", { .mandatory_depends = {},
.variants = {
kDevFwVersionAsd,
kDevFwVersionCe,
kDevFwVersionDmcu,
kDevFwVersionMc,
kDevFwVersionMe,
kDevFwVersionMec,
kDevFwVersionMec2,
kDevFwVersionPfp,
kDevFwVersionRlc,
kDevFwVersionRlcSrlc,
kDevFwVersionRlcSrlg,
kDevFwVersionRlcSrls,
kDevFwVersionSdma,
kDevFwVersionSdma2,
kDevFwVersionSmc,
kDevFwVersionSos,
kDevFwVersionTaRas,
kDevFwVersionTaXgmi,
kDevFwVersionUvd,
kDevFwVersionVce,
kDevFwVersionVcn,
}
}
},
{"rsmi_dev_ecc_count_get", { .mandatory_depends = {},
.variants = {
kDevErrCntUMC,
kDevErrCntSDMA,
kDevErrCntGFX,
}
}
},
{"rsmi_counter_available_counters_get", { .mandatory_depends = {},
.variants = {
kDevDFCountersAvailable,
}
}
},
};
#define RET_IF_NONZERO(X) { \
if (X) return X; \
}
@@ -632,6 +806,109 @@ int Device::getKFDNodeProperty(DevKFDNodePropTypes prop, uint64_t *val) {
return 0;
}
void Device::DumpSupportedFunctions(void) {
SupportedFuncMapIt func_iter = supported_funcs_.begin();
std::cout << "*** Supported Functions ***" << std::endl;
while (func_iter != supported_funcs_.end()) {
std::cout << func_iter->first << std::endl;
std::cout << "\tSupported Variants(Monitors): ";
if (func_iter->second) {
VariantMapIt var_iter = func_iter->second->begin();
// We should have at least 1 supported variant or the function should
// not be listed as supported.
assert(var_iter != func_iter->second->end());
while (var_iter != func_iter->second->end()) {
std::cout << static_cast<uint32_t>(var_iter->first);
if (var_iter->second) {
std::cout << "(";
SubVariantIt mon_iter = var_iter->second->begin();
// We should have at least 1 supported monitor or the function should
// not be listed as supported.
assert(mon_iter != var_iter->second->end());
while (mon_iter != var_iter->second->end()) {
std::cout << static_cast<uint32_t>(*mon_iter) << ", ";
mon_iter++;
}
std::cout << ")";
}
std::cout << ", ";
var_iter++;
}
std::cout << std::endl;
} else {
std::cout << "Not Applicable" << std::endl;
}
func_iter++;
}
}
void Device::fillSupportedFuncs(void) {
if (supported_funcs_.size() != 0) {
return;
}
std::map<const char *, dev_depends_t>::const_iterator it =
kDevFuncDependsMap.begin();
std::string dev_rt = path_ + "/device";
bool mand_depends_met;
std::shared_ptr<VariantMap> supported_variants;
while (it != kDevFuncDependsMap.end()) {
// First, see if all the mandatory dependencies are there
std::vector<const char *>::const_iterator dep =
it->second.mandatory_depends.begin();
mand_depends_met = true;
for (; dep != it->second.mandatory_depends.end(); dep++) {
std::string dep_path = dev_rt + "/" + *dep;
if (!FileExists(dep_path.c_str())) {
mand_depends_met = false;
break;
}
}
if (!mand_depends_met) {
it++;
continue;
}
// Then, see if the variants are supported.
std::vector<DevInfoTypes>::const_iterator var =
it->second.variants.begin();
if (it->second.variants.size() == 0) {
supported_funcs_[it->first] = nullptr;
it++;
continue;
}
supported_variants = std::make_shared<VariantMap>();
for (; var != it->second.variants.end(); var++) {
std::string variant_path = dev_rt + "/" + kDevAttribNameMap.at(*var);
if (!FileExists(variant_path.c_str())) {
continue;
}
// At this point we assume no monitors, so map to nullptr
(*supported_variants)[kDevInfoVarTypeToRSMIVariant.at(*var)] = nullptr;
}
if ((*supported_variants).size() > 0) {
supported_funcs_[it->first] = supported_variants;
}
it++;
}
monitor()->fillSupportedFuncs(&supported_funcs_);
// DumpSupportedFunctions();
}
#undef RET_IF_NONZERO
} // namespace smi
} // namespace amd
+235 -1
View File
@@ -42,6 +42,7 @@
*/
#include <assert.h>
#include <dirent.h>
#include <fstream>
#include <string>
@@ -49,6 +50,8 @@
#include <map>
#include <iostream>
#include <algorithm>
#include <regex> // NOLINT
#include <vector>
#include "rocm_smi/rocm_smi_main.h"
#include "rocm_smi/rocm_smi_monitor.h"
@@ -126,7 +129,100 @@ static const std::map<MonitorTypes, const char *> kMonitorNameMap = {
{kMonTempLabel, kMonTempLabelName},
};
Monitor::Monitor(std::string path, RocmSMI_env_vars const *e) :
static std::map<MonitorTypes, uint64_t> kMonInfoVarTypeToRSMIVariant = {
// rsmi_temperature_metric_t
{kMonTemp, RSMI_TEMP_CURRENT},
{kMonTempMax, RSMI_TEMP_MAX},
{kMonTempMin, RSMI_TEMP_MIN},
{kMonTempMaxHyst, RSMI_TEMP_MAX_HYST},
{kMonTempMinHyst, RSMI_TEMP_MIN_HYST},
{kMonTempCritical, RSMI_TEMP_CRITICAL},
{kMonTempCriticalHyst, RSMI_TEMP_CRITICAL_HYST},
{kMonTempEmergency, RSMI_TEMP_EMERGENCY},
{kMonTempEmergencyHyst, RSMI_TEMP_EMERGENCY_HYST},
{kMonTempCritMin, RSMI_TEMP_CRIT_MIN},
{kMonTempCritMinHyst, RSMI_TEMP_CRIT_MIN_HYST},
{kMonTempOffset, RSMI_TEMP_OFFSET},
{kMonTempLowest, RSMI_TEMP_LOWEST},
{kMonTempHighest, RSMI_TEMP_HIGHEST},
{kMonInvalid, RSMI_DEFAULT_VARIANT},
};
typedef struct {
std::vector<const char *> mandatory_depends;
std::vector<MonitorTypes> variants;
} monitor_depends_t;
static const std::map<const char *, monitor_depends_t> kMonFuncDependsMap = {
{"rsmi_dev_power_ave_get", { .mandatory_depends = {kMonPowerAveName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_get", { .mandatory_depends = {kMonPowerCapName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_range_get", { .mandatory_depends =
{kMonPowerCapMaxName,
kMonPowerCapMinName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_power_cap_set", { .mandatory_depends =
{kMonPowerCapMaxName,
kMonPowerCapMinName,
kMonPowerCapName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_rpms_get", { .mandatory_depends = {kMonFanRPMsName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_get", { .mandatory_depends = {kMonFanSpeedFName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_max_get", { .mandatory_depends =
{kMonMaxFanSpeedFName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_temp_metric_get", { .mandatory_depends =
{kMonTempLabelName},
.variants = {kMonTemp,
kMonTempMax,
kMonTempMin,
kMonTempMaxHyst,
kMonTempMinHyst,
kMonTempCritical,
kMonTempCriticalHyst,
kMonTempEmergency,
kMonTempEmergencyHyst,
kMonTempCritMin,
kMonTempCritMinHyst,
kMonTempOffset,
kMonTempLowest,
kMonTempHighest,
},
}
},
{"rsmi_dev_fan_reset", { .mandatory_depends =
{kMonFanControlEnableName},
.variants = {kMonInvalid},
}
},
{"rsmi_dev_fan_speed_set", { .mandatory_depends =
{kMonMaxFanSpeedFName,
kMonFanControlEnableName,
kMonFanSpeedFName},
.variants = {kMonInvalid},
}
},
};
Monitor::Monitor(std::string path, RocmSMI_env_vars const *e) :
path_(path), env_(e) {
}
Monitor::~Monitor(void) {
@@ -193,11 +289,149 @@ Monitor::setSensorLabelMap(void) {
return 0;
}
static int get_supported_sensors(std::string dir_path, std::string fn_reg_ex,
std::vector<uint64_t> *sensors) {
auto hwmon_dir = opendir(dir_path.c_str());
assert(hwmon_dir != nullptr);
assert(sensors != nullptr);
sensors->clear();
std::string::size_type pos = fn_reg_ex.find('#');
if (pos == std::string::npos) {
return -1;
}
fn_reg_ex.erase(pos, 1);
fn_reg_ex.insert(pos, "([0-9]+)");
fn_reg_ex = "\\b" + fn_reg_ex + "\\b";
auto dentry = readdir(hwmon_dir);
std::smatch match;
int64_t mon_val;
char *endptr;
std::regex re(fn_reg_ex);
std::string fn;
while (dentry != nullptr) {
fn = dentry->d_name;
if (std::regex_search(fn, match, re)) {
assert(match.size() == 2); // 1 for whole match + 1 for sub-match
errno = 0;
mon_val = strtol(match.str(1).c_str(), &endptr, 10);
assert(errno == 0);
assert(*endptr == '\0');
if (errno) {
return -2;
}
sensors->push_back(mon_val);
}
dentry = readdir(hwmon_dir);
}
return 0;
}
uint32_t
Monitor::getSensorIndex(rsmi_temperature_type_t type) {
return temp_type_index_map_.at(type);
}
static std::vector<uint64_t> get_intersection(std::vector<uint64_t> *v1,
std::vector<uint64_t> *v2) {
assert(v1 != nullptr);
assert(v2 != nullptr);
std::vector<uint64_t> intersect;
std::sort(v1->begin(), v1->end());
std::sort(v2->begin(), v2->end());
std::set_intersection(v1->begin(), v1->end(), v2->begin(), v2->end(),
std::back_inserter(intersect));
return intersect;
}
void Monitor::fillSupportedFuncs(SupportedFuncMap *supported_funcs) {
std::map<const char *, monitor_depends_t>::const_iterator it =
kMonFuncDependsMap.begin();
std::string mon_root = path_;
bool mand_depends_met;
std::shared_ptr<VariantMap> supported_variants;
std::vector<uint64_t> sensors_i;
std::vector<uint64_t> intersect;
int ret;
assert(supported_funcs != nullptr);
while (it != kMonFuncDependsMap.end()) {
// First, see if all the mandatory dependencies are there
std::vector<const char *>::const_iterator dep =
it->second.mandatory_depends.begin();
mand_depends_met = true;
// Initialize "intersect". A monitor is considered supported if all of its
// dependency monitors with the same sensor index are present. So we
// initialize "intersect" with the set of sensors that exist for the first
// mandatory monitor, and take intersection of that with the subsequent
// dependency monitors. The main assumption here is that
// variant_<sensor_i>'s sensor-based dependencies have the same index i;
// in other words, variant_i is not dependent on a sensor j, j != i
do {
ret = get_supported_sensors(mon_root + "/", *dep, &intersect);
if (ret == -1) {
// In this case, the dependency is not sensor-specific, so just
// see if the file exists.
std::string dep_path = mon_root + "/" + *dep;
if (!FileExists(dep_path.c_str())) {
mand_depends_met = false;
break;
}
}
dep++;
} while (dep != it->second.mandatory_depends.end());
if (!mand_depends_met) {
it++;
continue;
}
// "intersect" holds the set of sensors for the mandatory dependencies
// that exist.
std::vector<MonitorTypes>::const_iterator var =
it->second.variants.begin();
supported_variants = std::make_shared<VariantMap>();
std::vector<uint64_t> supported_monitors;
for (; var != it->second.variants.end(); var++) {
if (*var != kMonInvalid) {
ret = get_supported_sensors(mon_root + "/",
kMonitorNameMap.at(*var), &sensors_i);
if (ret == 0) {
supported_monitors = get_intersection(&sensors_i, &intersect);
}
} else {
supported_monitors = intersect;
}
if (supported_monitors.size() > 0) {
(*supported_variants)[kMonInfoVarTypeToRSMIVariant.at(*var)] =
std::make_shared<SubVariant>(supported_monitors);
}
}
if (it->second.variants.size() == 0) {
(*supported_funcs)[it->first] = nullptr;
supported_variants = nullptr; // Invoke destructor
} else if ((*supported_variants).size() > 0) {
(*supported_funcs)[it->first] = supported_variants;
}
it++;
}
}
} // namespace smi
} // namespace amd