diff --git a/projects/rocm-smi-lib/docs/ROCm_SMI_Manual.pdf b/projects/rocm-smi-lib/docs/ROCm_SMI_Manual.pdf index 9265d98c4c..876670d61a 100644 Binary files a/projects/rocm-smi-lib/docs/ROCm_SMI_Manual.pdf and b/projects/rocm-smi-lib/docs/ROCm_SMI_Manual.pdf differ 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 a3e9d65903..ec57bf7c78 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi.h @@ -114,6 +114,9 @@ typedef enum { //!< execution of function RSMI_STATUS_UNEXPECTED_SIZE, //!< An unexpected amount of data //!< was read + RSMI_STATUS_NO_DATA, //!< No data was found for a given + //!< input + RSMI_STATUS_UNKNOWN_ERROR = 0xFFFFFFFF, //!< An unknown error occurred } rsmi_status_t; @@ -667,6 +670,43 @@ typedef struct { uint32_t pasid; //!< PASID } rsmi_process_info_t; + +/** + * @brief Opaque handle to function-support object + */ +typedef struct rsmi_func_id_iter_handle * rsmi_func_id_iter_handle_t; + +//! Place-holder "variant" for functions that have don't have any variants, +//! but do have monitors or sensors. +#define RSMI_DEFAULT_VARIANT 0xFFFFFFFFFFFFFFFF + +/** + * @brief This union holds the value of an ::rsmi_func_id_iter_handle_t. The + * value may be a function name, or an ennumerated variant value of types + * such as ::rsmi_memory_type_t, ::rsmi_temperature_metric_t, etc. + */ +typedef union id { + uint64_t id; //!< uint64_t representation of value + const char *name; //!< name string (applicable to functions only) + union { + //!< Used for ::rsmi_memory_type_t variants + rsmi_memory_type_t memory_type; + //!< Used for ::rsmi_temperature_metric_t variants + rsmi_temperature_metric_t temp_metric; + //!< Used for ::rsmi_event_type_t variants + rsmi_event_type_t evnt_type; + //!< Used for ::rsmi_event_group_t variants + rsmi_event_group_t evnt_group; + //!< Used for ::rsmi_clk_type_t variants + rsmi_clk_type_t clk_type; + //!< Used for ::rsmi_fw_block_t variants + rsmi_fw_block_t fw_block; + //!< Used for ::rsmi_gpu_block_t variants + rsmi_gpu_block_t gpu_block_type; + }; +} rsmi_func_id_value_t; + + /*****************************************************************************/ /** @defgroup InitShutAdmin Initialization and Shutdown * These functions are used for initialization of ROCm SMI and clean up when @@ -811,10 +851,10 @@ rsmi_status_t rsmi_dev_brand_get(uint32_t dv_ind, char *brand, uint32_t len); /** * @brief Get the name string for a give vendor ID * - * @details Given vendor ID @p id, a pointer to a caller provided char buffer - * @p name, and a length of this buffer @p len, this function will write the - * name of the vendor (up to @p len characters) buffer @p name. The @p id may - * be a device vendor or subsystem vendor ID. + * @details Given a device index @p dv_ind, a pointer to a caller provided + * char buffer @p name, and a length of this buffer @p len, this function will + * write the name of the vendor (up to @p len characters) buffer @p name. The + * @p id may be a device vendor or subsystem vendor ID. * * If the integer ID associated with the vendor is not found in one of the * system files containing device name information (e.g. @@ -822,7 +862,7 @@ rsmi_status_t rsmi_dev_brand_get(uint32_t dv_ind, char *brand, uint32_t len); * as a string. Updating the system name files can be accompplished with * "sudo update-pciids". * - * @param[in] id a vendor ID + * @param[in] dv_ind a device index * * @param[inout] name a pointer to a caller provided char buffer to which the * name will be written @@ -835,7 +875,8 @@ rsmi_status_t rsmi_dev_brand_get(uint32_t dv_ind, char *brand, uint32_t len); * be written. * */ -rsmi_status_t rsmi_dev_vendor_name_get(uint32_t id, char *name, size_t len); +rsmi_status_t rsmi_dev_vendor_name_get(uint32_t dv_ind, char *name, + size_t len); /** * @brief Get the serial number string for a device @@ -1202,16 +1243,14 @@ rsmi_dev_power_cap_set(uint32_t dv_ind, uint32_t sensor_ind, uint64_t cap); /** * @brief Set the power profile * - * @details Given a device index @p dv_ind, a sensor index sensor_ind, and a - * @p profile, this function will attempt to set the current profile to the - * provided profile. The provided profile must be one of the currently - * supported profiles, as indicated by a call to - * ::rsmi_dev_power_profile_presets_get() + * @details Given a device index @p dv_ind and a @p profile, this function will + * attempt to set the current profile to the provided profile. The provided + * profile must be one of the currently supported profiles, as indicated by a + * call to ::rsmi_dev_power_profile_presets_get() * * @param[in] dv_ind a device index * - * @param[in] sensor_ind a 0-based sensor index. Normally, this will be 0. - * If a device has more than one sensor, it could be greater than 0. + * @param[in] reserved Not currently used. Set to 0. * * @param[in] profile a ::rsmi_power_profile_preset_masks_t that hold the mask * of the desired new power profile @@ -1220,7 +1259,7 @@ rsmi_dev_power_cap_set(uint32_t dv_ind, uint32_t sensor_ind, uint64_t cap); * */ 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 reserved, rsmi_power_profile_preset_masks_t profile); /** @} */ // end of PowerCont /*****************************************************************************/ @@ -1728,25 +1767,6 @@ rsmi_status_t rsmi_dev_overdrive_level_set(int32_t dv_ind, uint32_t od); rsmi_status_t rsmi_dev_gpu_clk_freq_set(uint32_t dv_ind, rsmi_clk_type_t clk_type, uint64_t freq_bitmask); -/** - * @brief Set the frequency limits for the specified clock - * - * @details Given a device index @p dv_ind, a clock type (::rsmi_clk_type_t) - * @p clk, and a pointer to a ::rsmi_range_t @p range containing the desired - * upper and lower frequency limits, this function will attempt to set the - * frequency limits to those specified in @p range. - * - * @param[in] dv_ind a device index - * - * @param[in] clk The clock type for which the limits should be imposed. - * - * @param[in] range A pointer to the ::rsmi_range_t containing the desired limits - * - * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. - */ -rsmi_status_t rsmi_dev_od_freq_range_set(uint32_t dv_ind, rsmi_clk_type_t clk, - rsmi_range_t *range); - /** @} */ // end of PerfCont /*****************************************************************************/ @@ -1958,7 +1978,7 @@ rsmi_status_string(rsmi_status_t status, const char **status_string); * ::RSMI_STATUS_SUCCESS if the device associatee with @p dv_ind * support counting events of the type indicated by @p group. * - * ::RSMI_STATUS_NOT_SUPPORTED If the device does not support event group @p + * ::RSMI_STATUS_NOT_FOUND If the device does not support event group @p * group * */ @@ -2125,6 +2145,7 @@ rsmi_compute_process_info_get(rsmi_process_info_t *procs, uint32_t *num_items); rsmi_status_t rsmi_compute_process_info_by_pid_get(uint32_t pid, rsmi_process_info_t *proc); + /** @} */ // end of SysInfo /*****************************************************************************/ @@ -2169,6 +2190,225 @@ rsmi_dev_xgmi_error_reset(uint32_t dv_ind); /** @} */ // end of SysInfo + +/*****************************************************************************/ +/** @defgroup APISupport Supported Functions + * API function support varies by both GPU type and the version of the + * installed ROCm stack. The functions described in this section can be used + * to determine, up front, which functions are supported for a given device + * on a system. If such "up front" knowledge of support for a function is not + * needed, alternatively, one can call a device related function and check the + * return code. + * + * Some functions have several variations ("variants") where some variants are + * supported and others are not. For example, on a given device, + * ::rsmi_dev_temp_metric_get may support some types of temperature metrics + * (e.g., ::RSMI_TEMP_CRITICAL_HYST), but not others + * (e.g., ::RSMI_TEMP_EMERGENCY). + * + * In addition to a top level of variant support for a function, a function + * may have varying support for monitors/sensors. These are considered + * "sub-variants" in functions described in this section. Continuing the + * ::rsmi_dev_temp_metric_get example, if variant + * ::RSMI_TEMP_CRITICAL_HYST is supported, perhaps + * only the sub-variant sensors ::RSMI_TEMP_TYPE_EDGE + * and ::RSMI_TEMP_TYPE_EDGE are supported, but not + * ::RSMI_TEMP_TYPE_MEMORY. + * + * In cases where a function takes in a sensor id parameter but does not have + * any "top level" variants, the functions in this section will indicate a + * default "variant", ::RSMI_DEFAULT_VARIANT, for the top level variant, and + * the various monitor support will be sub-variants of this. + * + * The functions in this section use the "iterator" concept to list which + * functions are supported; to list which variants of the supported functions + * are supported; and finally which monitors/sensors are supported for a + * variant. + * + * Here is example code that prints out all supported functions, their + * supported variants and sub-variants. Please see the related descriptions + * functions and RSMI types. + * \latexonly + * \pagebreak + * \endlatexonly + * \code{.cpp} + * rsmi_func_id_iter_handle_t iter_handle, var_iter, sub_var_iter; + * rsmi_func_id_value_t value; + * rsmi_status_t err; + * + * for (uint32_t i = 0; i < ; ++i) { + * std::cout << "Supported RSMI Functions:" << std::endl; + * std::cout << "\tVariants (Monitors)" << std::endl; + * + * err = rsmi_dev_supported_func_iterator_open(i, &iter_handle); + * + * while (1) { + * err = rsmi_func_iter_value_get(iter_handle, &value); + * std::cout << "Function Name: " << value.name << std::endl; + * + * err = rsmi_dev_supported_variant_iterator_open(iter_handle, &var_iter); + * if (err != RSMI_STATUS_NO_DATA) { + * std::cout << "\tVariants/Monitors: "; + * while (1) { + * err = rsmi_func_iter_value_get(var_iter, &value); + * if (value.id == RSMI_DEFAULT_VARIANT) { + * std::cout << "Default Variant "; + * } else { + * std::cout << value.id; + * } + * std::cout << " ("; + * + * err = + * rsmi_dev_supported_variant_iterator_open(var_iter, &sub_var_iter); + * if (err != RSMI_STATUS_NO_DATA) { + * + * while (1) { + * err = rsmi_func_iter_value_get(sub_var_iter, &value); + * std::cout << value.id << ", "; + * + * err = rsmi_func_iter_next(sub_var_iter); + * + * if (err == RSMI_STATUS_NO_DATA) { + * break; + * } + * } + * err = rsmi_dev_supported_func_iterator_close(&sub_var_iter); + * } + * + * std::cout << "), "; + * + * err = rsmi_func_iter_next(var_iter); + * + * if (err == RSMI_STATUS_NO_DATA) { + * break; + * } + * } + * std::cout << std::endl; + * + * err = rsmi_dev_supported_func_iterator_close(&var_iter); + * } + * + * err = rsmi_func_iter_next(iter_handle); + * + * if (err == RSMI_STATUS_NO_DATA) { + * break; + * } + * } + * err = rsmi_dev_supported_func_iterator_close(&iter_handle); + * } + * \endcode + * + * @{ + */ + + +/** + * @brief Get a function name iterator of supported RSMI functions for a device + * + * @details Given a device index @p dv_ind, this function will write a function + * iterator handle to the caller-provided memory pointed to by @p handle. This + * handle can be used to iterate through all the supported functions. + * + * @param[in] dv_ind a device index of device for which support information is + * requested + * + * @param[inout] handle A pointer to caller-provided memory to which the + * function iterator will be written. + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * + */ +rsmi_status_t +rsmi_dev_supported_func_iterator_open(uint32_t dv_ind, + rsmi_func_id_iter_handle_t *handle); + +/** + * @brief Get a variant iterator for a given handle + * + * @details Given a ::rsmi_func_id_iter_handle_t @p obj_h, this function will + * write a function iterator handle to the caller-provided memory pointed to + * by @p var_iter. This handle can be used to iterate through all the supported + * variants of the provided handle. @p obj_h may be a handle to a function + * object, as provided by a call to ::rsmi_dev_supported_func_iterator_open, or + * it may be a variant itself (from a call to + * ::rsmi_dev_supported_variant_iterator_open), it which case @p var_iter will + * be an iterator of the sub-variants of @p obj_h (e.g., monitors). + * + * This call allocates a small amount of memory to @p var_iter. To free this memory + * ::rsmi_dev_supported_func_iterator_close should be called on the returned + * iterator handle @p var_iter when it is no longer needed. + * + * @param[in] obj_h an iterator handle for which the variants are being requested + * + * @param[inout] var_iter A pointer to caller-provided memory to which the + * sub-variant iterator will be written. + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * + */ +rsmi_status_t +rsmi_dev_supported_variant_iterator_open(rsmi_func_id_iter_handle_t obj_h, + rsmi_func_id_iter_handle_t *var_iter); + +/** + * @brief Advance a function identifer iterator + * + * @details Given a function id iterator handle (::rsmi_func_id_iter_handle_t) + * @p handle, this function will increment the iterator to point to the next + * identifier. After a successful call to this function, obtaining the value + * of the iterator @p handle will provide the value of the next item in the + * list of functions/variants. + * + * If there are no more items in the list, ::RSMI_STATUS_NO_DATA is returned. + * + * @param[in] handle A pointer to an iterator handle to be incremented + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * @retval ::RSMI_STATUS_NO_DATA is returned when list of identifiers has been + * exhausted + * + */ +rsmi_status_t +rsmi_func_iter_next(rsmi_func_id_iter_handle_t handle); + +/** + * @brief Close a variant iterator handle + * + * @details Given a pointer to an ::rsmi_func_id_iter_handle_t @p handle, this + * function will free the resources being used by the handle + * + * @param[in] handle A pointer to an iterator handle to be closed + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * + */ +rsmi_status_t +rsmi_dev_supported_func_iterator_close(rsmi_func_id_iter_handle_t *handle); + +/** + * @brief Get the value associated with a function/variant iterator + * + * @details Given an ::rsmi_func_id_iter_handle_t @p handle, this function + * will write the identifier of the function/variant to the user provided + * memory pointed to by @p value. + * + * @p value may point to a function name, a variant id, or a monitor/sensor + * index, depending on what kind of iterator @p handle is + * + * @param[in] handle An iterator for which the value is being requested + * + * @param[inout] value A pointer to an ::rsmi_func_id_value_t provided by the + * caller to which this function will write the value assocaited with @p handle + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * + */ +rsmi_status_t +rsmi_func_iter_value_get(rsmi_func_id_iter_handle_t handle, + rsmi_func_id_value_t *value); + +/** @} */ // end of APISupport + #ifdef __cplusplus } #endif // __cplusplus 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 92b7116969..fd99fb2f6c 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 @@ -45,6 +45,11 @@ #ifndef INCLUDE_ROCM_SMI_ROCM_SMI_COMMON_H_ #define INCLUDE_ROCM_SMI_ROCM_SMI_COMMON_H_ +#include +#include +#include +#include + #define DBG_FILE_ERROR(FN, WR_STR) \ if (env_->debug_output_bitfield & RSMI_DEBUG_SYSFS_FILE_PATHS) { \ std::cout << "*****" << __FUNCTION__ << std::endl; \ @@ -60,6 +65,12 @@ // Add different debug filters here, as powers of 2; e.g, 1, 2, 4, 8, ... #define RSMI_DEBUG_SYSFS_FILE_PATHS 1 +struct rsmi_func_id_iter_handle { + uintptr_t func_id_iter; + uintptr_t container_ptr; + uint32_t id_type; +}; + struct RocmSMI_env_vars { // Bitfield that is AND'd with various RSMI_DEBUG_* bits to determine // which debugging information should be turned on. Env. variable @@ -82,4 +93,14 @@ struct RocmSMI_env_vars { const char *path_power_root_override; }; +// Support information data structures +typedef std::vector SubVariant; +typedef SubVariant::const_iterator SubVariantIt; + +typedef std::map> VariantMap; +typedef VariantMap::const_iterator VariantMapIt; + +typedef std::map> SupportedFuncMap; +typedef SupportedFuncMap::const_iterator SupportedFuncMapIt; + #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 6803cfe3ef..f9d700b38a 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 @@ -155,6 +155,11 @@ enum DevInfoTypes { kDevMemPageBad, }; +typedef struct { + std::vector mandatory_depends; + std::vector variants; +} dev_depends_t; + class Device { public: explicit Device(std::string path, RocmSMI_env_vars const *e); @@ -185,6 +190,9 @@ class Device { pthread_mutex_t *mutex(void) {return mutex_.ptr;} evt::dev_evt_grp_set_t* supported_event_groups(void) { return &supported_event_groups_;} + SupportedFuncMap *supported_funcs(void) {return &supported_funcs_;} + void fillSupportedFuncs(void); + void DumpSupportedFunctions(void); private: std::shared_ptr monitor_; @@ -205,6 +213,7 @@ class Device { std::unordered_set supported_event_groups_; std::map kfdNodePropMap_; + SupportedFuncMap supported_funcs_; }; } // namespace smi diff --git a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_monitor.h b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_monitor.h index 695f94c8fe..8192ba2963 100755 --- a/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_monitor.h +++ b/projects/rocm-smi-lib/include/rocm_smi/rocm_smi_monitor.h @@ -94,6 +94,7 @@ class Monitor { int writeMonitor(MonitorTypes type, uint32_t sensor_ind, std::string val); uint32_t setSensorLabelMap(void); uint32_t getSensorIndex(rsmi_temperature_type_t type); + void fillSupportedFuncs(SupportedFuncMap *supported_funcs); private: std::string MakeMonitorPath(MonitorTypes type, int32_t sensor_id); diff --git a/projects/rocm-smi-lib/src/rocm_smi.cc b/projects/rocm-smi-lib/src/rocm_smi.cc index d2ac0f9a49..ef3faa5fc2 100755 --- a/projects/rocm-smi-lib/src/rocm_smi.cc +++ b/projects/rocm-smi-lib/src/rocm_smi.cc @@ -57,6 +57,7 @@ #include #include +#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(supp_func_iter); + (*handle)->container_ptr = + reinterpret_cast(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 var_map_container; + std::shared_ptr sub_var_map_container; + + switch (parent_iter->id_type) { + case FUNC_ITER: + func_iter = + reinterpret_cast(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(variant_itr); + (*var_iter)->container_ptr = + reinterpret_cast(var_map_container.get()); + (*var_iter)->id_type = VARIANT_ITER; + break; + + case VARIANT_ITER: + variant_itr = + reinterpret_cast(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(sub_var_itr); + (*var_iter)->container_ptr = + reinterpret_cast(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((*handle)->func_id_iter); + delete supp_func_iter; + } else if ((*handle)->id_type == VARIANT_ITER) { + VariantMapIt *var_iter = + reinterpret_cast((*handle)->func_id_iter); + delete var_iter; + } else if ((*handle)->id_type == SUBVARIANT_ITER) { + SubVariant *subvar_iter = + reinterpret_cast((*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(handle->func_id_iter); + value->name = (*func_itr)->first.c_str(); + break; + + case VARIANT_ITER: + variant_itr = reinterpret_cast(handle->func_id_iter); + value->id = (*variant_itr)->first; + break; + + case SUBVARIANT_ITER: + sub_var_itr = reinterpret_cast(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(handle->func_id_iter); + (*func_iter)++; + + if (*func_iter == + reinterpret_cast(handle->container_ptr)->end()) { + handle->func_id_iter = 0; + return RSMI_STATUS_NO_DATA; + } + break; + + case VARIANT_ITER: + var_iter = reinterpret_cast(handle->func_id_iter); + (*var_iter)++; + if (*var_iter == + reinterpret_cast(handle->container_ptr)->end()) { + handle->func_id_iter = 0; + return RSMI_STATUS_NO_DATA; + } + break; + + case SUBVARIANT_ITER: + sub_var_iter = reinterpret_cast(handle->func_id_iter); + (*sub_var_iter)++; + if (*sub_var_iter == + reinterpret_cast(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 +} diff --git a/projects/rocm-smi-lib/src/rocm_smi_device.cc b/projects/rocm-smi-lib/src/rocm_smi_device.cc index 1caae50516..64c4efd78b 100755 --- a/projects/rocm-smi-lib/src/rocm_smi_device.cc +++ b/projects/rocm-smi-lib/src/rocm_smi_device.cc @@ -55,6 +55,7 @@ #include #include #include +#include #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 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 kDevAttribNameMap = { {kDevPerfLevel, kDevPerfLevelFName}, {kDevOverDriveLevel, kDevOverDriveLevelFName}, @@ -217,7 +219,7 @@ static const std::map 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 kDevPerfLvlMap = { {RSMI_DEV_PERF_LEVEL_UNKNOWN, kDevPerfLevelUnknownStr}, }; +static std::map 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 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(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(*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_iterator it = + kDevFuncDependsMap.begin(); + std::string dev_rt = path_ + "/device"; + bool mand_depends_met; + std::shared_ptr supported_variants; + + while (it != kDevFuncDependsMap.end()) { + // First, see if all the mandatory dependencies are there + std::vector::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::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(); + + 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 diff --git a/projects/rocm-smi-lib/src/rocm_smi_monitor.cc b/projects/rocm-smi-lib/src/rocm_smi_monitor.cc index 4ab035fb86..b23f0682b9 100755 --- a/projects/rocm-smi-lib/src/rocm_smi_monitor.cc +++ b/projects/rocm-smi-lib/src/rocm_smi_monitor.cc @@ -42,6 +42,7 @@ */ #include +#include #include #include @@ -49,6 +50,8 @@ #include #include #include +#include // NOLINT +#include #include "rocm_smi/rocm_smi_main.h" #include "rocm_smi/rocm_smi_monitor.h" @@ -126,7 +129,100 @@ static const std::map kMonitorNameMap = { {kMonTempLabel, kMonTempLabelName}, }; -Monitor::Monitor(std::string path, RocmSMI_env_vars const *e) : +static std::map 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 mandatory_depends; + std::vector variants; +} monitor_depends_t; + +static const std::map 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 *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 get_intersection(std::vector *v1, + std::vector *v2) { + assert(v1 != nullptr); + assert(v2 != nullptr); + std::vector 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_iterator it = + kMonFuncDependsMap.begin(); + std::string mon_root = path_; + bool mand_depends_met; + std::shared_ptr supported_variants; + std::vector sensors_i; + std::vector intersect; + int ret; + + assert(supported_funcs != nullptr); + + while (it != kMonFuncDependsMap.end()) { + // First, see if all the mandatory dependencies are there + std::vector::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_'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::const_iterator var = + it->second.variants.begin(); + supported_variants = std::make_shared(); + + std::vector 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(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 diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.cc new file mode 100755 index 0000000000..3a503de19f --- /dev/null +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.cc @@ -0,0 +1,173 @@ +/* + * ============================================================================= + * ROC Runtime Conformance Release License + * ============================================================================= + * The University of Illinois/NCSA + * Open Source License (NCSA) + * + * Copyright (c) 2019, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Developed by: + * + * AMD Research and AMD ROC Software Development + * + * Advanced Micro Devices, Inc. + * + * www.amd.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal with the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimers. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimers in + * the documentation and/or other materials provided with the distribution. + * - Neither the names of , + * nor the names of its contributors may be used to endorse or promote + * products derived from this Software without specific prior written + * permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS WITH THE SOFTWARE. + * + */ + +#include +#include + +#include +#include + +#include "gtest/gtest.h" +#include "rocm_smi/rocm_smi.h" +#include "rocm_smi_test/functional/api_support_read.h" +#include "rocm_smi_test/test_common.h" +#include "rocm_smi_test/test_utils.h" + +TestAPISupportRead::TestAPISupportRead() : TestBase() { + set_title("RSMI API Support Read Test"); + set_description("This test verifies that the supported APIs are corretly " + "identified."); +} + +TestAPISupportRead::~TestAPISupportRead(void) { +} + +void TestAPISupportRead::SetUp(void) { + TestBase::SetUp(); + + return; +} + +void TestAPISupportRead::DisplayTestInfo(void) { + TestBase::DisplayTestInfo(); +} + +void TestAPISupportRead::DisplayResults(void) const { + TestBase::DisplayResults(); + return; +} + +void TestAPISupportRead::Close() { + // This will close handles opened within rsmitst utility calls and call + // rsmi_shut_down(), so it should be done after other hsa cleanup + TestBase::Close(); +} + +void TestAPISupportRead::Run(void) { + rsmi_status_t err; + + TestBase::Run(); + + rsmi_func_id_iter_handle_t iter_handle, var_iter, sub_var_iter; + rsmi_func_id_value_t value; + + for (uint32_t i = 0; i < num_monitor_devs(); ++i) { + PrintDeviceHeader(i); + + std::cout << "Supported RSMI Functions:" << std::endl; + std::cout << "\tVariants (Monitors)" << std::endl; + + err = rsmi_dev_supported_func_iterator_open(i, &iter_handle); + CHK_ERR_ASRT(err) + + while (1) { + err = rsmi_func_iter_value_get(iter_handle, &value); + CHK_ERR_ASRT(err) + std::cout << "Function Name: " << value.name << std::endl; + + err = rsmi_dev_supported_variant_iterator_open(iter_handle, &var_iter); + if (err != RSMI_STATUS_NO_DATA) { + CHK_ERR_ASRT(err) + std::cout << "\tVariants/Monitors: "; + while (1) { + err = rsmi_func_iter_value_get(var_iter, &value); + CHK_ERR_ASRT(err) + if (value.id == RSMI_DEFAULT_VARIANT) { + std::cout << "Default Variant "; + } else { + std::cout << value.id; + } + std::cout << " ("; + + err = + rsmi_dev_supported_variant_iterator_open(var_iter, &sub_var_iter); + if (err != RSMI_STATUS_NO_DATA) { + CHK_ERR_ASRT(err) + + while (1) { + err = rsmi_func_iter_value_get(sub_var_iter, &value); + CHK_ERR_ASRT(err) + std::cout << value.id << ", "; + + err = rsmi_func_iter_next(sub_var_iter); + + if (err == RSMI_STATUS_NO_DATA) { + break; + } + CHK_ERR_ASRT(err) + } + err = rsmi_dev_supported_func_iterator_close(&sub_var_iter); + CHK_ERR_ASRT(err) + } + + std::cout << "), "; + + err = rsmi_func_iter_next(var_iter); + + if (err == RSMI_STATUS_NO_DATA) { + break; + } + CHK_ERR_ASRT(err) + } + std::cout << std::endl; + + err = rsmi_dev_supported_func_iterator_close(&var_iter); + CHK_ERR_ASRT(err) + } + + err = rsmi_func_iter_next(iter_handle); + + if (err == RSMI_STATUS_NO_DATA) { + break; + } + CHK_ERR_ASRT(err) + + // err = rsmi_dev_supported_variant_iterator_open(iter_handle, &var_iter); + // + } + err = rsmi_dev_supported_func_iterator_close(&iter_handle); + CHK_ERR_ASRT(err) + } +} diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.h b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.h new file mode 100755 index 0000000000..08a6f0bf56 --- /dev/null +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/api_support_read.h @@ -0,0 +1,73 @@ +/* + * ============================================================================= + * ROC Runtime Conformance Release License + * ============================================================================= + * The University of Illinois/NCSA + * Open Source License (NCSA) + * + * Copyright (c) 2019, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Developed by: + * + * AMD Research and AMD ROC Software Development + * + * Advanced Micro Devices, Inc. + * + * www.amd.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal with the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimers. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimers in + * the documentation and/or other materials provided with the distribution. + * - Neither the names of , + * nor the names of its contributors may be used to endorse or promote + * products derived from this Software without specific prior written + * permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS WITH THE SOFTWARE. + * + */ +#ifndef TESTS_ROCM_SMI_TEST_FUNCTIONAL_API_SUPPORT_READ_H_ +#define TESTS_ROCM_SMI_TEST_FUNCTIONAL_API_SUPPORT_READ_H_ + +#include "rocm_smi_test/test_base.h" + +class TestAPISupportRead : public TestBase { + public: + TestAPISupportRead(); + + // @Brief: Destructor for test case of TestAPISupportRead + virtual ~TestAPISupportRead(); + + // @Brief: Setup the environment for measurement + virtual void SetUp(); + + // @Brief: Core measurement execution + virtual void Run(); + + // @Brief: Clean up and retrive the resource + virtual void Close(); + + // @Brief: Display results + virtual void DisplayResults() const; + + // @Brief: Display information about what this test does + virtual void DisplayTestInfo(void); +}; + +#endif // TESTS_ROCM_SMI_TEST_FUNCTIONAL_API_SUPPORT_READ_H_ diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/id_info_read.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/id_info_read.cc index e7e7966204..14321fac11 100755 --- a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/id_info_read.cc +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/id_info_read.cc @@ -120,7 +120,7 @@ void TestIdInfoRead::Run(void) { } } err = rsmi_dev_brand_get(i, buffer, kBufferLen); - if(err != RSMI_STATUS_SUCCESS) { + if (err != RSMI_STATUS_SUCCESS) { CHK_ERR_ASRT(err) } else { IF_VERB(STANDARD) { diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/perf_cntr_read_write.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/perf_cntr_read_write.cc index 00f547fdb0..b9fde50d53 100755 --- a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/perf_cntr_read_write.cc +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/perf_cntr_read_write.cc @@ -118,8 +118,8 @@ TestPerfCntrReadWrite::testEventsIndividually(uint32_t dv_ind) { std::cout << "****************************" << std::endl; for (PerfCntrEvtGrp grp : s_event_groups) { - if (rsmi_dev_counter_group_supported(dv_ind, grp.group()) - == RSMI_STATUS_NOT_SUPPORTED) { + ret = rsmi_dev_counter_group_supported(dv_ind, grp.group()); + if (ret == RSMI_STATUS_NOT_SUPPORTED) { continue; } @@ -202,12 +202,14 @@ TestPerfCntrReadWrite::testEventsSimultaneously(uint32_t dv_ind) { std::cout << "****************************" << std::endl; for (PerfCntrEvtGrp grp : s_event_groups) { - if (rsmi_dev_counter_group_supported(dv_ind, grp.group()) - == RSMI_STATUS_NOT_SUPPORTED) { - std::cout << "\tEvent Group" << grp.name() << + + ret = rsmi_dev_counter_group_supported(dv_ind, grp.group()); + if (ret == RSMI_STATUS_NOT_SUPPORTED) { + std::cout << "\tEvent Group " << grp.name() << " is not supported. Skipping." << std::endl; continue; } + IF_VERB(STANDARD) { std::cout << "Testing Event Group " << grp.name() << std::endl; } diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/process_info_read.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/process_info_read.cc index 382e1bac8b..6010f6a910 100755 --- a/projects/rocm-smi-lib/tests/rocm_smi_test/functional/process_info_read.cc +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/functional/process_info_read.cc @@ -100,7 +100,7 @@ void TestProcInfoRead::Run(void) { err = rsmi_compute_process_info_get(nullptr, &num_proc_found); if (err != RSMI_STATUS_SUCCESS) { - if (err == RSMI_STATUS_FILE_ERROR) { + if (err == RSMI_STATUS_NOT_SUPPORTED) { IF_VERB(STANDARD) { std::cout << "\t**Process info. read: Not supported on this machine" << std::endl; diff --git a/projects/rocm-smi-lib/tests/rocm_smi_test/main.cc b/projects/rocm-smi-lib/tests/rocm_smi_test/main.cc index 5a3290692f..149a4ed738 100755 --- a/projects/rocm-smi-lib/tests/rocm_smi_test/main.cc +++ b/projects/rocm-smi-lib/tests/rocm_smi_test/main.cc @@ -76,6 +76,7 @@ #include "functional/process_info_read.h" #include "functional/xgmi_read_write.h" #include "functional/mem_page_info_read.h" +#include "functional/api_support_read.h" static RSMITstGlobals *sRSMIGlvalues = nullptr; @@ -218,6 +219,10 @@ TEST(rsmitstReadOnly, TestMemPageInfoRead) { TestMemPageInfoRead tst; RunGenericTest(&tst); } +TEST(rsmitstReadOnly, TestAPISupportRead) { + TestAPISupportRead tst; + RunGenericTest(&tst); +} int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv);