diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c20043bf2..60225229de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,36 @@ Full documentation for amd_smi_lib is available at [https://rocm.docs.amd.com/pr ### Added +- **Added enumeration mapping `amdsmi_get_gpu_enumeration_info()` to Python & C APIs.** + - Enumeration mapping consists of `amdsmi_enumeration_info_t` + + ```shell + typedef struct { + uint32_t drm_render; // the render node under /sys/class/drm/renderD* + uint32_t drm_card; // the graphic card device under /sys/class/drm/card* + uint32_t hsa_id; // the HSA enumeration ID + uint32_t hip_id; // the HIP enumeration ID + char hip_uuid[AMDSMI_MAX_STRING_LENGTH]; // the HIP unique identifer + } amdsmi_enumeration_info_t; + ``` + + - The mapping is also enabled in the CLI interface via `amd-smi list -e` + + ```shell + $ amd-smi list -e + GPU: 0 + BDF: 0000:23:00.0 + UUID: XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + KFD_ID: 45412 + NODE_ID: 1 + PARTITION_ID: 0 + RENDER: renderD128 + CARD: card0 + HSA_ID: 1 + HIP_ID: 0 + HIP_UUID: GPU-XXXXXXXXXXXXXXXX + ``` + - **Added dynamic virtualization mode detection**. - Added new C and Python API `amdsmi_get_gpu_virtualization_mode_info` - Added new C and Python enum `amdsmi_virtualization_mode_t` diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 4ec06309e2..627eb76889 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -175,7 +175,6 @@ class AMDSMICommands(): elif self.logger.is_json_format() or self.logger.is_csv_format(): self.logger.print_output() - def list(self, args, multiple_devices=False, gpu=None): """List information for target gpu @@ -214,12 +213,20 @@ class AMDSMICommands(): bdf = amdsmi_interface.amdsmi_get_gpu_device_bdf(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: bdf = e.get_error_info() - try: uuid = amdsmi_interface.amdsmi_get_gpu_device_uuid(args.gpu) except amdsmi_exception.AmdSmiLibraryException as e: uuid = e.get_error_info() + try: + enumeration_info = amdsmi_interface.amdsmi_get_gpu_enumeration_info(args.gpu) + except: + enumeration_info = {"drm_render": "N/A", + "drm_card": "N/A", + "hip_id": "N/A", + "hip_uuid": "N/A", + "hsa_id": "N/A"} + try: kfd_info = amdsmi_interface.amdsmi_get_gpu_kfd_info(args.gpu) kfd_id = kfd_info['kfd_id'] @@ -233,15 +240,26 @@ class AMDSMICommands(): if self.logger.is_csv_format(): self.logger.store_output(args.gpu, 'gpu_bdf', bdf) self.logger.store_output(args.gpu, 'gpu_uuid', uuid) - self.logger.store_output(args.gpu, 'kfd_id', kfd_id) - self.logger.store_output(args.gpu, 'node_id', node_id) - self.logger.store_output(args.gpu, 'partition_id', partition_id) else: self.logger.store_output(args.gpu, 'bdf', bdf) self.logger.store_output(args.gpu, 'uuid', uuid) - self.logger.store_output(args.gpu, 'kfd_id', kfd_id) - self.logger.store_output(args.gpu, 'node_id', node_id) - self.logger.store_output(args.gpu, 'partition_id', partition_id) + + self.logger.store_output(args.gpu, 'kfd_id', kfd_id) + self.logger.store_output(args.gpu, 'node_id', node_id) + self.logger.store_output(args.gpu, 'partition_id', partition_id) + + if args.e: + if enumeration_info['drm_render'] == "N/A": + self.logger.store_output(args.gpu, 'render', enumeration_info['drm_render']) + else: + self.logger.store_output(args.gpu, 'render', f"renderD{enumeration_info['drm_render']}") + if enumeration_info['drm_card'] == "N/A": + self.logger.store_output(args.gpu, 'card', enumeration_info['drm_card']) + else: + self.logger.store_output(args.gpu, 'card', f"card{enumeration_info['drm_card']}") + self.logger.store_output(args.gpu, 'hsa_id', enumeration_info['hsa_id']) + self.logger.store_output(args.gpu, 'hip_id', enumeration_info['hip_id']) + self.logger.store_output(args.gpu, 'hip_uuid', enumeration_info['hip_uuid']) if multiple_devices: self.logger.store_multiple_device_output() diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index 964e4bcc23..0e5ac166ad 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -626,6 +626,8 @@ class AMDSMIParser(argparse.ArgumentParser): # Create list subparser list_parser = subparsers.add_parser('list', help=list_help, description=list_subcommand_help) + # Create -e subparser + list_parser.add_argument("-e", action="store_true", help="Enumeration mapping to other features.\n Lists the BDF, UUID, KFD_ID, CARD, RENDER, HIP_ID, HIP_UUID and HSA_ID for each GPU.") list_parser.formatter_class=lambda prog: AMDSMISubparserHelpFormatter(prog) list_parser.set_defaults(func=func) diff --git a/docs/reference/amdsmi-py-api.md b/docs/reference/amdsmi-py-api.md index 5d2a449e7c..71dd620832 100644 --- a/docs/reference/amdsmi-py-api.md +++ b/docs/reference/amdsmi-py-api.md @@ -274,6 +274,46 @@ except AmdSmiException as e: print(e) ``` +### amdsmi_get_gpu_enumeration_info + +Description: Returns enumeration information for the given GPU + +Input parameters: + +* `processor_handle` device which to query + +Output: Dictionary with fields + +Field | Content +---|--- +`drm_render` | DRM render ID +`drm_card` | DRM card ID +`hsa_id` | HSA ID +`hip_id` | HIP ID +`hip_uuid` | HIP UUID + +Exceptions that can be thrown by `amdsmi_get_gpu_enumeration_info` function: + +* `AmdSmiLibraryException` +* `AmdSmiRetryException` +* `AmdSmiParameterException` + +Example: + +```python +try: + devices = amdsmi_get_processor_handles() + for device in devices: + info = amdsmi_get_gpu_enumeration_info(device) + print("DRM Render ID:", info['drm_render']) + print("DRM Card ID:", info['drm_card']) + print("HSA ID:", info['hsa_id']) + print("HIP ID:", info['hip_id']) + print("HIP UUID:", info['hip_uuid']) +except AmdSmiException as e: + print(e) +``` + ### amdsmi_get_gpu_driver_info Description: Returns the info of the driver diff --git a/include/amd_smi/amdsmi.h b/include/amd_smi/amdsmi.h index a6765dd3e2..291baf834f 100644 --- a/include/amd_smi/amdsmi.h +++ b/include/amd_smi/amdsmi.h @@ -174,7 +174,7 @@ typedef enum { * * Refer to amd.com documentation for more detail: * https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/white-papers/amd-cdna-3-white-paper.pdf - * + * * @cond @tag{gpu_bm_linux} @tag{host} @tag{guest_windows} @endcond */ #define AMDSMI_MAX_NUM_XCP 8 @@ -680,6 +680,19 @@ typedef union { uint64_t as_uint; } amdsmi_bdf_t; +/** + * @brief Structure holds enumeration information + * + * @cond @tag{gpu_bm_linux} @tag{host} @endcond + */ +typedef struct { + uint32_t drm_render; // the render node under /sys/class/drm/renderD* + uint32_t drm_card; // the graphic card device under /sys/class/drm/card* + uint32_t hsa_id; // the HSA enumeration ID + uint32_t hip_id; // the HIP enumeration ID + char hip_uuid[AMDSMI_MAX_STRING_LENGTH]; // the HIP unique identifer +} amdsmi_enumeration_info_t; + /** * @brief Card Form Factor * @@ -813,6 +826,7 @@ typedef struct { uint32_t reserved[22]; } amdsmi_asic_info_t; + /** * @brief Structure holds kfd information * @@ -2448,6 +2462,7 @@ amdsmi_status_t amdsmi_get_processor_handles(amdsmi_socket_handle socket_handle, uint32_t *processor_count, amdsmi_processor_handle* processor_handles); + #ifdef ENABLE_ESMI_LIB /** * @brief Get the list of the cpu core handles in a system. @@ -2541,13 +2556,13 @@ amdsmi_get_gpu_device_bdf(amdsmi_processor_handle processor_handle, amdsmi_bdf_t * * @ingroup tagProcDiscovery * - * @platform{gpu_bm_linux} @platform{host} @platform{guest_1vf} @platform{guest_mvf} + * @platform{gpu_bm_linux} @platform{host} @platform{guest_1vf} @platform{guest_mvf} * @platform{guest_windows} * * @param[in] processor_handle Device which to query * * @param[in,out] uuid_length Length of the uuid string. As input, must be - * equal or greater than SMI_GPU_UUID_SIZE and be allocated by + * equal or greater than AMDSMI_GPU_UUID_SIZE and be allocated by * user. As output it is the length of the uuid string. * * @param[out] uuid Pointer to string to store the UUID. Must be @@ -2558,6 +2573,28 @@ amdsmi_get_gpu_device_bdf(amdsmi_processor_handle processor_handle, amdsmi_bdf_t amdsmi_status_t amdsmi_get_gpu_device_uuid(amdsmi_processor_handle processor_handle, unsigned int *uuid_length, char *uuid); +/** + * @brief Returns the Enumeration information for the device + * + * @ingroup tagProcDiscovery + * + * @platform{gpu_bm_linux} @platform{host} @platform{guest_1vf} @platform{guest_mvf} + * @platform{guest_windows} + * + * @details This function returns Enumeration information of the corresponding + * processor_handle. It will return the render number, card number, + * HSA ID, HIP ID, and the HIP UUID. + * + * @param[in] processor_handle Device which to query + * + * @param[out] info Reference to Enumeration information structure. + * Must be allocated by user. + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail + */ +amdsmi_status_t +amdsmi_get_gpu_enumeration_info(amdsmi_processor_handle processor_handle, amdsmi_enumeration_info_t *info); + /** @} End tagProcDiscovery */ /*****************************************************************************/ @@ -2746,7 +2783,7 @@ amdsmi_get_gpu_subsystem_name(amdsmi_processor_handle processor_handle, char *na * @brief Returns the virtualization mode for the target device. * * @ingroup tagIdentQuery - * + * * @platform{gpu_bm_linux} @platform{host} * * @details The virtualization mode is detected and returned as an enum. @@ -3194,7 +3231,7 @@ amdsmi_get_gpu_memory_total(amdsmi_processor_handle processor_handle, amdsmi_mem /** * @brief Get the current memory usage - * + * * @ingroup tagMemoryQuery * * @platform{gpu_bm_linux} @@ -3279,7 +3316,7 @@ amdsmi_get_gpu_bad_page_threshold(amdsmi_processor_handle processor_handle, uint * * @details This call will verify the device @p processor_handle for the * checksum of RAS EEPROM. - * + * * @param[in] processor_handle a processor handle * * @note This function requires root access @@ -5718,6 +5755,7 @@ amdsmi_get_gpu_driver_info(amdsmi_processor_handle processor_handle, amdsmi_driv amdsmi_status_t amdsmi_get_gpu_asic_info(amdsmi_processor_handle processor_handle, amdsmi_asic_info_t *info); + /** * @brief Returns the KFD (Kernel Fusion Driver) information for the device * diff --git a/include/amd_smi/impl/amd_smi_gpu_device.h b/include/amd_smi/impl/amd_smi_gpu_device.h index 8d3c9907d2..568ca60f22 100644 --- a/include/amd_smi/impl/amd_smi_gpu_device.h +++ b/include/amd_smi/impl/amd_smi_gpu_device.h @@ -80,6 +80,11 @@ class AMDSmiGPUDevice: public AMDSmiProcessor { amdsmi_status_t amdgpu_query_driver_name(std::string& name) const; amdsmi_status_t amdgpu_query_driver_date(std::string& date) const; +// New methods for -e feature + std::string bdf_to_string() const; + uint32_t get_card_from_bdf() const; + uint32_t get_render_id() const; + private: uint32_t gpu_id_; uint32_t fd_; diff --git a/py-interface/__init__.py b/py-interface/__init__.py index b1cb885070..e1c89f942f 100644 --- a/py-interface/__init__.py +++ b/py-interface/__init__.py @@ -80,9 +80,10 @@ try: except AttributeError: pass +from .amdsmi_interface import amdsmi_get_processor_handle_from_bdf from .amdsmi_interface import amdsmi_get_gpu_device_bdf from .amdsmi_interface import amdsmi_get_gpu_device_uuid -from .amdsmi_interface import amdsmi_get_processor_handle_from_bdf +from .amdsmi_interface import amdsmi_get_gpu_enumeration_info # # SW Version Information from .amdsmi_interface import amdsmi_get_gpu_driver_info diff --git a/py-interface/amdsmi_interface.py b/py-interface/amdsmi_interface.py index 984d1db939..a6e026eb82 100644 --- a/py-interface/amdsmi_interface.py +++ b/py-interface/amdsmi_interface.py @@ -1690,6 +1690,65 @@ def amdsmi_get_gpu_device_bdf(processor_handle: amdsmi_wrapper.amdsmi_processor_ return _format_bdf(bdf_info) +def amdsmi_get_gpu_device_uuid(processor_handle: amdsmi_wrapper.amdsmi_processor_handle) -> str: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException( + processor_handle, amdsmi_wrapper.amdsmi_processor_handle + ) + + uuid = ctypes.create_string_buffer(AMDSMI_GPU_UUID_SIZE) + + uuid_length = ctypes.c_uint32() + uuid_length.value = AMDSMI_GPU_UUID_SIZE + + _check_res( + amdsmi_wrapper.amdsmi_get_gpu_device_uuid( + processor_handle, ctypes.byref(uuid_length), uuid + ) + ) + + return uuid.value.decode("utf-8") + + +def amdsmi_get_gpu_enumeration_info(processor_handle: amdsmi_wrapper.amdsmi_processor_handle) -> Dict[str, Any]: + """ + Retrieves GPU enumeration information including DRM card ID, DRM render ID, HIP ID, and HIP UUID. + + Parameters: + processor_handle (amdsmi_processor_handle): The processor handle. + + Returns: + Dict[str, Any]: A dictionary containing the retrieved enumeration information. + + Raises: + AmdSmiParameterException: If the input parameters are invalid. + """ + # Validate the processor handle + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException( + processor_handle, amdsmi_wrapper.amdsmi_processor_handle + ) + + # Create an instance of the enumeration info struct + enumeration_info = amdsmi_wrapper.amdsmi_enumeration_info_t() + + # Call the C function to populate the struct + status = amdsmi_wrapper.amdsmi_get_gpu_enumeration_info(processor_handle, ctypes.byref(enumeration_info)) + + # Validate the status result + _check_res(status) + + # Convert the struct fields into a dictionary and return + enumeration_info = { + "drm_render": _validate_if_max_uint(enumeration_info.drm_render, MaxUIntegerTypes.UINT32_T), + "drm_card": _validate_if_max_uint(enumeration_info.drm_render, MaxUIntegerTypes.UINT32_T), + "hsa_id": _validate_if_max_uint(enumeration_info.hsa_id, MaxUIntegerTypes.UINT32_T), + "hip_id": _validate_if_max_uint(enumeration_info.hip_id, MaxUIntegerTypes.UINT32_T), + "hip_uuid": enumeration_info.hip_uuid.decode('utf-8') + } + + return enumeration_info + def amdsmi_get_gpu_asic_info( processor_handle: amdsmi_wrapper.amdsmi_processor_handle, ) -> Dict[str, Any]: @@ -2258,26 +2317,6 @@ def amdsmi_get_gpu_process_list( return result -def amdsmi_get_gpu_device_uuid(processor_handle: amdsmi_wrapper.amdsmi_processor_handle) -> str: - if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): - raise AmdSmiParameterException( - processor_handle, amdsmi_wrapper.amdsmi_processor_handle - ) - - uuid = ctypes.create_string_buffer(AMDSMI_GPU_UUID_SIZE) - - uuid_length = ctypes.c_uint32() - uuid_length.value = AMDSMI_GPU_UUID_SIZE - - _check_res( - amdsmi_wrapper.amdsmi_get_gpu_device_uuid( - processor_handle, ctypes.byref(uuid_length), uuid - ) - ) - - return uuid.value.decode("utf-8") - - def amdsmi_get_gpu_driver_info( processor_handle: amdsmi_wrapper.amdsmi_processor_handle, ) -> Dict[str, Any]: diff --git a/py-interface/amdsmi_wrapper.py b/py-interface/amdsmi_wrapper.py index a979d04e29..6b9d770c8d 100644 --- a/py-interface/amdsmi_wrapper.py +++ b/py-interface/amdsmi_wrapper.py @@ -827,6 +827,19 @@ union_amdsmi_bdf_t._fields_ = [ ] amdsmi_bdf_t = union_amdsmi_bdf_t +class struct_amdsmi_enumeration_info_t(Structure): + pass + +struct_amdsmi_enumeration_info_t._pack_ = 1 # source:False +struct_amdsmi_enumeration_info_t._fields_ = [ + ('drm_render', ctypes.c_uint32), + ('drm_card', ctypes.c_uint32), + ('hsa_id', ctypes.c_uint32), + ('hip_id', ctypes.c_uint32), + ('hip_uuid', ctypes.c_char * 256), +] + +amdsmi_enumeration_info_t = struct_amdsmi_enumeration_info_t # values for enumeration 'amdsmi_card_form_factor_t' amdsmi_card_form_factor_t__enumvalues = { @@ -843,21 +856,6 @@ amdsmi_card_form_factor_t = ctypes.c_uint32 # enum class struct_amdsmi_pcie_info_t(Structure): pass -class struct_pcie_static_(Structure): - pass - -struct_pcie_static_._pack_ = 1 # source:False -struct_pcie_static_._fields_ = [ - ('max_pcie_width', ctypes.c_uint16), - ('PADDING_0', ctypes.c_ubyte * 2), - ('max_pcie_speed', ctypes.c_uint32), - ('pcie_interface_version', ctypes.c_uint32), - ('slot_type', amdsmi_card_form_factor_t), - ('max_pcie_interface_version', ctypes.c_uint32), - ('PADDING_1', ctypes.c_ubyte * 4), - ('reserved', ctypes.c_uint64 * 9), -] - class struct_pcie_metric_(Structure): pass @@ -878,6 +876,21 @@ struct_pcie_metric_._fields_ = [ ('reserved', ctypes.c_uint64 * 12), ] +class struct_pcie_static_(Structure): + pass + +struct_pcie_static_._pack_ = 1 # source:False +struct_pcie_static_._fields_ = [ + ('max_pcie_width', ctypes.c_uint16), + ('PADDING_0', ctypes.c_ubyte * 2), + ('max_pcie_speed', ctypes.c_uint32), + ('pcie_interface_version', ctypes.c_uint32), + ('slot_type', amdsmi_card_form_factor_t), + ('max_pcie_interface_version', ctypes.c_uint32), + ('PADDING_1', ctypes.c_ubyte * 4), + ('reserved', ctypes.c_uint64 * 9), +] + struct_amdsmi_pcie_info_t._pack_ = 1 # source:False struct_amdsmi_pcie_info_t._fields_ = [ ('pcie_static', struct_pcie_static_), @@ -2243,6 +2256,9 @@ amdsmi_get_gpu_device_bdf.argtypes = [amdsmi_processor_handle, ctypes.POINTER(un amdsmi_get_gpu_device_uuid = _libraries['libamd_smi.so'].amdsmi_get_gpu_device_uuid amdsmi_get_gpu_device_uuid.restype = amdsmi_status_t amdsmi_get_gpu_device_uuid.argtypes = [amdsmi_processor_handle, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_char)] +amdsmi_get_gpu_enumeration_info = _libraries['libamd_smi.so'].amdsmi_get_gpu_enumeration_info +amdsmi_get_gpu_enumeration_info.restype = amdsmi_status_t +amdsmi_get_gpu_enumeration_info.argtypes = [amdsmi_processor_handle, ctypes.POINTER(struct_amdsmi_enumeration_info_t)] amdsmi_get_gpu_id = _libraries['libamd_smi.so'].amdsmi_get_gpu_id amdsmi_get_gpu_id.restype = amdsmi_status_t amdsmi_get_gpu_id.argtypes = [amdsmi_processor_handle, ctypes.POINTER(ctypes.c_uint16)] @@ -2957,9 +2973,9 @@ __all__ = \ 'amdsmi_dimm_thermal_t', 'amdsmi_dpm_level_t', 'amdsmi_dpm_policy_entry_t', 'amdsmi_dpm_policy_t', 'amdsmi_driver_info_t', 'amdsmi_engine_usage_t', - 'amdsmi_error_count_t', 'amdsmi_event_group_t', - 'amdsmi_event_handle_t', 'amdsmi_event_type_t', - 'amdsmi_evt_notification_data_t', + 'amdsmi_enumeration_info_t', 'amdsmi_error_count_t', + 'amdsmi_event_group_t', 'amdsmi_event_handle_t', + 'amdsmi_event_type_t', 'amdsmi_evt_notification_data_t', 'amdsmi_evt_notification_type_t', 'amdsmi_first_online_core_on_cpu_socket', 'amdsmi_free_name_value_pairs', 'amdsmi_freq_ind_t', @@ -3005,6 +3021,7 @@ __all__ = \ 'amdsmi_get_gpu_device_bdf', 'amdsmi_get_gpu_device_uuid', 'amdsmi_get_gpu_driver_info', 'amdsmi_get_gpu_ecc_count', 'amdsmi_get_gpu_ecc_enabled', 'amdsmi_get_gpu_ecc_status', + 'amdsmi_get_gpu_enumeration_info', 'amdsmi_get_gpu_event_notification', 'amdsmi_get_gpu_fan_rpms', 'amdsmi_get_gpu_fan_speed', 'amdsmi_get_gpu_fan_speed_max', 'amdsmi_get_gpu_id', 'amdsmi_get_gpu_kfd_info', @@ -3123,7 +3140,7 @@ __all__ = \ 'struct_amdsmi_dimm_thermal_t', 'struct_amdsmi_dpm_level_t', 'struct_amdsmi_dpm_policy_entry_t', 'struct_amdsmi_dpm_policy_t', 'struct_amdsmi_driver_info_t', 'struct_amdsmi_engine_usage_t', - 'struct_amdsmi_error_count_t', + 'struct_amdsmi_enumeration_info_t', 'struct_amdsmi_error_count_t', 'struct_amdsmi_evt_notification_data_t', 'struct_amdsmi_freq_volt_region_t', 'struct_amdsmi_frequencies_t', 'struct_amdsmi_frequency_range_t', 'struct_amdsmi_fw_info_t', diff --git a/src/amd_smi/amd_smi.cc b/src/amd_smi/amd_smi.cc index a334f1e3d8..767fd257dd 100644 --- a/src/amd_smi/amd_smi.cc +++ b/src/amd_smi/amd_smi.cc @@ -54,6 +54,7 @@ #include "rocm_smi/rocm_smi_logger.h" #include "rocm_smi/rocm_smi_utils.h" #include "rocm_smi/rocm_smi.h" +#include "rocm_smi/rocm_smi_kfd.h" // a global instance of std::mutex to protect data passed during threads std::mutex myMutex; @@ -124,6 +125,7 @@ static amdsmi_status_t get_gpu_device_from_handle(amdsmi_processor_handle proces return AMDSMI_STATUS_NOT_SUPPORTED; } + template amdsmi_status_t rsmi_wrapper(F && f, amdsmi_processor_handle processor_handle, uint32_t increment_gpu_id = 0, Args &&... args) { @@ -510,8 +512,8 @@ amdsmi_status_t amdsmi_get_processor_handles_by_type(amdsmi_socket_handle socket return AMDSMI_STATUS_SUCCESS; } - #endif + amdsmi_status_t amdsmi_get_processor_type(amdsmi_processor_handle processor_handle , processor_type_t* processor_type) { @@ -549,7 +551,103 @@ amdsmi_get_gpu_device_bdf(amdsmi_processor_handle processor_handle, amdsmi_bdf_t return AMDSMI_STATUS_SUCCESS; } -amdsmi_status_t amdsmi_get_gpu_board_info(amdsmi_processor_handle processor_handle, amdsmi_board_info_t *board_info) { +amdsmi_status_t +amdsmi_get_gpu_device_uuid(amdsmi_processor_handle processor_handle, + unsigned int *uuid_length, + char *uuid) { + AMDSMI_CHECK_INIT(); + + if (uuid_length == nullptr || uuid == nullptr || uuid_length == nullptr || *uuid_length < AMDSMI_GPU_UUID_SIZE) { + return AMDSMI_STATUS_INVAL; + } + + amd::smi::AMDSmiGPUDevice* gpu_device = nullptr; + amdsmi_status_t r = get_gpu_device_from_handle(processor_handle, &gpu_device); + if (r != AMDSMI_STATUS_SUCCESS) + return r; + + amdsmi_status_t status = AMDSMI_STATUS_SUCCESS; + SMIGPUDEVICE_MUTEX(gpu_device->get_mutex()) + + amdsmi_asic_info_t asic_info = {}; + const uint8_t fcn = 0xff; + + status = amdsmi_get_gpu_asic_info(processor_handle, &asic_info); + if (status != AMDSMI_STATUS_SUCCESS) { + printf("Getting asic info failed. Return code: %d", status); + return status; + } + + /* generate random UUID */ + status = amdsmi_uuid_gen(uuid, + strtoull(asic_info.asic_serial, nullptr, 16), + (uint16_t)asic_info.device_id, fcn); + return status; +} + +amdsmi_status_t +amdsmi_get_gpu_enumeration_info(amdsmi_processor_handle processor_handle, + amdsmi_enumeration_info_t *info){ + + // Ensure library initialization + AMDSMI_CHECK_INIT(); + + if (info == nullptr) { + return AMDSMI_STATUS_INVAL; + } + + amdsmi_status_t status; + + // Retrieve GPU device from the processor handle + amd::smi::AMDSmiGPUDevice* gpu_device = nullptr; + status = get_gpu_device_from_handle(processor_handle, &gpu_device); + if (status != AMDSMI_STATUS_SUCCESS) { + return status; + } + + // Retrieve DRM Card ID + info->drm_card = gpu_device->get_card_from_bdf(); + + // Retrieve DRM Render ID + info->drm_render = gpu_device->get_render_id(); + + // Retrieve HIP ID (difference from the smallest node ID) and HSA ID + std::map> nodes; + if (amd::smi::DiscoverKFDNodes(&nodes) == 0) { + uint32_t smallest_node_id = std::numeric_limits::max(); + for (const auto& node_pair : nodes) { + uint32_t node_id = 0; + if (node_pair.second->get_node_id(&node_id) == 0) { + smallest_node_id = std::min(smallest_node_id, node_id); + } + } + + // Default to 0xffffffff as not supported + info->hsa_id = std::numeric_limits::max(); + info->hip_id = std::numeric_limits::max(); + amdsmi_kfd_info_t kfd_info; + status = amdsmi_get_gpu_kfd_info(processor_handle, &kfd_info); + if (status == AMDSMI_STATUS_SUCCESS) { + info->hsa_id = kfd_info.node_id; + info->hip_id = kfd_info.node_id - smallest_node_id; + } + } + + // Retrieve HIP UUID + std::string hip_uuid_str = "GPU-"; + amdsmi_asic_info_t asic_info = {}; + status = amdsmi_get_gpu_asic_info(processor_handle, &asic_info); + if (status == AMDSMI_STATUS_SUCCESS) { + hip_uuid_str += std::string(asic_info.asic_serial).substr(0, sizeof(info->hip_uuid) - hip_uuid_str.size() - 1); + std::strncpy(info->hip_uuid, hip_uuid_str.c_str(), sizeof(info->hip_uuid) - 1); + info->hip_uuid[sizeof(info->hip_uuid) - 1] = '\0'; // Ensure null termination + } + + return AMDSMI_STATUS_SUCCESS; +} + +amdsmi_status_t +amdsmi_get_gpu_board_info(amdsmi_processor_handle processor_handle, amdsmi_board_info_t *board_info) { AMDSMI_CHECK_INIT(); if (board_info == nullptr) { @@ -1277,6 +1375,7 @@ amdsmi_get_gpu_asic_info(amdsmi_processor_handle processor_handle, amdsmi_asic_i return AMDSMI_STATUS_SUCCESS; } + amdsmi_status_t amdsmi_get_gpu_xgmi_link_status(amdsmi_processor_handle processor_handle, amdsmi_xgmi_link_status_t *link_status) { @@ -3399,38 +3498,6 @@ amdsmi_status_t amdsmi_get_gpu_driver_info(amdsmi_processor_handle processor_han } -amdsmi_status_t -amdsmi_get_gpu_device_uuid(amdsmi_processor_handle processor_handle, unsigned int *uuid_length, char *uuid) { - AMDSMI_CHECK_INIT(); - - if (uuid_length == nullptr || uuid == nullptr || uuid_length == nullptr || *uuid_length < AMDSMI_GPU_UUID_SIZE) { - return AMDSMI_STATUS_INVAL; - } - - amd::smi::AMDSmiGPUDevice* gpu_device = nullptr; - amdsmi_status_t r = get_gpu_device_from_handle(processor_handle, &gpu_device); - if (r != AMDSMI_STATUS_SUCCESS) - return r; - - amdsmi_status_t status = AMDSMI_STATUS_SUCCESS; - SMIGPUDEVICE_MUTEX(gpu_device->get_mutex()) - - amdsmi_asic_info_t asic_info = {}; - const uint8_t fcn = 0xff; - - status = amdsmi_get_gpu_asic_info(processor_handle, &asic_info); - if (status != AMDSMI_STATUS_SUCCESS) { - printf("Getting asic info failed. Return code: %d", status); - return status; - } - - /* generate random UUID */ - status = amdsmi_uuid_gen(uuid, - strtoull(asic_info.asic_serial, nullptr, 16), - (uint16_t)asic_info.device_id, fcn); - return status; -} - amdsmi_status_t amdsmi_get_pcie_info(amdsmi_processor_handle processor_handle, amdsmi_pcie_info_t *info) { AMDSMI_CHECK_INIT(); diff --git a/src/amd_smi/amd_smi_gpu_device.cc b/src/amd_smi/amd_smi_gpu_device.cc index 5ba60a17d0..317cc50f66 100644 --- a/src/amd_smi/amd_smi_gpu_device.cc +++ b/src/amd_smi/amd_smi_gpu_device.cc @@ -30,6 +30,7 @@ #include #include #include +#include namespace amd { namespace smi { @@ -285,6 +286,77 @@ const GPUComputeProcessList_t& AMDSmiGPUDevice::amdgpu_get_compute_process_list( return compute_process_list_; } +// Convert `amdsmi_bdf_t` to a PCI BDF string +std::string AMDSmiGPUDevice::bdf_to_string() const { + std::ostringstream oss; + oss << std::setfill('0') << std::hex // Use hexadecimal formatting + << std::setw(4) << bdf_.domain_number << ":" // Domain (4 digits) + << std::setw(2) << static_cast(bdf_.bus_number) << ":" // Bus (2 digits) + << std::setw(2) << static_cast(bdf_.device_number) << "." // Device (2 digits) + << static_cast(bdf_.function_number); // Function (1 digit) + return oss.str(); +} + +uint32_t AMDSmiGPUDevice::get_card_from_bdf() const { + const std::string drm_path = "/sys/class/drm/"; + + // Iterate over the contents of /sys/class/drm/ + for (const auto& entry : std::filesystem::directory_iterator(drm_path)) { + const std::string device_name = entry.path().filename(); + + // Check if the entry starts with "card" + if (device_name.find("card") == 0) { + const std::string card_path = drm_path + device_name + "/device"; + + // Open the uevent file for the device + std::ifstream uevent_file(card_path + "/uevent"); + if (!uevent_file) { + continue; // Skip if the file is not found + } + + std::string line; + while (std::getline(uevent_file, line)) { + // Check for the PCI_SLOT_NAME and if it contains the BDF + if (line.rfind("PCI_SLOT_NAME", 0) == 0 && line.find(bdf_to_string()) != std::string::npos) { + return std::stoi(device_name.substr(4)); // Convert extracted number to int + } + } + } + } + + return std::numeric_limits::max(); // Return -1 if no matching card is found +} + +uint32_t AMDSmiGPUDevice::get_render_id() const { + const std::string drm_path = "/sys/class/drm/"; + + // Iterate over the contents of /sys/class/drm/ + for (const auto& entry : std::filesystem::directory_iterator(drm_path)) { + const std::string device_name = entry.path().filename(); + + // Check if the entry starts with "renderD" + if (device_name.find("renderD") == 0) { + const std::string render_path = drm_path + device_name + "/device"; + + // Open the uevent file for the device + std::ifstream uevent_file(render_path + "/uevent"); + if (!uevent_file) { + continue; // Skip if the file is not found + } + + std::string line; + while (std::getline(uevent_file, line)) { + // Check for the PCI_SLOT_NAME and if it contains the BDF + if (line.rfind("PCI_SLOT_NAME", 0) == 0 && line.find(bdf_to_string()) != std::string::npos) { + return std::stoi(device_name.substr(7)); // Extract only the number after "renderD" + } + } + } + } + + return std::numeric_limits::max(); // Return -1 if no matching render ID is found +} + } // namespace smi } // namespace amd