diff --git a/src/rocprof_compute_soc/soc_base.py b/src/rocprof_compute_soc/soc_base.py index 13ada9f73c..30e4be66aa 100644 --- a/src/rocprof_compute_soc/soc_base.py +++ b/src/rocprof_compute_soc/soc_base.py @@ -186,12 +186,73 @@ class OmniSoC_Base: self._mspec.gpu_model = mi_gpu_specs.get_gpu_model( self._mspec.gpu_arch, self._mspec.gpu_chip_id ) + + if not self._mspec.gpu_model: + self._mspec.gpu_model = self.detect_gpu_model(self._mspec.gpu_arch) + self._mspec.num_xcd = str( mi_gpu_specs.get_num_xcds( - self._mspec.gpu_model, self._mspec.compute_partition + self._mspec.gpu_arch, self._mspec.gpu_model, self._mspec.compute_partition ) ) + @demarcate + def detect_gpu_model(self, gpu_arch): + """ + Detects the GPU model using various identifiers from 'amd-smi static'. + Falls back through multiple methods if the primary method fails. + """ + + from utils.specs import run, search + + # TODO: use amd-smi python api when available + amd_smi_static = run(["amd-smi", "static", "--gpu=0"], exit_on_error=True) + + # Purposely search for patterns without variants suffix to try and match a known GPU model. + detection_methods = [ + { + "name": "Market Name", + "pattern": r"MARKET_NAME:\s*.*(mi|MI\d*[a-zA-Z]*)", + }, + { + "name": "VBIOS Name", + "pattern": r"NAME:\s*.*(mi|MI\d*[a-zA-Z]*)", + }, + {"name": "Product Name", "pattern": r"PRODUCT_NAME:\s*.*(mi|MI\d*[a-zA-Z]*)"}, + ] + + gpu_model = None + for method in detection_methods: + console_log(f"Determining GPU model using {method['name']}.") + gpu_model = search(method["pattern"], amd_smi_static) + if gpu_model: + break + + if not gpu_model: + console_warning("Unable to determine the GPU model.") + return + + gpu_model = self._adjust_mi300_model(gpu_model.lower(), gpu_arch.lower()) + + if gpu_model.lower() not in mi_gpu_specs.get_num_xcds_dict().keys(): + console_warning(f"Unknown GPU model detected: '{gpu_model}'.") + return + + return gpu_model.upper() + + def _adjust_mi300_model(self, gpu_model, gpu_arch): + """ + Applies specific adjustments for MI300 series GPU models based on architecture. + """ + + if gpu_model in ["mi300a", "mi300x"]: + if gpu_arch in ["gfx940", "gfx941"]: + gpu_model += "_a0" + elif gpu_arch == "gfx942": + gpu_model += "_a1" + + return gpu_model + @demarcate def detect_counters(self): """ diff --git a/src/rocprof_compute_soc/soc_gfx906.py b/src/rocprof_compute_soc/soc_gfx906.py index dee7022e10..3619167b81 100644 --- a/src/rocprof_compute_soc/soc_gfx906.py +++ b/src/rocprof_compute_soc/soc_gfx906.py @@ -22,11 +22,9 @@ # SOFTWARE. ##############################################################################el -from pathlib import Path - -import config from rocprof_compute_soc.soc_base import OmniSoC_Base from utils.logger import console_error, demarcate +from utils.mi_gpu_spec import mi_gpu_specs class gfx906_soc(OmniSoC_Base): @@ -35,20 +33,7 @@ class gfx906_soc(OmniSoC_Base): self.set_arch("gfx906") self.set_compatible_profilers(["rocprofv1", "rocscope"]) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config({mi_gpu_specs.get_perfmon_config("gfx906")}) # Set arch specific specs self._mspec._l2_banks = 16 diff --git a/src/rocprof_compute_soc/soc_gfx908.py b/src/rocprof_compute_soc/soc_gfx908.py index 54e7c4a7a5..2957e83104 100644 --- a/src/rocprof_compute_soc/soc_gfx908.py +++ b/src/rocprof_compute_soc/soc_gfx908.py @@ -27,6 +27,7 @@ from pathlib import Path import config from rocprof_compute_soc.soc_base import OmniSoC_Base from utils.logger import console_error, demarcate +from utils.mi_gpu_spec import mi_gpu_specs class gfx908_soc(OmniSoC_Base): @@ -37,20 +38,7 @@ class gfx908_soc(OmniSoC_Base): ["rocprofv1", "rocscope", "rocprofv3", "rocprofiler-sdk"] ) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx908")) # Set arch specific specs self._mspec._l2_banks = 32 diff --git a/src/rocprof_compute_soc/soc_gfx90a.py b/src/rocprof_compute_soc/soc_gfx90a.py index 56e1dc39d6..a034675bcc 100644 --- a/src/rocprof_compute_soc/soc_gfx90a.py +++ b/src/rocprof_compute_soc/soc_gfx90a.py @@ -28,6 +28,7 @@ import config from rocprof_compute_soc.soc_base import OmniSoC_Base from roofline import Roofline from utils.logger import console_log, console_warning, demarcate +from utils.mi_gpu_spec import mi_gpu_specs from utils.utils import mibench @@ -50,20 +51,7 @@ class gfx90a_soc(OmniSoC_Base): ["rocprofv1", "rocscope", "rocprofv2", "rocprofv3", "rocprofiler-sdk"] ) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx90a")) # Create roofline object if mode is provided; skip for --specs if hasattr(self.get_args(), "mode") and self.get_args().mode: self.roofline_obj = Roofline(args, self._mspec) diff --git a/src/rocprof_compute_soc/soc_gfx940.py b/src/rocprof_compute_soc/soc_gfx940.py index 9a007cc8ab..8145693e21 100644 --- a/src/rocprof_compute_soc/soc_gfx940.py +++ b/src/rocprof_compute_soc/soc_gfx940.py @@ -28,6 +28,7 @@ import config from rocprof_compute_soc.soc_base import OmniSoC_Base from roofline import Roofline from utils.logger import console_error, console_log, console_warning, demarcate +from utils.mi_gpu_spec import mi_gpu_specs from utils.utils import mibench @@ -50,20 +51,7 @@ class gfx940_soc(OmniSoC_Base): ["rocprofv1", "rocprofv2", "rocprofv3", "rocprofiler-sdk"] ) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx940")) # Create roofline object if mode is provided; skip for --specs if hasattr(self.get_args(), "mode") and self.get_args().mode: self.roofline_obj = Roofline(args, self._mspec) diff --git a/src/rocprof_compute_soc/soc_gfx941.py b/src/rocprof_compute_soc/soc_gfx941.py index a360302e75..105bb1cde1 100644 --- a/src/rocprof_compute_soc/soc_gfx941.py +++ b/src/rocprof_compute_soc/soc_gfx941.py @@ -28,6 +28,7 @@ import config from rocprof_compute_soc.soc_base import OmniSoC_Base from roofline import Roofline from utils.logger import console_error, console_log, console_warning, demarcate +from utils.mi_gpu_spec import mi_gpu_specs from utils.utils import mibench @@ -50,20 +51,7 @@ class gfx941_soc(OmniSoC_Base): ["rocprofv1", "rocprofv2", "rocprofv3", "rocprofiler-sdk"] ) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx941")) # Create roofline object if mode is provided; skip for --specs if hasattr(self.get_args(), "mode") and self.get_args().mode: self.roofline_obj = Roofline(args, self._mspec) diff --git a/src/rocprof_compute_soc/soc_gfx942.py b/src/rocprof_compute_soc/soc_gfx942.py index 0efb5d85bd..0fb2c08ac3 100644 --- a/src/rocprof_compute_soc/soc_gfx942.py +++ b/src/rocprof_compute_soc/soc_gfx942.py @@ -28,6 +28,7 @@ import config from rocprof_compute_soc.soc_base import OmniSoC_Base from roofline import Roofline from utils.logger import console_error, console_log, console_warning, demarcate +from utils.mi_gpu_spec import mi_gpu_specs from utils.utils import mibench @@ -50,20 +51,7 @@ class gfx942_soc(OmniSoC_Base): ["rocprofv1", "rocprofv2", "rocprofv3", "rocprofiler-sdk"] ) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx942")) # Create roofline object if mode is provided; skip for --specs if hasattr(self.get_args(), "mode") and self.get_args().mode: self.roofline_obj = Roofline(args, self._mspec) diff --git a/src/rocprof_compute_soc/soc_gfx950.py b/src/rocprof_compute_soc/soc_gfx950.py index 63a1d5ce3e..2d24cd61da 100644 --- a/src/rocprof_compute_soc/soc_gfx950.py +++ b/src/rocprof_compute_soc/soc_gfx950.py @@ -27,8 +27,9 @@ from pathlib import Path import config from rocprof_compute_soc.soc_base import OmniSoC_Base from roofline import Roofline -from utils.logger import demarcate -from utils.utils import console_error, console_log, console_warning, mibench +from utils.logger import console_error, console_log, console_warning, demarcate +from utils.mi_gpu_spec import mi_gpu_specs +from utils.utils import mibench class gfx950_soc(OmniSoC_Base): @@ -48,21 +49,7 @@ class gfx950_soc(OmniSoC_Base): ) self.set_compatible_profilers(["rocprofv3", "rocprofiler-sdk"]) # Per IP block max number of simultaneous counters. GFX IP Blocks - self.set_perfmon_config( - { - "SQ": 8, - "TA": 2, - "TD": 2, - "TCP": 4, - "TCC": 4, - "CPC": 2, - "CPF": 2, - "SPI": 2, - "GRBM": 2, - "GDS": 4, - "TCC_channels": 16, - } - ) + self.set_perfmon_config(mi_gpu_specs.get_perfmon_config("gfx950")) # Create roofline object if mode is provided; skip for --specs if hasattr(self.get_args(), "mode") and self.get_args().mode: self.roofline_obj = Roofline(args, self._mspec) diff --git a/src/utils/mi_gpu_spec.py b/src/utils/mi_gpu_spec.py index a75a2a7802..3d23e1ece3 100644 --- a/src/utils/mi_gpu_spec.py +++ b/src/utils/mi_gpu_spec.py @@ -1,10 +1,10 @@ import os -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Dict import yaml -from utils.logger import console_debug, console_error, console_log, console_warning +from utils.logger import console_debug, console_error, console_warning # Constants for MI series # NOTE: Currently supports MI50, MI100, MI200, MI300 @@ -32,10 +32,15 @@ MI_CONSTANS = { class MIGPUSpecs: _instance = None - _gpu_series_dict = {} # key: gpu arch + _gpu_series_dict = {} # key: gpu_arch _gpu_model_dict = {} # key: gpu_arch - _num_xcds_dict = {} # key: gpu model - _chip_id_dict = {} # key: chip id (int) + _num_xcds_dict = {} # key: gpu_model + _chip_id_dict = {} # key: chip_id (int) + _perfmon_config = {} # key: gpu_arch + + _gpu_arch_to_compute_partition_dict = ( + {} + ) # key: gpu_arch, used for gpu archs containing only one gpu model and thus one compute partition _initialized = False @@ -88,9 +93,14 @@ class MIGPUSpecs: MI GPUs |-- series |-- architecture (list) + |-- perfmon_config |-- gpu model |-- chip_ids + | -- physical + | -- virtual |-- partition_mode + | -- compute partition mode + | -- memory partition mode """ current_dir = os.path.dirname(__file__) @@ -105,6 +115,7 @@ class MIGPUSpecs: for archs in series["gpu_archs"]: curr_gpu_arch = archs["gpu_arch"] cls._gpu_series_dict[curr_gpu_arch] = curr_gpu_series + cls._perfmon_config[curr_gpu_arch] = archs["perfmon_config"] cls._gpu_model_dict[curr_gpu_arch] = [] for models in archs["models"]: curr_gpu_model = models["gpu_model"] @@ -119,6 +130,28 @@ class MIGPUSpecs: if "chip_ids" in models and "virtual" in models["chip_ids"]: cls._chip_id_dict[models["chip_ids"]["virtual"]] = curr_gpu_model + # detect gpu arch to compute partition relationships + cls._populate_gpu_arch_to_compute_partition_dict() + + @classmethod + def _populate_gpu_arch_to_compute_partition_dict(cls): + """ + This creates a mapping of gpu_arch -> compute_partition for architectures + where there's only one model (and therefore one partition configuration). + """ + for gpu_arch, gpu_models in cls._gpu_model_dict.items(): + if len(gpu_models) == 1: + single_model = gpu_models[0] + compute_partition = cls._num_xcds_dict.get(single_model) + + if compute_partition is not None: + cls._gpu_arch_to_compute_partition_dict[gpu_arch] = compute_partition + console_debug( + "[populate_single_arch_partition_dict] Single model arch found: " + "%s -> %s (partition: %s)" + % (gpu_arch, single_model, compute_partition) + ) + @classmethod def get_gpu_series_dict(cls): if not cls._gpu_series_dict: @@ -146,6 +179,19 @@ class MIGPUSpecs: console_warning(f"No matching gpu series found for gpu arch: {gpu_arch_}") return None + @classmethod + def get_perfmon_config(cls, gpu_arch_): + # Check that gpu_model_dict is populated first + if not cls._perfmon_config: + console_error( + "gpu_model_dict not yet populated. Did you run parse_mi_gpu_spec()?" + ) + return None + + gpu_arch_lower = gpu_arch_.lower() + + return cls._perfmon_config.get(gpu_arch_lower, None) + @classmethod def get_gpu_model(cls, gpu_arch_, chip_id_): # Check that gpu_model_dict is populated first @@ -180,38 +226,99 @@ class MIGPUSpecs: return gpu_model.upper() @classmethod - def get_num_xcds(cls, gpu_model_, compute_partition_): - # Only gpu in and above mi 300 series have more than one XCDs - if gpu_model_.lower() in ("mi50", "mi60", "mi100", "mi210", "mi250", "mi250x"): + def set_default_gpu_settings(self, gpu_arch, gpu_model, compute_partition): + """ + Set default GPU settings when model is unknown or cannot be determined. + NOTE: This is a fallback to gfx942 settings - consider making this architecture-specific. + """ + DEFAULT_COMPUTE_PARTITION = "SPX" + DEFAULT_NUM_XCD = 8 + console_warning( + f"Unable to determine xcd count from:\n\t" + f"GPU arch: '{gpu_arch}', model: '{gpu_model}', partition: '{compute_partition}'" + ) + console_warning( + f"Applying default gfx942 settings:\n" + f"\t- Compute partition: {DEFAULT_COMPUTE_PARTITION}\n" + f"\t- Number of XCDs: {DEFAULT_NUM_XCD}" + ) + + return DEFAULT_NUM_XCD + + @classmethod + def get_num_xcds( + cls, gpu_arch: str = None, gpu_model: str = None, compute_partition: str = None + ): + """ + Retrieve the number of XCDs based on GPU architecture, model, and compute partition. + + Priority order: + 1. Legacy GPU check (returns 1 XCD for older architectures/models) + 2. Architecture-based lookup (preferred) + 3. Model + partition-based lookup (fallback) + 4. Default settings (last resort) + """ + # Constants for legacy GPUs that don't support compute partitions + LEGACY_ARCHS = {"gfx906", "gfx908", "gfx90a"} + LEGACY_MODELS = {"mi50", "mi60", "mi100", "mi210", "mi250", "mi250x"} + + # Normalize inputs to lowercase for consistent comparison + gpu_arch_norm = gpu_arch.lower().strip() if gpu_arch else "" + gpu_model_norm = gpu_model.lower().strip() if gpu_model else "" + partition_norm = compute_partition.lower().strip() if compute_partition else "" + + # 1. Return 1 XCDs for archs/models not supporting compute partition + # NOTE: gpu arch is enough to verify this logic, gpu model is used as a backup. + if gpu_arch_norm in LEGACY_ARCHS or gpu_model_norm in LEGACY_MODELS: return 1 - if not cls._num_xcds_dict: - console_error( - "mi300_num_xcds_dict not yet populated, did you run parse_mi_gpu_spec()?" - ) - return None + # 2. Try architecture-based lookup first (preferred method) + if gpu_arch_norm and hasattr(cls, "_gpu_arch_to_compute_partition_dict"): + arch_dict = cls._gpu_arch_to_compute_partition_dict + if gpu_arch_norm in arch_dict: + num_xcds = arch_dict[gpu_arch_norm] + if num_xcds is not None: + return num_xcds + else: + console_warning( + f"No compute partition data found for architecture '{gpu_arch.upper()}'" + ) - gpu_model_lower = gpu_model_.lower() - partition_lower = compute_partition_.lower() + # 3. Fall back to model + partition-based lookup + if gpu_model_norm: + # Validate XCD dictionary is populated + if not hasattr(cls, "_num_xcds_dict") or not cls._num_xcds_dict: + console_error( + "mi300_num_xcds_dict not populated. Did you run parse_mi_gpu_spec()?" + ) + elif gpu_model_norm not in cls._num_xcds_dict: + console_warning( + f"Unknown gpu model provided for num xcds lookup: {gpu_model}." + ) + else: + model_dict = cls._num_xcds_dict[gpu_model_norm] - if gpu_model_lower not in cls._num_xcds_dict: - return None + if not partition_norm: + console_warning( + "No compute partition provided for model-based lookup" + ) + elif partition_norm not in model_dict: + console_warning( + f"Unknown compute partition '{compute_partition}' for model '{gpu_model}'" + ) + else: + num_xcds = model_dict[partition_norm] + if num_xcds is not None: + return num_xcds + else: + console_warning( + f"Unknown compute partition found for {compute_partition} / {gpu_model}" + ) + else: + console_warning("No gpu model provided for num xcds lookup.") - model_dict = cls._num_xcds_dict[gpu_model_lower] - if partition_lower not in model_dict: - console_log(f"Unknown compute partition: {compute_partition_}") - return None - - num_xcds = model_dict[partition_lower] - if not num_xcds: - console_warning( - "Unknown compute partition found for %s / %s", - compute_partition_, - gpu_model_, - ) - return None - - return num_xcds + # 4. Last resort: use default settings + return cls.set_default_gpu_settings(gpu_arch, gpu_model, compute_partition) @classmethod def get_chip_id_dict(cls): @@ -220,7 +327,17 @@ class MIGPUSpecs: else: console_error() + @classmethod + def get_num_xcds_dict(cls): + if cls._num_xcds_dict: + return cls._num_xcds_dict + else: + console_error() + + @classmethod + def get_gpu_arch_to_compute_partition_dict(cls): + return cls._gpu_arch_to_compute_partition_dict + # pre-initialize the instance when module loads - mi_gpu_specs = MIGPUSpecs() diff --git a/src/utils/mi_gpu_spec.yaml b/src/utils/mi_gpu_spec.yaml index dc07e8a631..a897fb28b4 100644 --- a/src/utils/mi_gpu_spec.yaml +++ b/src/utils/mi_gpu_spec.yaml @@ -9,8 +9,11 @@ # MI GPUs # |-- series: the specific MI series; mi50, mi100, mi200, mi300 # |-- architecture: currently, only mi300 gpus hold different architectures +# |-- perfmon_config # |-- gpu model # |-- chip_ids: chip id is specific to the environment the gpu is being used on +# | -- physical +# | -- virtual # |-- partition_mode # | -- compute partition mode # | -- memory partition mode @@ -21,6 +24,17 @@ mi_gpu_spec: - gpu_series: mi50 gpu_archs: - gpu_arch: gfx906 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi50 - gpu_model: mi60 @@ -28,6 +42,17 @@ mi_gpu_spec: - gpu_series: mi100 gpu_archs: - gpu_arch: gfx908 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi100 chip_ids: @@ -36,6 +61,17 @@ mi_gpu_spec: - gpu_series: mi200 gpu_archs: - gpu_arch: gfx90a + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi210 chip_ids: @@ -46,12 +82,21 @@ mi_gpu_spec: - gpu_model: mi250x chip_ids: physical: 29704 - - gpu_model: mi250 - - gpu_model: mi250x - gpu_series: mi300 gpu_archs: - gpu_arch: gfx940 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi300a_a0 partition_mode: @@ -59,11 +104,29 @@ mi_gpu_spec: num_xcds: spx: 6 tpx: 2 + cpx: 1 memory_partition_mode: - nps4: [tpx] - nps1: [spx, tpx] + nps4: + tpx: 3 + nps1: + spx: 1 + tpx: 3 + chip_ids: + physical: null + virtual: null - gpu_arch: gfx941 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi300x_a0 partition_mode: @@ -74,10 +137,31 @@ mi_gpu_spec: qpx: 2 cpx: 1 memory_partition_mode: - nps4: [qpx, cpx] - nps1: [spx, qpx, cpx] + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 + chip_ids: + physical: null + virtual: null - gpu_arch: gfx942 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 models: - gpu_model: mi300a_a1 partition_mode: @@ -85,9 +169,14 @@ mi_gpu_spec: num_xcds: spx: 6 tpx: 2 + cpx: 1 memory_partition_mode: - nps4: [tpx] - nps1: [spx, tpx] + nps4: + tpx: 3 + nps1: + spx: 1 + tpx: 3 + cpx: 8 chip_ids: physical: 29856 virtual: 29876 @@ -101,12 +190,41 @@ mi_gpu_spec: qpx: 2 cpx: 1 memory_partition_mode: - nps4: [qpx, cpx] - nps1: [spx, qpx, cpx] + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 chip_ids: physical: 29857 virtual: 29877 + - gpu_model: mi300xhf + partition_mode: + compute_partition_mode: + num_xcds: + spx: 8 + dpx: 4 + qpx: 2 + cpx: 1 + memory_partition_mode: + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 + chip_ids: + physical: 29865 + virtual: 29885 + - gpu_model: mi308x partition_mode: compute_partition_mode: @@ -115,12 +233,34 @@ mi_gpu_spec: dpx: 2 cpx: 1 memory_partition_mode: - nps4: [cpx] - nps1: [spx, dpx, cpx] + nps4: + cpx: 8 + nps1: + spx: 1 + qpx: 4 + cpx: 8 chip_ids: physical: 29858 virtual: 29878 + - gpu_model: mi308xhf + partition_mode: + compute_partition_mode: + num_xcds: + spx: 4 + dpx: 2 + cpx: 1 + memory_partition_mode: + nps4: + cpx: 8 + nps1: + spx: 1 + qpx: 4 + cpx: 8 + chip_ids: + physical: 29864 + virtual: 29884 + - gpu_model: mi325x partition_mode: compute_partition_mode: @@ -130,8 +270,15 @@ mi_gpu_spec: qpx: 2 cpx: 1 memory_partition_mode: - nps4: [qpx, cpx] - nps1: [spx, qpx, cpx] + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 chip_ids: physical: 29861 virtual: 29881 @@ -139,6 +286,18 @@ mi_gpu_spec: - gpu_series: mi350 gpu_archs: - gpu_arch: gfx950 + perfmon_config: + SQ: 8 + TA: 2 + TD: 2 + TCP: 4 + TCC: 4 + CPC: 2 + CPF: 2 + SPI: 2 + GRBM: 2 + GDS: 4 + TCC_channels: 16 models: - gpu_model: mi350 partition_mode: @@ -149,7 +308,55 @@ mi_gpu_spec: qpx: 2 cpx: 1 memory_partition_mode: - nps1: [spx, dpx, qpx, cpx] - nps4: [qpx, cpx] + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 chip_ids: physical: 30112 + virutal: 30128 + - gpu_model: mi355 + partition_mode: + compute_partition_mode: + num_xcds: + spx: 8 + dpx: 4 + qpx: 2 + cpx: 1 + memory_partition_mode: + nps4: + qpx: 4 + cpx: 8 + nps2: + dpx: 2 + nps1: + spx: 1 + qpx: 4 + cpx: 8 + chip_ids: + physical: 30115 + virtual: 30131 + - gpu_model: mi358 + partition_mode: + compute_partition_mode: + num_xcds: + spx: 8 + dpx: 4 + qpx: 2 + cpx: 1 + memory_partition_mode: + nps4: + qpx: 4 + cpx: 8 + nps1: + spx: 1 + qpx: 4 + cpx: 8 + chip_ids: + physical: 30114 + virtual: 30130 \ No newline at end of file diff --git a/src/utils/specs.py b/src/utils/specs.py index 7bb65b32dc..7dfe1205f3 100644 --- a/src/utils/specs.py +++ b/src/utils/specs.py @@ -38,13 +38,7 @@ from pathlib import Path as path import pandas as pd import config -from utils.logger import ( - console_debug, - console_error, - console_log, - console_warning, - demarcate, -) +from utils.logger import console_debug, console_error, console_log, console_warning from utils.mi_gpu_spec import mi_gpu_specs from utils.tty import get_table_string from utils.utils import get_version @@ -158,15 +152,40 @@ def generate_machine_specs(args, sysinfo: dict = None): rocm_version = get_rocm_ver().strip() # FIXME: use device + amd_smi_output = run(["amd-smi", "static"], exit_on_error=True) vbios_pattern = r"PART_NUMBER:\s*(\S+)" compute_partition_pattern = r"COMPUTE_PARTITION:\s*(\S+)" + accelerator_partition_pattern = r"ACCELERATOR_PARTITION:\s*(\S+)" memory_partition_pattern = r"MEMORY_PARTITION:\s*(\S+)" - vbios = search(vbios_pattern, run(["amd-smi", "static"], exit_on_error=True)) - compute_partition = search(compute_partition_pattern, run(["amd-smi", "static"])) + rocm_smi_compute_partition_output = run( + ["rocm-smi", "--showcomputepartition"], exit_on_error=True + ) + rocm_smi_compute_partition_pattern = r"Compute Partition:\s*(\S+)" + + vbios = search(vbios_pattern, amd_smi_output) + # 1. get compute partition from amd-smi + compute_partition = search(compute_partition_pattern, amd_smi_output) + console_debug(f"amd-smi compute partition: {compute_partition}") + # 2. get compute partition from rocm-smi if compute_partition is None: - compute_partition = "NA" - memory_partition = search(memory_partition_pattern, run(["amd-smi", "static"])) + compute_partition = search( + rocm_smi_compute_partition_pattern, rocm_smi_compute_partition_output + ) + console_debug(f"rocm-smi compute partition: {compute_partition}") + # 3. get compute partition from amd-smi using keyword accelerator + if compute_partition is None: + compute_partition = search(accelerator_partition_pattern, amd_smi_output) + console_debug(f"amd-smi accelerator partition: {compute_partition}") + # 4. apply default compute partition + if compute_partition is None: + console_warning( + f"Can not detect compute/accelerator partition from amd-smi and rocm-smi." + ) + console_warning(f"Applying default compute partition: SPX") + compute_partition = "SPX" + + memory_partition = search(memory_partition_pattern, amd_smi_output) if memory_partition is None: memory_partition = "NA" @@ -216,8 +235,12 @@ def generate_machine_specs(args, sysinfo: dict = None): soc_class = getattr(soc_module, specs.gpu_arch + "_soc") soc_obj = soc_class(args, specs) # Update arch specific specs + specs.gpu_model = mi_gpu_specs.get_gpu_model(specs.gpu_arch, specs.gpu_chip_id) + specs.num_xcd = mi_gpu_specs.get_num_xcds( + specs.gpu_arch, specs.gpu_model, specs.compute_partition + ) specs.total_l2_chan: str = total_l2_banks( - specs.gpu_model, int(specs._l2_banks), specs.compute_partition + specs.gpu_arch, specs.gpu_model, specs._l2_banks, specs.compute_partition ) specs.num_hbm_channels: str = str(specs.get_hbm_channels()) return specs @@ -673,10 +696,13 @@ def total_sqc(archname, numCUs, numSEs): return int(sq_per_se) * int(numSEs) -def total_l2_banks(archname, L2Banks, compute_partition): - xcds = mi_gpu_specs.get_num_xcds(archname, compute_partition) - totalL2Banks = L2Banks * xcds - return totalL2Banks +def total_l2_banks(gpu_arch, gpu_model, L2Banks, compute_partition): + xcd_count = mi_gpu_specs.get_num_xcds(gpu_arch, gpu_model, compute_partition) + + # TODO: MachineSpecs and OmniSoC mspec should converge... + if L2Banks is not None and xcd_count is not None: + return int(L2Banks) * int(xcd_count) + return None if __name__ == "__main__": diff --git a/src/utils/utils.py b/src/utils/utils.py index cd8ba60e61..0d31ce553d 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -756,7 +756,9 @@ def run_prof( if new_env and not using_v3() and not using_v1(): # flatten tcc for applicable mi300 input f = path(workload_dir + "/out/pmc_1/results_" + fbase + ".csv") - xcds = mi_gpu_specs.get_num_xcds(mspec.gpu_model, mspec.compute_partition) + xcds = mi_gpu_specs.get_num_xcds( + mspec.gpu_arch, mspec.gpu_model, mspec.compute_partition + ) df = flatten_tcc_info_across_xcds(f, xcds, int(mspec._l2_banks)) df.to_csv(f, index=False) diff --git a/tests/test_gpu_specs.py b/tests/test_gpu_specs.py index 84acb27033..4844ab86e2 100644 --- a/tests/test_gpu_specs.py +++ b/tests/test_gpu_specs.py @@ -22,6 +22,10 @@ GFX942_CHIP_IDS_TO_NUM_XCDS = { "29878": {"spx": 4, "dpx": 2, "cpx": 1}, "29861": {"spx": 8, "dpx": 4, "qpx": 2, "cpx": 1}, "29881": {"spx": 8, "dpx": 4, "qpx": 2, "cpx": 1}, + "29864": {"spx": 4, "dpx": 2, "cpx": 1}, + "29884": {"spx": 4, "dpx": 2, "cpx": 1}, + "29865": {"spx": 8, "dpx": 4, "qpx": 2, "cpx": 1}, + "29885": {"spx": 8, "dpx": 4, "qpx": 2, "cpx": 1}, } # helper to strip ANSI color codes if your app uses them @@ -91,17 +95,37 @@ def get_num_xcds(): if str(chip_id) in GFX942_CHIP_IDS_TO_NUM_XCDS.keys(): num_xcds = GFX942_CHIP_IDS_TO_NUM_XCDS[str(chip_id)] + if num_xcds is None: + return + return num_xcds +def get_gpu_arch(): + + rocminfo = str( + # decode with utf-8 to account for rocm-smi changes in latest rocm + subprocess.run( + ["rocminfo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ).stdout.decode("utf-8") + ) + rocminfo = rocminfo.split("\n") + + soc_regex = re.compile(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", re.MULTILINE) + devices = list(filter(soc_regex.match, rocminfo)) + gpu_arch = devices[0].split()[1] + return gpu_arch + + @pytest.mark.num_xcds_spec_class def test_num_xcds_spec_class(monkeypatch): - num_xcds = get_num_xcds() - # 1. Check if gfx942 soc - if not num_xcds: + gpu_arch = get_gpu_arch() + if gpu_arch is None or gpu_arch.lower() != "gfx942": pytest.skip("Skipping num xcds test for non-gfx942 socs.") + num_xcds = get_num_xcds() + # 2. load machine specs machine_spec = generate_machine_specs(None) @@ -114,12 +138,13 @@ def test_num_xcds_spec_class(monkeypatch): @pytest.mark.num_xcds_cli_output def test_num_xcds_cli_output(): - num_xcds = get_num_xcds() - # 1. Check if gfx942 soc - if not num_xcds: + gpu_arch = get_gpu_arch() + if gpu_arch is None or gpu_arch.lower() != "gfx942": pytest.skip("Skipping num xcds test for non-gfx942 socs.") + num_xcds = get_num_xcds() + # 2. Run rocprof-compute -s and grab rocprof-compute num_xcd proc = subprocess.run( ["rocprof-compute", "-s"],