Reorganize the specs module to reduce duplicate code

Signed-off-by: colramos-amd <colramos@amd.com>


[ROCm/rocprofiler-compute commit: 3b1b8d7b5b]
Этот коммит содержится в:
colramos-amd
2024-02-20 13:34:56 -06:00
коммит произвёл Cole Ramos
родитель f240822ea1
Коммит 5352eafde4
20 изменённых файлов: 495 добавлений и 781 удалений
+1
Просмотреть файл
@@ -90,6 +90,7 @@ 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.")
profile_group.add_argument(
"-n",
+2 -3
Просмотреть файл
@@ -135,7 +135,7 @@ class OmniAnalyze_Base:
# load required configs
for d in self.__args.path:
sys_info = file_io.load_sys_info(Path(d[0], "sysinfo.csv"))
arch = sys_info.iloc[0]["gpu_soc"]
arch = sys_info.iloc[0]["arch"]
args = self.__args
self.generate_configs(
arch,
@@ -155,10 +155,9 @@ class OmniAnalyze_Base:
w.sys_info, self.__args.specs_correction
)
w.avail_ips = w.sys_info["ip_blocks"].item().split("|")
arch = w.sys_info.iloc[0]["gpu_soc"]
arch = w.sys_info.iloc[0]["arch"]
w.dfs = copy.deepcopy(self._arch_configs[arch].dfs)
w.dfs_type = self._arch_configs[arch].dfs_type
w.soc_spec = self.get_socs()[arch].get_soc_param()
self._runs[d[0]] = w
return self._runs
+4 -8
Просмотреть файл
@@ -70,17 +70,13 @@ 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_soc"]
],
self._output,
self._arch_configs[self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["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_soc"]
],
self._output,
self._arch_configs[self._runs[self.get_args().path[0][0]].sys_info.iloc[0]["arch"]],
self._output
)
+11 -12
Просмотреть файл
@@ -23,7 +23,7 @@
##############################################################################el
from omniperf_analyze.analysis_base import OmniAnalyze_Base
from utils.utils import demarcate
from utils.utils import demarcate, error
from utils import file_io, parser
from utils.gui import build_bar_chart, build_table_chart
@@ -163,12 +163,12 @@ class webui_analysis(OmniAnalyze_Base):
# update roofline for visualization in GUI
self.get_socs()[self.arch].analysis_setup(
roofline_parameters={
"path_to_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,12 +284,10 @@ 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_soc"]
self.arch = self._runs[self.dest_dir].sys_info.iloc[0]['GPU']
else:
self.error(
"Multiple runs not yet supported in GUI. Retry without --gui flag."
)
error("Multiple runs not yet supported in GUI. Retry without --gui flag.")
@demarcate
def run_analysis(self):
@@ -308,6 +306,7 @@ class webui_analysis(OmniAnalyze_Base):
input_filters,
self._arch_configs[self.arch],
)
# Here I expect that self._runs[<path>].raw_pmc will no longer be populated
if args.random_port:
self.app.run_server(
debug=False, host="0.0.0.0", port=random.randint(1024, 49151)
+25 -54
Просмотреть файл
@@ -28,16 +28,8 @@ import sys
import os
from pathlib import Path
import shutil
from utils.specs import get_machine_specs
from utils.utils import (
demarcate,
trace_logger,
get_version,
get_version_display,
detect_rocprof,
error,
get_submodules,
)
from utils.specs import MachineSpecs
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
@@ -68,6 +60,7 @@ class Omniperf:
}
self.__options = {}
self.__supported_archs = SUPPORTED_ARCHS
self.__mspec: MachineSpecs = None # to be initalized in load_soc_specs()
self.setup_logging()
self.set_version()
@@ -163,33 +156,22 @@ class Omniperf:
return
@demarcate
def detect_soc(self, sys_info=pd.DataFrame()):
"""Load OmniSoC instance for Omniperf run"""
# in case of analyze mode, we can explicitly specify an arch
# rather than detect from rocminfo
if sys_info.empty:
mspec = get_machine_specs(0)
arch = mspec.arch
target = mspec.GPU
else:
arch = sys_info.iloc[0]["gpu_soc"]
target = sys_info.iloc[0]["name"]
def load_soc_specs(self, sysinfo=None):
"""Load OmniSoC instance for Omniperf run
"""
if not sysinfo is None:
self.__mspec = MachineSpecs(self.__args, sysinfo)
# instantiate underlying SoC support class
# in case of analyze mode, __soc can accommodate multiple archs
arch = self.__mspec.arch
# NB: This checker is a bit redundent. We already check this in specs module
if arch not in self.__supported_archs.keys():
error("%s is an unsupported SoC" % arch)
else:
self.__soc_name.add(target)
if hasattr(self.__args, "target"):
self.__args.target = target
soc_module = importlib.import_module("omniperf_soc.soc_" + arch)
soc_class = getattr(soc_module, arch + "_soc")
self.__soc[arch] = soc_class(self.__args)
logging.info("SoC = %s" % self.__soc_name)
return arch
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
@demarcate
def parse_args(self):
@@ -207,7 +189,7 @@ class Omniperf:
self.__args = parser.parse_args()
if self.__args.specs:
print(get_machine_specs(0))
print(MachineSpecs(self.__args))
sys.exit(0)
if self.__args.mode == None:
parser.print_help(sys.stderr)
@@ -218,47 +200,36 @@ class Omniperf:
@demarcate
def run_profiler(self):
self.print_graphic()
targ_arch = self.detect_soc()
self.load_soc_specs()
# 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.__args.target
)
self.__args.path = os.path.join(self.__args.path, self.__args.name, self.__mspec.GPU)
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[targ_arch]
)
profiler = rocprof_v1_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.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[targ_arch]
)
profiler = rocprof_v2_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.arch])
elif self.__profiler_mode == "rocscope":
from omniperf_profile.profiler_rocscope import rocscope_profiler
profiler = rocscope_profiler(
self.__args, self.__profiler_mode, self.__soc[targ_arch]
)
profiler = rocscope_profiler(self.__args, self.__profiler_mode, self.__soc[self.__mspec.arch])
else:
logging.error("Unsupported profiler")
sys.exit(1)
# -----------------------
# run profiling workflow
# -----------------------
self.__soc[targ_arch].profiling_setup()
#-----------------------
self.__soc[self.__mspec.arch].profiling_setup()
profiler.pre_processing()
profiler.run_profiling(self.__version["ver"], config.prog)
profiler.post_processing()
self.__soc[targ_arch].post_profiling()
self.__soc[self.__mspec.arch].post_profiling()
return
@@ -305,7 +276,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"))
self.detect_soc(sys_info)
self.load_soc_specs(sys_info)
analyzer.set_soc(self.__soc)
analyzer.pre_processing()
+4 -7
Просмотреть файл
@@ -312,7 +312,7 @@ class OmniProfiler_Base:
# log basic info
logging.info(str(prog) + " ver: " + str(version))
logging.info("Path: " + str(os.path.abspath(self.__args.path)))
logging.info("Target: " + str(self.__args.target))
logging.info("Target: " + str(self._soc._mspec.GPU))
logging.info("Command: " + str(self.__args.remaining))
logging.info("Kernel Selection: " + str(self.__args.kernel))
logging.info("Dispatch Selection: " + str(self.__args.dispatch))
@@ -374,14 +374,10 @@ class OmniProfiler_Base:
if self.__profiler == "rocprofv1" or self.__profiler == "rocprofv2":
run_prof(
fname=fname,
# workload_dir=self.get_args().path,
# perfmon_dir=self.__perfmon_dir,
# cmd=self.__args.remaining,
# target=self.__args.target,
fname=fname,
profiler_options=options,
target=self.__args.target,
workload_dir=self.get_args().path,
mspec=self._soc._mspec,
)
elif self.__profiler == "rocscope":
@@ -403,6 +399,7 @@ class OmniProfiler_Base:
app_cmd=self.__args.remaining,
skip_roof=self.__args.no_roof,
roof_only=self.__args.roof_only,
mspec=self._soc._mspec,
)
+109 -38
Просмотреть файл
@@ -33,53 +33,46 @@ import numpy as np
from utils.utils import demarcate
from pathlib import Path
from omniperf_base import SUPPORTED_ARCHS
class OmniSoC_Base:
def __init__(self, args):
class OmniSoC_Base():
def __init__(self,args,mspec): # new info field will contain rocminfo or sysinfo to populate properties
self.__args = args
self.__name = None # SoC name
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
if self.__args.path == os.path.join(os.getcwd(), "workloads"):
self.__workload_dir = os.path.join(
self.__args.path, self.__args.name, self.__args.target
)
else:
self.__workload_dir = self.__args.path
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)
else:
self.__workload_dir = self.__args.path
def __hash__(self):
return hash(self.__name)
return hash(self.__arch)
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
return self.__name == other.get_soc()
return self.__arch == other.get_soc()
def set_perfmon_dir(self, path: str):
self.__perfmon_dir = path
def set_perfmon_config(self, config: dict):
self.__perfmon_config = config
def set_soc_param(self, param: dict):
self.__soc_params = param
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_soc_name(self, soc: str):
self.__name = soc
def get_soc_name(self):
return self.__name
def set_arch(self, arch: str):
self.__arch = arch
def get_arch(self):
return self.__arch
def get_args(self):
return self.__args
@@ -95,6 +88,83 @@ class OmniSoC_Base:
# assume no SoC specific options and return empty list by default
return []
@demarcate
def populate_mspec(self):
from utils.specs import search, run
if not hasattr(self._mspec, "_rocminfo"):
return
# load stats from rocminfo
self._mspec.L1 = ""
self._mspec.L2 = ""
for idx2, linetext in enumerate(self._mspec._rocminfo):
key = search(r"^\s*L1:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.L1 = key
continue
key = search(r"^\s*L2:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.L2 = key
continue
key = search(r"^\s*Max Clock Freq\. \(MHz\):\s+([0-9]+)", linetext)
if key != None:
self._mspec.max_sclk = key
continue
key = search(r"^\s*Compute Unit:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.CU = key
continue
key = search(r"^\s*SIMDs per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.SIMD = key
continue
key = search(r"^\s*Shader Engines:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.SE = key
continue
key = search(r"^\s*Wavefront Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.wave_size = key
continue
key = search(r"^\s*Workgroup Max Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.workgroup_max_size = key
continue
key = search(r"^\s*Max Waves Per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
self._mspec.max_waves_per_cu = key
break
# 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)
# 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)
self._mspec.cur_sclk = self._mspec.max_sclk
self._mspec.cur_mclk = self._mspec.max_mclk
self._mspec.compute_partition = ""
self._mspec.memory_partition = ""
# specify gpu name for gfx942 hardware
self._mspec.GPU = list(SUPPORTED_ARCHS[self._mspec.arch].keys())[0].upper()
if self._mspec.GPU == "MI300":
self._mspec.GPU = list(SUPPORTED_ARCHS[self._mspec.arch].values())[0][0]
if (self._mspec.arch == "gfx942") and ("MI300A" in self._mspec._rocminfo):
self._mspec.GPU = "MI300A_A1"
if (self._mspec.arch == "gfx942") and ("MI300A" not in self._mspec._rocminfo):
self._mspec.GPU = "MI300X_A1"
@demarcate
def perfmon_filter(self, roofline_perfmon_only: bool):
"""Filter default performance counter set based on user arguments"""
@@ -114,9 +184,7 @@ 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.__name + "/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:
@@ -152,19 +220,22 @@ class OmniSoC_Base:
# ----------------------------------------------------
@abstractmethod
def profiling_setup(self):
"""Perform any SoC-specific setup prior to profiling."""
logging.debug("[profiling] perform SoC profiling setup for %s" % self.__name)
"""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."""
logging.debug("[profiling] perform SoC post processing for %s" % self.__name)
"""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."""
logging.debug("[analysis] perform SoC analysis setup for %s" % self.__name)
"""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):
+12 -28
Просмотреть файл
@@ -27,32 +27,11 @@ import config
from omniperf_soc.soc_base import OmniSoC_Base
from utils.utils import demarcate, error
SOC_PARAM = {
"numSE": 4,
"numCU": 60,
"numSIMD": 240,
"numPipes": 4,
"numWavesPerCU": 40,
"numSQC": 15,
"L2Banks": 16,
"LDSBanks": 32,
"Freq": 1725,
"mclk": 1000,
}
class gfx906_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("gfx906")
self.set_perfmon_dir(
os.path.join(
str(config.omniperf_home),
"omniperf_soc",
"profile_configs",
self.get_soc_name(),
)
)
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_compatible_profilers(["rocprofv1", "rocscope"])
# Per IP block max number of simultaneous counters. GFX IP Blocks
self.set_perfmon_config(
@@ -70,7 +49,12 @@ class gfx906_soc(OmniSoC_Base):
"TCC_channels": 16,
}
)
self.set_soc_param(SOC_PARAM)
# Set arch specific specs
self._mspec.L2Banks = 16
self._mspec.LDSBanks = 32
self._mspec.numSQC = 15
self._mspec.numPipes = 4
# -----------------------
# Required child methods
@@ -80,7 +64,7 @@ class gfx906_soc(OmniSoC_Base):
"""Perform any SoC-specific setup prior to profiling."""
super().profiling_setup()
if self.get_args().roof_only:
error("%s does not support roofline analysis" % self.get_soc_name())
error("%s does not support roofline analysis" % self.get_arch())
# Perfmon filtering
self.perfmon_filter()
+15 -28
Просмотреть файл
@@ -27,32 +27,11 @@ import config
from omniperf_soc.soc_base import OmniSoC_Base
from utils.utils import demarcate, error
SOC_PARAM = {
"numSE": 8,
"numCU": 120,
"numSIMD": 480,
"numPipes": 4,
"numWavesPerCU": 40,
"numSQC": 30,
"L2Banks": 32,
"LDSBanks": 32,
"Freq": 1502,
"mclk": 1200,
}
class gfx908_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("gfx908")
self.set_perfmon_dir(
os.path.join(
str(config.omniperf_home),
"omniperf_soc",
"profile_configs",
self.get_soc_name(),
)
)
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_compatible_profilers(["rocprofv1", "rocscope"])
# Per IP block max number of simultaneous counters. GFX IP Blocks
self.set_perfmon_config(
@@ -70,7 +49,15 @@ class gfx908_soc(OmniSoC_Base):
"TCC_channels": 32,
}
)
self.set_soc_param(SOC_PARAM)
# Set arch specific specs
self._mspec.L2Banks = 32
self._mspec.LDSBanks = 32
self._mspec.numSQC = 30
self._mspec.numPipes = 4
# --showmclkrange is broken in Mi100, hardcode freq
self._info['max_mclk'] = 1200
self._info['cur_mclk'] = 1200
@demarcate
def get_profiler_options(self):
@@ -85,7 +72,7 @@ class gfx908_soc(OmniSoC_Base):
"""Perform any SoC-specific setup prior to profiling."""
super().profiling_setup()
if self.get_args().roof_only:
error("%s does not support roofline analysis" % self.get_soc_name())
error("%s does not support roofline analysis" % self.get_arch())
# Perfmon filtering
self.perfmon_filter(self.get_args().roof_only)
+15 -38
Просмотреть файл
@@ -29,42 +29,14 @@ from utils.utils import demarcate, mibench
from roofline import Roofline
import logging
SOC_PARAM = {
"numSE": 8,
"numCU": 110,
"numSIMD": 440,
"numPipes": 4,
"numWavesPerCU": 32,
"numSQC": 56,
"L2Banks": 32,
"LDSBanks": 32,
"Freq": 1700,
"mclk": 1600,
}
class gfx90a_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("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",
)
)
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"))
else:
self.set_perfmon_dir(
os.path.join(
str(config.omniperf_home),
"omniperf_soc",
"profile_configs",
self.get_soc_name(),
)
)
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,8 +54,13 @@ class gfx90a_soc(OmniSoC_Base):
"TCC_channels": 32,
}
)
self.set_soc_param(SOC_PARAM)
self.roofline_obj = Roofline(args)
self.roofline_obj = Roofline(args, self._mspec)
# Set arch specific specs
self._mspec.L2Banks = 32
self._mspec.LDSBanks = 32
self._mspec.numSQC = 56
self._mspec.numPipes = 4
# -----------------------
# Required child methods
@@ -104,7 +81,7 @@ class gfx90a_soc(OmniSoC_Base):
"[roofline] Checking for roofline.csv in " + str(self.get_args().path)
)
if not os.path.isfile(os.path.join(self.get_args().path, "roofline.csv")):
mibench(self.get_args())
mibench(self.get_args(), self._mspec)
self.roofline_obj.post_processing()
else:
logging.info("[roofline] Skipping roofline")
+13 -29
Просмотреть файл
@@ -29,33 +29,12 @@ from utils.utils import demarcate, mibench
from roofline import Roofline
import logging
SOC_PARAM = {
"numSE": 8,
"numCU": 38,
"numSIMD": 4,
"numPipes": 4,
"numWavesPerCU": 32,
"numSQC": 56,
"L2Banks": 16,
"LDSBanks": 32,
"Freq": 1950,
"mclk": 1300,
}
class gfx940_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("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",
)
)
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"))
else:
# NB: We're using generalized Mi300 perfmon configs
self.set_perfmon_dir(
@@ -80,8 +59,13 @@ class gfx940_soc(OmniSoC_Base):
"TCC_channels": 32,
}
)
self.set_soc_param(SOC_PARAM)
self.roofline_obj = Roofline(args)
self.roofline_obj = Roofline(args, self._mspec)
# Set arch specific specs
self._mspec.L2Banks = 16
self._mspec.LDSBanks = 32
self._mspec.numSQC = 56
self._mspec.numPipes = 4
# -----------------------
# Required child methods
+13 -29
Просмотреть файл
@@ -29,33 +29,12 @@ from utils.utils import demarcate, mibench
from roofline import Roofline
import logging
SOC_PARAM = {
"numSE": 8,
"numCU": 38,
"numSIMD": 4,
"numPipes": 4,
"numWavesPerCU": 32,
"numSQC": 56,
"L2Banks": 16,
"LDSBanks": 32,
"Freq": 1950,
"mclk": 1300,
}
class gfx941_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("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",
)
)
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"))
else:
# NB: We're using generalized Mi300 perfmon configs
self.set_perfmon_dir(
@@ -80,8 +59,13 @@ class gfx941_soc(OmniSoC_Base):
"TCC_channels": 32,
}
)
self.set_soc_param(SOC_PARAM)
self.roofline_obj = Roofline(args)
self.roofline_obj = Roofline(args, self._mspec)
# Set arch specific specs
self._mspec.L2Banks = 16
self._mspec.LDSBanks = 32
self._mspec.numSQC = 56
self._mspec.numPipes = 4
# -----------------------
# Required child methods
+13 -29
Просмотреть файл
@@ -29,33 +29,12 @@ from utils.utils import demarcate, mibench
from roofline import Roofline
import logging
SOC_PARAM = {
"numSE": 8,
"numCU": 38,
"numSIMD": 4,
"numPipes": 4,
"numWavesPerCU": 32,
"numSQC": 56,
"L2Banks": 16,
"LDSBanks": 32,
"Freq": 1950,
"mclk": 1300,
}
class gfx942_soc(OmniSoC_Base):
def __init__(self, args):
super().__init__(args)
self.set_soc_name("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",
)
)
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"))
else:
# NB: We're using generalized Mi300 perfmon configs
self.set_perfmon_dir(
@@ -80,8 +59,13 @@ class gfx942_soc(OmniSoC_Base):
"TCC_channels": 32,
}
)
self.set_soc_param(SOC_PARAM)
self.roofline_obj = Roofline(args)
self.roofline_obj = Roofline(args, self.__mspec)
# Set arch specific specs
self._mspec.L2Banks = 16
self._mspec.LDSBanks = 32
self._mspec.numSQC = 56
self._mspec.numPipes = 4
# -----------------------
# Required child methods
+48 -60
Просмотреть файл
@@ -38,34 +38,35 @@ SYMBOLS = [0, 1, 2, 3, 4, 5, 13, 17, 18, 20]
class Roofline:
def __init__(self, args, run_parameters=None):
def __init__(self, args, mspec, run_parameters=None):
self.__args = args
self.__run_parameters = (
run_parameters
if run_parameters
else {
"path_to_dir": self.__args.path,
"device_id": 0,
"sort_type": "kernels",
"mem_level": "ALL",
"include_kernel_names": False,
"is_standalone": False,
}
)
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.__ai_data = None
self.__ceiling_data = None
self.__figure = go.Figure()
if not isinstance(self.__run_parameters["path_to_dir"], list):
self.roof_setup()
# Set roofline run parameters from args
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'):
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):
self.roof_setup()
self.validate_parameters()
@@ -77,13 +78,11 @@ class Roofline:
def roof_setup(self):
# set default workload path if not specified
if self.__run_parameters["path_to_dir"] == os.path.join(os.getcwd(), "workloads"):
self.__run_parameters["path_to_dir"] = os.path.join(
self.__run_parameters["path_to_dir"], self.__args.name, self.__args.target
)
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)
# create new directory for roofline if it doesn't exist
if not os.path.isdir(self.__run_parameters["path_to_dir"]):
os.makedirs(self.__run_parameters["path_to_dir"])
if not os.path.isdir(self.__run_parameters['workload_dir']):
os.makedirs(self.__run_parameters['workload_dir'])
@demarcate
def empirical_roofline(
@@ -92,9 +91,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["path_to_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]))
@@ -132,33 +131,21 @@ class Roofline:
if self.__run_parameters["is_standalone"]:
dev_id = str(self.__run_parameters["device_id"])
fp32_fig.write_image(
self.__run_parameters["path_to_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["path_to_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["path_to_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["path_to_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["path_to_dir"]
+ "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
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["path_to_dir"] + "/kernelName_legend.pdf"
)
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(
@@ -345,7 +332,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["path_to_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))
@@ -366,12 +353,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
)
@abstractmethod
@@ -383,7 +371,7 @@ class Roofline:
)
roof_path = os.path.join(self.__args.path, "roofline.csv")
if not os.path.isfile(roof_path):
mibench(self.__args)
mibench(self.__args, self.__mspec)
# check for profiling data
logging.info(
@@ -401,7 +389,7 @@ class Roofline:
elif self.__args.no_roof:
logging.info("[roofline] Skipping roofline.")
else:
mibench(self.__args)
mibench(self.__args, self.__mspec)
# NB: Currently the post_prossesing() method is the only one being used by omniperf,
# we include pre_processing() and profile() methods for those who wish to borrow the roofline module
+1 -5
Просмотреть файл
@@ -54,11 +54,7 @@ class DatabaseConnector:
self.client: MongoClient = None
@demarcate
def prep_import(self, profile_and_export=False):
if profile_and_export:
self.connection_info["workload"] = os.path.join(
self.connection_info["workload"], self.args.target
)
def prep_import(self):
# Extract SoC and workload name from sysinfo.csv
sys_info = os.path.join(self.connection_info["workload"], "sysinfo.csv")
+8 -16
Просмотреть файл
@@ -663,7 +663,7 @@ def build_metric_value_string(dfs, dfs_type, normal_unit):
# print(tabulate(df, headers='keys', tablefmt='fancy_grid'))
def eval_metric(dfs, dfs_type, sys_info, soc_spec, raw_pmc_df, debug):
def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug):
"""
Execute the expr string for each metric in the df.
"""
@@ -679,25 +679,18 @@ def eval_metric(dfs, dfs_type, sys_info, soc_spec, raw_pmc_df, debug):
print("WARNING: Dectected GRBM_GUI_ACTIVE == 0\nHaulting execution.")
sys.exit(1)
# NB:
# Following with Omniperf 0.2.0, we are using HW spec from sys_info instead.
# The soc_spec is not in using right now, but can be used to do verification
# against sys_info, forced theoretical evaluation, or supporting tool-chains
# broken.
ammolite__numSE = sys_info.numSE
ammolite__numSE = sys_info.SE
ammolite__numPipes = sys_info.numPipes
ammolite__numCU = sys_info.numCU
ammolite__numSIMD = sys_info.numSIMD
ammolite__numWavesPerCU = sys_info.maxWavesPerCU # todo: check do we still need it
ammolite__numCU = sys_info.CU
ammolite__numSIMD = sys_info.SIMD
ammolite__numWavesPerCU = sys_info.max_waves_per_cu # todo: check do we still need it
ammolite__numSQC = sys_info.numSQC
ammolite__L2Banks = sys_info.L2Banks
ammolite__LDSBanks = soc_spec[
"LDSBanks"
] # todo: eventually switch this over to sys_info. its a new spec so trying not to break compatibility
ammolite__LDSBanks = sys_info.LDSBanks
ammolite__freq = sys_info.cur_sclk # todo: check do we still need it
ammolite__mclk = sys_info.cur_mclk
ammolite__sclk = sys_info.sclk
ammolite__maxWavesPerCU = sys_info.maxWavesPerCU
ammolite__sclk = sys_info.max_sclk
ammolite__maxWavesPerCU = sys_info.max_waves_per_cu
ammolite__hbmBW = sys_info.hbmBW
ammolite__totalL2Banks = calc_builtin_var("$totalL2Banks", sys_info)
@@ -947,7 +940,6 @@ def load_table_data(workload, dir, is_gui, debug, verbose, skipKernelTop=False):
workload.dfs,
workload.dfs_type,
workload.sys_info.iloc[0],
workload.soc_spec,
apply_filters(workload, dir, is_gui, debug),
debug,
)
+1 -1
Просмотреть файл
@@ -474,7 +474,7 @@ def calc_ai(sort_type, ret_df):
def constuct_roof(roofline_parameters, dtype):
benchmark_results = os.path.join(roofline_parameters["path_to_dir"], "roofline.csv")
benchmark_results = os.path.join(roofline_parameters["workload_dir"], "roofline.csv")
# -----------------------------------------------------
# Initialize roofline data dictionary from roofline.csv
# -----------------------------------------------------
-1
Просмотреть файл
@@ -59,7 +59,6 @@ class ArchConfig:
@dataclass
class Workload:
sys_info: pd.DataFrame = None
soc_spec: dict = None # TODO: might move it to ArchConfig
raw_pmc: pd.DataFrame = None
dfs: Dict[int, pd.DataFrame] = field(default_factory=dict)
dfs_type: Dict[int, str] = field(default_factory=dict)
+175 -304
Просмотреть файл
@@ -31,46 +31,158 @@ import socket
import subprocess
import importlib
import logging
import pandas as pd
from datetime import datetime
from dataclasses import dataclass
from pathlib import Path as path
from textwrap import dedent
from utils.utils import error, get_hbm_stack_num
VERSION_LOC = [
"version",
"version-dev",
"version-hip-libraries",
"version-hiprt",
"version-hiprt-devel",
"version-hip-sdk",
"version-libs",
"version-utils",
]
@dataclass
class MachineSpecs:
hostname: str
CPU: str
sbios: str
kernel_version: str
ram: str
distro: str
rocm_version: str
GPU: str
arch: str
vbios: str
L1: str
L2: str
CU: str
SIMD: str
SE: str
wave_size: str
workgroup_max_size: str
max_sclk: str
max_mclk: str
cur_sclk: str
cur_mclk: str
max_waves_per_cu: str
L2Banks: str
totalL2Banks: str
LDSBanks: str
numSQC: str
numPipes: str
hbmBW: str
compute_partition: str
memory_partition: str
def __init__(self, args, sysinfo=None):
if not sysinfo is None:
self.arch = sysinfo.iloc[0]["arch"]
return
# read timestamp info
now = datetime.now()
local_now = now.astimezone()
local_tz = local_now.tzinfo
local_tzname = local_tz.tzname(local_now)
self.timestamp = now.strftime("%c") + " (" + local_tzname + ")"
# read rocminfo
rocminfo_full = run(["rocminfo"])
self._rocminfo = rocminfo_full.split("\n")
##########################################
## A. Machine Specs
##########################################
cpuinfo = path("/proc/cpuinfo").read_text()
meminfo = path("/proc/meminfo").read_text()
version = path("/proc/version").read_text()
os_release = path("/etc/os-release").read_text()
self.hostname: str = socket.gethostname()
self.CPU: str = search(r"^model name\s*: (.*?)$", cpuinfo)
self.sbios: str = (
path("/sys/class/dmi/id/bios_vendor").read_text().strip()
+ path("/sys/class/dmi/id/bios_version").read_text().strip()
)
self.kernel_version: str = search(r"version (\S*)", version)
self.ram: str = search(r"MemTotal:\s*(\S*)", meminfo)
self.distro: str = search(r'PRETTY_NAME="(.*?)"', os_release)
if self.distro is None:
self.distro = ""
self.rocm_version: str = get_rocm_ver().strip()
#FIXME: use device
self.vbios: str = search(
r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True)
)
self.compute_partition: str = search(
r"Compute Partition:\s*(\w+)", run(["rocm-smi", "--showcomputepartition"])
)
if self.compute_partition is None:
self.compute_partition = "NA"
self.memory_partition: str = search(
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"])
)
if self.memory_partition is None:
self.memory_partition = "NA"
##########################################
## B. SoC Specs
##########################################
self.arch: str = self.detect_arch()[0]
self.L1: str = None
self.L2: str = None
self.CU: str = None
self.SIMD: str = None
self.SE: str = None
self.wave_size: str = None
self.workgroup_max_size: str = None
self.max_sclk: str = None
self.max_mclk: str = None
self.cur_sclk: str = None
self.cur_mclk: str = None
self.max_waves_per_cu: str = None
self.GPU: str = None
self.L2Banks: str = None
self.LDSBanks: str = None
self.numSQC: str = None
self.numPipes: str = None
self.totalL2Banks: str = None
self.hbmBW: str = None
# Load above SoC specs via module import
try:
soc_module = importlib.import_module('omniperf_soc.soc_'+ self.arch)
except ModuleNotFoundError as e:
error("Arch %s marked as supported, but couldn't find class implementation %s." % (self.arch, e))
soc_class = getattr(soc_module, self.arch+'_soc')
self._rocminfo = self._rocminfo[self.detect_arch()[1] + 1 :] # update rocminfo for target section
soc_obj = soc_class(args, self)
# Update arch specific specs
self.totalL2Banks: str = total_l2_banks(
self.GPU, int(self.L2Banks), self.memory_partition
)
self.hbmBW: str = str(int(self.max_mclk) / 1000 * 32 * self.get_hbm_channels())
def detect_arch(self):
from omniperf_base import SUPPORTED_ARCHS
for idx1, linetext in enumerate(self._rocminfo):
gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext)
if gpu_arch in SUPPORTED_ARCHS.keys():
break
if str(gpu_arch) in SUPPORTED_ARCHS.keys():
gpu_arch = str(gpu_arch)
break
if not gpu_arch in SUPPORTED_ARCHS.keys():
error("[profiling] Cannot find a supported arch in rocminfo")
else:
return (gpu_arch, idx1)
def get_hbm_channels(self):
hbmchannels = int(self.totalL2Banks)
if (
self.GPU.lower() == "mi300a_a0"
or self.GPU.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 = {}
# dataclass uses an OrderedDict for member variables, ensuring order consistency
for attr_name in self.__dict__.keys():
if not attr_name.startswith("_"):
attr_value = getattr(self, attr_name)
if attr_value is None:
#TODO: use proper logging function when that's merged
logging.warning(f"WARNING: Incomplete class definition for {self.arch}. Expecting populated {attr_name} but detected None.")
all_populated = False
data[attr_name] = attr_value
if not all_populated:
error("Missing specs fields for %s" % self.arch)
return pd.DataFrame(data, index=[0])
def __str__(self):
return dedent(
f"""\
@@ -110,145 +222,27 @@ class MachineSpecs:
)
def gpuinfo():
from omniperf_base import SUPPORTED_ARCHS
gpu_info = {
"gpu_name": None,
"gpu_arch": None,
"L1": None,
"L2": None,
"max_sclk": None,
"max_mclk": None,
"num_CU": None,
"num_SIMD": None,
"numPipes": None,
"num_SE": None,
"wave_size": None,
"grp_size": None,
"max_waves_per_cu": None,
"L2Banks": None,
"LDSBanks": None,
"numSQC": None,
"compute_partition": None,
"memory_partition": None,
}
# Fixme: find better way to differentiate cards, GPU vs APU, etc.
rocminfo_full = run(["rocminfo"])
rocminfo = rocminfo_full.split("\n")
for idx1, linetext in enumerate(rocminfo):
gpu_arch = search(r"^\s*Name\s*:\s+ ([a-zA-Z0-9]+)\s*$", linetext)
if gpu_arch in SUPPORTED_ARCHS.keys():
break
if str(gpu_arch) in SUPPORTED_ARCHS.keys():
gpu_arch = str(gpu_arch)
break
if not gpu_arch in SUPPORTED_ARCHS.keys():
return gpu_info
gpu_info["L1"], gpu_info["L1"] = "", ""
for idx2, linetext in enumerate(rocminfo[idx1 + 1 :]):
key = search(r"^\s*L1:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["L1"] = key
continue
key = search(r"^\s*L2:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["L2"] = key
continue
key = search(r"^\s*Max Clock Freq\. \(MHz\):\s+([0-9]+)", linetext)
if key != None:
gpu_info["max_sclk"] = key
continue
key = search(r"^\s*Compute Unit:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["num_CU"] = key
continue
key = search(r"^\s*SIMDs per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["num_SIMD"] = key
continue
key = search(r"^\s*Shader Engines:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["num_SE"] = key
continue
key = search(r"^\s*Wavefront Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["wave_size"] = key
continue
key = search(r"^\s*Workgroup Max Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["grp_size"] = key
continue
key = search(r"^\s*Max Waves Per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info["max_waves_per_cu"] = key
break
try:
soc_module = importlib.import_module("omniperf_soc.soc_" + gpu_arch)
except ModuleNotFoundError as e:
error(
"Arch %s marked as supported, but couldn't find class implementation %s."
% (gpu_arch, e)
)
# load arch specific info
try:
gpu_name = list(SUPPORTED_ARCHS[gpu_arch].keys())[0].upper()
gpu_info["L2Banks"] = str(soc_module.SOC_PARAM["L2Banks"])
gpu_info["numSQC"] = str(soc_module.SOC_PARAM["numSQC"])
gpu_info["LDSBanks"] = str(soc_module.SOC_PARAM["LDSBanks"])
gpu_info["numPipes"] = str(soc_module.SOC_PARAM["numPipes"])
except KeyError as e:
error(
"Incomplete class definition for %s. Expected a field for %s in SOC_PARAM."
% (gpu_arch, e)
)
# we get the max mclk from rocm-smi --showmclkrange
rocm_smi_mclk = run(["rocm-smi", "--showmclkrange"], exit_on_error=True)
gpu_info["max_mclk"] = search(r"(\d+)Mhz\s*$", rocm_smi_mclk)
# check that we got the mclk from smi
if gpu_info["max_mclk"] is None:
if gpu_name == "MI100":
# hardcoded due to rocm-smi limitation
gpu_info["max_mclk"] = str(1200)
else:
error(
"Could not obtain maximum mclk from rocm-smi for GPU: {}".format(gpu_info)
def get_rocm_ver():
rocm_found = False
for itr in VERSION_LOC:
_path = os.path.join(os.getenv("ROCM_PATH", "/opt/rocm"), ".info", itr)
if os.path.exists(_path):
rocm_ver = path(_path).read_text()
rocm_found = True
break
if not rocm_found:
# check if ROCM_VER is supplied externally
ROCM_VER_USER = os.getenv("ROCM_VER")
if ROCM_VER_USER is not None:
logging.info(
"Overriding missing ROCm version detection with ROCM_VER = %s"
% ROCM_VER_USER
)
# specify gpu name for gfx942 hardware
if gpu_name == "MI300":
gpu_name = list(SUPPORTED_ARCHS[gpu_arch].values())[0][0]
if (gpu_info["gpu_arch"] == "gfx942") and ("MI300A" in rocminfo_full):
gpu_name = "MI300A_A1"
if (gpu_arch == "gfx942") and ("MI300A" not in rocminfo_full):
gpu_name = "MI300X_A1"
gpu_info["gpu_name"] = gpu_name
gpu_info["gpu_arch"] = gpu_arch
gpu_info["compute_partition"] = ""
gpu_info["memory_partition"] = ""
# verify all fields are filled
for key, value in gpu_info.items():
if value is None:
logging.info("Warning: %s is missing from gpu_info dictionary." % key)
return gpu_info
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)
return rocm_ver
def run(cmd, exit_on_error=False):
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -275,143 +269,20 @@ 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 totalL2Banks
def get_machine_specs(devicenum):
cpuinfo = path("/proc/cpuinfo").read_text()
meminfo = path("/proc/meminfo").read_text()
version = path("/proc/version").read_text()
os_release = path("/etc/os-release").read_text()
version_loc = [
"version",
"version-dev",
"version-hip-libraries",
"version-hiprt",
"version-hiprt-devel",
"version-hip-sdk",
"version-libs",
"version-utils",
]
rocmFound = False
for itr in version_loc:
_path = os.path.join(os.getenv("ROCM_PATH", "/opt/rocm"), ".info", itr)
if os.path.exists(_path):
rocm_ver = path(_path).read_text()
rocmFound = True
break
if not rocmFound:
# check if ROCM_VER is supplied externally
ROCM_VER_USER = os.getenv("ROCM_VER")
if ROCM_VER_USER is not None:
print(
"Overriding missing ROCm version detection with ROCM_VER = %s"
% ROCM_VER_USER
)
rocm_ver = ROCM_VER_USER
else:
_rocm_path = os.getenv("ROCM_PATH", "/opt/rocm")
print("Error: Unable to detect a complete local ROCm installation.")
print(
"\nThe expected %s/.info/ versioning directory is missing. Please"
% _rocm_path
)
print("ensure you have valid ROCm installation.")
sys.exit(1)
gpu_info = gpuinfo()
rocm_smi = run(["rocm-smi"], exit_on_error=True)
device = rf"^\s*{devicenum}(.*)"
hostname = socket.gethostname()
sbios = (
path("/sys/class/dmi/id/bios_vendor").read_text().strip()
+ path("/sys/class/dmi/id/bios_version").read_text().strip()
)
CPU = search(r"^model name\s*: (.*?)$", cpuinfo)
kernel_version = search(r"version (\S*)", version)
ram = search(r"MemTotal:\s*(\S*)", meminfo)
distro = search(r'PRETTY_NAME="(.*?)"', os_release)
if distro is None:
distro = ""
rocm_version = rocm_ver.strip()
# 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)
cur_sclk = gpu_info["max_sclk"]
cur_mclk = gpu_info["max_mclk"]
# FIXME with 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"])
)
if compute_partition == None:
compute_partition = "NA"
memory_partition = search(
r"Memory Partition:\s*(\w+)", run(["rocm-smi", "--showmemorypartition"])
)
if memory_partition == None:
memory_partition = "NA"
totalL2Banks = total_l2_banks(
gpu_info["gpu_name"], int(gpu_info["L2Banks"]), memory_partition
)
hbmchannels = totalL2Banks
if (
gpu_info["gpu_name"].lower() == "mi300a_a0"
or gpu_info["gpu_name"].lower() == "mi300a_a1"
) and memory_partition.lower() == "nps1":
# we have an extra 32 channels for the CCD
hbmchannels += 32
hbmBW = str(int(gpu_info["max_mclk"]) / 1000 * 32 * hbmchannels)
totalL2Banks = str(totalL2Banks)
return MachineSpecs(
hostname,
CPU,
sbios,
kernel_version,
ram,
distro,
rocm_version,
gpu_info["gpu_name"],
gpu_info["gpu_arch"],
vbios,
gpu_info["L1"],
gpu_info["L2"],
gpu_info["num_CU"],
gpu_info["num_SIMD"],
gpu_info["num_SE"],
gpu_info["wave_size"],
gpu_info["grp_size"],
gpu_info["max_sclk"],
gpu_info["max_mclk"],
cur_sclk,
cur_mclk,
gpu_info["max_waves_per_cu"],
gpu_info["L2Banks"],
totalL2Banks,
gpu_info["LDSBanks"],
gpu_info["numSQC"],
gpu_info["numPipes"],
hbmBW,
compute_partition,
memory_partition,
)
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)
if __name__ == "__main__":
print(get_machine_specs(0))
print(MachineSpecs())
+25 -91
Просмотреть файл
@@ -198,12 +198,10 @@ def capture_subprocess_output(subprocess_args, new_env=None):
return (success, output)
def run_prof(fname, profiler_options, target, workload_dir):
def run_prof(fname, profiler_options, workload_dir, mspec):
fbase = os.path.splitext(os.path.basename(fname))[0]
m_specs = specs.get_machine_specs(0)
logging.debug("pmc file: %s" % str(os.path.basename(fname)))
# standard rocprof options
@@ -212,12 +210,7 @@ def run_prof(fname, profiler_options, target, workload_dir):
# set required env var for mi300
new_env = None
if (
target.lower() == "mi300x_a0"
or target.lower() == "mi300x_a1"
or target.lower() == "mi300a_a0"
or target.lower() == "mi300a_a1"
) and (
if (mspec.GPU.lower() == "mi300x_a0" or mspec.GPU.lower() == "mi300x_a1" or mspec.GPU.lower() == "mi300a_a0" or mspec.GPU.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"
@@ -239,8 +232,10 @@ def run_prof(fname, profiler_options, target, workload_dir):
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(target, m_specs.memory_partition)
df = flatten_tcc_info_across_hbm_stacks(f, hbm_stack_num, int(m_specs.L2Banks))
hbm_stack_num = get_hbm_stack_num(mspec.GPU, mspec.memory_partition)
df = flatten_tcc_info_across_hbm_stacks(
f, hbm_stack_num, int(mspec.L2Banks)
)
df.to_csv(f, index=False)
if os.path.exists(workload_dir + "/out"):
@@ -300,88 +295,27 @@ def replace_timestamps(workload_dir):
)
logging.warning(warning + "\n")
def gen_sysinfo(workload_name, workload_dir, ip_blocks, app_cmd, skip_roof, roof_only):
# Record system information
mspec = specs.get_machine_specs(0)
sysinfo = open(workload_dir + "/" + "sysinfo.csv", "w")
# write header
header = "workload_name,"
header += "command,"
header += "host_name,host_cpu,sbios,host_distro,host_kernel,host_rocmver,date,"
header += "gpu_soc,vbios,numSE,numCU,numSIMD,waveSize,maxWavesPerCU,maxWorkgroupSize,"
header += "L1,L2,sclk,mclk,cur_sclk,cur_mclk,L2Banks,totalL2Banks,LDSBanks,name,numSQC,numPipes,"
header += "hbmBW,compute_partition,memory_partition,"
header += "ip_blocks\n"
sysinfo.write(header)
# timestamp
now = datetime.now()
local_now = now.astimezone()
local_tz = local_now.tzinfo
local_tzname = local_tz.tzname(local_now)
timestamp = now.strftime("%c") + " (" + local_tzname + ")"
# host info
param = [workload_name]
param += ['"' + app_cmd + '"']
param += [
mspec.hostname,
mspec.CPU,
'"' + mspec.sbios + '"',
mspec.distro,
mspec.kernel_version,
mspec.rocm_version,
timestamp,
]
# GPU info
param += [
mspec.arch,
mspec.vbios,
mspec.SE,
mspec.CU,
mspec.SIMD,
mspec.wave_size,
mspec.max_waves_per_cu,
mspec.workgroup_max_size,
]
param += [
mspec.L1,
mspec.L2,
mspec.max_sclk,
mspec.max_mclk,
mspec.cur_sclk,
mspec.cur_mclk,
mspec.L2Banks,
mspec.totalL2Banks,
mspec.LDSBanks,
mspec.GPU,
mspec.numSQC,
mspec.numPipes,
mspec.hbmBW,
mspec.compute_partition,
mspec.memory_partition,
]
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.insert(0, 'command', app_cmd)
df.insert(0,'workload_name', workload_name)
blocks = []
if mspec.arch == "gfx90a" and (not skip_roof):
blocks.append("roofline")
# ip block info
if ip_blocks == None:
t = ["SQ", "LDS", "SQC", "TA", "TD", "TCP", "TCC", "SPI", "CPC", "CPF"]
blocks += t
else:
blocks += ip_blocks
param.append("|".join(blocks))
if mspec.arch == "gfx90a" and (not skip_roof):
blocks.append("roofline")
df['ip_blocks'] = "|".join(blocks)
sysinfo.write(",".join(param))
sysinfo.close()
# Save csv
df.to_csv(workload_dir + "/" + "sysinfo.csv", index=False)
def detect_roofline():
mspec = specs.get_machine_specs(0)
def detect_roofline(mspec):
rocm_ver = mspec.rocm_version[:1]
os_release = path("/etc/os-release").read_text()
@@ -446,13 +380,13 @@ def run_rocscope(args, fname):
logging.error(result.stderr.decode("ascii"))
sys.exit(1)
def mibench(args):
"""Run roofline microbenchmark to generate peak BW and FLOP measurements."""
def mibench(args, mspec):
"""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"}
target_binary = detect_roofline()
target_binary = detect_roofline(mspec)
if target_binary["rocm_ver"] == "override":
path_to_binary = target_binary["path"]
else:
@@ -462,7 +396,7 @@ def mibench(args):
+ "-"
+ distro_map[target_binary["distro"]]
+ "-"
+ args.target.lower()
+ mspec.GPU.lower()
+ "-rocm"
+ target_binary["rocm_ver"]
)