From 422253f871a9025469bc10c947e9077423a0402f Mon Sep 17 00:00:00 2001 From: Adam Pryor <61172547+adam360x@users.noreply.github.com> Date: Wed, 26 Nov 2025 08:33:27 -0600 Subject: [PATCH] Implement PTL support (#1957) * Implement PTL support Signed-off-by: adapryor (cherry picked from commit 45bc31292e7940a3b8fca044ef7df22047b95733) Signed-off-by: Maisam Arif --------- Signed-off-by: adapryor Signed-off-by: Maisam Arif Co-authored-by: Maisam Arif --- projects/amdsmi/CHANGELOG.md | 12 ++ projects/amdsmi/amdsmi_cli/amdsmi_commands.py | 94 ++++++++- projects/amdsmi/amdsmi_cli/amdsmi_helpers.py | 4 + projects/amdsmi/amdsmi_cli/amdsmi_parser.py | 58 ++++++ .../amdsmi/docs/how-to/amdsmi-cli-tool.md | 2 + projects/amdsmi/include/amd_smi/amdsmi.h | 147 +++++++++++-- .../include/amd_smi/impl/amd_smi_utils.h | 1 + projects/amdsmi/py-interface/__init__.py | 7 + .../amdsmi/py-interface/amdsmi_interface.py | 76 +++++++ .../amdsmi/py-interface/amdsmi_wrapper.py | 48 ++++- .../rocm_smi/include/rocm_smi/rocm_smi.h | 124 ++++++++++- .../include/rocm_smi/rocm_smi_device.h | 5 + projects/amdsmi/rocm_smi/src/rocm_smi.cc | 143 +++++++++++++ .../amdsmi/rocm_smi/src/rocm_smi_device.cc | 15 ++ projects/amdsmi/src/amd_smi/amd_smi.cc | 196 ++++++++++++++++++ projects/amdsmi/src/amd_smi/amd_smi_utils.cc | 19 ++ 16 files changed, 917 insertions(+), 34 deletions(-) diff --git a/projects/amdsmi/CHANGELOG.md b/projects/amdsmi/CHANGELOG.md index 05e2245830..3e2254638b 100644 --- a/projects/amdsmi/CHANGELOG.md +++ b/projects/amdsmi/CHANGELOG.md @@ -78,6 +78,18 @@ Full documentation for amd_smi_lib is available at [https://rocm.docs.amd.com/pr - amdsmi_set_power_cap() - See the Changed section for changes made to the `set` and `static` commands regarding support for PPT1. +- **Added PTL Support to `amd-smi static` and `amd-smi set`** + - `amd-smi set` now support --ptl-status 0|1 and --ptl-format FORMAT1,FORMAT2 + - `amd-smi static -l` shows current state and format of PTL + + ```console + $ amd-smi static -l + GPU: 0 + LIMIT: + PTL_STATE: Enabled + PTL_FORMAT: I8,F64 + ``` + ### Changed - **The `amd-smi` command now shows hsmp rather than amd_hsmp**. diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py index a5a0e1a45a..232c200b1d 100644 --- a/projects/amdsmi/amdsmi_cli/amdsmi_commands.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_commands.py @@ -721,6 +721,26 @@ class AMDSMICommands(): shutdown_temp_vram_limit = "N/A" logging.debug("Failed to get vram temperature shutdown metrics for gpu %s | %s", gpu_id, e.get_error_info()) + # PTL + try: + ptl_state = amdsmi_interface.amdsmi_get_gpu_ptl_state(args.gpu) + ptl_state = "Enabled" if ptl_state else "Disabled" + except amdsmi_exception.AmdSmiLibraryException as e: + ptl_state = "N/A" + logging.debug("Failed to get PTL state for gpu %s | %s", gpu_id, e.get_error_info()) + + try: + ptl_format1, ptl_format2 = amdsmi_interface.amdsmi_get_gpu_ptl_formats(args.gpu) + fmt1_name = amdsmi_interface.amdsmi_wrapper.amdsmi_ptl_data_format_t__enumvalues.get(ptl_format1) + fmt2_name = amdsmi_interface.amdsmi_wrapper.amdsmi_ptl_data_format_t__enumvalues.get(ptl_format2) + + fmt1_short = fmt1_name.replace("AMDSMI_PTL_DATA_FORMAT_", "") if fmt1_name else "UNKNOWN" + fmt2_short = fmt2_name.replace("AMDSMI_PTL_DATA_FORMAT_", "") if fmt2_name else "UNKNOWN" + + ptl_format = f"{fmt1_short},{fmt2_short}" + except amdsmi_exception.AmdSmiLibraryException as e: + ptl_format = "N/A" + logging.debug("Failed to get PTL state for gpu %s | %s", gpu_id, e.get_error_info()) # Assign units power_unit = 'W' @@ -773,6 +793,11 @@ class AMDSMICommands(): limit_info['shutdown_edge_temperature'] = shutdown_temp_edge_limit limit_info['shutdown_hotspot_temperature'] = shutdown_temp_hotspot_limit limit_info['shutdown_vram_temperature'] = shutdown_temp_vram_limit + + # PTL + limit_info['ptl_state'] = ptl_state + limit_info['ptl_format'] = ptl_format + static_dict['limit'] = limit_info if args.driver: driver_info_dict = {"name" : "N/A", @@ -4499,7 +4524,7 @@ class AMDSMICommands(): def set_gpu(self, args, multiple_devices=False, gpu=None, fan=None, perf_level=None, profile=None, perf_determinism=None, compute_partition=None, memory_partition=None, power_cap=None, soc_pstate=None, xgmi_plpd = None, - process_isolation=None, clk_limit=None, clk_level=None): + process_isolation=None, clk_limit=None, clk_level=None, ptl_status=None, ptl_format=None): """Issue reset commands to target gpu(s) Args: @@ -4516,6 +4541,8 @@ class AMDSMICommands(): soc_pstate (int, optional): Value override for args.soc_pstate. Defaults to None. xgmi_plpd (int, optional): Value override for args.xgmi_plpd. Defaults to None. process_isolation (int, optional): Value override for args.process_isolation. Defaults to None. + ptl_status (int, optional): Value override for args.ptl_status. Defaults to None. + ptl_format(string, optional): Value override for args.ptl_format. Defaults to None. Raises: ValueError: Value error if no gpu value is provided IndexError: Index error if gpu list is empty @@ -4550,6 +4577,10 @@ class AMDSMICommands(): args.clk_limit = clk_limit if clk_level: args.clk_level = clk_level + if ptl_status: + args.ptl_status = ptl_status + if ptl_format: + args.ptl_format = ptl_format # Handle No GPU passed if args.gpu == None: @@ -4579,6 +4610,8 @@ class AMDSMICommands(): args.xgmi_plpd is not None, args.clk_level is not None, args.clk_limit is not None, + args.ptl_status is not None, + args.ptl_format is not None, args.process_isolation is not None]): command = " ".join(sys.argv[1:]) raise AmdSmiRequiredCommandException(command, self.logger.format) @@ -4898,6 +4931,55 @@ class AMDSMICommands(): self.logger.print_output() self.logger.clear_multiple_devices_output() return + if isinstance(args.ptl_status, int): + status_string = "Enabled" if args.ptl_status else "Disabled" + result = f"Requested PTL status to {status_string}" # This should not print out + try: + current_state = amdsmi_interface.amdsmi_get_gpu_ptl_state(args.gpu) + if current_state == args.ptl_status: + result = f"PTL state is already {status_string}" + else: + amdsmi_interface.amdsmi_set_gpu_ptl_state(args.gpu, args.ptl_status) + result = f"Successfully set PTL state to {status_string}" + except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: + raise PermissionError('Command requires elevation') from e + self.logger.store_output(args.gpu, 'ptlstatus', f"[{e.get_error_info(detailed=False)}] Unable to set ptl status to {args.ptl_status}") + self.logger.print_output() + self.logger.clear_multiple_devices_output() + return + self.logger.store_output(args.gpu, 'ptlstatus', result) + self.logger.print_output() + self.logger.clear_multiple_devices_output() + return + if isinstance(args.ptl_format, tuple): + requested_fmt1_enum, requested_fmt2_enum = args.ptl_format + requested_str = f"{requested_fmt1_enum.name},{requested_fmt2_enum.name}" + + result = f"Requested PTL status to {requested_str}" # This should not print out + try: + # Get current formats as ints + cur1_code, cur2_code = amdsmi_interface.amdsmi_get_gpu_ptl_formats(args.gpu) + cur1_enum = amdsmi_interface.AmdSmiPtlData(cur1_code) + cur2_enum = amdsmi_interface.AmdSmiPtlData(cur2_code) + current_str = f"{cur1_enum.name},{cur2_enum.name}" + if (cur1_enum, cur2_enum) == (requested_fmt1_enum, requested_fmt2_enum): + result = f"PTL format is already {current_str}" + else: + amdsmi_interface.amdsmi_set_gpu_ptl_formats(args.gpu, requested_fmt1_enum, requested_fmt2_enum) + result = f"Successfully set PTL format to {requested_str}" + except amdsmi_exception.AmdSmiLibraryException as e: + if e.get_error_code() == amdsmi_interface.amdsmi_wrapper.AMDSMI_STATUS_NO_PERM: + raise PermissionError('Command requires elevation') from e + self.logger.store_output(args.gpu, 'ptlformat', f"[{e.get_error_info(detailed=False)}] Unable to set PTL format to {requested_str}") + self.logger.print_output() + self.logger.clear_multiple_devices_output() + return + self.logger.store_output(args.gpu, 'ptlformat', result) + self.logger.print_output() + self.logger.clear_multiple_devices_output() + return + # Universal args if isinstance(args.power_cap, tuple): pwr_type = args.power_cap.pwr_type @@ -5053,7 +5135,7 @@ class AMDSMICommands(): cpu_pwr_eff_mode=None, cpu_gmi3_link_width=None, cpu_pcie_link_rate=None, cpu_df_pstate_range=None, cpu_enable_apb=None, cpu_disable_apb=None, soc_boost_limit=None, core=None, core_boost_limit=None, soc_pstate=None, xgmi_plpd=None, - process_isolation=None, clk_limit=None, clk_level=None): + process_isolation=None, clk_limit=None, clk_level=None, ptl_status=None, ptl_format=None): """Issue reset commands to target gpu(s) Args: @@ -5105,7 +5187,7 @@ class AMDSMICommands(): gpu_args_enabled = False gpu_attributes = ["fan", "perf_level", "profile", "perf_determinism", "compute_partition", "memory_partition", "power_cap", "soc_pstate", "xgmi_plpd", - "process_isolation", "clk_limit", "clk_level"] + "process_isolation", "clk_limit", "clk_level", "ptl_status", "ptl_format"] for attr in gpu_attributes: if hasattr(args, attr): if getattr(args, attr) is not None: @@ -5150,6 +5232,8 @@ class AMDSMICommands(): args.xgmi_plpd is not None, args.clk_limit is not None, args.clk_level is not None, + args.ptl_status is not None, + args.ptl_format is not None, args.process_isolation is not None ]) except AttributeError: @@ -5232,7 +5316,7 @@ class AMDSMICommands(): self.set_gpu(args, multiple_devices, gpu, fan, perf_level, profile, perf_determinism, compute_partition, memory_partition, power_cap, soc_pstate, xgmi_plpd, - process_isolation, clk_limit, clk_level) + process_isolation, clk_limit, clk_level, ptl_status, ptl_format) elif self.helpers.is_amd_hsmp_initialized(): # Only CPU is initialized if args.cpu == None and args.core == None: raise ValueError('No CPU or CORE provided, specific target(s) are needed') @@ -5252,7 +5336,7 @@ class AMDSMICommands(): self.set_gpu(args, multiple_devices, gpu, fan, perf_level, profile, perf_determinism, compute_partition, memory_partition, power_cap, soc_pstate, xgmi_plpd, - process_isolation, clk_limit, clk_level) + process_isolation, clk_limit, clk_level, ptl_status, ptl_format) def reset(self, args, multiple_devices=False, gpu=None, gpureset=None, diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_helpers.py b/projects/amdsmi/amdsmi_cli/amdsmi_helpers.py index 17bfed3f9d..0933579ae2 100755 --- a/projects/amdsmi/amdsmi_cli/amdsmi_helpers.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_helpers.py @@ -781,6 +781,10 @@ class AMDSMIHelpers(): perf_levels_int = list(set(clock.value for clock in amdsmi_interface.AmdSmiDevPerfLevel)) return perf_levels_str, perf_levels_int + def get_ptl_values(self): + ptl_values_str = [ptl.name for ptl in amdsmi_interface.AmdSmiPtlData] + ptl_values_int = list(set(ptl.name for ptl in amdsmi_interface.AmdSmiPtlData)) + return ptl_values_str,ptl_values_int def get_accelerator_partition_profile_config(self): device_handles = amdsmi_interface.amdsmi_get_processor_handles() diff --git a/projects/amdsmi/amdsmi_cli/amdsmi_parser.py b/projects/amdsmi/amdsmi_cli/amdsmi_parser.py index c158412b22..bb61927276 100644 --- a/projects/amdsmi/amdsmi_cli/amdsmi_parser.py +++ b/projects/amdsmi/amdsmi_cli/amdsmi_parser.py @@ -649,6 +649,59 @@ class AMDSMIParser(argparse.ArgumentParser): raise argparse.ArgumentError(self, f"Invalid argument: '{values}' needs to be 0-20 or 0-20%") return _ValidateOverdrivePercent + def _validate_ptl_format(self): + """Validate and normalize --ptl-format FRMT1,FRMT2.""" + valid_names = [name for name in amdsmi_interface.AmdSmiPtlData.__members__ if name != 'INVALID'] + + class _ValidatePtlFormat(argparse.Action): + def __call__(self, parser, args, values, option_string=None): + if not isinstance(values, str): + raise argparse.ArgumentError( + self, + f"Invalid argument for {option_string}: '{values}' " + f"(expected string like I8,F32)" + ) + + parts = values.split(',') + if len(parts) != 2: + raise argparse.ArgumentError( + self, + f"{option_string} expects exactly two comma-separated formats, " + f"e.g. I8,F32 (got '{values}')" + ) + + enums = [] + for raw in parts: + token = raw.strip().upper() + if token == '': + raise argparse.ArgumentError( + self, + f"Empty PTL format in '{values}'. Expected formats like I8,F32." + ) + try: + enum_val = amdsmi_interface.AmdSmiPtlData[token] + except KeyError: + raise argparse.ArgumentError( + self, + f"Invalid PTL format '{raw}'. Valid formats are: " + + ", ".join(valid_names) + ) + if enum_val == amdsmi_interface.AmdSmiPtlData.INVALID: + raise argparse.ArgumentError( + self, + f"INVALID is not a usable PTL format." + ) + enums.append(enum_val) + + if enums[0] == enums[1]: + raise argparse.ArgumentError( + self, + f"PTL formats must be different (got '{values}')." + ) + + setattr(args, self.dest, (enums[0], enums[1])) + + return _ValidatePtlFormat ### Building parsers ### def _add_device_arguments(self, subcommand_parser: argparse.ArgumentParser, required=False): @@ -1263,6 +1316,9 @@ class AMDSMIParser(argparse.ArgumentParser): xgmi_plpd_help_info = ", ".join(self.helpers.get_xgmi_plpd_policies()) set_xgmi_plpd_help = f"Set the GPU XGMI per-link power down policy using policy id, an integer. Valid id's include:\n\t{xgmi_plpd_help_info}" set_clock_freq_help = "Set one or more sclk (aka gfxclk), mclk, fclk, pcie, or socclk frequency levels.\n\tUse `amd-smi static --clock` to find acceptable levels.\n\tUse `amd-smi static --bus` to find acceptable pcie levels." + set_ptl_status_help = "Enable or disable the PTL on a GPU processor:\n 0 for disable and 1 for enable." + ptl_format_help_choices_str = ", ".join(self.helpers.get_ptl_values()[0][0:-1]) + set_ptl_format_help = f"Set the PTL format on a GPU processor. For example, --ptl-format I8,F32\n\tSet to one of the following PTL formats: {ptl_format_help_choices_str}" ppt0_power_cap_min, ppt0_power_cap_max, ppt1_power_cap_min, ppt1_power_cap_max = self.helpers.get_power_caps() set_power_cap_help = f"Set either PPT0 or PPT1 power capacity limit:\n\tEx: `amd-smi set -o ppt0 1300`\n\tPPT0 min cap: {ppt0_power_cap_min}, PPT0 max cap: {ppt0_power_cap_max}\n\tPPT1 min cap: {ppt1_power_cap_min}, PPT1 max cap: {ppt1_power_cap_max}" set_clk_limit_help = "Sets the sclk (aka gfxclk) or mclk minimum and maximum frequencies. \n\tex: amd-smi set -L (sclk | mclk) (min | max) value" @@ -1308,6 +1364,8 @@ class AMDSMIParser(argparse.ArgumentParser): set_value_exclusive_group.add_argument('-p', '--soc-pstate', action='store', required=False, type=lambda value: self._not_negative_int(value, '--soc-pstate'), help=set_soc_pstate_help, metavar='POLICY_ID') set_value_exclusive_group.add_argument('-x', '--xgmi-plpd', action='store', required=False, type=lambda value: self._not_negative_int(value, '--xgmi-plpd'), help=set_xgmi_plpd_help, metavar='POLICY_ID') set_value_exclusive_group.add_argument('-c', '--clk-level', action=self._level_select(), nargs='+', required=False, help=set_clock_freq_help, metavar=('CLK_TYPE', 'PERF_LEVELS')) + set_value_exclusive_group.add_argument('-S', '--ptl-status', action='store', choices=[0,1], type=lambda value: self._not_negative_int(value, '--ptl-status'), required=False, help=set_ptl_status_help, metavar=('STATUS')) + set_value_exclusive_group.add_argument('-F', '--ptl-format', action=self._validate_ptl_format(), required=False, help=set_ptl_format_help, metavar=('FRMT1,FRMT2')) set_value_exclusive_group.add_argument('-L', '--clk-limit', action=self._limit_select(), nargs=3, required=False, help=set_clk_limit_help, metavar=('CLK_TYPE', 'LIM_TYPE', 'VALUE')) set_value_exclusive_group.add_argument('-R', '--process-isolation', action='store', choices=[0,1], type=lambda value: self._not_negative_int(value, '--process-isolation'), required=False, help=set_process_isolation_help, metavar='STATUS') diff --git a/projects/amdsmi/docs/how-to/amdsmi-cli-tool.md b/projects/amdsmi/docs/how-to/amdsmi-cli-tool.md index 9e82502e3a..6edc7260a1 100644 --- a/projects/amdsmi/docs/how-to/amdsmi-cli-tool.md +++ b/projects/amdsmi/docs/how-to/amdsmi-cli-tool.md @@ -580,6 +580,8 @@ Set Arguments: -L, --clk-limit CLK_TYPE LIM_TYPE VALUE Sets the sclk (aka gfxclk) or mclk minimum and maximum frequencies. ex: amd-smi set -L (sclk | mclk) (min | max) value -R, --process-isolation STATUS Enable or disable the GPU process isolation on a per partition basis: 0 for disable and 1 for enable. + --ptl-status STATUS Enable or disable the PTL on a GPU processor: 0 for disable and 1 for enable + --ptl-format FRMT1,FRMT2 Set the PTL format on a GPU processor. For example, --ptl-format I8,F32 CPU Arguments: --cpu-pwr-limit PWR_LIMIT Set power limit for the given socket. Input parameter is power limit value. diff --git a/projects/amdsmi/include/amd_smi/amdsmi.h b/projects/amdsmi/include/amd_smi/amdsmi.h index da11c1ad9e..eb9609be60 100644 --- a/projects/amdsmi/include/amd_smi/amdsmi.h +++ b/projects/amdsmi/include/amd_smi/amdsmi.h @@ -473,7 +473,7 @@ typedef enum { // GPU Board Node temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_FIRST = 100, - AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_RETIMER_X + AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_RETIMER_X = AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_FIRST, //!< Retimer X temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_OAM_X_IBC, //!< OAM X IBC temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_OAM_X_IBC_2, //!< OAM X IBC 2 temperature @@ -482,7 +482,7 @@ typedef enum { AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_OAM_X_04_HBM_D_VR, //!< OAM X 0.4V HBM D voltage regulator temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_NODE_LAST = 149, - // GPU Board VR (Voltage Regulator) temperature + // GPU Board VR (Voltage Regulator) temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VR_FIRST = 150, AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDCR_VDD0 = AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VR_FIRST, //!< VDDCR VDD0 voltage regulator temperature @@ -500,7 +500,7 @@ typedef enum { AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VDDIO_11_E32, //!< VDDIO 1.1V E32 voltage regulator temperature AMDSMI_TEMPERATURE_TYPE_GPUBOARD_VR_LAST = 199, - // Baseboard System temperature + // Baseboard System temperature AMDSMI_TEMPERATURE_TYPE_BASEBOARD_FIRST = 200, AMDSMI_TEMPERATURE_TYPE_BASEBOARD_UBB_FPGA = AMDSMI_TEMPERATURE_TYPE_BASEBOARD_FIRST, //!< UBB FPGA temperature AMDSMI_TEMPERATURE_TYPE_BASEBOARD_UBB_FRONT, //!< UBB front temperature @@ -2169,6 +2169,22 @@ typedef struct { uint64_t reserved[6]; } amdsmi_npm_info_t; +/** + * @brief PTL (Peak Tops Limiter) data format types + * These correspond to the hardware data types used in matrix operations. + * Only F8 and XF32 are always supported at full performance. From the remaining + * five types, only two can be supported at peak performance simultaneously. + * + */ +typedef enum { + AMDSMI_PTL_DATA_FORMAT_I8 = 0x0, //!< Integer 8-bit format + AMDSMI_PTL_DATA_FORMAT_F16 = 0x1, //!< Float 16-bit format + AMDSMI_PTL_DATA_FORMAT_BF16 = 0x2, //!< Brain Float 16-bit format + AMDSMI_PTL_DATA_FORMAT_F32 = 0x3, //!< Float 32-bit format + AMDSMI_PTL_DATA_FORMAT_F64 = 0x4, //!< Float 64-bit format + AMDSMI_PTL_DATA_FORMAT_INVALID = 0xFFFFFFFF //!< Invalid format +} amdsmi_ptl_data_format_t; + #ifdef ENABLE_ESMI_LIB /** @@ -2406,7 +2422,7 @@ typedef struct { * @platform{guest_mvf} @platform{guest_windows} * * @details This function initializes the library and the internal data structures, - * including those corresponding to sources of information that SMI provides. + * including those corresponding to sources of information that SMI provides. * Singleton Design, requires the same number of inits as shutdowns. * * The @p init_flags decides which type of processor @@ -2654,7 +2670,7 @@ amdsmi_status_t amdsmi_get_processor_handles(amdsmi_socket_handle socket_handle, amdsmi_processor_handle* processor_handles); /** - * @brief Get the node handle associated with processor handle. + * @brief Get the node handle associated with processor handle. * * @ingroup tagProcDiscovery * @@ -2664,7 +2680,7 @@ amdsmi_status_t amdsmi_get_processor_handles(amdsmi_socket_handle socket_handle, * @p processor_handle must be provided for the processor. * Currently, only AMD GPUs are supported. * - * @param[in] processor_handle A pointer to a ::amdsmi_processor_handle, this + * @param[in] processor_handle A pointer to a ::amdsmi_processor_handle, this * is required to be OAM ID 0 otherwise the API will fail. OAM ID is sourced * from amdsmi_get_gpu_asic_info API. * @@ -3356,7 +3372,7 @@ amdsmi_set_gpu_power_profile(amdsmi_processor_handle processor_handle, uint32_t * * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail. */ -amdsmi_status_t +amdsmi_status_t amdsmi_get_supported_power_cap(amdsmi_processor_handle processor_handle, uint32_t *sensor_count, uint32_t *sensor_inds, amdsmi_power_cap_type_t *sensor_types); @@ -6571,23 +6587,23 @@ amdsmi_get_gpu_process_list(amdsmi_processor_handle processor_handle, uint32_t * * https://docs.kernel.org/admin-guide/sysctl/kernel.html#modprobe * with no extra parameters as specified in * https://docs.kernel.org/gpu/amdgpu/module-parameters.html. - * + * * Use this function with caution, as it will unload and reload the AMD GPU - * driver: `modprobe -r amdgpu && modprobe amdgpu`. - * + * driver: `modprobe -r amdgpu && modprobe amdgpu`. + * * Any process or workload using the AMD GPU driver is REQUIRED to be * stopped before calling this function. Otherwise, function will return * ::AMDSMI_STATUS_AMDGPU_RESTART_ERR could not successfully restart * the amdgpu driver. - * + * * User is REQUIRED to have root/admin privileges to call this function. * Otherwise, this function will return ::AMDSMI_STATUS_NO_PERM. - * + * * This API will take time to complete, as we are checking the driver's * loading status to confirm it reloaded properly. If * ::AMDSMI_STATUS_AMDGPU_RESTART_ERR is returned, it means the driver * did not reload properly and the user should check dmesg logs. - * + * * This function has been created in order to conviently reload the * AMD GPU driver once `amdsmi_set_gpu_memory_partition()` or * `amdsmi_set_gpu_memory_partition_mode()` successfully has been changed @@ -6608,6 +6624,111 @@ amdsmi_status_t amdsmi_gpu_driver_reload(void); /** @} End tagDriverControl */ +/*****************************************************************************/ +/** @defgroup tagPTL Peak Tops Limiter + * @{ + */ + +/** + * @brief Get PTL enable/disable state + * + * @ingroup tagPTL + * + * @platform{gpu_bm_linux} @platform{host} + * + * @details This function retrieves whether PTL (Peak Tops Limiter) is currently + * enabled or disabled for the specified processor. This is a simple state query + * that returns the current PTL operational state without detailed configuration. + * + * @param[in] processor_handle Device which to query + * + * @param[out] enabled Pointer to boolean that will be set to true if PTL is + * enabled, false if PTL is disabled + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, + * ::AMDSMI_STATUS_NOT_SUPPORTED if PTL is not supported on this device, + * non-zero on other failures + */ +amdsmi_status_t +amdsmi_get_gpu_ptl_state(amdsmi_processor_handle processor_handle, bool *enabled); + +/** + * @brief Set PTL enable/disable state + * + * @ingroup tagPTL + * + * @platform{gpu_bm_linux} @platform{host} + * + * @details This function enables or disables PTL (Peak Tops Limiter) operation. + * Use amdsmi_set_gpu_ptl_enable_with_formats() + * for more control over the preferred data formats when enabling. + * + * @param[in] processor_handle Device to configure + * + * @param[in] enable Boolean flag: true to enable PTL with default formats, + * false to disable PTL + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail + */ +amdsmi_status_t amdsmi_set_gpu_ptl_state(amdsmi_processor_handle processor_handle, bool enable); + +/** + * @brief Get PTL (Peak Tops Limiter) formats for the processor + * + * @ingroup tagPTL + * + * @platform{gpu_bm_linux} @platform{host} + * + * @details This function retrieves the current PTL fromats + * for the specified processor. PTL constrains the product to never deliver more + * than a specified TOPS/second. + * + * @param[in] processor_handle Device which to query +* + * @param[out] data_format1 Pointer to first preferred data format that receives peak performance + * + * @param[out] data_format2 Pointer to second preferred data format that receives peak performance + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, + * ::AMDSMI_STATUS_NOT_SUPPORTED if PTL is not supported on this device, + * non-zero on other failures + */ +amdsmi_status_t +amdsmi_get_gpu_ptl_formats(amdsmi_processor_handle processor_handle, + amdsmi_ptl_data_format_t *data_format1, + amdsmi_ptl_data_format_t *data_format2); + +/** + * @brief Set PTL with specified preferred data formats + * + * @ingroup tagPTL + * + * @platform{gpu_bm_linux} @platform{host} + * + * @details This function sets PTL with the specified preferred data format pair. + * PTL must be enabled first before calling this function using amdsmi_set_gpu_ptl_state. + * The two specified formats will receive accurate performance monitoring and peak + * performance. F8 and XF32 formats always receive peak performance regardless of this setting. + * + * @param[in] processor_handle Device to configure + * + * @param[in] data_format1 First preferred data format (must be from the limited set: + * I8, F16, BF16, F32, F64) + * + * @param[in] data_format2 Second preferred data format (must be from the limited set: + * I8, F16, BF16, F32, F64, and different from data_format1) + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, + * ::AMDSMI_STATUS_NOT_SUPPORTED if PTL is not supported on this device, + * non-zero on other failures + **/ +amdsmi_status_t +amdsmi_set_gpu_ptl_formats(amdsmi_processor_handle processor_handle, + amdsmi_ptl_data_format_t data_format1, + amdsmi_ptl_data_format_t data_format2); + +/** @} End tagPTL */ + #ifdef ENABLE_ESMI_LIB /*****************************************************************************/ diff --git a/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h b/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h index 97593f1e7a..794a727d62 100644 --- a/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h +++ b/projects/amdsmi/include/amd_smi/impl/amd_smi_utils.h @@ -57,6 +57,7 @@ amdsmi_status_t smi_amdgpu_get_pcie_speed_from_pcie_type(uint16_t pcie_type, uin amdsmi_status_t smi_amdgpu_get_market_name_from_dev_id(amd::smi::AMDSmiGPUDevice* device, char *market_name); amdsmi_status_t smi_amdgpu_is_gpu_power_management_enabled(amd::smi::AMDSmiGPUDevice* device, bool *enabled); std::string smi_split_string(std::string str, char delim); +std::vector split_string(const std::string& line, char delim); std::string smi_amdgpu_get_status_string(amdsmi_status_t ret, bool fullStatus); amdsmi_status_t smi_clear_char_and_reinitialize(char buffer[], uint32_t len, std::string newString); diff --git a/projects/amdsmi/py-interface/__init__.py b/projects/amdsmi/py-interface/__init__.py index 0d9a5554bc..c0aafb21d7 100644 --- a/projects/amdsmi/py-interface/__init__.py +++ b/projects/amdsmi/py-interface/__init__.py @@ -266,6 +266,12 @@ from .amdsmi_interface import amdsmi_get_gpu_pm_metrics_info # # Virtualization Mode Detection from .amdsmi_interface import amdsmi_get_gpu_virtualization_mode +# # PTL implementation +from .amdsmi_interface import amdsmi_get_gpu_ptl_state +from .amdsmi_interface import amdsmi_set_gpu_ptl_state +from .amdsmi_interface import amdsmi_get_gpu_ptl_formats +from .amdsmi_interface import amdsmi_set_gpu_ptl_formats + # # Functions where library initialization is not needed # # Version information from .amdsmi_interface import amdsmi_get_lib_version @@ -306,6 +312,7 @@ from .amdsmi_interface import AmdSmiProcessorType from .amdsmi_interface import AmdSmiVirtualizationMode from .amdsmi_interface import AmdSmiVramType from .amdsmi_interface import AmdSmiAffinityScope +from .amdsmi_interface import AmdSmiPtlData # Exceptions from .amdsmi_exception import AmdSmiLibraryException diff --git a/projects/amdsmi/py-interface/amdsmi_interface.py b/projects/amdsmi/py-interface/amdsmi_interface.py index 97bd458865..43dba82ec8 100644 --- a/projects/amdsmi/py-interface/amdsmi_interface.py +++ b/projects/amdsmi/py-interface/amdsmi_interface.py @@ -604,6 +604,13 @@ class AmdSmiAffinityScope(IntEnum): NUMA_SCOPE = amdsmi_wrapper.AMDSMI_AFFINITY_SCOPE_NODE SOCKET_SCOPE = amdsmi_wrapper.AMDSMI_AFFINITY_SCOPE_SOCKET +class AmdSmiPtlData(IntEnum): + I8 = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_I8 + F16 = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_F16 + BF16 = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_BF16 + F32 = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_F32 + F64 = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_F64 + INVALID = amdsmi_wrapper.AMDSMI_PTL_DATA_FORMAT_INVALID class AmdSmiPowerCapType(IntEnum): PPT0 = amdsmi_wrapper.AMDSMI_POWER_CAP_TYPE_PPT0 @@ -5540,6 +5547,75 @@ def amdsmi_get_gpu_virtualization_mode( "mode": AmdSmiVirtualizationMode(mode.value) } +def amdsmi_get_gpu_ptl_state( + processor_handle: processor_handle_t + ) -> bool: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException(processor_handle, amdsmi_wrapper.amdsmi_processor_handle) + + is_ptl_enabled = ctypes.c_bool() + _check_res( + amdsmi_wrapper.amdsmi_get_gpu_ptl_state( + processor_handle, ctypes.byref(is_ptl_enabled) + ) + ) + + return is_ptl_enabled.value + +def amdsmi_set_gpu_ptl_state( + processor_handle: processor_handle_t, + state: int + ) -> None: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException( + processor_handle, amdsmi_wrapper.amdsmi_processor_handle + ) + _check_res( + amdsmi_wrapper.amdsmi_set_gpu_ptl_state( + processor_handle, state + ) + ) + +def amdsmi_get_gpu_ptl_formats( + processor_handle: processor_handle_t + ) -> tuple[int, int]: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException(processor_handle, amdsmi_wrapper.amdsmi_processor_handle) + data_format1 = amdsmi_wrapper.amdsmi_ptl_data_format_t() + data_format2 = amdsmi_wrapper.amdsmi_ptl_data_format_t() + + _check_res( + amdsmi_wrapper.amdsmi_get_gpu_ptl_formats( + processor_handle, ctypes.byref(data_format1), ctypes.byref(data_format2) + ) + ) + + return int(data_format1.value), int(data_format2.value) + +def amdsmi_set_gpu_ptl_formats( + processor_handle: processor_handle_t, + fmt1: AmdSmiPtlData, + fmt2: AmdSmiPtlData, + ) -> None: + if not isinstance(processor_handle, amdsmi_wrapper.amdsmi_processor_handle): + raise AmdSmiParameterException( + processor_handle, amdsmi_wrapper.amdsmi_processor_handle + ) + + for fmt in (fmt1, fmt2): + if not isinstance(fmt, AmdSmiPtlData): + raise AmdSmiParameterException(fmt, AmdSmiPtlData) + if fmt is AmdSmiPtlData.INVALID: + raise AmdSmiParameterException(fmt, "A valid PTL data format (not INVALID)") + + c_fmt1 = amdsmi_wrapper.amdsmi_ptl_data_format_t(int(fmt1)) + c_fmt2 = amdsmi_wrapper.amdsmi_ptl_data_format_t(int(fmt2)) + + _check_res( + amdsmi_wrapper.amdsmi_set_gpu_ptl_formats( + processor_handle, c_fmt1, c_fmt2) + ) + ### Non C-Lib APIs ### def amdsmi_get_rocm_version()-> Tuple[bool, str]: diff --git a/projects/amdsmi/py-interface/amdsmi_wrapper.py b/projects/amdsmi/py-interface/amdsmi_wrapper.py index 33b248fc9b..71c8a15560 100644 --- a/projects/amdsmi/py-interface/amdsmi_wrapper.py +++ b/projects/amdsmi/py-interface/amdsmi_wrapper.py @@ -2281,6 +2281,22 @@ struct_amdsmi_npm_info_t._fields_ = [ ] amdsmi_npm_info_t = struct_amdsmi_npm_info_t +# values for enumeration 'amdsmi_ptl_data_format_t' +amdsmi_ptl_data_format_t__enumvalues = { + 0: 'AMDSMI_PTL_DATA_FORMAT_I8', + 1: 'AMDSMI_PTL_DATA_FORMAT_F16', + 2: 'AMDSMI_PTL_DATA_FORMAT_BF16', + 3: 'AMDSMI_PTL_DATA_FORMAT_F32', + 4: 'AMDSMI_PTL_DATA_FORMAT_F64', + 4294967295: 'AMDSMI_PTL_DATA_FORMAT_INVALID', +} +AMDSMI_PTL_DATA_FORMAT_I8 = 0 +AMDSMI_PTL_DATA_FORMAT_F16 = 1 +AMDSMI_PTL_DATA_FORMAT_BF16 = 2 +AMDSMI_PTL_DATA_FORMAT_F32 = 3 +AMDSMI_PTL_DATA_FORMAT_F64 = 4 +AMDSMI_PTL_DATA_FORMAT_INVALID = 4294967295 +amdsmi_ptl_data_format_t = ctypes.c_uint32 # enum class struct_amdsmi_smu_fw_version_t(Structure): pass @@ -2997,6 +3013,18 @@ amdsmi_get_gpu_process_list.argtypes = [amdsmi_processor_handle, ctypes.POINTER( amdsmi_gpu_driver_reload = _libraries['libamd_smi.so'].amdsmi_gpu_driver_reload amdsmi_gpu_driver_reload.restype = amdsmi_status_t amdsmi_gpu_driver_reload.argtypes = [] +amdsmi_get_gpu_ptl_state = _libraries['libamd_smi.so'].amdsmi_get_gpu_ptl_state +amdsmi_get_gpu_ptl_state.restype = amdsmi_status_t +amdsmi_get_gpu_ptl_state.argtypes = [amdsmi_processor_handle, ctypes.POINTER(ctypes.c_bool)] +amdsmi_set_gpu_ptl_state = _libraries['libamd_smi.so'].amdsmi_set_gpu_ptl_state +amdsmi_set_gpu_ptl_state.restype = amdsmi_status_t +amdsmi_set_gpu_ptl_state.argtypes = [amdsmi_processor_handle, ctypes.c_bool] +amdsmi_get_gpu_ptl_formats = _libraries['libamd_smi.so'].amdsmi_get_gpu_ptl_formats +amdsmi_get_gpu_ptl_formats.restype = amdsmi_status_t +amdsmi_get_gpu_ptl_formats.argtypes = [amdsmi_processor_handle, ctypes.POINTER(amdsmi_ptl_data_format_t), ctypes.POINTER(amdsmi_ptl_data_format_t)] +amdsmi_set_gpu_ptl_formats = _libraries['libamd_smi.so'].amdsmi_set_gpu_ptl_formats +amdsmi_set_gpu_ptl_formats.restype = amdsmi_status_t +amdsmi_set_gpu_ptl_formats.argtypes = [amdsmi_processor_handle, amdsmi_ptl_data_format_t, amdsmi_ptl_data_format_t] amdsmi_get_cpu_core_energy = _libraries['libamd_smi.so'].amdsmi_get_cpu_core_energy amdsmi_get_cpu_core_energy.restype = amdsmi_status_t amdsmi_get_cpu_core_energy.argtypes = [amdsmi_processor_handle, ctypes.POINTER(ctypes.c_uint64)] @@ -3267,7 +3295,10 @@ __all__ = \ 'AMDSMI_PROCESSOR_TYPE_AMD_GPU', 'AMDSMI_PROCESSOR_TYPE_NON_AMD_CPU', 'AMDSMI_PROCESSOR_TYPE_NON_AMD_GPU', - 'AMDSMI_PROCESSOR_TYPE_UNKNOWN', + 'AMDSMI_PROCESSOR_TYPE_UNKNOWN', 'AMDSMI_PTL_DATA_FORMAT_BF16', + 'AMDSMI_PTL_DATA_FORMAT_F16', 'AMDSMI_PTL_DATA_FORMAT_F32', + 'AMDSMI_PTL_DATA_FORMAT_F64', 'AMDSMI_PTL_DATA_FORMAT_I8', + 'AMDSMI_PTL_DATA_FORMAT_INVALID', 'AMDSMI_PWR_PROF_PRST_3D_FULL_SCR_MASK', 'AMDSMI_PWR_PROF_PRST_BOOTUP_DEFAULT', 'AMDSMI_PWR_PROF_PRST_COMPUTE_MASK', @@ -3485,6 +3516,7 @@ __all__ = \ 'amdsmi_get_gpu_pm_metrics_info', 'amdsmi_get_gpu_power_profile_presets', 'amdsmi_get_gpu_process_isolation', 'amdsmi_get_gpu_process_list', + 'amdsmi_get_gpu_ptl_formats', 'amdsmi_get_gpu_ptl_state', 'amdsmi_get_gpu_ras_block_features_enabled', 'amdsmi_get_gpu_ras_feature_info', 'amdsmi_get_gpu_reg_table_info', 'amdsmi_get_gpu_revision', @@ -3538,11 +3570,12 @@ __all__ = \ 'amdsmi_power_info_t', 'amdsmi_power_profile_preset_masks_t', 'amdsmi_power_profile_status_t', 'amdsmi_proc_info_t', 'amdsmi_process_handle_t', 'amdsmi_process_info_t', - 'amdsmi_processor_handle', 'amdsmi_range_t', - 'amdsmi_ras_err_state_t', 'amdsmi_ras_feature_t', - 'amdsmi_reg_type_t', 'amdsmi_reset_gpu', 'amdsmi_reset_gpu_fan', - 'amdsmi_reset_gpu_xgmi_error', 'amdsmi_retired_page_record_t', - 'amdsmi_set_clk_freq', 'amdsmi_set_cpu_core_boostlimit', + 'amdsmi_processor_handle', 'amdsmi_ptl_data_format_t', + 'amdsmi_range_t', 'amdsmi_ras_err_state_t', + 'amdsmi_ras_feature_t', 'amdsmi_reg_type_t', 'amdsmi_reset_gpu', + 'amdsmi_reset_gpu_fan', 'amdsmi_reset_gpu_xgmi_error', + 'amdsmi_retired_page_record_t', 'amdsmi_set_clk_freq', + 'amdsmi_set_cpu_core_boostlimit', 'amdsmi_set_cpu_df_pstate_range', 'amdsmi_set_cpu_gmi3_link_width_range', 'amdsmi_set_cpu_pcie_link_rate', @@ -3560,7 +3593,8 @@ __all__ = \ 'amdsmi_set_gpu_overdrive_level', 'amdsmi_set_gpu_pci_bandwidth', 'amdsmi_set_gpu_perf_determinism_mode', 'amdsmi_set_gpu_perf_level', 'amdsmi_set_gpu_power_profile', - 'amdsmi_set_gpu_process_isolation', 'amdsmi_set_power_cap', + 'amdsmi_set_gpu_process_isolation', 'amdsmi_set_gpu_ptl_formats', + 'amdsmi_set_gpu_ptl_state', 'amdsmi_set_power_cap', 'amdsmi_set_soc_pstate', 'amdsmi_set_xgmi_plpd', 'amdsmi_shut_down', 'amdsmi_smu_fw_version_t', 'amdsmi_sock_info_t', 'amdsmi_socket_handle', diff --git a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi.h b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi.h index 09c91200f9..321f903d9a 100644 --- a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi.h +++ b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi.h @@ -109,7 +109,7 @@ typedef enum { //!< being used RSMI_STATUS_REFCOUNT_OVERFLOW, //!< An internal reference counter //!< exceeded INT32_MAX - RSMI_STATUS_DIRECTORY_NOT_FOUND, //!< Error when a directory is not + RSMI_STATUS_DIRECTORY_NOT_FOUND, //!< Error when a directory is not //!< found, maps to ENOTDIR RSMI_STATUS_SETTING_UNAVAILABLE, //!< Requested setting is unavailable //!< for the current device @@ -1474,6 +1474,22 @@ typedef enum { RSMI_REG_USR1, } rsmi_reg_type_t; +/** + * @brief PTL (Peak Tops Limiter) data format types + * These correspond to the hardware data types used in matrix operations. + * Only F8 and XF32 are always supported at full performance. From the remaining + * five types, only two can be supported at peak performance simultaneously. + * + */ +typedef enum { + RSMI_PTL_DATA_FORMAT_I8 = 0x0, //!< Integer 8-bit format + RSMI_PTL_DATA_FORMAT_F16 = 0x1, //!< Float 16-bit format + RSMI_PTL_DATA_FORMAT_BF16 = 0x2, //!< Brain Float 16-bit format + RSMI_PTL_DATA_FORMAT_F32 = 0x3, //!< Float 32-bit format + RSMI_PTL_DATA_FORMAT_F64 = 0x4, //!< Float 64-bit format + RSMI_PTL_DATA_FORMAT_INVALID = 0xFFFFFFFF //!< Invalid format +} rsmi_ptl_data_format_t; + /** * @brief This structure holds error counts. */ @@ -2666,7 +2682,7 @@ rsmi_dev_power_profile_set(uint32_t dv_ind, uint32_t reserved, * * @return ::rsmi_status_t | ::RSMI_STATUS_SUCCESS on success, non-zero on fail. */ -rsmi_status_t +rsmi_status_t rsmi_dev_supported_power_cap_get(uint32_t dv_ind, uint32_t *sensor_count, uint32_t *sensor_inds, rsmi_power_cap_type_t *sensor_types); /** @} */ // end of PowerCont @@ -5097,7 +5113,7 @@ rsmi_dev_compute_partition_xcp_config_set(uint32_t dv_ind, * @param[in] dv_ind a device index * * @param[in] type a pointer to a requested resource using enum ::rsmi_accelerator_partition_resource_type_t - * + * * @param[inout] profile a pointer to the requested rsmi_accelerator_partition_resource_profile_t details * * @retval ::RSMI_STATUS_SUCCESS call was successful @@ -5600,6 +5616,96 @@ rsmi_dev_metrics_header_info_get(uint32_t dv_ind, metrics_table_header_t* header rsmi_status_t rsmi_dev_metrics_xcd_counter_get(uint32_t dv_ind, uint16_t* xcd_counter_value); +/** + * @brief Check if ptl enabled for device + * + * @details Given a device index @p dv_ind and a pointer to a bool in which + * the status will stored + * + * @param[in] dv_ind a device index + * + * @param[inout] enabled a pointer to bool to which the status will be stored + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * ::RSMI_STATUS_NOT_SUPPORTED is returned in case the sysfs fails + * + */ +rsmi_status_t +rsmi_get_gpu_ptl_state(uint32_t dv_ind, bool* enabled); + +/** + * @brief Set PTL enable/disable state + * + * @ingroup tagPTL + * + * @platform{gpu_bm_linux} @platform{host} + * + * @details This function enables or disables PTL (Peak Tops Limiter) operation. + * Use rsmi_set_gpu_ptl_enable_with_formats() + * for more control over the preferred data formats when enabling. + * + * @param[in] processor_handle Device to configure + * + * @param[in] enable Boolean flag: true to enable PTL with default formats, + * false to disable PTL + * + * @return ::amdsmi_status_t | ::AMDSMI_STATUS_SUCCESS on success, non-zero on fail + */ +rsmi_status_t +rsmi_set_gpu_ptl_state(uint32_t dv_ind, bool enabled); + +/** + * @brief Get ptl data formats + * + * @details Given a device index @p dv_ind and string pointers to store ptl data + * + * @param[in] dv_ind a device index + * + * @param[inout] format a pointer to data format to which the raw format string will be stored + * + * @param[in] len the length of the caller provided buffer @p name. + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * ::RSMI_STATUS_NOT_SUPPORTED is returned in case the sysfs fails + * + */ +rsmi_status_t +rsmi_get_gpu_ptl_formats(uint32_t dv_ind, char* format, size_t len); + +/** + * @brief Set ptl data formats + * + * @details Given a device index @p dv_ind and raw string poitner in which to set ptl format + * + * @param[in] dv_ind a device index + * + * @param[inout] format string pointer format to set ptl level to + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * ::RSMI_STATUS_NOT_SUPPORTED is returned in case the sysfs fails + * + */ +rsmi_status_t +rsmi_set_gpu_ptl_formats(uint32_t dv_ind, const char* format); + +/** + * @brief Get supported ptl formats + * + * @details Given a device index @p dv_ind and string pointer return supported ptl formats + * + * @param[in] dv_ind a device index + * + * @param[inout] supported string pointer to return supported ptl formats + * + * @param[in] len the length of the caller provided buffer @p name. + * + * @retval ::RSMI_STATUS_SUCCESS is returned upon successful call. + * ::RSMI_STATUS_NOT_SUPPORTED is returned in case the sysfs fails + * + */ +rsmi_status_t +rsmi_read_supported_ptl_formats(uint32_t dv_ind, char* supported, size_t length); + /** * @brief Get the log from the GPU metrics associated with the device * @@ -5631,23 +5737,23 @@ rsmi_dev_metrics_log_get(uint32_t dv_ind); * https://docs.kernel.org/admin-guide/sysctl/kernel.html#modprobe * with no extra parameters as specified in * https://docs.kernel.org/gpu/amdgpu/module-parameters.html. - * + * * Use this function with caution, as it will unload and reload the AMD GPU - * driver: `modprobe -r amdgpu && modprobe amdgpu`. - * + * driver: `modprobe -r amdgpu && modprobe amdgpu`. + * * Any process or workload using the AMD GPU driver is REQUIRED to be * stopped before calling this function. Otherwise, function will return * ::RSMI_STATUS_AMDGPU_RESTART_ERR could not successfully restart * the amdgpu driver. - * + * * User is REQUIRED to have root/admin privileges to call this function. * Otherwise, this function will return ::RSMI_STATUS_PERMISSION. - * + * * This API will take time to complete, as we are checking the driver's * loading status to confirm it reloaded properly. If * ::RSMI_STATUS_AMDGPU_RESTART_ERR is returned, it means the driver * did not reload properly and the user should check dmesg logs. - * + * * This function has been created in order to conviently reload the * AMD GPU driver once `rsmi_dev_memory_partition_set()` * successfully has been changed on Baremetal systems. diff --git a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_device.h b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_device.h index 1abc04dce2..22c81939c4 100644 --- a/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_device.h +++ b/projects/amdsmi/rocm_smi/include/rocm_smi/rocm_smi_device.h @@ -187,6 +187,11 @@ enum DevInfoTypes { * Possible xcp config resources end */ + // PTL + kDevPtlSupported, + kDevPtlStatus, + kDevPtlFormat, + // The information read from pci core sysfs kDevPCieTypeStart = 1000, kDevPCieVendorID = kDevPCieTypeStart, diff --git a/projects/amdsmi/rocm_smi/src/rocm_smi.cc b/projects/amdsmi/rocm_smi/src/rocm_smi.cc index 8b6506c045..727843a8a2 100644 --- a/projects/amdsmi/rocm_smi/src/rocm_smi.cc +++ b/projects/amdsmi/rocm_smi/src/rocm_smi.cc @@ -269,6 +269,7 @@ static rsmi_status_t get_dev_value_str(amd::smi::DevInfoTypes type, return amd::smi::ErrnoToRsmiStatus(ret); } + static rsmi_status_t read_dev_port_map_file(amd::smi::DevInfoTypes type, uint32_t dv_ind, std::string *val_str) { assert(val_str != nullptr); if (val_str == nullptr) { @@ -320,6 +321,14 @@ static rsmi_status_t set_dev_value(amd::smi::DevInfoTypes type, return amd::smi::ErrnoToRsmiStatus(ret); } +static rsmi_status_t set_dev_value(amd::smi::DevInfoTypes type, + uint32_t dv_ind, const char* val) { + GET_DEV_FROM_INDX + + int ret = dev->writeDevInfo(type, val); + return amd::smi::ErrnoToRsmiStatus(ret); +} + static rsmi_status_t get_dev_mon_value(amd::smi::MonitorTypes type, uint32_t dv_ind, uint32_t sensor_ind, int64_t *val) { assert(val != nullptr); @@ -7888,6 +7897,140 @@ rsmi_dev_metrics_xcd_counter_get(uint32_t dv_ind, uint16_t* xcd_counter_value) CATCH } +// Internal only helper +rsmi_status_t +rsmi_read_supported_ptl_formats(uint32_t dv_ind, char* supported, size_t length){ + TRY + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << " | ======= start =======" + << " | dv_ind=" << dv_ind; + LOG_TRACE(ss); + + if (supported == nullptr) { + return RSMI_STATUS_INVALID_ARGS; + } + + std::string line; + DEVICE_MUTEX + rsmi_status_t ret = get_dev_value_line(amd::smi::kDevPtlSupported, dv_ind, &line); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + if (line.size() + 1 > length) { + return RSMI_STATUS_UNEXPECTED_SIZE; + } + + std::strncpy(supported, line.c_str(), length); + supported[length - 1] = '\0'; + return RSMI_STATUS_SUCCESS; + CATCH +} + +rsmi_status_t +rsmi_get_gpu_ptl_state(uint32_t dv_ind, bool *enabled) +{ + TRY + std::string val_str; + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << "| ======= start ======="; + LOG_TRACE(ss); + + DEVICE_MUTEX + if (!enabled) { + return RSMI_STATUS_INVALID_ARGS; + } + + rsmi_status_t ret = get_dev_value_str(amd::smi::kDevPtlStatus, dv_ind, + &val_str); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + if (val_str == "enabled") { *enabled = true; return RSMI_STATUS_SUCCESS; } + if (val_str == "disabled") { *enabled = false; return RSMI_STATUS_SUCCESS; } + + // unexpected value + return RSMI_STATUS_UNEXPECTED_DATA; + CATCH +} + +rsmi_status_t +rsmi_set_gpu_ptl_state(uint32_t dv_ind, bool enable) { + TRY + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << " | ======= start =======" + << " | dv_ind=" << dv_ind + << " | enable=" << enable; + LOG_TRACE(ss); + REQUIRE_ROOT_ACCESS + + DEVICE_MUTEX + return set_dev_value(amd::smi::kDevPtlStatus, dv_ind, enable); + CATCH +} + +rsmi_status_t +rsmi_get_gpu_ptl_formats(uint32_t dv_ind, char* format, size_t length) +{ + TRY + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << " | ======= start =======" + << " | dv_ind=" << dv_ind; + LOG_TRACE(ss); + + if (format == nullptr) { + return RSMI_STATUS_INVALID_ARGS; + } + + std::string line; + DEVICE_MUTEX + rsmi_status_t ret = get_dev_value_line(amd::smi::kDevPtlFormat, dv_ind, &line); + if (ret != RSMI_STATUS_SUCCESS) { + return ret; + } + + if (line.size() + 1 > length) { + return RSMI_STATUS_UNEXPECTED_SIZE; + } + + std::strncpy(format, line.c_str(), length); + format[length - 1] = '\0'; + return RSMI_STATUS_SUCCESS; + CATCH +} + +rsmi_status_t +rsmi_set_gpu_ptl_formats(uint32_t dv_ind, const char* format) +{ + TRY + std::ostringstream ss; + ss << __PRETTY_FUNCTION__ << " | ======= start =======" + << " | dv_ind=" << dv_ind + << " | format=" << format; + LOG_TRACE(ss); + + REQUIRE_ROOT_ACCESS + DEVICE_MUTEX + rsmi_status_t ret = set_dev_value(amd::smi::kDevPtlFormat, dv_ind, format); + if (ret != RSMI_STATUS_SUCCESS) { + ss << __PRETTY_FUNCTION__ + << " | Failed to write PTL format to sysfs" + << " | format='" << format << "'" + << " | ret=" << getRSMIStatusString(ret); + LOG_ERROR(ss); + return ret; + } + + ss << __PRETTY_FUNCTION__ + << " | PTL set formats success" + << " | format='" << format << "'"; + LOG_DEBUG(ss); + + return RSMI_STATUS_SUCCESS; + CATCH +} + rsmi_status_t rsmi_dev_metrics_log_get(uint32_t dv_ind) { diff --git a/projects/amdsmi/rocm_smi/src/rocm_smi_device.cc b/projects/amdsmi/rocm_smi/src/rocm_smi_device.cc index 90a818d6c7..90edb85e70 100755 --- a/projects/amdsmi/rocm_smi/src/rocm_smi_device.cc +++ b/projects/amdsmi/rocm_smi/src/rocm_smi_device.cc @@ -119,6 +119,9 @@ static const char *kDevPmMetricsFName = "pm_metrics"; // PM log static const char *kDevRegMetricsFName = "reg_state"; // register table static const char *kDevBaseBoardTempMetricsFName = "board/baseboard_temp"; static const char *kDevGpuBoardTempMetricsFName = "board/gpuboard_temp"; +static const char *kDevPtlSupportedFName = "ptl/ptl_supported_formats"; // Only used internally for verification +static const char *kDevPtlStatusFName = "ptl/ptl_enable"; +static const char *kDevPtlFormatFName = "ptl/ptl_format"; static const char *kDevAvailableComputePartitionFName = "available_compute_partition"; @@ -331,6 +334,9 @@ static const std::map kDevAttribNameMap = { {kDevRegMetrics, kDevRegMetricsFName}, {kDevBaseBoardTempMetrics, kDevBaseBoardTempMetricsFName}, {kDevGpuBoardTempMetrics, kDevGpuBoardTempMetricsFName}, + {kDevPtlSupported, kDevPtlSupportedFName}, + {kDevPtlStatus, kDevPtlStatusFName}, + {kDevPtlFormat, kDevPtlFormatFName}, {kDevGpuReset, kDevGpuResetFName}, {kDevAvailableComputePartition, kDevAvailableComputePartitionFName}, {kDevComputePartition, kDevComputePartitionFName}, @@ -605,6 +611,10 @@ static const std::map kDevFuncDependsMap = { {"rsmi_dev_compute_partition_set", {{kDevComputePartitionFName}, {}}}, {"rsmi_dev_memory_partition_get", {{kDevMemoryPartitionFName}, {}}}, {"rsmi_dev_memory_partition_set", {{kDevMemoryPartitionFName}, {}}}, + {"rsmi_get_gpu_ptl_state", {{kDevPtlStatusFName}, {}}}, + {"rsmi_set_gpu_ptl_state", {{kDevPtlStatusFName}, {}}}, + {"rsmi_get_gpu_ptl_formats", {{kDevPtlFormatFName}, {}}}, + {"rsmi_set_gpu_ptl_formats", {{kDevPtlFormatFName}, {}}}, // These functions with variants, but no sensors/units. (May or may not // have mandatory dependencies.) @@ -1035,6 +1045,7 @@ int Device::writeDevInfo(DevInfoTypes type, uint64_t val) { case kDevOverDriveLevel: // integer between 0 and 20 case kDevPowerODVoltage: case kDevPowerProfileMode: + case kDevPtlStatus: return writeDevInfoStr(type, std::to_string(val)); break; @@ -1066,6 +1077,7 @@ int Device::writeDevInfo(DevInfoTypes type, std::string val) { case kDevPCIEClk: case kDevPowerODVoltage: case kDevSOCClk: + case kDevPtlFormat: return writeDevInfoStr(type, val); case kDevComputePartition: case kDevMemoryPartition: @@ -1521,6 +1533,9 @@ int Device::readDevInfo(DevInfoTypes type, std::string *val) { case kDevJpegShared: case kDevXccInst: case kDevXccShared: + case kDevPtlSupported: + case kDevPtlStatus: + case kDevPtlFormat: return readDevInfoStr(type, val); break; diff --git a/projects/amdsmi/src/amd_smi/amd_smi.cc b/projects/amdsmi/src/amd_smi/amd_smi.cc index 82c6ddc8c8..2004c16793 100644 --- a/projects/amdsmi/src/amd_smi/amd_smi.cc +++ b/projects/amdsmi/src/amd_smi/amd_smi.cc @@ -5251,6 +5251,202 @@ amdsmi_get_gpu_virtualization_mode(amdsmi_processor_handle processor_handle, return status; } +// PTL + +bool amdsmi_is_supported_format( + const std::vector &supported, + amdsmi_ptl_data_format_t fmt) { + return std::find(supported.begin(), supported.end(), fmt) != supported.end(); +} + +amdsmi_status_t +amdsmi_get_gpu_ptl_state(amdsmi_processor_handle processor_handle, bool *enabled) { + return rsmi_wrapper(rsmi_get_gpu_ptl_state, processor_handle, 0, enabled); +} + +amdsmi_status_t +amdsmi_set_gpu_ptl_state(amdsmi_processor_handle processor_handle, bool enable) { + return rsmi_wrapper(rsmi_set_gpu_ptl_state, processor_handle, 0, enable); +} + +// Mapping for PTL string <-> enum +struct PtlFormatMapEntry { + const char* token; + amdsmi_ptl_data_format_t fmt; +}; + +PtlFormatMapEntry kPtlFormatMap[] = { + {"I8", AMDSMI_PTL_DATA_FORMAT_I8}, + {"F16", AMDSMI_PTL_DATA_FORMAT_F16}, + {"BF16", AMDSMI_PTL_DATA_FORMAT_BF16}, + {"F32", AMDSMI_PTL_DATA_FORMAT_F32}, + {"F64", AMDSMI_PTL_DATA_FORMAT_F64}, +}; +static constexpr size_t kPtlFormatMapSize = + sizeof(kPtlFormatMap) / sizeof(kPtlFormatMap[0]); + +// Given string, return ptl data format enum +amdsmi_ptl_data_format_t token_to_amdsmi_fmt(std::string token) { + token = amd::smi::trim(token); + if (token.empty()) { + return AMDSMI_PTL_DATA_FORMAT_INVALID; + } + + // Ensure upper case for comparison + for (auto &c : token) { + c = std::toupper(static_cast(c)); + } + + for (size_t i = 0; i < kPtlFormatMapSize; ++i) { + if (token == kPtlFormatMap[i].token) { + return kPtlFormatMap[i].fmt; + } + } + return AMDSMI_PTL_DATA_FORMAT_INVALID; +} + +// Given ptl format, return string representation +const char* amdsmi_fmt_to_token(amdsmi_ptl_data_format_t fmt) { + for (size_t i = 0; i < kPtlFormatMapSize; ++i) { + if (kPtlFormatMap[i].fmt == fmt) { + return kPtlFormatMap[i].token; + } + } + return "N/A"; +} + +// Internal only helper to create supported ptl formats +amdsmi_status_t amdsmi_read_supported_ptl_formats( + amdsmi_processor_handle processor_handle, + std::vector &out) { + + out.clear(); + + std::string line; + { + char buf[AMDSMI_MAX_STRING_LENGTH] = {0}; + amdsmi_status_t st = rsmi_wrapper( + rsmi_read_supported_ptl_formats, processor_handle, 0, buf, AMDSMI_MAX_STRING_LENGTH); + + if (st != AMDSMI_STATUS_SUCCESS) { + return st; + } + line.assign(buf); + } + + line = amd::smi::trim(line); + auto tokens = split_string(line, ','); + if (tokens.empty()) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + for (const auto &t : tokens) { + amdsmi_ptl_data_format_t f = token_to_amdsmi_fmt(t); + if (f == AMDSMI_PTL_DATA_FORMAT_INVALID) { + return AMDSMI_STATUS_UNEXPECTED_DATA; + } + out.push_back(f); + } + return AMDSMI_STATUS_SUCCESS; +} + +amdsmi_status_t +amdsmi_get_gpu_ptl_formats(amdsmi_processor_handle processor_handle, + amdsmi_ptl_data_format_t *data_format1, + amdsmi_ptl_data_format_t *data_format2) +{ + + if (data_format1 == nullptr || data_format2 == nullptr) { + return AMDSMI_STATUS_ARG_PTR_NULL; + } + *data_format1 = AMDSMI_PTL_DATA_FORMAT_INVALID; + *data_format2 = AMDSMI_PTL_DATA_FORMAT_INVALID; + + // Ensure PTL enabled + bool enabled = false; + amdsmi_status_t st = amdsmi_get_gpu_ptl_state(processor_handle, &enabled); + if (st != AMDSMI_STATUS_SUCCESS) { + return st; + } + if (!enabled) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + // Read ptl sysfs + std::string line; + { + char buf[AMDSMI_MAX_STRING_LENGTH] = {0}; + st = rsmi_wrapper(rsmi_get_gpu_ptl_formats, processor_handle, 0, buf, AMDSMI_MAX_STRING_LENGTH); + if (st != AMDSMI_STATUS_SUCCESS) { + return st; + } + line.assign(buf); + } + + line = amd::smi::trim(line); + auto tokens = split_string(line, ','); + if (tokens.empty() || tokens.size() != 2) { + return AMDSMI_STATUS_UNEXPECTED_SIZE; // malformed sysfs content + } + + // Parse tokens + amdsmi_ptl_data_format_t f1 = token_to_amdsmi_fmt(tokens[0]); + if (f1 == AMDSMI_PTL_DATA_FORMAT_INVALID) { + return AMDSMI_STATUS_UNEXPECTED_DATA; + } + + amdsmi_ptl_data_format_t f2 = token_to_amdsmi_fmt(tokens[1]); + if (f2 == AMDSMI_PTL_DATA_FORMAT_INVALID) { + return AMDSMI_STATUS_UNEXPECTED_DATA; + } + + *data_format1 = f1; + *data_format2 = f2; + return AMDSMI_STATUS_SUCCESS; +} + +amdsmi_status_t +amdsmi_set_gpu_ptl_formats(amdsmi_processor_handle processor_handle, + amdsmi_ptl_data_format_t data_format1, + amdsmi_ptl_data_format_t data_format2) +{ + + if (data_format1 == AMDSMI_PTL_DATA_FORMAT_INVALID || + data_format2 == AMDSMI_PTL_DATA_FORMAT_INVALID || + data_format1 == data_format2) { + return AMDSMI_STATUS_UNEXPECTED_DATA; + } + + // Ensure PTL enabled + bool enabled = false; + amdsmi_status_t st = amdsmi_get_gpu_ptl_state(processor_handle, &enabled); + if (st != AMDSMI_STATUS_SUCCESS) { + return st; + } + if (!enabled) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + // Read supported formats and check both are allowed + std::vector supported; + st = amdsmi_read_supported_ptl_formats(processor_handle, supported); + if (st != AMDSMI_STATUS_SUCCESS) { + return st; + } + + if (!amdsmi_is_supported_format(supported, data_format1) || + !amdsmi_is_supported_format(supported, data_format2)) { + return AMDSMI_STATUS_NOT_SUPPORTED; + } + + // Convert enums to string + std::string format = + std::string(amdsmi_fmt_to_token(data_format1)) + "," + + amdsmi_fmt_to_token(data_format2); + + return rsmi_wrapper(rsmi_set_gpu_ptl_formats, processor_handle, 0, format.c_str()); +} + amdsmi_status_t amdsmi_get_cpu_affinity_with_scope(amdsmi_processor_handle processor_handle, uint32_t cpu_set_size, uint64_t *cpu_set, amdsmi_affinity_scope_t scope) { diff --git a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc index 0d92421c93..8941c5f68e 100644 --- a/projects/amdsmi/src/amd_smi/amd_smi_utils.cc +++ b/projects/amdsmi/src/amd_smi/amd_smi_utils.cc @@ -793,6 +793,25 @@ std::string smi_amdgpu_split_string(std::string str, char delim) { return ""; } +// Split string at delimiter and return strings in vector +std::vector split_string(const std::string& line, char delim) { + std::vector out; + std::size_t start = 0; + + while (start < line.size()) { + auto pos = line.find(delim, start); + if (pos == std::string::npos) { + pos = line.size(); + } + std::string token = trim(line.substr(start, pos - start)); + if (!token.empty()) { + out.push_back(token); + } + start = pos + 1; + } + return out; +} + // wrapper to return string expression of a rsmi_status_t return // rsmi_status_t ret - return value of RSMI API function // bool fullStatus - defaults to true, set to false to chop off description