diff --git a/amdsmi_cli/amdsmi_commands.py b/amdsmi_cli/amdsmi_commands.py index 78b7435ac1..786fa1398c 100644 --- a/amdsmi_cli/amdsmi_commands.py +++ b/amdsmi_cli/amdsmi_commands.py @@ -163,19 +163,19 @@ class AMDSMICommands(): args.bus = bus if vbios: args.vbios = vbios - if driver: - args.driver = driver if numa: args.numa = numa + if board: + args.board = board + if driver: + args.driver = driver + if vram: + args.vram = vram if self.helpers.is_linux() and self.helpers.is_baremetal(): if ras: args.ras = ras if limit: args.limit = limit - if board: - args.board = board - if vram: - args.vram = vram # Handle No GPU passed if args.gpu == None: @@ -189,11 +189,11 @@ class AMDSMICommands(): # If all arguments are False, it means that no argument was passed and the entire static should be printed if self.helpers.is_linux() and self.helpers.is_baremetal(): - if not any([args.asic, args.bus, args.vbios, args.limit, args.driver, args.ras, args.board, args.numa, args.vram]): - args.asic = args.bus = args.vbios = args.limit = args.driver = args.ras = args.board = args.numa = args.vram = self.all_arguments = True + if not any([args.asic, args.bus, args.vbios, args.limit, args.board, args.ras, args.driver, args.numa, args.vram]): + args.asic = args.bus = args.vbios = args.limit = args.board = args.ras = args.driver = args.numa = args.vram = self.all_arguments = True if self.helpers.is_linux() and self.helpers.is_virtual_os(): - if not any([args.asic, args.bus, args.vbios, args.driver]): - args.asic = args.bus = args.vbios = args.driver = self.all_arguments = True + if not any([args.asic, args.bus, args.vbios, args.board, args.driver, args.vram]): + args.asic = args.bus = args.vbios = args.board = args.driver = args.vram = self.all_arguments = True static_dict = {} @@ -215,10 +215,17 @@ class AMDSMICommands(): static_dict['asic'] = "N/A" logging.debug("Failed to get asic info for gpu %s | %s", gpu_id, e.get_error_info()) if args.bus: - bus_output_info = {} + bus_info = {} try: - bus_info = amdsmi_interface.amdsmi_get_pcie_link_caps(args.gpu) + bus_info['bdf'] = amdsmi_interface.amdsmi_get_gpu_device_bdf(args.gpu) + except amdsmi_exception.AmdSmiLibraryException as e: + bus_info['bdf'] = "N/A" + logging.debug("Failed to get bdf for gpu %s | %s", gpu_id, e.get_error_info()) + + try: + link_caps = amdsmi_interface.amdsmi_get_pcie_link_caps(args.gpu) + bus_info.update(link_caps) if bus_info['max_pcie_speed'] % 1000 != 0: pcie_speed_GTs_value = round(bus_info['max_pcie_speed'] / 1000, 1) else: @@ -245,14 +252,7 @@ class AMDSMICommands(): bus_info = "N/A" logging.debug("Failed to get bus info for gpu %s | %s", gpu_id, e.get_error_info()) - try: - bus_output_info['bdf'] = amdsmi_interface.amdsmi_get_gpu_device_bdf(args.gpu) - except amdsmi_exception.AmdSmiLibraryException as e: - bus_output_info['bdf'] = "N/A" - logging.debug("Failed to get bdf for gpu %s | %s", gpu_id, e.get_error_info()) - - bus_output_info.update(bus_info) - static_dict['bus'] = bus_output_info + static_dict['bus'] = bus_info if args.vbios: try: vbios_info = amdsmi_interface.amdsmi_get_gpu_vbios_info(args.gpu) @@ -260,23 +260,23 @@ class AMDSMICommands(): except amdsmi_exception.AmdSmiLibraryException as e: static_dict['vbios'] = "N/A" logging.debug("Failed to get vbios info for gpu %s | %s", gpu_id, e.get_error_info()) + if args.board: + static_dict['board'] = {"model_number": "N/A", + "product_serial": "N/A", + "fru_id": "N/A", + "manufacturer_name": "N/A", + "product_name": "N/A"} + try: + board_info = amdsmi_interface.amdsmi_get_gpu_board_info(args.gpu) + for key, value in board_info.items(): + if isinstance(value, str): + if value.strip() == '': + board_info[key] = "N/A" + static_dict['board'] = board_info + except amdsmi_exception.AmdSmiLibraryException as e: + logging.debug("Failed to get board info for gpu %s | %s", gpu_id, e.get_error_info()) if self.helpers.is_linux() and self.helpers.is_baremetal(): - if args.board: - static_dict['board'] = {"model_number": "N/A", - "product_serial": "N/A", - "fru_id": "N/A", - "manufacturer_name": "N/A", - "product_name": "N/A"} - try: - board_info = amdsmi_interface.amdsmi_get_gpu_board_info(args.gpu) - for key, value in board_info.items(): - if isinstance(value, str): - if value.strip() == '': - board_info[key] = "N/A" - static_dict['board'] = board_info - except amdsmi_exception.AmdSmiLibraryException as e: - logging.debug("Failed to get board info for gpu %s | %s", gpu_id, e.get_error_info()) if args.limit: # Power limits try: @@ -401,6 +401,39 @@ class AMDSMICommands(): logging.debug("Failed to get driver info for gpu %s | %s", gpu_id, e.get_error_info()) static_dict['driver'] = driver_info + if args.vram: + try: + vram_info = amdsmi_interface.amdsmi_get_gpu_vram_info(args.gpu) + + # Get vram type string + vram_type_enum = vram_info['vram_type'] + if vram_type_enum == amdsmi_interface.amdsmi_wrapper.VRAM_TYPE_GDDR6: + vram_type = "GDDR6" + else: + vram_type = amdsmi_interface.amdsmi_wrapper.amdsmi_vram_type_t__enumvalues[vram_type_enum] + # Remove amdsmi enum prefix + vram_type = vram_type.replace('VRAM_TYPE_', '').replace('_', '') + + # Get vram vendor string + vram_vendor_enum = vram_info['vram_vendor'] + vram_vendor = amdsmi_interface.amdsmi_wrapper.amdsmi_vram_vendor_type_t__enumvalues[vram_vendor_enum] + if "PLACEHOLDER" in vram_vendor: + vram_vendor = "N/A" + else: + # Remove amdsmi enum prefix + vram_vendor = vram_vendor.replace('AMDSMI_VRAM_VENDOR__', '') + + vram_info['vram_type'] = vram_type + vram_info['vram_vendor'] = vram_vendor + if self.logger.is_human_readable_format(): + vram_info['vram_size_mb'] = f"{vram_info['vram_size_mb']} MB" + + except amdsmi_exception.AmdSmiLibraryException as e: + vram_info = "N/A" + logging.debug("Failed to get vram info for gpu %s | %s", gpu_id, e.get_error_info()) + + static_dict['vram'] = vram_info + if self.helpers.is_hypervisor() or self.helpers.is_baremetal(): if args.ras: try: @@ -408,26 +441,6 @@ class AMDSMICommands(): except amdsmi_exception.AmdSmiLibraryException as e: static_dict['ras'] = "N/A" logging.debug("Failed to get ras block features for gpu %s | %s", gpu_id, e.get_error_info()) - if args.vram: - try: - vram_info = amdsmi_interface.amdsmi_get_gpu_vram_info(args.gpu) - vram_type_enum = vram_info['vram_type'] - vram_vendor_enum = vram_info['vram_vendor'] - vram_type = amdsmi_interface.amdsmi_wrapper.amdsmi_vram_type_t__enumvalues[vram_type_enum] - vram_vendor = amdsmi_interface.amdsmi_wrapper.amdsmi_vram_vendor_type_t__enumvalues[vram_vendor_enum] - - # Remove amdsmi enum prefix - vram_info['vram_type'] = vram_type.replace('VRAM_TYPE_', '').replace('_', '') - vram_info['vram_vendor'] = vram_vendor.replace('AMDSMI_VRAM_VENDOR__', '') - if self.logger.is_human_readable_format(): - vram_info['vram_size_mb'] = f"{vram_info['vram_size_mb']} MB" - - except amdsmi_exception.AmdSmiLibraryException as e: - vram_info = "N/A" - logging.debug("Failed to get vram info for gpu %s | %s", gpu_id, e.get_error_info()) - - static_dict['vram'] = vram_info - if self.helpers.is_linux() and self.helpers.is_baremetal(): if args.numa: try: @@ -602,19 +615,16 @@ class AMDSMICommands(): try: bad_page_info = amdsmi_interface.amdsmi_get_gpu_bad_page_info(args.gpu) - bad_page_error = False except amdsmi_exception.AmdSmiLibraryException as e: - bad_page_error = True - bad_page_err_output = "N/A" + bad_page_info = "N/A" logging.debug("Failed to get bad page info for gpu %s | %s", gpu_id, e.get_error_info()) - if bad_page_info == "No bad pages found.": + if bad_page_info == "N/A" or bad_page_info == "No bad pages found.": bad_page_error = True - bad_page_err_output = bad_page_info if args.retired: if bad_page_error: - bad_page_info_output = bad_page_err_output + values_dict['retired'] = bad_page_info else: bad_page_info_output = [] for bad_page in bad_page_info: @@ -623,17 +633,16 @@ class AMDSMICommands(): bad_page_info_entry["page_address"] = bad_page["page_address"] bad_page_info_entry["page_size"] = bad_page["page_size"] bad_page_info_entry["status"] = bad_page["status"].name - bad_page_info_output.append(bad_page_info_entry) # Remove brackets if there is only one value if len(bad_page_info_output) == 1: bad_page_info_output = bad_page_info_output[0] - values_dict['retired'] = bad_page_info_output + values_dict['retired'] = bad_page_info_output if args.pending: if bad_page_error: - bad_page_info_output = bad_page_err_output + values_dict['pending'] = bad_page_info else: bad_page_info_output = [] for bad_page in bad_page_info: @@ -642,17 +651,16 @@ class AMDSMICommands(): bad_page_info_entry["page_address"] = bad_page["page_address"] bad_page_info_entry["page_size"] = bad_page["page_size"] bad_page_info_entry["status"] = bad_page["status"].name - bad_page_info_output.append(bad_page_info_entry) # Remove brackets if there is only one value if len(bad_page_info_output) == 1: bad_page_info_output = bad_page_info_output[0] - values_dict['pending'] = bad_page_info_output + values_dict['pending'] = bad_page_info_output if args.un_res: if bad_page_error: - bad_page_info_output = bad_page_err_output + values_dict['un_res'] = bad_page_info else: bad_page_info_output = [] for bad_page in bad_page_info: @@ -661,13 +669,12 @@ class AMDSMICommands(): bad_page_info_entry["page_address"] = bad_page["page_address"] bad_page_info_entry["page_size"] = bad_page["page_size"] bad_page_info_entry["status"] = bad_page["status"].name - bad_page_info_output.append(bad_page_info_entry) # Remove brackets if there is only one value if len(bad_page_info_output) == 1: bad_page_info_output = bad_page_info_output[0] - values_dict['un_res'] = bad_page_info_output + values_dict['un_res'] = bad_page_info_output # Store values in logger.output self.logger.store_output(args.gpu, 'values', values_dict) @@ -877,59 +884,62 @@ class AMDSMICommands(): values_dict['power'] = power_dict if args.clock: - clocks = {"gfx" : {"cur_clk": "N/A", - "max_clk": "N/A", - "min_clk": "N/A", - "sleep_clk": "N/A", - "is_clk_locked": "N/A"}, - "mem" : {"cur_clk": "N/A", - "max_clk": "N/A", - "min_clk": "N/A", - "sleep_clk": "N/A"} - } + clocks = {} + clock_types = [amdsmi_interface.AmdSmiClkType.GFX, + amdsmi_interface.AmdSmiClkType.MEM, + amdsmi_interface.AmdSmiClkType.VCLK0, + amdsmi_interface.AmdSmiClkType.VCLK1] + for clock_type in clock_types: + clock_name = amdsmi_interface.amdsmi_wrapper.amdsmi_clk_type_t__enumvalues[clock_type].replace("CLK_TYPE_", "") + # Ensure that gfx is the clock_name instead of another macro + if clock_type == amdsmi_interface.AmdSmiClkType.GFX: + clock_name = "gfx" - try: - gfx_clock = amdsmi_interface.amdsmi_get_clock_info(args.gpu, amdsmi_interface.AmdSmiClkType.GFX) - if gfx_clock['sleep_clk'] == 0xFFFFFFFF: - gfx_clock['sleep_clk'] = "N/A" + # Store the clock_name for vclk0 + vlck0_clock_name = None + if clock_type == amdsmi_interface.AmdSmiClkType.VCLK0: + vlck0_clock_name = clock_name - if self.logger.is_human_readable_format(): - unit = 'MHz' - for key, value in gfx_clock.items(): - if isinstance(value, int): - gfx_clock[key] = f"{value} {unit}" + try: + clock_info = amdsmi_interface.amdsmi_get_clock_info(args.gpu, clock_type) + if clock_info['sleep_clk'] == 0xFFFFFFFF: + clock_info['sleep_clk'] = "N/A" - clocks['gfx']['cur_clk'] = gfx_clock['cur_clk'] - clocks['gfx']['max_clk'] = gfx_clock['max_clk'] - clocks['gfx']['min_clk'] = gfx_clock['min_clk'] - clocks['gfx']['sleep_clk'] = gfx_clock['sleep_clk'] - except amdsmi_exception.AmdSmiLibraryException as e: - logging.debug("Failed to get gfx clock info for gpu %s | %s", gpu_id, e.get_error_info()) + if self.logger.is_human_readable_format(): + unit = 'MHz' + for key, value in clock_info.items(): + if isinstance(value, int): + clock_info[key] = f"{value} {unit}" + + clocks[clock_name] = clock_info + except amdsmi_exception.AmdSmiLibraryException as e: + # Handle the case where VCLK1 is not enaled in sysfs on all GPUs + if clock_type == amdsmi_interface.AmdSmiClkType.VCLK1: + # Check if VCLK0 was retrieved successfully + if vlck0_clock_name in clocks: + # Since VCLK0 exists, do not error + logging.debug("VLCK0 exists, not adding %s clock info to output for gpu %s | %s", clock_name, gpu_id, e.get_error_info()) + continue + else: + # Handle all other failed to get clock info + clocks[clock_name] = {"cur_clk": "N/A", + "max_clk": "N/A", + "min_clk": "N/A", + "sleep_clk": "N/A"} + logging.debug("Failed to get %s clock info for gpu %s | %s", clock_name, gpu_id, e.get_error_info()) try: # is_clk_locked = amdsmi_interface.amdsmi_is_clk_locked(args.gpu, amdsmi_interface.AmdSmiClkType.GFX) is_clk_locked = "N/A" - clocks['gfx']['is_clk_locked'] = is_clk_locked except amdsmi_exception.AmdSmiLibraryException as e: + is_clk_locked = "N/A" logging.debug("Failed to get gfx clock lock status info for gpu %s | %s", gpu_id, e.get_error_info()) - try: - mem_clock = amdsmi_interface.amdsmi_get_clock_info(args.gpu, amdsmi_interface.AmdSmiClkType.MEM) - if mem_clock['sleep_clk'] == 0xFFFFFFFF: - mem_clock['sleep_clk'] = "N/A" - - if self.logger.is_human_readable_format(): - unit = 'MHz' - for key, value in mem_clock.items(): - if isinstance(value, int): - gfx_clock[key] = f"{value} {unit}" - - clocks['mem']['cur_clk'] = mem_clock['cur_clk'] - clocks['mem']['max_clk'] = mem_clock['max_clk'] - clocks['mem']['min_clk'] = mem_clock['min_clk'] - clocks['mem']['sleep_clk'] = mem_clock['sleep_clk'] - except amdsmi_exception.AmdSmiLibraryException as e: - logging.debug("Failed to get mem clock info for gpu %s | %s", gpu_id, e.get_error_info()) + if "gfx" in clocks: + if isinstance(clocks['gfx'], dict): + clocks['gfx']['is_clk_locked'] = is_clk_locked + else: + clocks['gfx'] = {"is_clk_locked": is_clk_locked} values_dict['clock'] = clocks if args.temperature: @@ -1009,12 +1019,16 @@ class AMDSMICommands(): values_dict['ecc_block'] = "N/A" logging.debug("Failed to get ecc block features for gpu %s | %s", gpu_id, e.get_error_info()) if args.pcie: - pcie_dict = {'current_lanes': "N/A", - 'current_speed': "N/A", - 'replay_count' : "N/A", - 'current_bandwith_sent': "N/A", - 'current_bandwith_received': "N/A", - 'max_packet_size': "N/A"} + pcie_dict = {"current_lanes": "N/A", + "current_speed": "N/A", + "replay_count" : "N/A", + "l0_to_recovery_count" : "N/A", + "replay_roll_over_count" : "N/A", + "nak_sent_count" : "N/A", + "nak_received_count" : "N/A", + "current_bandwith_sent": "N/A", + "current_bandwith_received": "N/A", + "max_packet_size": "N/A"} try: pcie_link_status = amdsmi_interface.amdsmi_get_pcie_link_status(args.gpu) @@ -1039,6 +1053,33 @@ class AMDSMICommands(): except amdsmi_exception.AmdSmiLibraryException as e: logging.debug("Failed to get pci replay counter for gpu %s | %s", gpu_id, e.get_error_info()) + try: + # l0_to_recovery_counter = amdsmi_interface.amdsmi_get_gpu_pci_l0_to_recovery_counter(args.gpu) + # pcie_dict['l0_to_recovery_count'] = l0_to_recovery_counter + pcie_dict['l0_to_recovery_count'] = "N/A" + except amdsmi_exception.AmdSmiLibraryException as e: + pcie_dict['l0_to_recovery_count'] = "N/A" + logging.debug("Failed to get pcie l0 to recovery counter for gpu %s | %s", gpu_id, e.get_error_info()) + + try: + # pci_replay_rollover_counter = amdsmi_interface.amdsmi_get_gpu_pci_replay_rollover_counter(args.gpu) + # pcie_dict['replay_roll_over_count'] = pci_replay_rollover_counter + pcie_dict['replay_roll_over_count'] = "N/A" + except amdsmi_exception.AmdSmiLibraryException as e: + pcie_dict['replay_roll_over_count'] = "N/A" + logging.debug("Failed to get pcie replay rollover counter for gpu %s | %s", gpu_id, e.get_error_info()) + + try: + # nak_info = amdsmi_interface.amdsmi_get_gpu_pci_nak_info(args.gpu) + # pcie_dict['nak_sent_count'] = nak_info['nak_sent_count'] + # pcie_dict['nak_received_count'] = nak_info['nak_received_count'] + pcie_dict['nak_sent_count'] = "N/A" + pcie_dict['nak_received_count'] = "N/A" + except amdsmi_exception.AmdSmiLibraryException as e: + pcie_dict['nak_sent_count'] = "N/A" + pcie_dict['nak_received_count'] = "N/A" + logging.debug("Failed to get pcie nak info for gpu %s | %s", gpu_id, e.get_error_info()) + try: pcie_bw = amdsmi_interface.amdsmi_get_gpu_pci_throughput(args.gpu) sent = pcie_bw['sent'] * pcie_bw['max_pkt_sz'] @@ -1601,7 +1642,7 @@ class AMDSMICommands(): link_type = amdsmi_interface.amdsmi_topo_get_link_type(src_gpu, dest_gpu)['type'] if isinstance(link_type, int): if link_type != 2: - non_xgmi = True + # non_xgmi = True src_gpu_link_type[dest_gpu_key] = "N/A" continue except amdsmi_exception.AmdSmiLibraryException as e: diff --git a/amdsmi_cli/amdsmi_parser.py b/amdsmi_cli/amdsmi_parser.py index af95a8641f..ab54554dae 100644 --- a/amdsmi_cli/amdsmi_parser.py +++ b/amdsmi_cli/amdsmi_parser.py @@ -320,13 +320,13 @@ class AMDSMIParser(argparse.ArgumentParser): static_parser.add_argument('-b', '--bus', action='store_true', required=False, help=bus_help) static_parser.add_argument('-V', '--vbios', action='store_true', required=False, help=vbios_help) static_parser.add_argument('-d', '--driver', action='store_true', required=False, help=driver_help) + static_parser.add_argument('-v', '--vram', action='store_true', required=False, help=vram_help) + static_parser.add_argument('-B', '--board', action='store_true', required=False, help=board_help) # Options to display on Hypervisors and Baremetal if self.helpers.is_hypervisor() or self.helpers.is_baremetal(): static_parser.add_argument('-r', '--ras', action='store_true', required=False, help=ras_help) - static_parser.add_argument('-v', '--vram', action='store_true', required=False, help=vram_help) if self.helpers.is_linux(): - static_parser.add_argument('-B', '--board', action='store_true', required=False, help=board_help) static_parser.add_argument('-l', '--limit', action='store_true', required=False, help=limit_help) static_parser.add_argument('-u', '--numa', action='store_true', required=False, help=numa_help) diff --git a/example/amd_smi_drm_example.cc b/example/amd_smi_drm_example.cc index 2ee0bb3127..7b6997404b 100644 --- a/example/amd_smi_drm_example.cc +++ b/example/amd_smi_drm_example.cc @@ -306,6 +306,17 @@ int main() { printf("\tVBios Version String: %s\n\n", vbios_info.version); + // Get Cache info + amdsmi_gpu_cache_info_t cache_info = {}; + ret = amdsmi_get_gpu_cache_info(processor_handles[j], &cache_info); + CHK_AMDSMI_RET(ret) + printf(" Output of amdsmi_get_gpu_cache_info:\n"); + for (unsigned int i = 0 ; i < cache_info.num_cache_types; i++) { + printf("\tCache Level: %d, Cache Size: %d KB\n", + cache_info.cache[i].cache_level, + cache_info.cache[i].cache_size_kb); + } + // Get power measure amdsmi_power_info_t power_measure = {}; ret = amdsmi_get_power_info(processor_handles[j], &power_measure); diff --git a/include/amd_smi/amdsmi.h b/include/amd_smi/amdsmi.h index ce70d58f30..13897a9f83 100644 --- a/include/amd_smi/amdsmi.h +++ b/include/amd_smi/amdsmi.h @@ -84,6 +84,7 @@ typedef enum { #define AMDSMI_MAX_DRIVER_VERSION_LENGTH 80 #define AMDSMI_PRODUCT_NAME_LENGTH 128 #define AMDSMI_MAX_CONTAINER_TYPE 2 +#define AMDSMI_MAX_CACHE_TYPES 10 #define AMDSMI_GPU_UUID_SIZE 38 @@ -415,6 +416,16 @@ typedef struct { uint32_t reserved[16]; } amdsmi_vbios_info_t; +typedef struct { + uint32_t num_cache_types; + struct { + uint32_t cache_size_kb; /* In KB */ + uint32_t cache_level; + uint32_t reserved[3]; + } cache[AMDSMI_MAX_CACHE_TYPES]; + uint32_t reserved[15]; +} amdsmi_gpu_cache_info_t; + typedef struct { uint8_t num_fw_info; struct fw_info_list_ { @@ -2158,6 +2169,19 @@ amdsmi_status_t amdsmi_get_temp_metric(amdsmi_processor_handle processor_handle amdsmi_temperature_type_t sensor_type, amdsmi_temperature_metric_t metric, int64_t *temperature); +/** + * @brief Returns gpu cache info. + * + * @param[in] processor_handle PF of a processor for which to query + * + * @param[out] info reference to the cache info struct. + * Must be allocated by user. + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail + */ +amdsmi_status_t amdsmi_get_gpu_cache_info( + amdsmi_processor_handle processor_handle, amdsmi_gpu_cache_info_t *info); + /** * @brief Get the voltage metric value for the specified metric, from the * specified voltage sensor on the specified device. It is not supported on diff --git a/rocm_smi/include/rocm_smi/rocm_smi.h b/rocm_smi/include/rocm_smi/rocm_smi.h index 31064f3cc9..c041eb24a5 100755 --- a/rocm_smi/include/rocm_smi/rocm_smi.h +++ b/rocm_smi/include/rocm_smi/rocm_smi.h @@ -845,6 +845,22 @@ typedef struct { /// \cond Ignore in docs. typedef rsmi_version_t rsmi_version; /// \endcond + +/** + * @brief This structure represents the cache size and level + */ +#define RSMI_MAX_CACHE_TYPES 10 +typedef struct { + uint32_t num_cache_types; + struct { + uint32_t cache_size_kb; /* In KB */ + uint32_t cache_level; + } cache[RSMI_MAX_CACHE_TYPES]; +} rsmi_gpu_cache_info_t; +/// \cond Ignore in docs. +typedef rsmi_gpu_cache_info_t rsmi_gpu_cache_info; +/// \endcond + /** * @brief This structure represents a range (e.g., frequencies or voltages). */ @@ -2035,6 +2051,22 @@ rsmi_status_t rsmi_dev_memory_total_get(uint32_t dv_ind, rsmi_memory_type_t mem_type, uint64_t *total); +/** + * @brief Get gpu cache info. + * + * @details Given a device index @p dv_ind, and a pointer to a cache + * info @p info, this function will write the cache size and level + * to the location pointed to by @p info. + * @param[in] dv_ind a device index + * + * @param[inout] info reference to the cache info struct. + * Must be allocated by user. + * + * @return ::rsmi_status_t | ::RSMI_STATUS_SUCCESS on success, non-zero on fail + */ +rsmi_status_t rsmi_dev_cache_info_get( + uint32_t dv_ind, rsmi_gpu_cache_info_t *info); + /** * @brief Get the current memory usage * diff --git a/rocm_smi/include/rocm_smi/rocm_smi_kfd.h b/rocm_smi/include/rocm_smi/rocm_smi_kfd.h index 90c7f6ff3b..7e11130bd4 100755 --- a/rocm_smi/include/rocm_smi/rocm_smi_kfd.h +++ b/rocm_smi/include/rocm_smi/rocm_smi_kfd.h @@ -84,6 +84,9 @@ class KFDNode { int get_total_memory(uint64_t* total); int get_used_memory(uint64_t* used); + // Get cache info from kfd + int get_cache_info(rsmi_gpu_cache_info_t *info); + private: uint32_t node_indx_; uint32_t amdgpu_dev_index_; diff --git a/rocm_smi/src/rocm_smi.cc b/rocm_smi/src/rocm_smi.cc index 10cca04b8d..1d9da410d1 100755 --- a/rocm_smi/src/rocm_smi.cc +++ b/rocm_smi/src/rocm_smi.cc @@ -3282,6 +3282,26 @@ rsmi_dev_memory_total_get(uint32_t dv_ind, rsmi_memory_type_t mem_type, return ret; CATCH } + + +rsmi_status_t rsmi_dev_cache_info_get( + uint32_t dv_ind, rsmi_gpu_cache_info_t *info) { + TRY + rsmi_status_t ret; + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << "| ======= start ======="; + LOG_TRACE(ss); + + if (info == nullptr) return RSMI_STATUS_INVALID_ARGS; + + GET_DEV_AND_KFDNODE_FROM_INDX + + if (kfd_node->get_cache_info(info) == 0) return RSMI_STATUS_SUCCESS; + + return RSMI_STATUS_NOT_SUPPORTED; + CATCH +} + rsmi_status_t rsmi_dev_memory_usage_get(uint32_t dv_ind, rsmi_memory_type_t mem_type, uint64_t *used) { diff --git a/rocm_smi/src/rocm_smi_kfd.cc b/rocm_smi/src/rocm_smi_kfd.cc index 7fe9004cc3..00c7404711 100755 --- a/rocm_smi/src/rocm_smi_kfd.cc +++ b/rocm_smi/src/rocm_smi_kfd.cc @@ -130,6 +130,25 @@ static std::string KFDDevicePath(uint32_t dev_id) { return node_path; } +// A generic function to extract out a property from file. +// return empty string if file or property not found +// Assume the property_name is at the beginning of the line. +static std::string get_properties_from_file(const std::string& file_name, + const std::string& property_name) { + std::ifstream infile(file_name); + if (!infile) return ""; + std::string line; + while (std::getline(infile, line)) { + std::istringstream iss(line); + // the property name is at the beginning of the line + if (line.rfind(property_name.c_str(), 0) == 0) { + return line.substr(property_name.length()); + } + } + return ""; +} + + static int OpenKFDNodeFile(uint32_t dev_id, std::string node_file, std::ifstream *fs) { std::string line; @@ -874,6 +893,51 @@ int KFDNode::get_used_memory(uint64_t* used) { return 1; } +int KFDNode::get_cache_info(rsmi_gpu_cache_info_t *info) { + if (info == nullptr) return EINVAL; + uint64_t caches_count = 0; + int ret = get_property_value("caches_count", &caches_count); + if (ret != 0) return ret; + + // /sys/class/kfd/kfd/topology/nodes/1/caches/0/properties + std::string f_path = kKFDNodesPathRoot; + f_path += "/"; + f_path += std::to_string(node_indx_); + f_path += "/"; + f_path += "caches/"; + + info->num_cache_types = 0; + for (unsigned int cache_id = 0; cache_id < caches_count; cache_id++) { + const auto prop_file = f_path + std::to_string(cache_id) + "/properties"; + std::string level = get_properties_from_file(prop_file, "level "); + try { + int cache_level = std::stoi(level); + if (cache_level < 0 ) continue; + + // only count once + bool is_count_already = false; + for (unsigned int i=0; i < info->num_cache_types; i++) { + if (info->cache->cache_level == static_cast(cache_level)) { + is_count_already = true; + break; + } + } + if (is_count_already) continue; + + if (info->num_cache_types >= RSMI_MAX_CACHE_TYPES) return 1; + std::string size = get_properties_from_file(prop_file, "size "); + int cache_size = std::stoi(size); + if (cache_size <= 0) continue; + info->cache[info->num_cache_types].cache_level = cache_level; + info->cache[info->num_cache_types].cache_size_kb = cache_size; + info->num_cache_types++; + } catch (...) { + continue; + } + } + return 0; +} + // /sys/class/kfd/kfd/topology/nodes/*/properties int read_node_properties(uint32_t node, std::string property_name, uint64_t *val) { diff --git a/src/amd_smi/amd_smi.cc b/src/amd_smi/amd_smi.cc index 7040860e06..b9e61efcd4 100644 --- a/src/amd_smi/amd_smi.cc +++ b/src/amd_smi/amd_smi.cc @@ -478,6 +478,33 @@ amdsmi_status_t amdsmi_get_gpu_board_info(amdsmi_processor_handle processor_hand return AMDSMI_STATUS_SUCCESS; } +amdsmi_status_t amdsmi_get_gpu_cache_info( + amdsmi_processor_handle processor_handle, amdsmi_gpu_cache_info_t *info) { + AMDSMI_CHECK_INIT(); + if (info == nullptr) { + return AMDSMI_STATUS_INVAL; + } + + amd::smi::AMDSmiGPUDevice* gpu_device = nullptr; + amdsmi_status_t status = get_gpu_device_from_handle( + processor_handle, &gpu_device); + if (status != AMDSMI_STATUS_SUCCESS) + return status; + + rsmi_gpu_cache_info_t rsmi_info; + status = rsmi_wrapper(rsmi_dev_cache_info_get, + processor_handle, &rsmi_info); + if (status != AMDSMI_STATUS_SUCCESS) + return status; + + info->num_cache_types = rsmi_info.num_cache_types; + for (unsigned int i =0; i < rsmi_info.num_cache_types; i++) { + info->cache[i].cache_size_kb = rsmi_info.cache[i].cache_size_kb; + info->cache[i].cache_level = rsmi_info.cache[i].cache_level; + } + return AMDSMI_STATUS_SUCCESS; +} + amdsmi_status_t amdsmi_get_temp_metric(amdsmi_processor_handle processor_handle, amdsmi_temperature_type_t sensor_type, amdsmi_temperature_metric_t metric, int64_t *temperature) { @@ -778,7 +805,9 @@ amdsmi_status_t amdsmi_get_gpu_vram_info( uint64_t total = 0; r = rsmi_wrapper(rsmi_dev_memory_total_get, processor_handle, RSMI_MEM_TYPE_VRAM, &total); - info->vram_size_mb = total / (1024 * 1024); + if (r == AMDSMI_STATUS_SUCCESS) { + info->vram_size_mb = total / (1024 * 1024); + } return AMDSMI_STATUS_SUCCESS; }