diff --git a/src/utils/specs.py b/src/utils/specs.py index a528adc7a9..02f58489a6 100644 --- a/src/utils/specs.py +++ b/src/utils/specs.py @@ -37,7 +37,7 @@ from math import ceil from dataclasses import dataclass, field, fields from pathlib import Path as path from utils.utils import ( - get_hbm_stack_num, + total_xcds, get_version, console_error, console_warning, @@ -184,7 +184,7 @@ def generate_machine_specs(args, sysinfo: dict = None): soc_obj = soc_class(args, specs) # Update arch specific specs specs.total_l2_chan: str = total_l2_banks( - specs.gpu_model, int(specs._l2_banks), specs.memory_partition + specs.gpu_model, int(specs._l2_banks), specs.compute_partition ) specs.hbm_bw: str = str(int(specs.max_mclk) / 1000 * 32 * specs.get_hbm_channels()) return specs @@ -480,7 +480,7 @@ class MachineSpecs: "doc": "The peak theoretical HBM bandwidth for the accelerators/GPUs in the system. On systems with\n" "configurable partitioning, (e.g., MI300) this is the peak theoretical HBM bandwidth for a partition.", "name": "HBM BW", - "unit": "MB/s", + "unit": "GB/s", }, ) num_xcd: str = field( @@ -489,17 +489,26 @@ class MachineSpecs: "doc": "The total number of accelerator complex dies in a compute partition on the accelerators/GPUs in the\n" "system. For accelerators without partitioning (i.e., pre-MI300), this is considered to be one.", "name": "Num XCDs", - "unit": "MB/s", + "unit": "XCDs", }, ) def get_hbm_channels(self): - hbmchannels = int(self.total_l2_chan) - if ( - self.gpu_model.lower() == "mi300a_a0" or self.gpu_model.lower() == "mi300a_a1" - ) and self.memory_partition.lower() == "nps1": - # we have an extra 32 channels for the CCD - hbmchannels += 32 + # check MI300 has a valid compute partition + mi300a_archs = ["mi300a_a0", "mi300a_a1"] + mi300x_archs = ["mi300x_a0", "mi300x_a1"] + mi308x_archs = ["mi308x"] + if self.gpu_model.lower() in mi300a_archs + mi300x_archs + mi308x_archs: + hbmchannels = 128 + if self.memory_partition.lower() == "nps2": + hbmchannels /= 2 + elif self.memory_partition.lower() == "nps4": + hbmchannels /= 4 + elif self.memory_partition.lower() == "nps8": + hbmchannels /= 8 + return int(hbmchannels) + else: + hbmchannels = int(self.total_l2_chan) return hbmchannels def get_class_members(self): @@ -618,17 +627,6 @@ def search(pattern, string): return None -def total_l2_banks(archname, L2Banks, memory_partition): - # Fixme: support all supported partitioning mode - # Fixme: "name" is a bad name! - totalL2Banks = L2Banks - if archname.lower() == "mi300a_a0" or archname.lower() == "mi300a_a1": - totalL2Banks = L2Banks * get_hbm_stack_num(archname, memory_partition) - elif archname.lower() == "mi300x_a0" or archname.lower() == "mi300x_a1": - totalL2Banks = L2Banks * get_hbm_stack_num(archname, memory_partition) - return str(totalL2Banks) - - def total_sqc(archname, numCUs, numSEs): cu_per_se = float(numCUs) / float(numSEs) sq_per_se = cu_per_se / 2 @@ -638,38 +636,12 @@ def total_sqc(archname, numCUs, numSEs): return int(sq_per_se) * int(numSEs) -def total_xcds(archname, compute_partition): - # check MI300 has a valid compute partition - mi300a_archs = ["mi300a_a0", "mi300a_a1"] - mi300x_archs = ["mi300x_a0", "mi300x_a1"] - if archname.lower() in mi300a_archs + mi300x_archs and compute_partition == "NA": - console_error("Invalid compute partition found for {}".format(archname)) - if archname.lower() not in mi300a_archs + mi300x_archs: - return 1 - # from the whitepaper - # https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/white-papers/amd-cdna-3-white-paper.pdf - if compute_partition.lower() == "spx": - if archname.lower() in mi300a_archs: - return 6 - if archname.lower() in mi300x_archs: - return 8 - if compute_partition.lower() == "tpx": - if archname.lower() in mi300a_archs: - return 2 - if compute_partition.lower() == "dpx": - if archname.lower() in mi300x_archs: - return 4 - if compute_partition.lower() == "qpx": - if archname.lower() in mi300x_archs: - return 2 - if compute_partition.lower() == "cpx": - if archname.lower() in mi300x_archs: - return 2 - console_error( - "Unknown compute partition / arch found for {} / {}".format( - compute_partition, archname - ) - ) +def total_l2_banks(archname, L2Banks, compute_partition): + # Fixme: support all supported partitioning mode + # Fixme: "name" is a bad name! + totalL2Banks = L2Banks + xcds = total_xcds(archname, compute_partition) + return L2Banks * xcds if __name__ == "__main__": diff --git a/src/utils/utils.py b/src/utils/utils.py index a808baea52..9869c562a0 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -285,8 +285,8 @@ def run_prof(fname, profiler_options, workload_dir, mspec, loglevel): if new_env: # flatten tcc for applicable mi300 input f = path(workload_dir + "/out/pmc_1/results_" + fbase + ".csv") - hbm_stack_num = get_hbm_stack_num(mspec.gpu_model, mspec.memory_partition) - df = flatten_tcc_info_across_hbm_stacks(f, hbm_stack_num, int(mspec._l2_banks)) + xcds = total_xcds(mspec.gpu_model, mspec.compute_partition) + df = flatten_tcc_info_across_xcds(f, xcds, int(mspec._l2_banks)) df.to_csv(f, index=False) if os.path.exists(workload_dir + "/out"): @@ -492,9 +492,9 @@ def mibench(args, mspec): ) -def flatten_tcc_info_across_hbm_stacks(file, stack_num, tcc_channel_per_stack): +def flatten_tcc_info_across_xcds(file, xcds, tcc_channel_per_xcd): """ - Flatten TCC per channel counters across all HBM stacks in used. + Flatten TCC per channel counters across all XCDs in partition. NB: This func highly depends on the default behavior of rocprofv2 on MI300, which might be broken anytime in the future! """ @@ -513,22 +513,22 @@ def flatten_tcc_info_across_hbm_stacks(file, stack_num, tcc_channel_per_stack): cols = non_tcc_cols_orig tcc_cols_in_group = {} - for i in range(0, stack_num): + for i in range(0, xcds): tcc_cols_in_group[i] = [] for col in tcc_cols_orig: - for i in range(0, stack_num): + for i in range(0, xcds): # filter the channel index only p = re.compile(r"\[(\d+)\]") # pick up the 1st element only r = ( lambda match: "[" - + str(int(match.group(1)) + i * tcc_channel_per_stack) + + str(int(match.group(1)) + i * tcc_channel_per_xcd) + "]" ) tcc_cols_in_group[i].append(re.sub(pattern=p, repl=r, string=col)) - for i in range(0, stack_num): + for i in range(0, xcds): # print(tcc_cols_in_group[i]) cols += tcc_cols_in_group[i] # print(cols) @@ -537,7 +537,7 @@ def flatten_tcc_info_across_hbm_stacks(file, stack_num, tcc_channel_per_stack): ### Rearrange data with extended column names # print(len(df_orig.index)) - for idx in range(0, len(df_orig.index), stack_num): + for idx in range(0, len(df_orig.index), xcds): # assume the front none TCC columns are the same for all XCCs df_non_tcc = df_orig.iloc[idx].filter(regex=r"^(?!.*TCC).*$") # display(df_non_tcc) @@ -545,7 +545,7 @@ def flatten_tcc_info_across_hbm_stacks(file, stack_num, tcc_channel_per_stack): # extract all tcc from one dispatch # NB: assuming default contiguous order might not be safe! - df_tcc_all = df_orig.iloc[idx : (idx + stack_num)].filter(regex="TCC") + df_tcc_all = df_orig.iloc[idx : (idx + xcds)].filter(regex="TCC") # display(df_tcc_all) for idx, row in df_tcc_all.iterrows(): @@ -557,36 +557,46 @@ def flatten_tcc_info_across_hbm_stacks(file, stack_num, tcc_channel_per_stack): return df -def get_hbm_stack_num(gpu_name, memory_partition): - """ - Get total HBM stack numbers based on memory partition for MI300. - """ - - # TODO: - # - better err log - if gpu_name.lower() == "mi300a_a0" or gpu_name.lower() == "mi300a_a1": - if memory_partition.lower() == "nps1": +def total_xcds(archname, compute_partition): + # check MI300 has a valid compute partition + mi300a_archs = ["mi300a_a0", "mi300a_a1"] + mi300x_archs = ["mi300x_a0", "mi300x_a1"] + mi308x_archs = ["mi308x"] + if archname.lower() in mi300a_archs + mi300x_archs + mi308x_archs and compute_partition == "NA": + console_error("Invalid compute partition found for {}".format(archname)) + if archname.lower() not in mi300a_archs + mi300x_archs + mi308x_archs: + return 1 + # from the whitepaper + # https://www.amd.com/content/dam/amd/en/documents/instinct-tech-docs/white-papers/amd-cdna-3-white-paper.pdf + if compute_partition.lower() == "spx": + if archname.lower() in mi300a_archs: return 6 - elif memory_partition.lower() == "nps4": - return 2 - elif memory_partition.lower() == "nps8": - return 1 - else: - console_error("Invalid MI300A memory partition mode!") - elif gpu_name.lower() == "mi300x_a0" or gpu_name.lower() == "mi300x_a1": - if memory_partition.lower() == "nps1": + if archname.lower() in mi300x_archs: return 8 - elif memory_partition.lower() == "nps2": + if archname.lower() in mi308x_archs: return 4 - elif memory_partition.lower() == "nps4": + if compute_partition.lower() == "tpx": + if archname.lower() in mi300a_archs: return 2 - elif memory_partition.lower() == "nps8": + if compute_partition.lower() == "dpx": + if archname.lower() in mi300x_archs: + return 4 + if archname.lower() in mi308x_archs: + return 2 + if compute_partition.lower() == "qpx": + if archname.lower() in mi300x_archs: + return 2 + if compute_partition.lower() == "cpx": + if archname.lower() in mi300x_archs: + return 2 + if archname.lower() in mi308x_archs: return 1 - else: - console_error("Invalid MI300X memory partition mode!") - else: - # Fixme: add proper numbers for other archs - return -1 + # TODO implement other archs here as needed + console_error( + "Unknown compute partition / arch found for {} / {}".format( + compute_partition, archname + ) + ) def get_submodules(package_name):