+3
-1
@@ -90,7 +90,9 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
general_group.add_argument(
|
||||
"-V", "--verbose", help="Increase output verbosity", action="count", default=0
|
||||
)
|
||||
general_group.add_argument("-s", "--specs", action="store_true", help="Print system specs.")
|
||||
general_group.add_argument(
|
||||
"-s", "--specs", action="store_true", help="Print system specs."
|
||||
)
|
||||
|
||||
profile_group.add_argument(
|
||||
"-n",
|
||||
|
||||
@@ -41,8 +41,8 @@ class OmniAnalyze_Base:
|
||||
self._runs = OrderedDict()
|
||||
self._arch_configs = {}
|
||||
self.__supported_archs = supported_archs
|
||||
self._output = None
|
||||
self.__socs:dict = None # available OmniSoC objs
|
||||
self._output = None
|
||||
self.__socs: dict = None # available OmniSoC objs
|
||||
|
||||
def get_args(self):
|
||||
return self.__args
|
||||
|
||||
@@ -70,13 +70,17 @@ class cli_analysis(OmniAnalyze_Base):
|
||||
tty.show_kernel_stats(
|
||||
self.get_args(),
|
||||
self._runs,
|
||||
self._arch_configs[self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["gpu_arch"]],
|
||||
self._output
|
||||
self._arch_configs[
|
||||
self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["gpu_arch"]
|
||||
],
|
||||
self._output,
|
||||
)
|
||||
else:
|
||||
tty.show_all(
|
||||
self.get_args(),
|
||||
self._runs,
|
||||
self._arch_configs[self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["gpu_arch"]],
|
||||
self._output
|
||||
self._arch_configs[
|
||||
self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["gpu_arch"]
|
||||
],
|
||||
self._output,
|
||||
)
|
||||
|
||||
@@ -163,12 +163,12 @@ class webui_analysis(OmniAnalyze_Base):
|
||||
# update roofline for visualization in GUI
|
||||
self.get_socs()[self.arch].analysis_setup(
|
||||
roofline_parameters={
|
||||
'workload_dir': self.dest_dir,
|
||||
'device_id': 0,
|
||||
'sort_type': 'kernels',
|
||||
'mem_level': 'ALL',
|
||||
'include_kernel_names': False,
|
||||
'is_standalone': False
|
||||
"workload_dir": self.dest_dir,
|
||||
"device_id": 0,
|
||||
"sort_type": "kernels",
|
||||
"mem_level": "ALL",
|
||||
"include_kernel_names": False,
|
||||
"is_standalone": False,
|
||||
}
|
||||
)
|
||||
roof_obj = self.get_socs()[self.arch].roofline_obj
|
||||
@@ -284,10 +284,12 @@ class webui_analysis(OmniAnalyze_Base):
|
||||
# create the loaded kernel stats
|
||||
parser.load_kernel_top(self._runs[self.dest_dir], self.dest_dir)
|
||||
# set architecture
|
||||
self.arch = self._runs[self.dest_dir].sys_info.iloc[0]['gpu_arch']
|
||||
|
||||
self.arch = self._runs[self.dest_dir].sys_info.iloc[0]["gpu_arch"]
|
||||
|
||||
else:
|
||||
error("Multiple runs not yet supported in GUI. Retry without --gui flag.")
|
||||
self.error(
|
||||
"Multiple runs not yet supported in GUI. Retry without --gui flag."
|
||||
)
|
||||
|
||||
@demarcate
|
||||
def run_analysis(self):
|
||||
|
||||
+32
-15
@@ -29,7 +29,15 @@ import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
from utils.specs import generate_machine_specs
|
||||
from utils.utils import demarcate, trace_logger, get_version, get_version_display, detect_rocprof, error, get_submodules
|
||||
from utils.utils import (
|
||||
demarcate,
|
||||
trace_logger,
|
||||
get_version,
|
||||
get_version_display,
|
||||
detect_rocprof,
|
||||
error,
|
||||
get_submodules,
|
||||
)
|
||||
from argparser import omniarg_parser
|
||||
import config
|
||||
import pandas as pd
|
||||
@@ -60,7 +68,7 @@ class Omniperf:
|
||||
}
|
||||
self.__options = {}
|
||||
self.__supported_archs = SUPPORTED_ARCHS
|
||||
self.__mspec: MachineSpecs = None # to be initalized in load_soc_specs()
|
||||
self.__mspec: MachineSpecs = None # to be initalized in load_soc_specs()
|
||||
|
||||
self.setup_logging()
|
||||
self.set_version()
|
||||
@@ -76,8 +84,7 @@ class Omniperf:
|
||||
logging.info("Execution mode = %s" % self.__mode)
|
||||
|
||||
def print_graphic(self):
|
||||
"""Log program name as ascii art to terminal.
|
||||
"""
|
||||
"""Log program name as ascii art to terminal."""
|
||||
ascii_art = r"""
|
||||
___ _ __
|
||||
/ _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _|
|
||||
@@ -157,9 +164,8 @@ class Omniperf:
|
||||
return
|
||||
|
||||
@demarcate
|
||||
def load_soc_specs(self, sysinfo:dict=None):
|
||||
"""Load OmniSoC instance for Omniperf run
|
||||
"""
|
||||
def load_soc_specs(self, sysinfo: dict = None):
|
||||
"""Load OmniSoC instance for Omniperf run"""
|
||||
self.__mspec = generate_machine_specs(self.__args, sysinfo)
|
||||
if self.__args.specs:
|
||||
print(self.__mspec)
|
||||
@@ -171,8 +177,8 @@ class Omniperf:
|
||||
if arch not in self.__supported_archs.keys():
|
||||
error("%s is an unsupported SoC" % arch)
|
||||
|
||||
soc_module = importlib.import_module('omniperf_soc.soc_'+arch)
|
||||
soc_class = getattr(soc_module, arch+'_soc')
|
||||
soc_module = importlib.import_module("omniperf_soc.soc_" + arch)
|
||||
soc_class = getattr(soc_module, arch + "_soc")
|
||||
self.__soc[arch] = soc_class(self.__args, self.__mspec)
|
||||
return
|
||||
|
||||
@@ -207,27 +213,38 @@ class Omniperf:
|
||||
|
||||
# Update default path
|
||||
if self.__args.path == os.path.join(os.getcwd(), "workloads"):
|
||||
self.__args.path = os.path.join(self.__args.path, self.__args.name, self.__mspec.gpu_model)
|
||||
self.__args.path = os.path.join(
|
||||
self.__args.path, self.__args.name, self.__mspec.gpu_model
|
||||
)
|
||||
|
||||
logging.info("Profiler choice = %s" % self.__profiler_mode)
|
||||
|
||||
# instantiate desired profiler
|
||||
if self.__profiler_mode == "rocprofv1":
|
||||
from omniperf_profile.profiler_rocprof_v1 import rocprof_v1_profiler
|
||||
profiler = rocprof_v1_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch])
|
||||
|
||||
profiler = rocprof_v1_profiler(
|
||||
self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch]
|
||||
)
|
||||
elif self.__profiler_mode == "rocprofv2":
|
||||
from omniperf_profile.profiler_rocprof_v2 import rocprof_v2_profiler
|
||||
profiler = rocprof_v2_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch])
|
||||
|
||||
profiler = rocprof_v2_profiler(
|
||||
self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch]
|
||||
)
|
||||
elif self.__profiler_mode == "rocscope":
|
||||
from omniperf_profile.profiler_rocscope import rocscope_profiler
|
||||
profiler = rocscope_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch])
|
||||
|
||||
profiler = rocscope_profiler(
|
||||
self.__args, self.__profiler_mode, self.__soc[self.__mspec.gpu_arch]
|
||||
)
|
||||
else:
|
||||
logging.error("Unsupported profiler")
|
||||
sys.exit(1)
|
||||
|
||||
# -----------------------
|
||||
# run profiling workflow
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
self.__soc[self.__mspec.gpu_arch].profiling_setup()
|
||||
profiler.pre_processing()
|
||||
profiler.run_profiling(self.__version["ver"], config.prog)
|
||||
@@ -279,7 +296,7 @@ class Omniperf:
|
||||
# Load required SoC(s) from input
|
||||
for d in analyzer.get_args().path:
|
||||
sys_info = pd.read_csv(Path(d[0], "sysinfo.csv"))
|
||||
sys_info = sys_info.to_dict('list')
|
||||
sys_info = sys_info.to_dict("list")
|
||||
sys_info = {key: value[0] for key, value in sys_info.items()}
|
||||
self.load_soc_specs(sys_info)
|
||||
|
||||
|
||||
@@ -270,7 +270,14 @@ class OmniProfiler_Base:
|
||||
|
||||
# verify soc compatibility
|
||||
if self.__profiler not in self._soc.get_compatible_profilers():
|
||||
error("%s is not enabled in %s. Available profilers include: %s" % (self._soc.get_arch(), self.__profiler, self._soc.get_compatible_profilers()))
|
||||
error(
|
||||
"%s is not enabled in %s. Available profilers include: %s"
|
||||
% (
|
||||
self._soc.get_arch(),
|
||||
self.__profiler,
|
||||
self._soc.get_compatible_profilers(),
|
||||
)
|
||||
)
|
||||
# verify not accessing parent directories
|
||||
if ".." in str(self.__args.path):
|
||||
error("Access denied. Cannot access parent directories in path (i.e. ../)")
|
||||
@@ -367,7 +374,7 @@ class OmniProfiler_Base:
|
||||
|
||||
if self.__profiler == "rocprofv1" or self.__profiler == "rocprofv2":
|
||||
run_prof(
|
||||
fname=fname,
|
||||
fname=fname,
|
||||
profiler_options=options,
|
||||
workload_dir=self.get_args().path,
|
||||
mspec=self._soc._mspec,
|
||||
|
||||
@@ -35,25 +35,33 @@ from pathlib import Path
|
||||
|
||||
from omniperf_base import SUPPORTED_ARCHS
|
||||
|
||||
class OmniSoC_Base():
|
||||
def __init__(self,args,mspec): # new info field will contain rocminfo or sysinfo to populate properties
|
||||
|
||||
class OmniSoC_Base:
|
||||
def __init__(
|
||||
self, args, mspec
|
||||
): # new info field will contain rocminfo or sysinfo to populate properties
|
||||
self.__args = args
|
||||
self.__arch = None
|
||||
self._mspec = mspec
|
||||
self.__perfmon_dir = None
|
||||
self.__perfmon_config = {} # Per IP block max number of simulutaneous counters. GFX IP Blocks
|
||||
self.__soc_params = {} # SoC specifications
|
||||
self.__compatible_profilers = [] # Store profilers compatible with SoC
|
||||
self.__perfmon_config = (
|
||||
{}
|
||||
) # Per IP block max number of simulutaneous counters. GFX IP Blocks
|
||||
self.__soc_params = {} # SoC specifications
|
||||
self.__compatible_profilers = [] # Store profilers compatible with SoC
|
||||
self.populate_mspec()
|
||||
# In some cases (i.e. --specs) path will not be given
|
||||
if hasattr(self.__args, "path"):
|
||||
if self.__args.path == os.path.join(os.getcwd(), "workloads"):
|
||||
self.__workload_dir = os.path.join(self.__args.path, self.__args.name, self._mspec.gpu_model)
|
||||
self.__workload_dir = os.path.join(
|
||||
self.__args.path, self.__args.name, self._mspec.gpu_model
|
||||
)
|
||||
else:
|
||||
self.__workload_dir = self.__args.path
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__arch)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, type(self)):
|
||||
return NotImplemented
|
||||
@@ -64,15 +72,19 @@ class OmniSoC_Base():
|
||||
|
||||
def set_perfmon_config(self, config: dict):
|
||||
self.__perfmon_config = config
|
||||
|
||||
def get_workload_perfmon_dir(self):
|
||||
return str(Path(self.__perfmon_dir).parent.absolute())
|
||||
|
||||
def get_soc_param(self):
|
||||
return self.__soc_params
|
||||
|
||||
def set_arch(self, arch: str):
|
||||
self.__arch = arch
|
||||
|
||||
def get_arch(self):
|
||||
return self.__arch
|
||||
|
||||
def get_args(self):
|
||||
return self.__args
|
||||
|
||||
@@ -143,17 +155,16 @@ class OmniSoC_Base():
|
||||
if key != None:
|
||||
self._mspec.max_waves_per_cu = key
|
||||
break
|
||||
|
||||
|
||||
self._mspec.sqc_per_gpu = str(
|
||||
total_sqc(
|
||||
self._mspec.gpu_arch,
|
||||
self._mspec.cu_per_gpu,
|
||||
self._mspec.se_per_gpu
|
||||
))
|
||||
|
||||
self._mspec.gpu_arch, self._mspec.cu_per_gpu, self._mspec.se_per_gpu
|
||||
)
|
||||
)
|
||||
|
||||
# we get the max mclk from rocm-smi --showmclkrange
|
||||
rocm_smi_mclk = run(["rocm-smi", "--showmclkrange"], exit_on_error=True)
|
||||
self._mspec.max_mclk = search(r'(\d+)Mhz\s*$', rocm_smi_mclk)
|
||||
self._mspec.max_mclk = search(r"(\d+)Mhz\s*$", rocm_smi_mclk)
|
||||
|
||||
# these are just max's now, because the parsing was broken and this was inconsistent
|
||||
# with how we use the clocks elsewhere (all max, all the time)
|
||||
@@ -161,15 +172,25 @@ class OmniSoC_Base():
|
||||
self._mspec.cur_mclk = self._mspec.max_mclk
|
||||
|
||||
# specify gpu name for gfx942 hardware
|
||||
self._mspec.gpu_model = list(SUPPORTED_ARCHS[self._mspec.gpu_arch].keys())[0].upper()
|
||||
self._mspec.gpu_model = list(SUPPORTED_ARCHS[self._mspec.gpu_arch].keys())[
|
||||
0
|
||||
].upper()
|
||||
if self._mspec.gpu_model == "MI300":
|
||||
self._mspec.gpu_model = list(SUPPORTED_ARCHS[self._mspec.gpu_arch].values())[0][0]
|
||||
if (self._mspec.gpu_arch == "gfx942") and ("MI300A" in '\n'.join(self._mspec._rocminfo)):
|
||||
self._mspec.gpu_model = list(SUPPORTED_ARCHS[self._mspec.gpu_arch].values())[
|
||||
0
|
||||
][0]
|
||||
if (self._mspec.gpu_arch == "gfx942") and (
|
||||
"MI300A" in "\n".join(self._mspec._rocminfo)
|
||||
):
|
||||
self._mspec.gpu_model = "MI300A_A1"
|
||||
if (self._mspec.gpu_arch == "gfx942") and ("MI300A" not in '\n'.join(self._mspec._rocminfo)):
|
||||
if (self._mspec.gpu_arch == "gfx942") and (
|
||||
"MI300A" not in "\n".join(self._mspec._rocminfo)
|
||||
):
|
||||
self._mspec.gpu_model = "MI300X_A1"
|
||||
|
||||
self._mspec.num_xcd = str(total_xcds(self._mspec.gpu_model, self._mspec.compute_partition))
|
||||
self._mspec.num_xcd = str(
|
||||
total_xcds(self._mspec.gpu_model, self._mspec.compute_partition)
|
||||
)
|
||||
|
||||
@demarcate
|
||||
def perfmon_filter(self, roofline_perfmon_only: bool):
|
||||
@@ -190,7 +211,9 @@ class OmniSoC_Base():
|
||||
|
||||
if not roofline_perfmon_only:
|
||||
ref_pmc_files_list = glob.glob(self.__perfmon_dir + "/" + "pmc_*perf*.txt")
|
||||
ref_pmc_files_list += glob.glob(self.__perfmon_dir + "/" + self.__arch + "/pmc_*_perf*.txt")
|
||||
ref_pmc_files_list += glob.glob(
|
||||
self.__perfmon_dir + "/" + self.__arch + "/pmc_*_perf*.txt"
|
||||
)
|
||||
|
||||
# Perfmon list filtering
|
||||
if self.__args.ipblocks != None:
|
||||
@@ -226,22 +249,19 @@ class OmniSoC_Base():
|
||||
# ----------------------------------------------------
|
||||
@abstractmethod
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to profiling."""
|
||||
logging.debug("[profiling] perform SoC profiling setup for %s" % self.__arch)
|
||||
|
||||
@abstractmethod
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
logging.debug("[profiling] perform SoC post processing for %s" % self.__arch)
|
||||
|
||||
@abstractmethod
|
||||
def analysis_setup(self):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
logging.debug("[analysis] perform SoC analysis setup for %s" % self.__arch)
|
||||
|
||||
|
||||
|
||||
@demarcate
|
||||
def perfmon_coalesce(pmc_files_list, perfmon_config, workload_dir):
|
||||
|
||||
@@ -27,11 +27,19 @@ import config
|
||||
from omniperf_soc.soc_base import OmniSoC_Base
|
||||
from utils.utils import demarcate, error
|
||||
|
||||
class gfx906_soc (OmniSoC_Base):
|
||||
def __init__(self,args,mspec):
|
||||
super().__init__(args,mspec)
|
||||
|
||||
class gfx906_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx906")
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", self.get_arch()))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
self.get_arch(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -49,7 +57,7 @@ class gfx906_soc (OmniSoC_Base):
|
||||
"TCC_channels": 16,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# Set arch specific specs
|
||||
self._mspec._l2_banks = 16
|
||||
self._mspec.lds_banks_per_cu = 32
|
||||
|
||||
@@ -27,11 +27,19 @@ import config
|
||||
from omniperf_soc.soc_base import OmniSoC_Base
|
||||
from utils.utils import demarcate, error
|
||||
|
||||
class gfx908_soc (OmniSoC_Base):
|
||||
def __init__(self,args,mspec):
|
||||
super().__init__(args,mspec)
|
||||
|
||||
class gfx908_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx908")
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", self.get_arch()))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
self.get_arch(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -82,6 +90,5 @@ class gfx908_soc (OmniSoC_Base):
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
|
||||
@@ -29,14 +29,29 @@ from utils.utils import demarcate, mibench
|
||||
from roofline import Roofline
|
||||
import logging
|
||||
|
||||
class gfx90a_soc (OmniSoC_Base):
|
||||
def __init__(self,args,mspec):
|
||||
super().__init__(args,mspec)
|
||||
|
||||
class gfx90a_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx90a")
|
||||
if hasattr(self.get_args(), 'roof_only') and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "roofline"))
|
||||
if hasattr(self.get_args(), "roof_only") and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
"roofline",
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", self.get_arch()))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
self.get_arch(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -91,7 +106,6 @@ class gfx90a_soc (OmniSoC_Base):
|
||||
super().analysis_setup()
|
||||
# configure roofline for analysis
|
||||
if roofline_parameters:
|
||||
self.roofline_obj = Roofline(self.get_args(), self._mspec, roofline_parameters)
|
||||
|
||||
|
||||
|
||||
self.roofline_obj = Roofline(
|
||||
self.get_args(), self._mspec, roofline_parameters
|
||||
)
|
||||
|
||||
@@ -29,12 +29,20 @@ from utils.utils import demarcate, mibench
|
||||
from roofline import Roofline
|
||||
import logging
|
||||
|
||||
class gfx940_soc (OmniSoC_Base):
|
||||
def __init__(self,args,mspec):
|
||||
super().__init__(args,mspec)
|
||||
|
||||
class gfx940_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx940")
|
||||
if hasattr(self.get_args(), 'roof_only') and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "roofline"))
|
||||
if hasattr(self.get_args(), "roof_only") and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
"roofline",
|
||||
)
|
||||
)
|
||||
else:
|
||||
# NB: We're using generalized Mi300 perfmon configs
|
||||
self.set_perfmon_dir(
|
||||
|
||||
@@ -29,12 +29,20 @@ from utils.utils import demarcate, mibench
|
||||
from roofline import Roofline
|
||||
import logging
|
||||
|
||||
class gfx941_soc (OmniSoC_Base):
|
||||
def __init__(self,args, mspec):
|
||||
|
||||
class gfx941_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx941")
|
||||
if hasattr(self.get_args(), 'roof_only') and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "roofline"))
|
||||
if hasattr(self.get_args(), "roof_only") and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
"roofline",
|
||||
)
|
||||
)
|
||||
else:
|
||||
# NB: We're using generalized Mi300 perfmon configs
|
||||
self.set_perfmon_dir(
|
||||
|
||||
@@ -29,12 +29,20 @@ from utils.utils import demarcate, mibench
|
||||
from roofline import Roofline
|
||||
import logging
|
||||
|
||||
class gfx942_soc (OmniSoC_Base):
|
||||
def __init__(self,args,mspec):
|
||||
super().__init__(args,mspec)
|
||||
|
||||
class gfx942_soc(OmniSoC_Base):
|
||||
def __init__(self, args, mspec):
|
||||
super().__init__(args, mspec)
|
||||
self.set_arch("gfx942")
|
||||
if hasattr(self.get_args(), 'roof_only') and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "roofline"))
|
||||
if hasattr(self.get_args(), "roof_only") and self.get_args().roof_only:
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
"roofline",
|
||||
)
|
||||
)
|
||||
else:
|
||||
# NB: We're using generalized Mi300 perfmon configs
|
||||
self.set_perfmon_dir(
|
||||
|
||||
+67
-43
@@ -41,31 +41,37 @@ class Roofline:
|
||||
def __init__(self, args, mspec, run_parameters=None):
|
||||
self.__args = args
|
||||
self.__mspec = mspec
|
||||
self.__run_parameters = run_parameters if run_parameters else {
|
||||
'workload_dir': None, # in some cases (i.e. --specs) path will not be given
|
||||
'device_id': 0,
|
||||
'sort_type': 'kernels',
|
||||
'mem_level': 'ALL',
|
||||
'include_kernel_names': False,
|
||||
'is_standalone': False
|
||||
}
|
||||
self.__run_parameters = (
|
||||
run_parameters
|
||||
if run_parameters
|
||||
else {
|
||||
"workload_dir": None, # in some cases (i.e. --specs) path will not be given
|
||||
"device_id": 0,
|
||||
"sort_type": "kernels",
|
||||
"mem_level": "ALL",
|
||||
"include_kernel_names": False,
|
||||
"is_standalone": False,
|
||||
}
|
||||
)
|
||||
self.__ai_data = None
|
||||
self.__ceiling_data = None
|
||||
self.__figure = go.Figure()
|
||||
# Set roofline run parameters from args
|
||||
if hasattr(self.__args, 'path') and not run_parameters:
|
||||
self.__run_parameters['workload_dir'] = self.__args.path
|
||||
if hasattr(self.__args, 'roof_only') and self.__args.roof_only == True:
|
||||
self.__run_parameters['is_standalone'] = True
|
||||
if hasattr(self.__args, 'kernel_names') and self.__args.kernel_names == True:
|
||||
self.__run_parameters['include_kernel_names'] = True
|
||||
if hasattr(self.__args, 'mem_level') and self.__args.mem_level != "ALL":
|
||||
self.__run_parameters['mem_level'] = self.__args.mem_level
|
||||
if hasattr(self.__args, 'sort') and self.__args.sort != "ALL":
|
||||
self.__run_parameters['sort_type'] = self.__args.sort
|
||||
if hasattr(self.__args, "path") and not run_parameters:
|
||||
self.__run_parameters["workload_dir"] = self.__args.path
|
||||
if hasattr(self.__args, "roof_only") and self.__args.roof_only == True:
|
||||
self.__run_parameters["is_standalone"] = True
|
||||
if hasattr(self.__args, "kernel_names") and self.__args.kernel_names == True:
|
||||
self.__run_parameters["include_kernel_names"] = True
|
||||
if hasattr(self.__args, "mem_level") and self.__args.mem_level != "ALL":
|
||||
self.__run_parameters["mem_level"] = self.__args.mem_level
|
||||
if hasattr(self.__args, "sort") and self.__args.sort != "ALL":
|
||||
self.__run_parameters["sort_type"] = self.__args.sort
|
||||
|
||||
if (not isinstance(self.__run_parameters['workload_dir'], list)
|
||||
and self.__run_parameters['workload_dir'] != None):
|
||||
if (
|
||||
not isinstance(self.__run_parameters["workload_dir"], list)
|
||||
and self.__run_parameters["workload_dir"] != None
|
||||
):
|
||||
self.roof_setup()
|
||||
|
||||
self.validate_parameters()
|
||||
@@ -78,11 +84,17 @@ class Roofline:
|
||||
|
||||
def roof_setup(self):
|
||||
# set default workload path if not specified
|
||||
if self.__run_parameters['workload_dir'] == os.path.join(os.getcwd(), 'workloads'):
|
||||
self.__run_parameters['workload_dir'] = os.path.join(self.__run_parameters['workload_dir'], self.__args.name, self.__mspec.gpu_model)
|
||||
if self.__run_parameters["workload_dir"] == os.path.join(
|
||||
os.getcwd(), "workloads"
|
||||
):
|
||||
self.__run_parameters["workload_dir"] = os.path.join(
|
||||
self.__run_parameters["workload_dir"],
|
||||
self.__args.name,
|
||||
self.__mspec.gpu_model,
|
||||
)
|
||||
# create new directory for roofline if it doesn't exist
|
||||
if not os.path.isdir(self.__run_parameters['workload_dir']):
|
||||
os.makedirs(self.__run_parameters['workload_dir'])
|
||||
if not os.path.isdir(self.__run_parameters["workload_dir"]):
|
||||
os.makedirs(self.__run_parameters["workload_dir"])
|
||||
|
||||
@demarcate
|
||||
def empirical_roofline(
|
||||
@@ -91,9 +103,9 @@ class Roofline:
|
||||
):
|
||||
"""Generate a set of empirical roofline plots given a directory containing required profiling and benchmarking data"""
|
||||
# Create arithmetic intensity data that will populate the roofline model
|
||||
logging.debug("[roofline] Path: %s" % self.__run_parameters['workload_dir'])
|
||||
self.__ai_data = calc_ai(self.__run_parameters['sort_type'], ret_df)
|
||||
|
||||
logging.debug("[roofline] Path: %s" % self.__run_parameters["workload_dir"])
|
||||
self.__ai_data = calc_ai(self.__run_parameters["sort_type"], ret_df)
|
||||
|
||||
logging.debug("[roofline] AI at each mem level:")
|
||||
for i in self.__ai_data:
|
||||
logging.debug("%s -> %s" % (i, self.__ai_data[i]))
|
||||
@@ -131,21 +143,33 @@ class Roofline:
|
||||
if self.__run_parameters["is_standalone"]:
|
||||
dev_id = str(self.__run_parameters["device_id"])
|
||||
|
||||
fp32_fig.write_image(self.__run_parameters['workload_dir'] + "/empirRoof_gpu-{}_fp32.pdf".format(dev_id))
|
||||
fp32_fig.write_image(
|
||||
self.__run_parameters["workload_dir"]
|
||||
+ "/empirRoof_gpu-{}_fp32.pdf".format(dev_id)
|
||||
)
|
||||
ml_combo_fig.write_image(
|
||||
self.__run_parameters['workload_dir'] + "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
|
||||
self.__run_parameters["workload_dir"]
|
||||
+ "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
|
||||
)
|
||||
# only save a legend if kernel_names option is toggled
|
||||
if self.__run_parameters['include_kernel_names']:
|
||||
self.__figure.write_image(self.__run_parameters['workload_dir'] + "/kernelName_legend.pdf")
|
||||
if self.__run_parameters["include_kernel_names"]:
|
||||
self.__figure.write_image(
|
||||
self.__run_parameters["workload_dir"] + "/kernelName_legend.pdf"
|
||||
)
|
||||
time.sleep(1)
|
||||
# Re-save to remove loading MathJax pop up
|
||||
fp32_fig.write_image(self.__run_parameters['workload_dir'] + "/empirRoof_gpu-{}_fp32.pdf".format(dev_id))
|
||||
ml_combo_fig.write_image(
|
||||
self.__run_parameters['workload_dir'] + "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
|
||||
fp32_fig.write_image(
|
||||
self.__run_parameters["workload_dir"]
|
||||
+ "/empirRoof_gpu-{}_fp32.pdf".format(dev_id)
|
||||
)
|
||||
if self.__run_parameters['include_kernel_names']:
|
||||
self.__figure.write_image(self.__run_parameters['workload_dir'] + "/kernelName_legend.pdf")
|
||||
ml_combo_fig.write_image(
|
||||
self.__run_parameters["workload_dir"]
|
||||
+ "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
|
||||
)
|
||||
if self.__run_parameters["include_kernel_names"]:
|
||||
self.__figure.write_image(
|
||||
self.__run_parameters["workload_dir"] + "/kernelName_legend.pdf"
|
||||
)
|
||||
logging.info("[roofline] Empirical Roofline PDFs saved!")
|
||||
else:
|
||||
return html.Section(
|
||||
@@ -332,7 +356,7 @@ class Roofline:
|
||||
self.__run_parameters["mem_level"].remove("vL1D")
|
||||
self.__run_parameters["mem_level"].append("L1")
|
||||
|
||||
app_path = os.path.join(self.__run_parameters['workload_dir'], "pmc_perf.csv")
|
||||
app_path = os.path.join(self.__run_parameters["workload_dir"], "pmc_perf.csv")
|
||||
roofline_exists = os.path.isfile(app_path)
|
||||
if not roofline_exists:
|
||||
logging.error("[roofline] Error: {} does not exist".format(app_path))
|
||||
@@ -353,13 +377,13 @@ class Roofline:
|
||||
if not os.path.isfile(sysinfo_path):
|
||||
logging.info("[roofline] sysinfo.csv not found. Generating...")
|
||||
gen_sysinfo(
|
||||
workload_name=self.__args.name,
|
||||
workload_dir=self.__workload_dir,
|
||||
ip_blocks=self.__args.ipblocks,
|
||||
app_cmd=self.__args.remaining,
|
||||
skip_roof=self.__args.no_roof,
|
||||
workload_name=self.__args.name,
|
||||
workload_dir=self.__workload_dir,
|
||||
ip_blocks=self.__args.ipblocks,
|
||||
app_cmd=self.__args.remaining,
|
||||
skip_roof=self.__args.no_roof,
|
||||
roof_only=self.__args.roof_only,
|
||||
mspec=self.__mspec
|
||||
mspec=self.__mspec,
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
|
||||
+3
-3
@@ -227,9 +227,9 @@ def build_bar_chart(display_df, table_config, barchart_elements, norm_filt):
|
||||
).update_xaxes(range=[0, 1638])
|
||||
) # append second GB/s chart
|
||||
else:
|
||||
key = 'Avg'
|
||||
if table_config['id'] in [1101]:
|
||||
key = 'Pct of Peak'
|
||||
key = "Avg"
|
||||
if table_config["id"] in [1101]:
|
||||
key = "Pct of Peak"
|
||||
d_figs.append(
|
||||
px.bar(
|
||||
display_df,
|
||||
|
||||
+12
-9
@@ -79,11 +79,11 @@ supported_denom = {
|
||||
build_in_vars = {
|
||||
"GRBM_GUI_ACTIVE_PER_XCD": "(GRBM_GUI_ACTIVE / $num_xcd)",
|
||||
"GRBM_COUNT_PER_XCD": "(GRBM_COUNT / $num_xcd)",
|
||||
"GRBM_SPI_BUSY_PER_XCD" : "(GRBM_SPI_BUSY / $num_xcd)",
|
||||
"GRBM_SPI_BUSY_PER_XCD": "(GRBM_SPI_BUSY / $num_xcd)",
|
||||
"numActiveCUs": "TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / $GRBM_GUI_ACTIVE_PER_XCD)), \
|
||||
0) / $max_waves_per_cu) * 8) + MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) \
|
||||
/ $GRBM_GUI_ACTIVE_PER_XCD)), 0), $max_waves_per_cu), 8)), $cu_per_gpu))",
|
||||
"kernelBusyCycles": "ROUND(AVG((((End_Timestamp - Start_Timestamp) / 1000) * $max_sclk)), 0)"
|
||||
"kernelBusyCycles": "ROUND(AVG((((End_Timestamp - Start_Timestamp) / 1000) * $max_sclk)), 0)",
|
||||
}
|
||||
|
||||
supported_call = {
|
||||
@@ -685,11 +685,11 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug):
|
||||
ammolite__se_per_gpu = sys_info.se_per_gpu
|
||||
ammolite__pipes_per_gpu = sys_info.pipes_per_gpu
|
||||
ammolite__cu_per_gpu = sys_info.cu_per_gpu
|
||||
ammolite__simd_per_cu = sys_info.simd_per_cu # not used
|
||||
ammolite__simd_per_cu = sys_info.simd_per_cu # not used
|
||||
ammolite__sqc_per_gpu = sys_info.sqc_per_gpu
|
||||
ammolite__lds_banks_per_cu = sys_info.lds_banks_per_cu
|
||||
ammolite__cur_sclk = sys_info.cur_sclk # not used
|
||||
ammolite__mclk = sys_info.cur_mclk # not used
|
||||
ammolite__mclk = sys_info.cur_mclk # not used
|
||||
ammolite__max_sclk = sys_info.max_sclk
|
||||
ammolite__max_waves_per_cu = sys_info.max_waves_per_cu
|
||||
ammolite__hbm_bw = sys_info.hbm_bw
|
||||
@@ -924,7 +924,9 @@ def load_kernel_top(workload, dir):
|
||||
if file.exists():
|
||||
tmp[id] = pd.read_csv(file)
|
||||
else:
|
||||
logging.info("Warning: Issue loading top kernels. Check pmc_kernel_top.csv")
|
||||
logging.info(
|
||||
"Warning: Issue loading top kernels. Check pmc_kernel_top.csv"
|
||||
)
|
||||
# NB: Special case for sysinfo. Probably room for improvement in this whole function design
|
||||
elif "from_csv_columnwise" in df.columns and id == 101:
|
||||
tmp[id] = workload.sys_info.transpose()
|
||||
@@ -977,7 +979,8 @@ def build_comparable_columns(time_unit):
|
||||
|
||||
return comparable_columns
|
||||
|
||||
def correct_sys_info(mspec, specs_correction:dict):
|
||||
|
||||
def correct_sys_info(mspec, specs_correction: dict):
|
||||
"""
|
||||
Correct system spec items manually
|
||||
"""
|
||||
@@ -987,8 +990,8 @@ def correct_sys_info(mspec, specs_correction:dict):
|
||||
|
||||
for k, v in pairs.items():
|
||||
if not hasattr(mspec, str(k)):
|
||||
error(f"Invalid specs correction '{k}'. Please use --specs option to peak valid specs")
|
||||
error(
|
||||
f"Invalid specs correction '{k}'. Please use --specs option to peak valid specs"
|
||||
)
|
||||
setattr(mspec, str(k), v)
|
||||
return mspec.get_class_members()
|
||||
|
||||
|
||||
|
||||
+376
-212
@@ -53,6 +53,7 @@ VERSION_LOC = [
|
||||
"version-utils",
|
||||
]
|
||||
|
||||
|
||||
def detect_arch(_rocminfo):
|
||||
from omniperf_base import SUPPORTED_ARCHS
|
||||
|
||||
@@ -68,12 +69,15 @@ def detect_arch(_rocminfo):
|
||||
else:
|
||||
return (gpu_arch, idx1)
|
||||
|
||||
def generate_machine_specs(args, sysinfo:dict=None):
|
||||
|
||||
def generate_machine_specs(args, sysinfo: dict = None):
|
||||
if not sysinfo is None:
|
||||
sysinfo_ver = str(sysinfo['version'])
|
||||
version = get_version(config.omniperf_home)['version']
|
||||
if sysinfo_ver != version[:version.find(".")]:
|
||||
logging.warning("WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data.")
|
||||
sysinfo_ver = str(sysinfo["version"])
|
||||
version = get_version(config.omniperf_home)["version"]
|
||||
if sysinfo_ver != version[: version.find(".")]:
|
||||
logging.warning(
|
||||
"WARNING: Detected mismatch in sysinfo versioning. You may need to reprofile to update data."
|
||||
)
|
||||
return MachineSpecs(**sysinfo)
|
||||
# read timestamp info
|
||||
now = datetime.now()
|
||||
@@ -87,7 +91,9 @@ def generate_machine_specs(args, sysinfo:dict=None):
|
||||
vData = get_version(config.omniperf_home)
|
||||
version = vData["version"]
|
||||
# NB: Just taking major as specs version. May want to make this more specific in the future
|
||||
specs_version = version[:version.find(".")] # version will always follow 'major.minor.patch' format
|
||||
specs_version = version[
|
||||
: version.find(".")
|
||||
] # version will always follow 'major.minor.patch' format
|
||||
|
||||
##########################################
|
||||
## A. Machine Specs
|
||||
@@ -97,25 +103,28 @@ def generate_machine_specs(args, sysinfo:dict=None):
|
||||
version = path("/proc/version").read_text()
|
||||
os_release = path("/etc/os-release").read_text()
|
||||
cpu_model = search(r"^model name\s*: (.*?)$", cpuinfo)
|
||||
sbios = path("/sys/class/dmi/id/bios_vendor").read_text().strip() + \
|
||||
path("/sys/class/dmi/id/bios_version").read_text().strip()
|
||||
sbios = (
|
||||
path("/sys/class/dmi/id/bios_vendor").read_text().strip()
|
||||
+ path("/sys/class/dmi/id/bios_version").read_text().strip()
|
||||
)
|
||||
linux_kernel_version = search(r"version (\S*)", version)
|
||||
amd_gpu_kernel_version = "" #TODO: Extract amdgpu kernel version
|
||||
amd_gpu_kernel_version = "" # TODO: Extract amdgpu kernel version
|
||||
cpu_memory = search(r"MemTotal:\s*(\S*)", meminfo)
|
||||
gpu_memory = "" #TODO: Extract gpu memory
|
||||
gpu_memory = "" # TODO: Extract gpu memory
|
||||
linux_distro = search(r'PRETTY_NAME="(.*?)"', os_release)
|
||||
if linux_distro is None:
|
||||
linux_distro = ""
|
||||
rocm_version = get_rocm_ver().strip()
|
||||
#FIXME: use device
|
||||
vbios = search(
|
||||
r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True))
|
||||
# FIXME: use device
|
||||
vbios = search(r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True))
|
||||
compute_partition = search(
|
||||
r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"]))
|
||||
r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"])
|
||||
)
|
||||
if compute_partition is None:
|
||||
compute_partition = "NA"
|
||||
memory_partition = search(
|
||||
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"]))
|
||||
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"])
|
||||
)
|
||||
if memory_partition is None:
|
||||
memory_partition = "NA"
|
||||
|
||||
@@ -126,29 +135,34 @@ def generate_machine_specs(args, sysinfo:dict=None):
|
||||
rocminfo_full = run(["rocminfo"])
|
||||
_rocminfo = rocminfo_full.split("\n")
|
||||
gpu_arch, idx = detect_arch(_rocminfo)
|
||||
_rocminfo = _rocminfo[idx + 1 :] # update rocminfo for target section
|
||||
specs = MachineSpecs(version=specs_version,
|
||||
timestamp=timestamp,
|
||||
_rocminfo=_rocminfo,
|
||||
hostname=hostname,
|
||||
cpu_model=cpu_model,
|
||||
sbios=sbios,
|
||||
linux_kernel_version=linux_kernel_version,
|
||||
amd_gpu_kernel_version=amd_gpu_kernel_version,
|
||||
cpu_memory=cpu_memory,
|
||||
gpu_memory=gpu_memory,
|
||||
linux_distro=linux_distro,
|
||||
rocm_version=rocm_version,
|
||||
vbios=vbios,
|
||||
compute_partition=compute_partition,
|
||||
memory_partition=memory_partition,
|
||||
gpu_arch=gpu_arch)
|
||||
_rocminfo = _rocminfo[idx + 1 :] # update rocminfo for target section
|
||||
specs = MachineSpecs(
|
||||
version=specs_version,
|
||||
timestamp=timestamp,
|
||||
_rocminfo=_rocminfo,
|
||||
hostname=hostname,
|
||||
cpu_model=cpu_model,
|
||||
sbios=sbios,
|
||||
linux_kernel_version=linux_kernel_version,
|
||||
amd_gpu_kernel_version=amd_gpu_kernel_version,
|
||||
cpu_memory=cpu_memory,
|
||||
gpu_memory=gpu_memory,
|
||||
linux_distro=linux_distro,
|
||||
rocm_version=rocm_version,
|
||||
vbios=vbios,
|
||||
compute_partition=compute_partition,
|
||||
memory_partition=memory_partition,
|
||||
gpu_arch=gpu_arch,
|
||||
)
|
||||
# Load above SoC specs via module import
|
||||
try:
|
||||
soc_module = importlib.import_module('omniperf_soc.soc_'+ specs.gpu_arch)
|
||||
soc_module = importlib.import_module("omniperf_soc.soc_" + specs.gpu_arch)
|
||||
except ModuleNotFoundError as e:
|
||||
error("Arch %s marked as supported, but couldn't find class implementation %s." % (specs.gpu_arch, e))
|
||||
soc_class = getattr(soc_module, specs.gpu_arch+'_soc')
|
||||
error(
|
||||
"Arch %s marked as supported, but couldn't find class implementation %s."
|
||||
% (specs.gpu_arch, e)
|
||||
)
|
||||
soc_class = getattr(soc_module, specs.gpu_arch + "_soc")
|
||||
soc_obj = soc_class(args, specs)
|
||||
# Update arch specific specs
|
||||
specs.total_l2_chan: str = total_l2_banks(
|
||||
@@ -157,6 +171,7 @@ def generate_machine_specs(args, sysinfo:dict=None):
|
||||
specs.hbm_bw: str = str(int(specs.max_mclk) / 1000 * 32 * specs.get_hbm_channels())
|
||||
return specs
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class MachineSpecs:
|
||||
##########################################
|
||||
@@ -168,66 +183,135 @@ class MachineSpecs:
|
||||
# _are_ included in profiling/analysis, so we mark them as 'optional'
|
||||
# in the metadata to avoid erroring out on missing fields on
|
||||
# serialization
|
||||
workload_name: str = field(default=None, metadata={
|
||||
'doc': 'The name of the workload data was collected for.',
|
||||
'name': 'Workload Name',
|
||||
'optional': True})
|
||||
command: str = field(default=None, metadata={
|
||||
'doc': 'The command the workload was executed with.',
|
||||
'name': 'Command',
|
||||
'optional': True})
|
||||
ip_blocks: str = field(default=None, metadata={
|
||||
'doc': 'The hardware blocks profiling information was collected for.',
|
||||
'name': 'IP Blocks',
|
||||
'optional': True
|
||||
})
|
||||
timestamp: str = field(default=None, metadata={
|
||||
'doc': 'The time (in local system time) when data was collected',
|
||||
'name': 'Timestamp'})
|
||||
version: str = field(default=None, metadata={
|
||||
'doc': 'The version of the machine specification file format.',
|
||||
'name': 'MachineSpecs Version',
|
||||
'intable': False})
|
||||
timestamp: str = field(default=None, metadata={
|
||||
'doc': 'The time (in local system time) when data was collected',
|
||||
'name': 'Timestamp'})
|
||||
workload_name: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The name of the workload data was collected for.",
|
||||
"name": "Workload Name",
|
||||
"optional": True,
|
||||
},
|
||||
)
|
||||
command: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The command the workload was executed with.",
|
||||
"name": "Command",
|
||||
"optional": True,
|
||||
},
|
||||
)
|
||||
ip_blocks: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The hardware blocks profiling information was collected for.",
|
||||
"name": "IP Blocks",
|
||||
"optional": True,
|
||||
},
|
||||
)
|
||||
timestamp: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The time (in local system time) when data was collected",
|
||||
"name": "Timestamp",
|
||||
},
|
||||
)
|
||||
version: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The version of the machine specification file format.",
|
||||
"name": "MachineSpecs Version",
|
||||
"intable": False,
|
||||
},
|
||||
)
|
||||
timestamp: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The time (in local system time) when data was collected",
|
||||
"name": "Timestamp",
|
||||
},
|
||||
)
|
||||
_rocminfo: list = field(default=None)
|
||||
##########################################
|
||||
## A. Machine Specs
|
||||
##########################################
|
||||
hostname: str = field(default=None, metadata={'doc': 'The hostname of the machine.',
|
||||
'name': 'Hostname'})
|
||||
cpu_model: str = field(default=None, metadata={'doc': 'The model name of the CPU used.',
|
||||
'name': 'CPU Model'})
|
||||
sbios: str = field(default=None, metadata={'doc': 'The system management bios version and vendor.',
|
||||
'name': "SBIOS"})
|
||||
linux_distro: str = field(default=None, metadata={'doc': 'The Linux distribution installed on the machine.',
|
||||
'name': 'Linux Distribution'})
|
||||
linux_kernel_version: str = field(default=None,
|
||||
metadata={'doc': 'The Linux kernel version running on the machine.',
|
||||
'name': 'Linux Kernel Version'})
|
||||
amd_gpu_kernel_version: str = field(default=None, metadata={
|
||||
'doc': '[RESERVED] The version of the AMDGPU driver installed on the machine. Unimplemented.',
|
||||
'name': "AMD GPU Kernel Version"})
|
||||
cpu_memory: str = field(default=None, metadata={
|
||||
'doc': 'The total amount of memory available to the CPU.', 'unit': 'KB',
|
||||
'name': 'CPU Memory'})
|
||||
gpu_memory: str = field(default=None, metadata={
|
||||
'doc': '[RESERVED] The total amount of memory available to accelerators/GPUs in the system. Unimplemented.',
|
||||
'unit': 'KB',
|
||||
'name': 'GPU Memory'})
|
||||
rocm_version: str = field(default=None,
|
||||
metadata={'doc': 'The ROCm version used during data-collection.',
|
||||
'name': "ROCm Version"})
|
||||
vbios: str = field(default=None,
|
||||
metadata={'doc': 'The version of the accelerators/GPUs video bios in the system.',
|
||||
'name': 'VBIOS'})
|
||||
compute_partition: str = field(default=None,
|
||||
metadata={'doc': 'The compute partitioning mode active on the accelerators/GPUs in the system (MI300 only).',
|
||||
'name': 'Compute Partition'})
|
||||
memory_partition: str = field(default=None,
|
||||
metadata={'doc': 'The memory partitioning mode active on the accelerators/GPUs in the system (MI300 only).',
|
||||
'name': 'Memory Partition'})
|
||||
hostname: str = field(
|
||||
default=None, metadata={"doc": "The hostname of the machine.", "name": "Hostname"}
|
||||
)
|
||||
cpu_model: str = field(
|
||||
default=None,
|
||||
metadata={"doc": "The model name of the CPU used.", "name": "CPU Model"},
|
||||
)
|
||||
sbios: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The system management bios version and vendor.",
|
||||
"name": "SBIOS",
|
||||
},
|
||||
)
|
||||
linux_distro: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The Linux distribution installed on the machine.",
|
||||
"name": "Linux Distribution",
|
||||
},
|
||||
)
|
||||
linux_kernel_version: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The Linux kernel version running on the machine.",
|
||||
"name": "Linux Kernel Version",
|
||||
},
|
||||
)
|
||||
amd_gpu_kernel_version: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The version of the AMDGPU driver installed on the machine. Unimplemented.",
|
||||
"name": "AMD GPU Kernel Version",
|
||||
},
|
||||
)
|
||||
cpu_memory: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The total amount of memory available to the CPU.",
|
||||
"unit": "KB",
|
||||
"name": "CPU Memory",
|
||||
},
|
||||
)
|
||||
gpu_memory: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The total amount of memory available to accelerators/GPUs in the system. Unimplemented.",
|
||||
"unit": "KB",
|
||||
"name": "GPU Memory",
|
||||
},
|
||||
)
|
||||
rocm_version: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The ROCm version used during data-collection.",
|
||||
"name": "ROCm Version",
|
||||
},
|
||||
)
|
||||
vbios: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The version of the accelerators/GPUs video bios in the system.",
|
||||
"name": "VBIOS",
|
||||
},
|
||||
)
|
||||
compute_partition: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The compute partitioning mode active on the accelerators/GPUs in the system (MI300 only).",
|
||||
"name": "Compute Partition",
|
||||
},
|
||||
)
|
||||
memory_partition: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The memory partitioning mode active on the accelerators/GPUs in the system (MI300 only).",
|
||||
"name": "Memory Partition",
|
||||
},
|
||||
)
|
||||
|
||||
##########################################
|
||||
## B. SoC Specs
|
||||
@@ -235,93 +319,168 @@ class MachineSpecs:
|
||||
gpu_model: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
'doc': 'The product name of the accelerators/GPUs in the system.',
|
||||
'name': 'GPU Model'})
|
||||
"doc": "The product name of the accelerators/GPUs in the system.",
|
||||
"name": "GPU Model",
|
||||
},
|
||||
)
|
||||
gpu_arch: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
'doc': 'The architecture name of the accelerators/GPUs in the system,\n'
|
||||
'as used by (e.g.,) the AMDGPU backed of LLVM.',
|
||||
'name': 'GPU Arch'})
|
||||
gpu_l1: str = field(default=None, metadata={'doc':
|
||||
"The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
||||
'name': 'GPU L1'})
|
||||
gpu_l2: str = field(default=None, metadata={'doc':
|
||||
"The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
||||
'name': 'GPU L2'})
|
||||
cu_per_gpu: str = field(default=None, metadata={'doc':
|
||||
"The total number of compute units per accelerator/GPU in the system. On systems with configurable\n"
|
||||
"partitioning, (e.g., MI300) this is the total number of compute units in a partition.",
|
||||
'name': 'CU per GPU'})
|
||||
simd_per_cu: str = field(default=None, metadata={'doc':
|
||||
"The number of SIMD processors in a compute unit for the accelerators/GPUs in the system.",
|
||||
'name': 'SIMD per CU'})
|
||||
se_per_gpu: str = field(default=None, metadata={'doc':
|
||||
'The number of shader engines on the accelerators/GPUs in the system. On systems with configurable\n'
|
||||
'partitioning, (e.g., MI300) this is the total number of shader engines in a partition.',
|
||||
'name': 'SE per GPU'})
|
||||
wave_size: str = field(default=None, metadata={'doc':
|
||||
'The number work-items in a wavefront on the accelerators/GPUs in the system.',
|
||||
'name': 'Wave Size'})
|
||||
workgroup_max_size: str = field(default=None, metadata={'doc':
|
||||
'The maximum number of work-items in a workgroup on the accelerators/GPUs in the system.',
|
||||
'name': 'Workgroup Max Size'})
|
||||
max_waves_per_cu: str = field(default=None, metadata={'doc':
|
||||
'The maximum number of wavefronts that can be resident on a compute unit on the\n'
|
||||
'accelerators/GPUs in the system',
|
||||
'name': 'Max Waves per CU'})
|
||||
max_sclk: str = field(default=None, metadata={'doc':
|
||||
'The maximum engine (compute-unit) clock rate of the accelerators/GPUs in the system.',
|
||||
'name': 'Max SCLK',
|
||||
'unit': 'MHz'})
|
||||
max_mclk: str = field(default=None, metadata={'doc':
|
||||
'The maximum memory clock rate of the accelerators/GPUs in the system.',
|
||||
'name': 'Max MCLK',
|
||||
'unit': 'MHz'})
|
||||
cur_sclk: str = field(default=None, metadata={'doc':
|
||||
'[RESERVED] The current engine (compute unit) clock rate of the accelerators/GPUs in the system. Unused.',
|
||||
'name': 'Cur SCLK',
|
||||
'unit': 'MHz'})
|
||||
cur_mclk: str = field(default=None, metadata={'doc':
|
||||
'[RESERVED] The current memory clock rate of the accelerators/GPUs in the system. Unused.',
|
||||
'name': 'Cur MCLK',
|
||||
'unit': 'MHz'})
|
||||
_l2_banks: str = None # NB: This only used in flatten_tcc_info_across_hbm_stacks()
|
||||
total_l2_chan: str = field(default=None, metadata={
|
||||
'doc': 'The maximum number of L2 cache channels on the accelerators/GPUs in the system. On systems with\n'
|
||||
'configurable partitioning, (e.g., MI300) this is the total number of L2 cache channels in a partition.',
|
||||
'name': 'Total L2 Channels'})
|
||||
lds_banks_per_cu: str = field(default=None, metadata={'doc':
|
||||
'The number of banks in the LDS for a compute unit on the accelerators/GPUs in the system.',
|
||||
'name': 'LDS Banks per CU'})
|
||||
sqc_per_gpu: str = field(default=None, metadata={
|
||||
'doc': 'The number of L1I/sL1D caches on the accelerators/GPUs in the system. On systems with\n'
|
||||
'configurable partitioning, (e.g., MI300) this is the total number of L1I/sL1D caches in a partition.',
|
||||
'name': 'SQC per GPU'})
|
||||
pipes_per_gpu: str = field(default=None, metadata={
|
||||
'doc': 'The number of scheduler-pipes on the accelerators/GPUs in the system.',
|
||||
'name': 'Pipes per GPU'})
|
||||
hbm_bw: str = field(default=None, metadata={
|
||||
'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'})
|
||||
num_xcd: str = field(default=None, metadata={
|
||||
'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'})
|
||||
"doc": "The architecture name of the accelerators/GPUs in the system,\n"
|
||||
"as used by (e.g.,) the AMDGPU backed of LLVM.",
|
||||
"name": "GPU Arch",
|
||||
},
|
||||
)
|
||||
gpu_l1: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
||||
"name": "GPU L1",
|
||||
},
|
||||
)
|
||||
gpu_l2: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs in the system in KiB",
|
||||
"name": "GPU L2",
|
||||
},
|
||||
)
|
||||
cu_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The total number of compute units per accelerator/GPU in the system. On systems with configurable\n"
|
||||
"partitioning, (e.g., MI300) this is the total number of compute units in a partition.",
|
||||
"name": "CU per GPU",
|
||||
},
|
||||
)
|
||||
simd_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of SIMD processors in a compute unit for the accelerators/GPUs in the system.",
|
||||
"name": "SIMD per CU",
|
||||
},
|
||||
)
|
||||
se_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of shader engines on the accelerators/GPUs in the system. On systems with configurable\n"
|
||||
"partitioning, (e.g., MI300) this is the total number of shader engines in a partition.",
|
||||
"name": "SE per GPU",
|
||||
},
|
||||
)
|
||||
wave_size: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number work-items in a wavefront on the accelerators/GPUs in the system.",
|
||||
"name": "Wave Size",
|
||||
},
|
||||
)
|
||||
workgroup_max_size: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of work-items in a workgroup on the accelerators/GPUs in the system.",
|
||||
"name": "Workgroup Max Size",
|
||||
},
|
||||
)
|
||||
max_waves_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of wavefronts that can be resident on a compute unit on the\n"
|
||||
"accelerators/GPUs in the system",
|
||||
"name": "Max Waves per CU",
|
||||
},
|
||||
)
|
||||
max_sclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum engine (compute-unit) clock rate of the accelerators/GPUs in the system.",
|
||||
"name": "Max SCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
)
|
||||
max_mclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum memory clock rate of the accelerators/GPUs in the system.",
|
||||
"name": "Max MCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
)
|
||||
cur_sclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The current engine (compute unit) clock rate of the accelerators/GPUs in the system. Unused.",
|
||||
"name": "Cur SCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
)
|
||||
cur_mclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The current memory clock rate of the accelerators/GPUs in the system. Unused.",
|
||||
"name": "Cur MCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
)
|
||||
_l2_banks: str = None # NB: This only used in flatten_tcc_info_across_hbm_stacks()
|
||||
total_l2_chan: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of L2 cache channels on the accelerators/GPUs in the system. On systems with\n"
|
||||
"configurable partitioning, (e.g., MI300) this is the total number of L2 cache channels in a partition.",
|
||||
"name": "Total L2 Channels",
|
||||
},
|
||||
)
|
||||
lds_banks_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of banks in the LDS for a compute unit on the accelerators/GPUs in the system.",
|
||||
"name": "LDS Banks per CU",
|
||||
},
|
||||
)
|
||||
sqc_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of L1I/sL1D caches on the accelerators/GPUs in the system. On systems with\n"
|
||||
"configurable partitioning, (e.g., MI300) this is the total number of L1I/sL1D caches in a partition.",
|
||||
"name": "SQC per GPU",
|
||||
},
|
||||
)
|
||||
pipes_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of scheduler-pipes on the accelerators/GPUs in the system.",
|
||||
"name": "Pipes per GPU",
|
||||
},
|
||||
)
|
||||
hbm_bw: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"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",
|
||||
},
|
||||
)
|
||||
num_xcd: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"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",
|
||||
},
|
||||
)
|
||||
|
||||
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"
|
||||
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
|
||||
return hbmchannels
|
||||
|
||||
|
||||
def get_class_members(self):
|
||||
all_populated = True
|
||||
data = {}
|
||||
@@ -332,20 +491,25 @@ class MachineSpecs:
|
||||
value = getattr(self, name)
|
||||
if value is None:
|
||||
# check if we've marked it optional
|
||||
if field.metadata and 'optional' in field.metadata and field.metadata['optional']:
|
||||
if (
|
||||
field.metadata
|
||||
and "optional" in field.metadata
|
||||
and field.metadata["optional"]
|
||||
):
|
||||
pass
|
||||
else:
|
||||
#TODO: use proper logging function when that's merged
|
||||
# TODO: use proper logging function when that's merged
|
||||
logging.warning(
|
||||
f"WARNING: Incomplete class definition for {self.gpu_arch}. "
|
||||
f"Expecting populated {name} but detected None.")
|
||||
f"Expecting populated {name} but detected None."
|
||||
)
|
||||
all_populated = False
|
||||
data[name] = value
|
||||
|
||||
if not all_populated:
|
||||
error("Missing specs fields for %s" % self.gpu_arch)
|
||||
return pd.DataFrame(data, index=[0])
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
topstr = "Machine Specifications: describing the state of the machine that Omniperf data was collected on.\n"
|
||||
data = []
|
||||
@@ -356,32 +520,30 @@ class MachineSpecs:
|
||||
value = getattr(self, name)
|
||||
if field.metadata:
|
||||
# check out of table before any re-naming for pretty-printing
|
||||
if 'intable' in field.metadata and not field.metadata['intable']:
|
||||
if name == 'version':
|
||||
topstr += f'Output version: {value}\n'
|
||||
if "intable" in field.metadata and not field.metadata["intable"]:
|
||||
if name == "version":
|
||||
topstr += f"Output version: {value}\n"
|
||||
else:
|
||||
error(f"Unknown out of table printing field: {name}")
|
||||
continue
|
||||
if 'name' in field.metadata:
|
||||
name = field.metadata['name']
|
||||
if 'unit' in field.metadata:
|
||||
_data['Unit'] = field.metadata['unit']
|
||||
if 'doc' in field.metadata:
|
||||
_data['Description'] = field.metadata['doc']
|
||||
_data['Spec'] = name
|
||||
_data['Value'] = value
|
||||
if "name" in field.metadata:
|
||||
name = field.metadata["name"]
|
||||
if "unit" in field.metadata:
|
||||
_data["Unit"] = field.metadata["unit"]
|
||||
if "doc" in field.metadata:
|
||||
_data["Description"] = field.metadata["doc"]
|
||||
_data["Spec"] = name
|
||||
_data["Value"] = value
|
||||
data.append(_data)
|
||||
df = pd.DataFrame(data)
|
||||
columns = ['Spec', 'Value']
|
||||
if 'Description' in df.columns:
|
||||
columns += ['Description']
|
||||
if 'Unit' in df.columns:
|
||||
columns += ['Unit']
|
||||
columns = ["Spec", "Value"]
|
||||
if "Description" in df.columns:
|
||||
columns += ["Description"]
|
||||
if "Unit" in df.columns:
|
||||
columns += ["Unit"]
|
||||
df = df[columns]
|
||||
df = df.fillna('')
|
||||
return (
|
||||
topstr +
|
||||
get_table_string(df, transpose=False, decimal=2))
|
||||
df = df.fillna("")
|
||||
return topstr + get_table_string(df, transpose=False, decimal=2)
|
||||
|
||||
|
||||
def get_rocm_ver():
|
||||
@@ -403,14 +565,20 @@ def get_rocm_ver():
|
||||
rocm_ver = ROCM_VER_USER
|
||||
else:
|
||||
_rocm_path = os.getenv("ROCM_PATH", "/opt/rocm")
|
||||
error("Unable to detect a complete local ROCm installation.\nThe expected %s/.info/ versioning directory is missing. Please ensure you have valid ROCm installation." % _rocm_path)
|
||||
error(
|
||||
"Unable to detect a complete local ROCm installation.\nThe expected %s/.info/ versioning directory is missing. Please ensure you have valid ROCm installation."
|
||||
% _rocm_path
|
||||
)
|
||||
return rocm_ver
|
||||
|
||||
def run(cmd,exit_on_error=False):
|
||||
|
||||
def run(cmd, exit_on_error=False):
|
||||
try:
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except FileNotFoundError as e:
|
||||
error(f"Unable to parse specs. Can't find ROCm asset: {e.filename}\nTry passing a path to an existing workload results in 'analyze' mode.")
|
||||
error(
|
||||
f"Unable to parse specs. Can't find ROCm asset: {e.filename}\nTry passing a path to an existing workload results in 'analyze' mode."
|
||||
)
|
||||
|
||||
if exit_on_error:
|
||||
if cmd[0] == "rocm-smi":
|
||||
@@ -434,35 +602,28 @@ 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)
|
||||
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
|
||||
if archname.lower() in ['mi50', 'mi100']:
|
||||
if archname.lower() in ["mi50", "mi100"]:
|
||||
sq_per_se = cu_per_se / 3
|
||||
sq_per_se = ceil(sq_per_se)
|
||||
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":
|
||||
error("Invalid compute partition found for {}".format(archname))
|
||||
if archname.lower() in mi300a_archs + mi300x_archs and compute_partition == "NA":
|
||||
error("Invalid compute partition found for {}".format(archname))
|
||||
if archname.lower() not in mi300a_archs + mi300x_archs:
|
||||
return 1
|
||||
# from the whitepaper
|
||||
@@ -484,8 +645,11 @@ def total_xcds(archname, compute_partition):
|
||||
if compute_partition.lower() == "cpx":
|
||||
if archname.lower() in mi300x_archs:
|
||||
return 2
|
||||
error("Unknown compute partition / arch found for {} / {}".format(
|
||||
compute_partition, archname))
|
||||
error(
|
||||
"Unknown compute partition / arch found for {} / {}".format(
|
||||
compute_partition, archname
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+10
-6
@@ -51,10 +51,12 @@ def string_multiple_lines(source, width, max_rows):
|
||||
|
||||
|
||||
def get_table_string(df, transpose=False, decimal=2):
|
||||
return tabulate(df.transpose() if transpose else df,
|
||||
headers="keys",
|
||||
tablefmt="fancy_grid",
|
||||
floatfmt="." + str(decimal) + "f")
|
||||
return tabulate(
|
||||
df.transpose() if transpose else df,
|
||||
headers="keys",
|
||||
tablefmt="fancy_grid",
|
||||
floatfmt="." + str(decimal) + "f",
|
||||
)
|
||||
|
||||
|
||||
def show_all(args, runs, archConfigs, output):
|
||||
@@ -221,9 +223,11 @@ def show_all(args, runs, archConfigs, output):
|
||||
# df when load it, because we need those items in column.
|
||||
# For metric_table, we only need to show the data in column
|
||||
# fash for now.
|
||||
transpose = (type != "raw_csv_table"
|
||||
transpose = (
|
||||
type != "raw_csv_table"
|
||||
and "columnwise" in table_config
|
||||
and table_config["columnwise"] == True)
|
||||
and table_config["columnwise"] == True
|
||||
)
|
||||
ss += (
|
||||
get_table_string(df, transpose=transpose, decimal=args.decimal)
|
||||
+ "\n"
|
||||
|
||||
+21
-13
@@ -198,10 +198,11 @@ def capture_subprocess_output(subprocess_args, new_env=None):
|
||||
|
||||
return (success, output)
|
||||
|
||||
|
||||
def run_prof(fname, profiler_options, workload_dir, mspec):
|
||||
|
||||
fbase = os.path.splitext(os.path.basename(fname))[0]
|
||||
|
||||
|
||||
logging.debug("pmc file: %s" % str(os.path.basename(fname)))
|
||||
|
||||
# standard rocprof options
|
||||
@@ -210,7 +211,12 @@ def run_prof(fname, profiler_options, workload_dir, mspec):
|
||||
|
||||
# set required env var for mi300
|
||||
new_env = None
|
||||
if (mspec.gpu_model.lower() == "mi300x_a0" or mspec.gpu_model.lower() == "mi300x_a1" or mspec.gpu_model.lower() == "mi300a_a0" or mspec.gpu_model.lower() == "mi300a_a1") and (
|
||||
if (
|
||||
mspec.gpu_model.lower() == "mi300x_a0"
|
||||
or mspec.gpu_model.lower() == "mi300x_a1"
|
||||
or mspec.gpu_model.lower() == "mi300a_a0"
|
||||
or mspec.gpu_model.lower() == "mi300a_a1"
|
||||
) and (
|
||||
os.path.basename(fname) == "pmc_perf_13.txt"
|
||||
or os.path.basename(fname) == "pmc_perf_14.txt"
|
||||
or os.path.basename(fname) == "pmc_perf_15.txt"
|
||||
@@ -233,9 +239,7 @@ def run_prof(fname, profiler_options, workload_dir, mspec):
|
||||
# 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)
|
||||
)
|
||||
df = flatten_tcc_info_across_hbm_stacks(f, hbm_stack_num, int(mspec._l2_banks))
|
||||
df.to_csv(f, index=False)
|
||||
|
||||
if os.path.exists(workload_dir + "/out"):
|
||||
@@ -295,13 +299,16 @@ def replace_timestamps(workload_dir):
|
||||
)
|
||||
logging.warning(warning + "\n")
|
||||
|
||||
def gen_sysinfo(workload_name, workload_dir, ip_blocks, app_cmd, skip_roof, roof_only, mspec):
|
||||
|
||||
def gen_sysinfo(
|
||||
workload_name, workload_dir, ip_blocks, app_cmd, skip_roof, roof_only, mspec
|
||||
):
|
||||
df = mspec.get_class_members()
|
||||
|
||||
|
||||
# Append workload information to machine specs
|
||||
df['command'] = app_cmd
|
||||
df['workload_name'] = workload_name
|
||||
|
||||
df["command"] = app_cmd
|
||||
df["workload_name"] = workload_name
|
||||
|
||||
blocks = []
|
||||
if ip_blocks == None:
|
||||
t = ["SQ", "LDS", "SQC", "TA", "TD", "TCP", "TCC", "SPI", "CPC", "CPF"]
|
||||
@@ -310,11 +317,12 @@ def gen_sysinfo(workload_name, workload_dir, ip_blocks, app_cmd, skip_roof, roof
|
||||
blocks += ip_blocks
|
||||
if mspec.gpu_arch == "gfx90a" and (not skip_roof):
|
||||
blocks.append("roofline")
|
||||
df['ip_blocks'] = "|".join(blocks)
|
||||
df["ip_blocks"] = "|".join(blocks)
|
||||
|
||||
# Save csv
|
||||
df.to_csv(workload_dir + "/" + "sysinfo.csv", index=False)
|
||||
|
||||
|
||||
def detect_roofline(mspec):
|
||||
rocm_ver = mspec.rocm_version[:1]
|
||||
|
||||
@@ -380,9 +388,9 @@ def run_rocscope(args, fname):
|
||||
logging.error(result.stderr.decode("ascii"))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def mibench(args, mspec):
|
||||
"""Run roofline microbenchmark to generate peak BW and FLOP measurements.
|
||||
"""
|
||||
"""Run roofline microbenchmark to generate peak BW and FLOP measurements."""
|
||||
logging.info("[roofline] No roofline data found. Generating...")
|
||||
distro_map = {"platform:el8": "rhel8", "15.3": "sle15sp3", "20.04": "ubuntu20_04"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user