code formatting updates
Signed-off-by: Karl W Schulz <karl.schulz@amd.com>
This commit is contained in:
committed by
Karl W. Schulz
parent
4bcbc73080
commit
79b877d679
+30
-12
@@ -26,12 +26,14 @@ import argparse
|
||||
import shutil
|
||||
import os
|
||||
|
||||
|
||||
def print_avail_arch(avail_arch: list):
|
||||
ret_str = "\t\tList all available metrics for analysis on specified arch:"
|
||||
for arch in avail_arch:
|
||||
ret_str += "\n\t\t {}".format(arch)
|
||||
return ret_str
|
||||
|
||||
|
||||
def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
# -----------------------------------------
|
||||
# Parse arguments (dependent on mode)
|
||||
@@ -42,8 +44,12 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
general_group = parser.add_argument_group("General Options")
|
||||
parser._positionals.title = "Modes"
|
||||
parser._optionals.title = "Help"
|
||||
general_group.add_argument("-v", "--version", action="version", version=omniperf_version["ver_pretty"])
|
||||
general_group.add_argument("-s", "--specs", action="store_true", help="Print system specs.")
|
||||
general_group.add_argument(
|
||||
"-v", "--version", action="version", version=omniperf_version["ver_pretty"]
|
||||
)
|
||||
general_group.add_argument(
|
||||
"-s", "--specs", action="store_true", help="Print system specs."
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
dest="mode", help="Select mode of interaction with the target application:"
|
||||
@@ -78,7 +84,9 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
profile_group = profile_parser.add_argument_group("Profile Options")
|
||||
roofline_group = profile_parser.add_argument_group("Standalone Roofline Options")
|
||||
|
||||
general_group.add_argument("-v", "--version", action="version", version=omniperf_version["ver_pretty"])
|
||||
general_group.add_argument(
|
||||
"-v", "--version", action="version", version=omniperf_version["ver_pretty"]
|
||||
)
|
||||
general_group.add_argument(
|
||||
"-V", "--verbose", help="Increase output verbosity", action="count", default=0
|
||||
)
|
||||
@@ -283,11 +291,15 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
interaction_group = db_parser.add_argument_group("Interaction Type")
|
||||
connection_group = db_parser.add_argument_group("Connection Options")
|
||||
|
||||
general_group.add_argument("-v", "--version", action="version", version=omniperf_version["ver_pretty"])
|
||||
general_group.add_argument(
|
||||
"-v", "--version", action="version", version=omniperf_version["ver_pretty"]
|
||||
)
|
||||
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."
|
||||
)
|
||||
|
||||
interaction_group.add_argument(
|
||||
"-i",
|
||||
@@ -374,11 +386,15 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
analyze_group = analyze_parser.add_argument_group("Analyze Options")
|
||||
analyze_advanced_group = analyze_parser.add_argument_group("Advanced Options")
|
||||
|
||||
general_group.add_argument("-v", "--version", action="version", version=omniperf_version["ver_pretty"])
|
||||
general_group.add_argument(
|
||||
"-v", "--version", action="version", version=omniperf_version["ver_pretty"]
|
||||
)
|
||||
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."
|
||||
)
|
||||
|
||||
analyze_group.add_argument(
|
||||
"-p",
|
||||
@@ -398,7 +414,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
analyze_group.add_argument(
|
||||
"--list-metrics",
|
||||
metavar="",
|
||||
choices=supported_archs.keys(),#["gfx906", "gfx908", "gfx90a"],
|
||||
choices=supported_archs.keys(), # ["gfx906", "gfx908", "gfx90a"],
|
||||
help=print_avail_arch(supported_archs.keys()),
|
||||
)
|
||||
analyze_group.add_argument(
|
||||
@@ -460,7 +476,7 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
metavar="",
|
||||
type=int,
|
||||
default=10,
|
||||
help="\t\tSpecify the maximum number of stats shown in \"Top Stats\" tables (DEFAULT: 10)",
|
||||
help='\t\tSpecify the maximum number of stats shown in "Top Stats" tables (DEFAULT: 10)',
|
||||
)
|
||||
analyze_advanced_group.add_argument(
|
||||
"-n",
|
||||
@@ -508,7 +524,9 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
nargs="+",
|
||||
help="\t\tSpecify column indices to display.",
|
||||
)
|
||||
analyze_advanced_group.add_argument("-g", dest="debug", action="store_true", help="\t\tDebug single metric.")
|
||||
analyze_advanced_group.add_argument(
|
||||
"-g", dest="debug", action="store_true", help="\t\tDebug single metric."
|
||||
)
|
||||
analyze_advanced_group.add_argument(
|
||||
"--dependency", action="store_true", help="\t\tList the installation dependency."
|
||||
)
|
||||
@@ -527,5 +545,5 @@ def omniarg_parser(parser, omniperf_home, supported_archs, omniperf_version):
|
||||
"--specs-correction",
|
||||
type=str,
|
||||
metavar="",
|
||||
help="\t\tSpecify the specs to correct."
|
||||
)
|
||||
help="\t\tSpecify the specs to correct.",
|
||||
)
|
||||
|
||||
+1
-1
@@ -26,4 +26,4 @@ from pathlib import Path
|
||||
|
||||
# NB: Creating a new module to share global vars across modules
|
||||
omniperf_home = Path(__file__).resolve().parent
|
||||
prog = "omniperf"
|
||||
prog = "omniperf"
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ html_theme = "sphinx_rtd_theme"
|
||||
html_static_path = ["_static"]
|
||||
|
||||
latex_elements = {
|
||||
"sphinxsetup": 'verbatimwrapslines=true, verbatimforcewraps=true',
|
||||
"sphinxsetup": "verbatimwrapslines=true, verbatimforcewraps=true",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,26 +34,31 @@ from utils import schema, file_io, parser
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
class OmniAnalyze_Base():
|
||||
def __init__(self,args,supported_archs):
|
||||
|
||||
class OmniAnalyze_Base:
|
||||
def __init__(self, args, supported_archs):
|
||||
self.__args = args
|
||||
self._runs = OrderedDict()
|
||||
self._arch_configs = {}
|
||||
self._runs = OrderedDict()
|
||||
self._arch_configs = {}
|
||||
self.__supported_archs = supported_archs
|
||||
self._output = None
|
||||
self.__socs = None # available OmniSoC objs
|
||||
self._output = None
|
||||
self.__socs = None # available OmniSoC objs
|
||||
|
||||
def get_args(self):
|
||||
return self.__args
|
||||
|
||||
def set_soc(self, omni_socs):
|
||||
self.__socs = omni_socs
|
||||
|
||||
def get_socs(self):
|
||||
return self.__socs
|
||||
|
||||
|
||||
@demarcate
|
||||
def generate_configs(self, arch, config_dir, list_stats, filter_metrics, sys_info):
|
||||
single_panel_config = file_io.is_single_panel_config(Path(config_dir), self.__supported_archs)
|
||||
|
||||
single_panel_config = file_io.is_single_panel_config(
|
||||
Path(config_dir), self.__supported_archs
|
||||
)
|
||||
|
||||
ac = schema.ArchConfig()
|
||||
if list_stats:
|
||||
ac.panel_configs = file_io.top_stats_build_in_config
|
||||
@@ -66,22 +71,26 @@ class OmniAnalyze_Base():
|
||||
# TODO: filter_metrics should/might be one per arch
|
||||
# print(ac)
|
||||
|
||||
parser.build_dfs(
|
||||
archConfigs=ac,
|
||||
filter_metrics=filter_metrics,
|
||||
sys_info=sys_info
|
||||
)
|
||||
parser.build_dfs(archConfigs=ac, filter_metrics=filter_metrics, sys_info=sys_info)
|
||||
self._arch_configs[arch] = ac
|
||||
return self._arch_configs
|
||||
|
||||
|
||||
@demarcate
|
||||
def list_metrics(self):
|
||||
args = self.__args
|
||||
if args.list_metrics in self.__supported_archs.keys():
|
||||
arch = args.list_metrics
|
||||
if arch not in self._arch_configs.keys():
|
||||
sys_info = file_io.load_sys_info(Path(self.__args.path[0][0], "sysinfo.csv"))
|
||||
self.generate_configs(arch, args.config_dir, args.list_stats, args.filter_metrics, sys_info.iloc[0])
|
||||
sys_info = file_io.load_sys_info(
|
||||
Path(self.__args.path[0][0], "sysinfo.csv")
|
||||
)
|
||||
self.generate_configs(
|
||||
arch,
|
||||
args.config_dir,
|
||||
args.list_stats,
|
||||
args.filter_metrics,
|
||||
sys_info.iloc[0],
|
||||
)
|
||||
|
||||
for key, value in self._arch_configs[args.list_metrics].metric_list.items():
|
||||
prefix = ""
|
||||
@@ -100,11 +109,13 @@ class OmniAnalyze_Base():
|
||||
def load_options(self, normalization_filter):
|
||||
if not normalization_filter:
|
||||
for k, v in self._arch_configs.items():
|
||||
parser.build_metric_value_string(v.dfs, v.dfs_type, self.__args.normal_unit)
|
||||
parser.build_metric_value_string(
|
||||
v.dfs, v.dfs_type, self.__args.normal_unit
|
||||
)
|
||||
else:
|
||||
for k, v in self._arch_configs.items():
|
||||
parser.build_metric_value_string(v.dfs, v.dfs_type, normalization_filter)
|
||||
|
||||
|
||||
args = self.__args
|
||||
# Error checking for multiple runs and multiple gpu_kernel filters
|
||||
if args.gpu_kernel and (len(args.path) != len(args.gpu_kernel)):
|
||||
@@ -112,27 +123,37 @@ class OmniAnalyze_Base():
|
||||
for i in range(len(args.path) - 1):
|
||||
args.gpu_kernel.extend(args.gpu_kernel)
|
||||
else:
|
||||
error("Error: the number of --filter-kernels doesn't match the number of --dir.")
|
||||
|
||||
error(
|
||||
"Error: the number of --filter-kernels doesn't match the number of --dir."
|
||||
)
|
||||
|
||||
@demarcate
|
||||
def initalize_runs(self, normalization_filter=None):
|
||||
if self.__args.list_metrics:
|
||||
self.list_metrics()
|
||||
|
||||
|
||||
# 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"]
|
||||
args = self.__args
|
||||
self.generate_configs(arch, args.config_dir, args.list_stats, args.filter_metrics, sys_info.iloc[0])
|
||||
self.generate_configs(
|
||||
arch,
|
||||
args.config_dir,
|
||||
args.list_stats,
|
||||
args.filter_metrics,
|
||||
sys_info.iloc[0],
|
||||
)
|
||||
|
||||
self.load_options(normalization_filter)
|
||||
|
||||
|
||||
for d in self.__args.path:
|
||||
w = schema.Workload()
|
||||
w.sys_info = file_io.load_sys_info(Path(d[0], "sysinfo.csv"))
|
||||
if self.__args.specs_correction:
|
||||
w.sys_info = parser.correct_sys_info(w.sys_info, self.__args.specs_correction)
|
||||
w.sys_info = parser.correct_sys_info(
|
||||
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"]
|
||||
w.dfs = copy.deepcopy(self._arch_configs[arch].dfs)
|
||||
@@ -142,11 +163,9 @@ class OmniAnalyze_Base():
|
||||
|
||||
return self._runs
|
||||
|
||||
|
||||
@demarcate
|
||||
def sanitize(self):
|
||||
"""Perform sanitization of inputs
|
||||
"""
|
||||
"""Perform sanitization of inputs"""
|
||||
if not self.__args.path:
|
||||
error("The following arguments are required: -p/--path")
|
||||
# verify not accessing parent directories
|
||||
@@ -160,23 +179,23 @@ class OmniAnalyze_Base():
|
||||
error("Invalid directory {}\nPlease try again.".format(dir[0]))
|
||||
# validate profiling data
|
||||
is_workload_empty(dir[0])
|
||||
|
||||
|
||||
#----------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Required methods to be implemented by child classes
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
@abstractmethod
|
||||
def pre_processing(self):
|
||||
"""Perform initialization prior to analysis.
|
||||
"""
|
||||
"""Perform initialization prior to analysis."""
|
||||
logging.debug("[analysis] prepping to do some analysis")
|
||||
logging.info("[analysis] deriving Omniperf metrics...")
|
||||
# initalize output file
|
||||
self._output = open(self.__args.output_file, "w+") if self.__args.output_file else sys.stdout
|
||||
|
||||
self._output = (
|
||||
open(self.__args.output_file, "w+") if self.__args.output_file else sys.stdout
|
||||
)
|
||||
|
||||
# initalize runs
|
||||
self._runs = self.initalize_runs()
|
||||
|
||||
|
||||
# set filters
|
||||
if self.__args.gpu_kernel:
|
||||
for d, gk in zip(self.__args.path, self.__args.gpu_kernel):
|
||||
@@ -196,6 +215,5 @@ class OmniAnalyze_Base():
|
||||
|
||||
@abstractmethod
|
||||
def run_analysis(self):
|
||||
"""Run analysis.
|
||||
"""
|
||||
"""Run analysis."""
|
||||
logging.debug("[analysis] generating analysis")
|
||||
|
||||
@@ -27,15 +27,14 @@ from utils.utils import demarcate, error
|
||||
from utils import file_io, parser, tty
|
||||
from utils.kernel_name_shortener import kernel_name_shortener
|
||||
|
||||
class cli_analysis(OmniAnalyze_Base):
|
||||
|
||||
#-----------------------
|
||||
class cli_analysis(OmniAnalyze_Base):
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to analysis.
|
||||
"""
|
||||
"""Perform any pre-processing steps prior to analysis."""
|
||||
super().pre_processing()
|
||||
if self.get_args().random_port:
|
||||
error("--gui flag is required to enable --random-port")
|
||||
@@ -48,7 +47,7 @@ class cli_analysis(OmniAnalyze_Base):
|
||||
filter_gpu_ids=self._runs[d[0]].filter_gpu_ids,
|
||||
filter_dispatch_ids=self._runs[d[0]].filter_dispatch_ids,
|
||||
time_unit=self.get_args().time_unit,
|
||||
max_stat_num=self.get_args().max_stat_num
|
||||
max_stat_num=self.get_args().max_stat_num,
|
||||
)
|
||||
# create 'mega dataframe'
|
||||
self._runs[d[0]].raw_pmc = file_io.create_df_pmc(
|
||||
@@ -56,30 +55,32 @@ class cli_analysis(OmniAnalyze_Base):
|
||||
)
|
||||
# create the loaded table
|
||||
parser.load_table_data(
|
||||
workload=self._runs[d[0]],
|
||||
dir=d[0],
|
||||
workload=self._runs[d[0]],
|
||||
dir=d[0],
|
||||
is_gui=False,
|
||||
debug=self.get_args().debug,
|
||||
verbose=self.get_args().verbose
|
||||
debug=self.get_args().debug,
|
||||
verbose=self.get_args().verbose,
|
||||
)
|
||||
|
||||
|
||||
@demarcate
|
||||
def run_analysis(self):
|
||||
"""Run CLI analysis.
|
||||
"""
|
||||
"""Run CLI analysis."""
|
||||
super().run_analysis()
|
||||
if self.get_args().list_stats:
|
||||
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]["gpu_soc"]
|
||||
],
|
||||
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]["gpu_soc"]
|
||||
],
|
||||
self._output,
|
||||
)
|
||||
|
||||
+78
-45
@@ -29,7 +29,15 @@ 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.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
|
||||
@@ -44,13 +52,16 @@ SUPPORTED_ARCHS = {
|
||||
"gfx942": {"mi300": ["MI300A_A1", "MI300X_A1"]},
|
||||
}
|
||||
|
||||
|
||||
class Omniperf:
|
||||
def __init__(self):
|
||||
self.__args = None
|
||||
self.__profiler_mode = None
|
||||
self.__analyze_mode = None
|
||||
self.__soc_name = set() # gpu name, or in case of analyze mode, all loaded gpu name(s)
|
||||
self.__soc = dict() # set of key, value pairs. Where arch->OmniSoc() obj
|
||||
self.__soc_name = (
|
||||
set()
|
||||
) # gpu name, or in case of analyze mode, all loaded gpu name(s)
|
||||
self.__soc = dict() # set of key, value pairs. Where arch->OmniSoc() obj
|
||||
self.__version = {
|
||||
"ver": None,
|
||||
"ver_pretty": None,
|
||||
@@ -68,22 +79,21 @@ class Omniperf:
|
||||
self.detect_profiler()
|
||||
elif self.__mode == "analyze":
|
||||
self.detect_analyze()
|
||||
|
||||
|
||||
logging.info("Execution mode = %s" % self.__mode)
|
||||
|
||||
|
||||
def print_graphic(self):
|
||||
"""Log program name as ascii art to terminal.
|
||||
"""
|
||||
ascii_art = '''
|
||||
"""Log program name as ascii art to terminal."""
|
||||
ascii_art = """
|
||||
___ _ __
|
||||
/ _ \ _ __ ___ _ __ (_)_ __ ___ _ __ / _|
|
||||
| | | | '_ ` _ \| '_ \| | '_ \ / _ \ '__| |_
|
||||
| |_| | | | | | | | | | | |_) | __/ | | _|
|
||||
\___/|_| |_| |_|_| |_|_| .__/ \___|_| |_|
|
||||
|_|
|
||||
'''
|
||||
"""
|
||||
logging.info(ascii_art)
|
||||
|
||||
|
||||
def setup_logging(self):
|
||||
# register a trace level logger
|
||||
logging.TRACE = logging.DEBUG - 5
|
||||
@@ -92,16 +102,16 @@ class Omniperf:
|
||||
setattr(logging, "trace", trace_logger)
|
||||
|
||||
# demonstrate override of default loglevel via env variable
|
||||
loglevel=logging.INFO
|
||||
loglevel = logging.INFO
|
||||
if "OMNIPERF_LOGLEVEL" in os.environ.keys():
|
||||
loglevel = os.environ['OMNIPERF_LOGLEVEL']
|
||||
if loglevel in {"DEBUG","debug"}:
|
||||
loglevel = os.environ["OMNIPERF_LOGLEVEL"]
|
||||
if loglevel in {"DEBUG", "debug"}:
|
||||
loglevel = logging.DEBUG
|
||||
elif loglevel in {"TRACE","trace"}:
|
||||
elif loglevel in {"TRACE", "trace"}:
|
||||
loglevel = logging.TRACE
|
||||
elif loglevel in {"INFO","info"}:
|
||||
elif loglevel in {"INFO", "info"}:
|
||||
loglevel = logging.INFO
|
||||
elif loglevel in {"ERROR","error"}:
|
||||
elif loglevel in {"ERROR", "error"}:
|
||||
loglevel = logging.ERROR
|
||||
else:
|
||||
print("Ignoring unsupported OMNIPERF_LOGLEVEL setting (%s)" % loglevel)
|
||||
@@ -111,15 +121,21 @@ class Omniperf:
|
||||
|
||||
def get_mode(self):
|
||||
return self.__mode
|
||||
|
||||
|
||||
def set_version(self):
|
||||
vData = get_version(config.omniperf_home)
|
||||
self.__version["ver"] = vData["version"]
|
||||
self.__version["ver_pretty"] = get_version_display(vData["version"], vData["sha"], vData["mode"])
|
||||
self.__version["ver_pretty"] = get_version_display(
|
||||
vData["version"], vData["sha"], vData["mode"]
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
def detect_profiler(self):
|
||||
if self.__args.lucky == True or self.__args.summaries == True or self.__args.use_rocscope:
|
||||
if (
|
||||
self.__args.lucky == True
|
||||
or self.__args.summaries == True
|
||||
or self.__args.use_rocscope
|
||||
):
|
||||
if not shutil.which("rocscope"):
|
||||
logging.error("Rocscope must be in PATH")
|
||||
sys.exit(1)
|
||||
@@ -132,10 +148,13 @@ class Omniperf:
|
||||
elif str(rocprof_cmd).endswith("rocprofv2"):
|
||||
self.__profiler_mode = "rocprofv2"
|
||||
else:
|
||||
error("Incompatible profiler: %s. Supported profilers include: %s" % (rocprof_cmd, get_submodules('omniperf_profile')))
|
||||
|
||||
error(
|
||||
"Incompatible profiler: %s. Supported profilers include: %s"
|
||||
% (rocprof_cmd, get_submodules("omniperf_profile"))
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
def detect_analyze(self):
|
||||
if self.__args.gui:
|
||||
self.__analyze_mode = "web_ui"
|
||||
@@ -145,8 +164,7 @@ class Omniperf:
|
||||
|
||||
@demarcate
|
||||
def detect_soc(self, sys_info=pd.DataFrame()):
|
||||
"""Load OmniSoC instance for Omniperf run
|
||||
"""
|
||||
"""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:
|
||||
@@ -163,11 +181,11 @@ class Omniperf:
|
||||
error("%s is an unsupported SoC" % arch)
|
||||
else:
|
||||
self.__soc_name.add(target)
|
||||
if hasattr(self.__args, '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')
|
||||
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)
|
||||
@@ -176,14 +194,16 @@ class Omniperf:
|
||||
@demarcate
|
||||
def parse_args(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Command line interface for AMD's GPU profiler, Omniperf",
|
||||
prog="tool",
|
||||
formatter_class=lambda prog: argparse.RawTextHelpFormatter(
|
||||
description="Command line interface for AMD's GPU profiler, Omniperf",
|
||||
prog="tool",
|
||||
formatter_class=lambda prog: argparse.RawTextHelpFormatter(
|
||||
prog, max_help_position=30
|
||||
),
|
||||
usage="omniperf [mode] [options]",
|
||||
)
|
||||
omniarg_parser(parser, config.omniperf_home, self.__supported_archs ,self.__version)
|
||||
omniarg_parser(
|
||||
parser, config.omniperf_home, self.__supported_archs, self.__version
|
||||
)
|
||||
self.__args = parser.parse_args()
|
||||
|
||||
if self.__args.specs:
|
||||
@@ -202,27 +222,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.__args.target)
|
||||
self.__args.path = os.path.join(
|
||||
self.__args.path, self.__args.name, self.__args.target
|
||||
)
|
||||
|
||||
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[targ_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[targ_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[targ_arch]
|
||||
)
|
||||
else:
|
||||
logging.error("Unsupported profiler")
|
||||
sys.exit(1)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# run profiling workflow
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
self.__soc[targ_arch].profiling_setup()
|
||||
profiler.pre_processing()
|
||||
profiler.run_profiling(self.__version["ver"], config.prog)
|
||||
@@ -235,17 +266,18 @@ class Omniperf:
|
||||
def update_db(self):
|
||||
self.print_graphic()
|
||||
from utils.db_connector import DatabaseConnector
|
||||
|
||||
db_connection = DatabaseConnector(self.__args)
|
||||
|
||||
#-----------------------
|
||||
|
||||
# -----------------------
|
||||
# run database workflow
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
db_connection.pre_processing()
|
||||
if self.__args.upload:
|
||||
db_connection.db_import()
|
||||
else:
|
||||
db_connection.db_remove()
|
||||
|
||||
|
||||
return
|
||||
|
||||
@demarcate
|
||||
@@ -256,18 +288,20 @@ class Omniperf:
|
||||
|
||||
if self.__analyze_mode == "cli":
|
||||
from omniperf_analyze.analysis_cli import cli_analysis
|
||||
|
||||
analyzer = cli_analysis(self.__args, self.__supported_archs)
|
||||
elif self.__analyze_mode == "web_ui":
|
||||
from omniperf_analyze.analysis_webui import webui_analysis
|
||||
|
||||
analyzer = webui_analysis(self.__args, self.__supported_archs)
|
||||
else:
|
||||
error("Unsupported anlaysis mode -> %s" % self.__analyze_mode)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# run analysis workflow
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
analyzer.sanitize()
|
||||
|
||||
|
||||
# Load required SoC(s) from input
|
||||
for d in analyzer.get_args().path:
|
||||
sys_info = pd.read_csv(Path(d[0], "sysinfo.csv"))
|
||||
@@ -278,4 +312,3 @@ class Omniperf:
|
||||
analyzer.run_analysis()
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -28,31 +28,44 @@ import glob
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from utils.utils import capture_subprocess_output, run_prof, gen_sysinfo, run_rocscope, error, demarcate
|
||||
from utils.utils import (
|
||||
capture_subprocess_output,
|
||||
run_prof,
|
||||
gen_sysinfo,
|
||||
run_rocscope,
|
||||
error,
|
||||
demarcate,
|
||||
)
|
||||
import config
|
||||
import pandas as pd
|
||||
|
||||
class OmniProfiler_Base():
|
||||
|
||||
class OmniProfiler_Base:
|
||||
def __init__(self, args, profiler_mode, soc):
|
||||
self.__args = args
|
||||
self.__profiler = profiler_mode
|
||||
self._soc = soc # OmniSoC obj
|
||||
self.__perfmon_dir = os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs")
|
||||
self._soc = soc # OmniSoC obj
|
||||
self.__perfmon_dir = os.path.join(
|
||||
str(config.omniperf_home), "omniperf_soc", "profile_configs"
|
||||
)
|
||||
|
||||
def get_args(self):
|
||||
return self.__args
|
||||
|
||||
def get_profiler_options(self, fname):
|
||||
"""Fetch any version specific arguments required by profiler
|
||||
"""
|
||||
"""Fetch any version specific arguments required by profiler"""
|
||||
# assume no SoC specific options and return empty list by default
|
||||
return []
|
||||
|
||||
|
||||
@demarcate
|
||||
def pmc_perf_split(self):
|
||||
"""Avoid default rocprof join utility by spliting each line into a separate input file
|
||||
"""
|
||||
"""Avoid default rocprof join utility by spliting each line into a separate input file"""
|
||||
workload_perfmon_dir = os.path.join(self.__args.path, "perfmon")
|
||||
lines = open(os.path.join(workload_perfmon_dir, "pmc_perf.txt"), "r").read().splitlines()
|
||||
lines = (
|
||||
open(os.path.join(workload_perfmon_dir, "pmc_perf.txt"), "r")
|
||||
.read()
|
||||
.splitlines()
|
||||
)
|
||||
|
||||
# Iterate over each line in pmc_perf.txt
|
||||
mpattern = r"^pmc:(.*)"
|
||||
@@ -83,8 +96,7 @@ class OmniProfiler_Base():
|
||||
|
||||
@demarcate
|
||||
def join_prof(self, out=None):
|
||||
"""Manually join separated rocprof runs
|
||||
"""
|
||||
"""Manually join separated rocprof runs"""
|
||||
# Set default output directory if not specified
|
||||
if type(self.__args.path) == str:
|
||||
if out is None:
|
||||
@@ -105,7 +117,11 @@ class OmniProfiler_Base():
|
||||
elif self.__args.join_type == "grid":
|
||||
key = _df.groupby(["Kernel_Name", "Grid_Size"]).cumcount()
|
||||
_df["key"] = (
|
||||
_df["Kernel_Name"] + " - " + _df["Grid_Size"].astype(str) + " - " + key.astype(str)
|
||||
_df["Kernel_Name"]
|
||||
+ " - "
|
||||
+ _df["Grid_Size"].astype(str)
|
||||
+ " - "
|
||||
+ key.astype(str)
|
||||
)
|
||||
else:
|
||||
print("ERROR: Unrecognized --join-type")
|
||||
@@ -121,9 +137,15 @@ class OmniProfiler_Base():
|
||||
duplicate_cols = {
|
||||
"GPU_ID": [col for col in df.columns if col.startswith("GPU_ID")],
|
||||
"Grid_Size": [col for col in df.columns if col.startswith("Grid_Size")],
|
||||
"Workgroup_Size": [col for col in df.columns if col.startswith("Workgroup_Size")],
|
||||
"LDS_Per_Workgroup": [col for col in df.columns if col.startswith("LDS_Per_Workgroup")],
|
||||
"Scratch_Per_Workitem": [col for col in df.columns if col.startswith("Scratch_Per_Workitem")],
|
||||
"Workgroup_Size": [
|
||||
col for col in df.columns if col.startswith("Workgroup_Size")
|
||||
],
|
||||
"LDS_Per_Workgroup": [
|
||||
col for col in df.columns if col.startswith("LDS_Per_Workgroup")
|
||||
],
|
||||
"Scratch_Per_Workitem": [
|
||||
col for col in df.columns if col.startswith("Scratch_Per_Workitem")
|
||||
],
|
||||
"SGPR": [col for col in df.columns if col.startswith("SGPR")],
|
||||
}
|
||||
# Check for vgpr counter in ROCm < 5.3
|
||||
@@ -131,15 +153,17 @@ class OmniProfiler_Base():
|
||||
duplicate_cols["vgpr"] = [col for col in df.columns if col.startswith("vgpr")]
|
||||
# Check for vgpr counter in ROCm >= 5.3
|
||||
else:
|
||||
duplicate_cols["Arch_VGPR"] = [col for col in df.columns if col.startswith("Arch_VGPR")]
|
||||
duplicate_cols["Accum_VGPR"] = [col for col in df.columns if col.startswith("Accum_VGPR")]
|
||||
duplicate_cols["Arch_VGPR"] = [
|
||||
col for col in df.columns if col.startswith("Arch_VGPR")
|
||||
]
|
||||
duplicate_cols["Accum_VGPR"] = [
|
||||
col for col in df.columns if col.startswith("Accum_VGPR")
|
||||
]
|
||||
for key, cols in duplicate_cols.items():
|
||||
_df = df[cols]
|
||||
if not test_df_column_equality(_df):
|
||||
msg = (
|
||||
"WARNING: Detected differing {} values while joining pmc_perf.csv".format(
|
||||
key
|
||||
)
|
||||
msg = "WARNING: Detected differing {} values while joining pmc_perf.csv".format(
|
||||
key
|
||||
)
|
||||
logging.warning(msg + "\n")
|
||||
else:
|
||||
@@ -157,7 +181,7 @@ class OmniProfiler_Base():
|
||||
if not any(
|
||||
k.startswith(check)
|
||||
for check in [
|
||||
# rocprofv2 headers
|
||||
# rocprofv2 headers
|
||||
"GPU_ID_",
|
||||
"Grid_Size_",
|
||||
"Workgroup_Size_",
|
||||
@@ -236,31 +260,42 @@ class OmniProfiler_Base():
|
||||
else:
|
||||
return df
|
||||
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
# Required methods to be implemented by child classes
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
@abstractmethod
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to profiling.
|
||||
"""
|
||||
"""Perform any pre-processing steps prior to profiling."""
|
||||
logging.debug("[profiling] pre-processing using %s profiler" % self.__profiler)
|
||||
|
||||
|
||||
# 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_soc_name(), self.__profiler, self._soc.get_compatible_profilers()))
|
||||
error(
|
||||
"%s is not enabled in %s. Available profilers include: %s"
|
||||
% (
|
||||
self._soc.get_soc_name(),
|
||||
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. ../)")
|
||||
|
||||
|
||||
# verify correct formatting for application binary
|
||||
self.__args.remaining = self.__args.remaining[1:]
|
||||
if self.__args.remaining:
|
||||
if not os.path.isfile(self.__args.remaining[0]):
|
||||
error("Your command %s doesn't point to a executable. Please verify." % self.__args.remaining[0])
|
||||
error(
|
||||
"Your command %s doesn't point to a executable. Please verify."
|
||||
% self.__args.remaining[0]
|
||||
)
|
||||
self.__args.remaining = " ".join(self.__args.remaining)
|
||||
else:
|
||||
error("Profiling command required. Pass application executable after -- at the end of options.\n\t\ti.e. omniperf profile -n vcopy -- ./vcopy 1048576 256")
|
||||
|
||||
error(
|
||||
"Profiling command required. Pass application executable after -- at the end of options.\n\t\ti.e. omniperf profile -n vcopy -- ./vcopy 1048576 256"
|
||||
)
|
||||
|
||||
# verify name meets MongoDB length requirements and no illegal chars
|
||||
if len(self.__args.name) > 35:
|
||||
error("-n/--name exceeds 35 character limit. Try again.")
|
||||
@@ -268,11 +303,12 @@ class OmniProfiler_Base():
|
||||
error("'-' and '.' are not permitted in -n/--name")
|
||||
|
||||
@abstractmethod
|
||||
def run_profiling(self, version:str, prog:str):
|
||||
"""Run profiling.
|
||||
"""
|
||||
logging.debug("[profiling] performing profiling using %s profiler" % self.__profiler)
|
||||
|
||||
def run_profiling(self, version: str, prog: str):
|
||||
"""Run profiling."""
|
||||
logging.debug(
|
||||
"[profiling] performing profiling using %s profiler" % self.__profiler
|
||||
)
|
||||
|
||||
# log basic info
|
||||
logging.info(str(prog) + " ver: " + str(version))
|
||||
logging.info("Path: " + str(os.path.abspath(self.__args.path)))
|
||||
@@ -283,7 +319,7 @@ class OmniProfiler_Base():
|
||||
if self.__args.ipblocks == None:
|
||||
logging.info("IP Blocks: All")
|
||||
else:
|
||||
logging.info("IP Blocks: "+ str(self.__args.ipblocks))
|
||||
logging.info("IP Blocks: " + str(self.__args.ipblocks))
|
||||
if self.__args.kernel_verbose > 5:
|
||||
logging.info("KernelName verbose: DISABLED")
|
||||
else:
|
||||
@@ -298,7 +334,10 @@ class OmniProfiler_Base():
|
||||
"sed",
|
||||
"-i",
|
||||
"-r",
|
||||
"s%^(kernel:).*%" + "kernel: " + ",".join(self.__args.kernel) + "%g",
|
||||
"s%^(kernel:).*%"
|
||||
+ "kernel: "
|
||||
+ ",".join(self.__args.kernel)
|
||||
+ "%g",
|
||||
fname,
|
||||
]
|
||||
)
|
||||
@@ -315,7 +354,10 @@ class OmniProfiler_Base():
|
||||
"sed",
|
||||
"-i",
|
||||
"-r",
|
||||
"s%^(range:).*%" + "range: " + " ".join(self.__args.dispatch) + "%g",
|
||||
"s%^(range:).*%"
|
||||
+ "range: "
|
||||
+ " ".join(self.__args.dispatch)
|
||||
+ "%g",
|
||||
fname,
|
||||
]
|
||||
)
|
||||
@@ -325,42 +367,44 @@ class OmniProfiler_Base():
|
||||
else:
|
||||
logging.debug(output)
|
||||
logging.info("\nCurrent input file: %s" % fname)
|
||||
|
||||
|
||||
# Fetch any SoC/profiler specific profiling options
|
||||
options = self._soc.get_profiler_options()
|
||||
options += self.get_profiler_options(fname)
|
||||
|
||||
if self.__profiler == "rocprofv1" or self.__profiler == "rocprofv2":
|
||||
run_prof(
|
||||
fname=fname,
|
||||
# workload_dir=self.get_args().path,
|
||||
# perfmon_dir=self.__perfmon_dir,
|
||||
fname=fname,
|
||||
# workload_dir=self.get_args().path,
|
||||
# perfmon_dir=self.__perfmon_dir,
|
||||
# cmd=self.__args.remaining,
|
||||
# target=self.__args.target,
|
||||
profiler_options=options,
|
||||
target=self.__args.target,
|
||||
workload_dir=self.get_args().path
|
||||
workload_dir=self.get_args().path,
|
||||
)
|
||||
|
||||
elif self.__profiler == "rocscope":
|
||||
run_rocscope(self.__args, fname)
|
||||
else:
|
||||
#TODO: Finish logic
|
||||
# TODO: Finish logic
|
||||
error("profiler not supported")
|
||||
|
||||
@abstractmethod
|
||||
def post_processing(self):
|
||||
"""Perform any post-processing steps prior to profiling.
|
||||
"""
|
||||
logging.debug("[profiling] performing post-processing using %s profiler" % self.__profiler)
|
||||
"""Perform any post-processing steps prior to profiling."""
|
||||
logging.debug(
|
||||
"[profiling] performing post-processing using %s profiler" % self.__profiler
|
||||
)
|
||||
gen_sysinfo(
|
||||
workload_name=self.__args.name,
|
||||
workload_dir=self.get_args().path,
|
||||
ip_blocks=self.__args.ipblocks,
|
||||
app_cmd=self.__args.remaining,
|
||||
skip_roof=self.__args.no_roof,
|
||||
workload_name=self.__args.name,
|
||||
workload_dir=self.get_args().path,
|
||||
ip_blocks=self.__args.ipblocks,
|
||||
app_cmd=self.__args.remaining,
|
||||
skip_roof=self.__args.no_roof,
|
||||
roof_only=self.__args.roof_only,
|
||||
)
|
||||
|
||||
|
||||
def test_df_column_equality(df):
|
||||
return df.eq(df.iloc[:, 0], axis=0).all(1).all()
|
||||
|
||||
@@ -31,39 +31,42 @@ from utils.kernel_name_shortener import kernel_name_shortener
|
||||
|
||||
|
||||
class rocprof_v1_profiler(OmniProfiler_Base):
|
||||
def __init__(self,profiling_args,profiler_mode,soc):
|
||||
super().__init__(profiling_args,profiler_mode,soc)
|
||||
self.ready_to_profile = (self.get_args().roof_only and not os.path.isfile(os.path.join(self.get_args().path, "pmc_perf.csv"))
|
||||
or not self.get_args().roof_only)
|
||||
def __init__(self, profiling_args, profiler_mode, soc):
|
||||
super().__init__(profiling_args, profiler_mode, soc)
|
||||
self.ready_to_profile = (
|
||||
self.get_args().roof_only
|
||||
and not os.path.isfile(os.path.join(self.get_args().path, "pmc_perf.csv"))
|
||||
or not self.get_args().roof_only
|
||||
)
|
||||
|
||||
def get_profiler_options(self, fname):
|
||||
fbase = os.path.splitext(os.path.basename(fname))[0]
|
||||
app_cmd = self.get_args().remaining
|
||||
args = [
|
||||
# v1 requires request for timestamps
|
||||
"--timestamp", "on",
|
||||
"--timestamp",
|
||||
"on",
|
||||
# v1 requires csv extension
|
||||
"-o", self.get_args().path + "/" + fbase + ".csv",
|
||||
"-o",
|
||||
self.get_args().path + "/" + fbase + ".csv",
|
||||
# v1 does require quotes on app cmd
|
||||
'"' + app_cmd + '"',
|
||||
]
|
||||
return args
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to profiling.
|
||||
"""
|
||||
"""Perform any pre-processing steps prior to profiling."""
|
||||
super().pre_processing()
|
||||
if self.ready_to_profile:
|
||||
self.pmc_perf_split()
|
||||
|
||||
@demarcate
|
||||
def run_profiling(self, version:str, prog:str):
|
||||
"""Run profiling.
|
||||
"""
|
||||
def run_profiling(self, version: str, prog: str):
|
||||
"""Run profiling."""
|
||||
if self.ready_to_profile:
|
||||
if self.get_args().roof_only:
|
||||
logging.info("[roofline] Generating pmc_perf.csv")
|
||||
@@ -71,11 +74,10 @@ class rocprof_v1_profiler(OmniProfiler_Base):
|
||||
super().run_profiling(version, prog)
|
||||
else:
|
||||
logging.info("[roofline] Detected existing pmc_perf.csv")
|
||||
|
||||
|
||||
@demarcate
|
||||
def post_processing(self):
|
||||
"""Perform any post-processing steps prior to profiling.
|
||||
"""
|
||||
"""Perform any post-processing steps prior to profiling."""
|
||||
super().post_processing()
|
||||
|
||||
if self.ready_to_profile:
|
||||
|
||||
@@ -28,39 +28,44 @@ from omniperf_profile.profiler_base import OmniProfiler_Base
|
||||
from utils.utils import demarcate
|
||||
from utils.kernel_name_shortener import kernel_name_shortener
|
||||
|
||||
|
||||
class rocprof_v2_profiler(OmniProfiler_Base):
|
||||
def __init__(self,profiling_args,profiler_mode,soc):
|
||||
super().__init__(profiling_args,profiler_mode,soc)
|
||||
self.ready_to_profile = (self.get_args().roof_only and not os.path.isfile(os.path.join(self.get_args().path, "pmc_perf.csv"))
|
||||
or not self.get_args().roof_only)
|
||||
def __init__(self, profiling_args, profiler_mode, soc):
|
||||
super().__init__(profiling_args, profiler_mode, soc)
|
||||
self.ready_to_profile = (
|
||||
self.get_args().roof_only
|
||||
and not os.path.isfile(os.path.join(self.get_args().path, "pmc_perf.csv"))
|
||||
or not self.get_args().roof_only
|
||||
)
|
||||
|
||||
def get_profiler_options(self, fname):
|
||||
fbase = os.path.splitext(os.path.basename(fname))[0]
|
||||
app_cmd = self.get_args().remaining
|
||||
args = [
|
||||
# v2 requires output directory argument
|
||||
"-d", self.get_args().path + "/" + "out",
|
||||
"-d",
|
||||
self.get_args().path + "/" + "out",
|
||||
# v2 does not require csv extension
|
||||
"-o", fbase,
|
||||
"-o",
|
||||
fbase,
|
||||
# v2 doen not require quotes on cmd
|
||||
app_cmd
|
||||
app_cmd,
|
||||
]
|
||||
return args
|
||||
#-----------------------
|
||||
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to profiling.
|
||||
"""
|
||||
"""Perform any pre-processing steps prior to profiling."""
|
||||
super().pre_processing()
|
||||
if self.ready_to_profile:
|
||||
self.pmc_perf_split()
|
||||
|
||||
@demarcate
|
||||
def run_profiling(self, version, prog):
|
||||
"""Run profiling.
|
||||
"""
|
||||
"""Run profiling."""
|
||||
if self.ready_to_profile:
|
||||
if self.get_args().roof_only:
|
||||
logging.info("[roofline] Generating pmc_perf.csv")
|
||||
@@ -70,13 +75,11 @@ class rocprof_v2_profiler(OmniProfiler_Base):
|
||||
|
||||
@demarcate
|
||||
def post_processing(self):
|
||||
"""Perform any post-processing steps prior to profiling.
|
||||
"""
|
||||
"""Perform any post-processing steps prior to profiling."""
|
||||
super().post_processing()
|
||||
|
||||
if self.ready_to_profile:
|
||||
# Pass headers to join on
|
||||
# Pass headers to join on
|
||||
self.join_prof()
|
||||
# Demangle and overwrite original KernelNames
|
||||
kernel_name_shortener(self.get_args().path, self.get_args().kernel_verbose)
|
||||
|
||||
|
||||
@@ -26,26 +26,30 @@ import logging
|
||||
from omniperf_profile.profiler_base import OmniProfiler_Base
|
||||
from utils.utils import demarcate
|
||||
|
||||
class rocscope_profiler(OmniProfiler_Base):
|
||||
def __init__(self,profiling_args,profiler_mode,soc):
|
||||
super().__init__(profiling_args,profiler_mode,soc)
|
||||
|
||||
#-----------------------
|
||||
class rocscope_profiler(OmniProfiler_Base):
|
||||
def __init__(self, profiling_args, profiler_mode, soc):
|
||||
super().__init__(profiling_args, profiler_mode, soc)
|
||||
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to profiling.
|
||||
"""
|
||||
self.__profiler="rocscope"
|
||||
"""Perform any pre-processing steps prior to profiling."""
|
||||
self.__profiler = "rocscope"
|
||||
logging.debug("[profiling] pre-processing using %s profiler" % self.__profiler)
|
||||
|
||||
@demarcate
|
||||
def run_profiling(self, version, prog):
|
||||
"""Run profiling.
|
||||
"""
|
||||
logging.debug("[profiling] performing profiling using %s profiler" % self.__profiler)
|
||||
"""Run profiling."""
|
||||
logging.debug(
|
||||
"[profiling] performing profiling using %s profiler" % self.__profiler
|
||||
)
|
||||
|
||||
@demarcate
|
||||
def post_processing(self):
|
||||
"""Perform any post-processing steps prior to profiling.
|
||||
"""
|
||||
logging.debug("[profiling] performing post-processing using %s profiler" % self.__profiler)
|
||||
"""Perform any post-processing steps prior to profiling."""
|
||||
logging.debug(
|
||||
"[profiling] performing post-processing using %s profiler" % self.__profiler
|
||||
)
|
||||
|
||||
@@ -33,59 +33,74 @@ import numpy as np
|
||||
from utils.utils import demarcate
|
||||
from pathlib import Path
|
||||
|
||||
class OmniSoC_Base():
|
||||
def __init__(self,args):
|
||||
|
||||
class OmniSoC_Base:
|
||||
def __init__(self, args):
|
||||
self.__args = args
|
||||
self.__name = None # SoC name
|
||||
self.__name = None # SoC name
|
||||
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
|
||||
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)
|
||||
self.__workload_dir = os.path.join(
|
||||
self.__args.path, self.__args.name, self.__args.target
|
||||
)
|
||||
else:
|
||||
self.__workload_dir = self.__args.path
|
||||
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__name)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, type(self)):
|
||||
return NotImplemented
|
||||
return self.__name == other.get_soc()
|
||||
|
||||
def set_perfmon_dir(self, path:str):
|
||||
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 get_args(self):
|
||||
return self.__args
|
||||
|
||||
def set_compatible_profilers(self, profiler_names: list):
|
||||
self.__compatible_profilers = profiler_names
|
||||
|
||||
def get_compatible_profilers(self):
|
||||
return self.__compatible_profilers
|
||||
|
||||
|
||||
@demarcate
|
||||
def get_profiler_options(self):
|
||||
"""Fetch any SoC specific arguments required by the profiler
|
||||
"""
|
||||
"""Fetch any SoC specific arguments required by the profiler"""
|
||||
# assume no SoC specific options and return empty list by default
|
||||
return []
|
||||
|
||||
|
||||
@demarcate
|
||||
def perfmon_filter(self, roofline_perfmon_only: bool):
|
||||
"""Filter default performance counter set based on user arguments
|
||||
"""
|
||||
if roofline_perfmon_only and os.path.isfile(os.path.join(self.get_args().path, "pmc_perf.csv")):
|
||||
"""Filter default performance counter set based on user arguments"""
|
||||
if roofline_perfmon_only and os.path.isfile(
|
||||
os.path.join(self.get_args().path, "pmc_perf.csv")
|
||||
):
|
||||
return
|
||||
workload_perfmon_dir = self.__workload_dir + "/perfmon"
|
||||
|
||||
@@ -99,7 +114,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.__name + "/pmc_*_perf*.txt")
|
||||
ref_pmc_files_list += glob.glob(
|
||||
self.__perfmon_dir + "/" + self.__name + "/pmc_*_perf*.txt"
|
||||
)
|
||||
|
||||
# Perfmon list filtering
|
||||
if self.__args.ipblocks != None:
|
||||
@@ -124,38 +141,34 @@ class OmniSoC_Base():
|
||||
ref_pmc_files_list = glob.glob(self.__perfmon_dir + "/" + "pmc_roof_perf.txt")
|
||||
pmc_files_list = ref_pmc_files_list
|
||||
|
||||
|
||||
# Coalesce and writeback workload specific perfmon
|
||||
pmc_list = perfmon_coalesce(pmc_files_list, self.__perfmon_config, self.__workload_dir)
|
||||
pmc_list = perfmon_coalesce(
|
||||
pmc_files_list, self.__perfmon_config, self.__workload_dir
|
||||
)
|
||||
perfmon_emit(pmc_list, self.__perfmon_config, self.__workload_dir)
|
||||
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
# Required methods to be implemented by child classes
|
||||
#----------------------------------------------------
|
||||
# ----------------------------------------------------
|
||||
@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.__name)
|
||||
|
||||
|
||||
@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.__name)
|
||||
|
||||
@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.__name)
|
||||
|
||||
|
||||
|
||||
@demarcate
|
||||
def perfmon_coalesce(pmc_files_list, perfmon_config, workload_dir):
|
||||
"""Sort and bucket all related performance counters to minimize required application passes
|
||||
"""
|
||||
"""Sort and bucket all related performance counters to minimize required application passes"""
|
||||
workload_perfmon_dir = workload_dir + "/perfmon"
|
||||
|
||||
# match pattern for pmc counters
|
||||
@@ -216,9 +229,15 @@ def perfmon_coalesce(pmc_files_list, perfmon_config, workload_dir):
|
||||
|
||||
return pmc_list
|
||||
|
||||
|
||||
@demarcate
|
||||
def update_pmc_bucket(
|
||||
counters, save_file, perfmon_config, pmc_list=None, stext=None, workload_perfmon_dir=None
|
||||
counters,
|
||||
save_file,
|
||||
perfmon_config,
|
||||
pmc_list=None,
|
||||
stext=None,
|
||||
workload_perfmon_dir=None,
|
||||
):
|
||||
# Verify inputs.
|
||||
# If save_file is True, we're being called internally, from perfmon_coalesce
|
||||
@@ -303,6 +322,7 @@ def update_pmc_bucket(
|
||||
pmc_list["TCC2"][str(ch)].sort()
|
||||
return pmc_list
|
||||
|
||||
|
||||
@demarcate
|
||||
def perfmon_emit(pmc_list, perfmon_config, workload_dir=None):
|
||||
# Calculate the minimum number of iteration to save the pmc counters
|
||||
@@ -363,13 +383,13 @@ def perfmon_emit(pmc_list, perfmon_config, workload_dir=None):
|
||||
for iter in range(niter):
|
||||
# Prefix
|
||||
line = "pmc: "
|
||||
|
||||
|
||||
N = perfmon_config["TCC"]
|
||||
# TCC per-channel counters
|
||||
tcc_counters = []
|
||||
for ch in range(perfmon_config["TCC_channels"]):
|
||||
tcc_counters += pmc_list["TCC2"][str(ch)][tcc2_index * N : tcc2_index * N + N]
|
||||
|
||||
|
||||
tcc2_index += 1
|
||||
|
||||
# TCC2 aggregated counters
|
||||
@@ -387,4 +407,4 @@ def perfmon_emit(pmc_list, perfmon_config, workload_dir=None):
|
||||
fd.write("kernel:\n")
|
||||
fd.close()
|
||||
else:
|
||||
return batches
|
||||
return batches
|
||||
|
||||
@@ -37,14 +37,22 @@ SOC_PARAM = {
|
||||
"L2Banks": 16,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1725,
|
||||
"mclk": 1000
|
||||
"mclk": 1000,
|
||||
}
|
||||
|
||||
class gfx906_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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()))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
self.get_soc_name(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -64,13 +72,12 @@ class gfx906_soc (OmniSoC_Base):
|
||||
)
|
||||
self.set_soc_param(SOC_PARAM)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""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())
|
||||
@@ -79,13 +86,10 @@ class gfx906_soc (OmniSoC_Base):
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
|
||||
|
||||
@@ -37,14 +37,22 @@ SOC_PARAM = {
|
||||
"L2Banks": 32,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1502,
|
||||
"mclk": 1200
|
||||
"mclk": 1200,
|
||||
}
|
||||
|
||||
class gfx908_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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()))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home),
|
||||
"omniperf_soc",
|
||||
"profile_configs",
|
||||
self.get_soc_name(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -69,13 +77,12 @@ class gfx908_soc (OmniSoC_Base):
|
||||
# Mi100 requires a custom xml config
|
||||
return ["-m", self.get_workload_perfmon_dir() + "/" + "metrics.xml"]
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""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())
|
||||
@@ -84,12 +91,10 @@ class gfx908_soc (OmniSoC_Base):
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
super().analysis_setup()
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
|
||||
@@ -39,17 +39,32 @@ SOC_PARAM = {
|
||||
"L2Banks": 32,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1700,
|
||||
"mclk": 1600
|
||||
"mclk": 1600,
|
||||
}
|
||||
|
||||
class gfx90a_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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"))
|
||||
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_soc_name(),
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv1", "rocscope"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -64,46 +79,40 @@ class gfx90a_soc (OmniSoC_Base):
|
||||
"SPI": 2,
|
||||
"GRBM": 2,
|
||||
"GDS": 4,
|
||||
"TCC_channels": 32
|
||||
"TCC_channels": 32,
|
||||
}
|
||||
)
|
||||
self.set_soc_param(SOC_PARAM)
|
||||
self.roofline_obj = Roofline(args)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to profiling."""
|
||||
super().profiling_setup()
|
||||
# Performance counter filtering
|
||||
self.perfmon_filter(self.get_args().roof_only)
|
||||
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
if not self.get_args().no_roof:
|
||||
logging.info("[roofline] Checking for roofline.csv in " + str(self.get_args().path))
|
||||
logging.info(
|
||||
"[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())
|
||||
self.roofline_obj.post_processing()
|
||||
else:
|
||||
logging.info("[roofline] Skipping roofline")
|
||||
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self, roofline_parameters=None):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
# configure roofline for analysis
|
||||
if roofline_parameters:
|
||||
self.roofline_obj = Roofline(self.get_args(), roofline_parameters)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,18 +39,30 @@ SOC_PARAM = {
|
||||
"L2Banks": 16,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1950,
|
||||
"mclk": 1300
|
||||
"mclk": 1300,
|
||||
}
|
||||
|
||||
class gfx940_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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"))
|
||||
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(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv2"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -65,28 +77,25 @@ class gfx940_soc (OmniSoC_Base):
|
||||
"SPI": 2,
|
||||
"GRBM": 2,
|
||||
"GDS": 4,
|
||||
"TCC_channels": 32
|
||||
"TCC_channels": 32,
|
||||
}
|
||||
)
|
||||
self.set_soc_param(SOC_PARAM)
|
||||
self.roofline_obj = Roofline(args)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to profiling."""
|
||||
super().profiling_setup()
|
||||
# Performance counter filtering
|
||||
self.perfmon_filter(self.get_args().roof_only)
|
||||
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
@@ -98,16 +107,11 @@ class gfx940_soc (OmniSoC_Base):
|
||||
# else:
|
||||
# logging.info("[roofline] Skipping roofline")
|
||||
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self, roofline_parameters=None):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
# configure roofline for analysis
|
||||
# if roofline_parameters:
|
||||
# self.roofline_obj = Roofline(self.get_args(), roofline_parameters)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,18 +39,30 @@ SOC_PARAM = {
|
||||
"L2Banks": 16,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1950,
|
||||
"mclk": 1300
|
||||
"mclk": 1300,
|
||||
}
|
||||
|
||||
class gfx941_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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"))
|
||||
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(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv2"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -65,28 +77,25 @@ class gfx941_soc (OmniSoC_Base):
|
||||
"SPI": 2,
|
||||
"GRBM": 2,
|
||||
"GDS": 4,
|
||||
"TCC_channels": 32
|
||||
"TCC_channels": 32,
|
||||
}
|
||||
)
|
||||
self.set_soc_param(SOC_PARAM)
|
||||
self.roofline_obj = Roofline(args)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to profiling."""
|
||||
super().profiling_setup()
|
||||
# Performance counter filtering
|
||||
self.perfmon_filter(self.get_args().roof_only)
|
||||
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
@@ -98,16 +107,11 @@ class gfx941_soc (OmniSoC_Base):
|
||||
# else:
|
||||
# logging.info("[roofline] Skipping roofline")
|
||||
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self, roofline_parameters=None):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
# configure roofline for analysis
|
||||
# if roofline_parameters:
|
||||
# self.roofline_obj = Roofline(self.get_args(), roofline_parameters)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,18 +39,30 @@ SOC_PARAM = {
|
||||
"L2Banks": 16,
|
||||
"LDSBanks": 32,
|
||||
"Freq": 1950,
|
||||
"mclk": 1300
|
||||
"mclk": 1300,
|
||||
}
|
||||
|
||||
class gfx942_soc (OmniSoC_Base):
|
||||
def __init__(self,args):
|
||||
|
||||
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"))
|
||||
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(os.path.join(str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"))
|
||||
self.set_perfmon_dir(
|
||||
os.path.join(
|
||||
str(config.omniperf_home), "omniperf_soc", "profile_configs", "gfx940"
|
||||
)
|
||||
)
|
||||
self.set_compatible_profilers(["rocprofv2"])
|
||||
# Per IP block max number of simultaneous counters. GFX IP Blocks
|
||||
self.set_perfmon_config(
|
||||
@@ -65,28 +77,25 @@ class gfx942_soc (OmniSoC_Base):
|
||||
"SPI": 2,
|
||||
"GRBM": 2,
|
||||
"GDS": 4,
|
||||
"TCC_channels": 32
|
||||
"TCC_channels": 32,
|
||||
}
|
||||
)
|
||||
self.set_soc_param(SOC_PARAM)
|
||||
self.roofline_obj = Roofline(args)
|
||||
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
# Required child methods
|
||||
#-----------------------
|
||||
# -----------------------
|
||||
@demarcate
|
||||
def profiling_setup(self):
|
||||
"""Perform any SoC-specific setup prior to profiling.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to profiling."""
|
||||
super().profiling_setup()
|
||||
# Performance counter filtering
|
||||
self.perfmon_filter(self.get_args().roof_only)
|
||||
|
||||
|
||||
@demarcate
|
||||
def post_profiling(self):
|
||||
"""Perform any SoC-specific post profiling activities.
|
||||
"""
|
||||
"""Perform any SoC-specific post profiling activities."""
|
||||
super().post_profiling()
|
||||
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
@@ -98,16 +107,11 @@ class gfx942_soc (OmniSoC_Base):
|
||||
# else:
|
||||
# logging.info("[roofline] Skipping roofline")
|
||||
|
||||
|
||||
@demarcate
|
||||
def analysis_setup(self, roofline_parameters=None):
|
||||
"""Perform any SoC-specific setup prior to analysis.
|
||||
"""
|
||||
"""Perform any SoC-specific setup prior to analysis."""
|
||||
super().analysis_setup()
|
||||
logging.info("[roofline] Roofline temporarily disabled in Mi300")
|
||||
# configure roofline for analysis
|
||||
# if roofline_parameters:
|
||||
# self.roofline_obj = Roofline(self.get_args(), roofline_parameters)
|
||||
|
||||
|
||||
|
||||
|
||||
+112
-90
@@ -36,69 +36,73 @@ import numpy as np
|
||||
|
||||
SYMBOLS = [0, 1, 2, 3, 4, 5, 13, 17, 18, 20]
|
||||
|
||||
|
||||
class Roofline:
|
||||
def __init__(self, args, 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.__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.__ai_data = None
|
||||
self.__ceiling_data = None
|
||||
self.__figure = go.Figure()
|
||||
if not isinstance(self.__run_parameters['path_to_dir'], list):
|
||||
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, "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
|
||||
|
||||
self.validate_parameters()
|
||||
|
||||
def validate_parameters(self):
|
||||
if self.__run_parameters['include_kernel_names'] and (not self.__run_parameters['is_standalone']):
|
||||
if self.__run_parameters["include_kernel_names"] and (
|
||||
not self.__run_parameters["is_standalone"]
|
||||
):
|
||||
error("--roof-only is required for --kernel-names")
|
||||
|
||||
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["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
|
||||
)
|
||||
# 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["path_to_dir"]):
|
||||
os.makedirs(self.__run_parameters["path_to_dir"])
|
||||
|
||||
@demarcate
|
||||
def empirical_roofline(
|
||||
self,
|
||||
ret_df,
|
||||
):
|
||||
"""Generate a set of empirical roofline plots given a directory containing required profiling and benchmarking data
|
||||
"""
|
||||
"""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["path_to_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]))
|
||||
logging.debug("\n")
|
||||
|
||||
# Generate a roofline figure for each data type
|
||||
fp32_fig = self.generate_plot(
|
||||
dtype="FP32"
|
||||
)
|
||||
fp16_fig = self.generate_plot(
|
||||
dtype="FP16"
|
||||
)
|
||||
fp32_fig = self.generate_plot(dtype="FP32")
|
||||
fp16_fig = self.generate_plot(dtype="FP16")
|
||||
ml_combo_fig = self.generate_plot(
|
||||
dtype="I8",
|
||||
fig=fp16_fig,
|
||||
@@ -125,24 +129,36 @@ class Roofline:
|
||||
self.__figure.update_xaxes(dtick=1)
|
||||
# Output will be different depending on interaction type:
|
||||
# Save PDFs if we're in "standalone roofline" mode, otherwise return HTML to be used in GUI output
|
||||
if self.__run_parameters['is_standalone']:
|
||||
dev_id = str(self.__run_parameters['device_id'])
|
||||
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["path_to_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["path_to_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["path_to_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))
|
||||
ml_combo_fig.write_image(
|
||||
self.__run_parameters['path_to_dir'] + "/empirRoof_gpu-{}_int8_fp16.pdf".format(dev_id)
|
||||
fp32_fig.write_image(
|
||||
self.__run_parameters["path_to_dir"]
|
||||
+ "/empirRoof_gpu-{}_fp32.pdf".format(dev_id)
|
||||
)
|
||||
if self.__run_parameters['include_kernel_names']:
|
||||
self.__figure.write_image(self.__run_parameters['path_to_dir'] + "/kernelName_legend.pdf")
|
||||
ml_combo_fig.write_image(
|
||||
self.__run_parameters["path_to_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"
|
||||
)
|
||||
logging.info("[roofline] Empirical Roofline PDFs saved!")
|
||||
else:
|
||||
return html.Section(
|
||||
@@ -173,17 +189,13 @@ class Roofline:
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
|
||||
@demarcate
|
||||
def generate_plot(
|
||||
self, dtype, fig=None
|
||||
) -> go.Figure():
|
||||
"""Create graph object from ai_data (coordinate points) and ceiling_data (peak FLOP and BW) data.
|
||||
"""
|
||||
def generate_plot(self, dtype, fig=None) -> go.Figure():
|
||||
"""Create graph object from ai_data (coordinate points) and ceiling_data (peak FLOP and BW) data."""
|
||||
if fig is None:
|
||||
fig = go.Figure()
|
||||
plot_mode = "lines+text" if self.__run_parameters['is_standalone'] else "lines"
|
||||
plot_mode = "lines+text" if self.__run_parameters["is_standalone"] else "lines"
|
||||
self.__ceiling_data = constuct_roof(
|
||||
roofline_parameters=self.__run_parameters,
|
||||
dtype=dtype,
|
||||
@@ -193,10 +205,10 @@ class Roofline:
|
||||
#######################
|
||||
# Plot ceilings
|
||||
#######################
|
||||
if self.__run_parameters['mem_level'] == "ALL":
|
||||
if self.__run_parameters["mem_level"] == "ALL":
|
||||
cache_hierarchy = ["HBM", "L2", "L1", "LDS"]
|
||||
else:
|
||||
cache_hierarchy = self.__run_parameters['mem_level']
|
||||
cache_hierarchy = self.__run_parameters["mem_level"]
|
||||
|
||||
# Plot peak BW ceiling(s)
|
||||
for cache_level in cache_hierarchy:
|
||||
@@ -208,10 +220,14 @@ class Roofline:
|
||||
mode=plot_mode,
|
||||
hovertemplate="<b>%{text}</b>",
|
||||
text=[
|
||||
"{} GB/s".format(to_int(self.__ceiling_data[cache_level.lower()][2])),
|
||||
"{} GB/s".format(
|
||||
to_int(self.__ceiling_data[cache_level.lower()][2])
|
||||
),
|
||||
None
|
||||
if self.__run_parameters['is_standalone']
|
||||
else "{} GB/s".format(to_int(self.__ceiling_data[cache_level.lower()][2])),
|
||||
if self.__run_parameters["is_standalone"]
|
||||
else "{} GB/s".format(
|
||||
to_int(self.__ceiling_data[cache_level.lower()][2])
|
||||
),
|
||||
],
|
||||
textposition="top right",
|
||||
)
|
||||
@@ -228,7 +244,7 @@ class Roofline:
|
||||
hovertemplate="<b>%{text}</b>",
|
||||
text=[
|
||||
None
|
||||
if self.__run_parameters['is_standalone']
|
||||
if self.__run_parameters["is_standalone"]
|
||||
else "{} GFLOP/s".format(to_int(self.__ceiling_data["valu"][2])),
|
||||
"{} GFLOP/s".format(to_int(self.__ceiling_data["valu"][2])),
|
||||
],
|
||||
@@ -250,7 +266,7 @@ class Roofline:
|
||||
hovertemplate="<b>%{text}</b>",
|
||||
text=[
|
||||
None
|
||||
if self.__run_parameters['is_standalone']
|
||||
if self.__run_parameters["is_standalone"]
|
||||
else "{} GFLOP/s".format(to_int(self.__ceiling_data["mfma"][2])),
|
||||
"{} GFLOP/s".format(to_int(self.__ceiling_data["mfma"][2])),
|
||||
],
|
||||
@@ -269,7 +285,9 @@ class Roofline:
|
||||
name="ai_l1",
|
||||
mode="markers",
|
||||
marker={"color": "#00CC96"},
|
||||
marker_symbol=SYMBOLS if self.__run_parameters['include_kernel_names'] else None,
|
||||
marker_symbol=SYMBOLS
|
||||
if self.__run_parameters["include_kernel_names"]
|
||||
else None,
|
||||
)
|
||||
)
|
||||
fig.add_trace(
|
||||
@@ -279,7 +297,9 @@ class Roofline:
|
||||
name="ai_l2",
|
||||
mode="markers",
|
||||
marker={"color": "#EF553B"},
|
||||
marker_symbol=SYMBOLS if self.__run_parameters['include_kernel_names'] else None,
|
||||
marker_symbol=SYMBOLS
|
||||
if self.__run_parameters["include_kernel_names"]
|
||||
else None,
|
||||
)
|
||||
)
|
||||
fig.add_trace(
|
||||
@@ -289,7 +309,9 @@ class Roofline:
|
||||
name="ai_hbm",
|
||||
mode="markers",
|
||||
marker={"color": "#636EFA"},
|
||||
marker_symbol=SYMBOLS if self.__run_parameters['include_kernel_names'] else None,
|
||||
marker_symbol=SYMBOLS
|
||||
if self.__run_parameters["include_kernel_names"]
|
||||
else None,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -311,78 +333,78 @@ class Roofline:
|
||||
from collections import OrderedDict
|
||||
|
||||
# Change vL1D to a interpretable str, if required
|
||||
if "vL1D" in self.__run_parameters['mem_level']:
|
||||
self.__run_parameters['mem_level'].remove("vL1D")
|
||||
self.__run_parameters['mem_level'].append("L1")
|
||||
if "vL1D" in self.__run_parameters["mem_level"]:
|
||||
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["path_to_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))
|
||||
sys.exit(1)
|
||||
t_df = OrderedDict()
|
||||
t_df["pmc_perf"] = pd.read_csv(app_path)
|
||||
self.empirical_roofline(
|
||||
ret_df=t_df
|
||||
)
|
||||
self.empirical_roofline(ret_df=t_df)
|
||||
|
||||
# Main methods
|
||||
@abstractmethod
|
||||
def pre_processing(self):
|
||||
if self.__args.roof_only:
|
||||
# check for sysinfo
|
||||
logging.info("[roofline] Checking for sysinfo.csv in " + str(self.__args.path))
|
||||
logging.info(
|
||||
"[roofline] Checking for sysinfo.csv in " + str(self.__args.path)
|
||||
)
|
||||
sysinfo_path = os.path.join(self.__args.path, "sysinfo.csv")
|
||||
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,
|
||||
roof_only=self.__args.roof_only
|
||||
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,
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def profile(self):
|
||||
if self.__args.roof_only:
|
||||
# check for roofline benchmark
|
||||
logging.info("[roofline] Checking for roofline.csv in " + str(self.__args.path))
|
||||
logging.info(
|
||||
"[roofline] Checking for roofline.csv in " + str(self.__args.path)
|
||||
)
|
||||
roof_path = os.path.join(self.__args.path, "roofline.csv")
|
||||
if not os.path.isfile(roof_path):
|
||||
mibench(self.__args)
|
||||
|
||||
# check for profiling data
|
||||
logging.info("[roofline] Checking for pmc_perf.csv in " + str(self.__args.path))
|
||||
logging.info(
|
||||
"[roofline] Checking for pmc_perf.csv in " + str(self.__args.path)
|
||||
)
|
||||
app_path = os.path.join(self.__args.path, "pmc_perf.csv")
|
||||
if not os.path.isfile(app_path):
|
||||
logging.info("[roofline] pmc_perf.csv not found. Generating...")
|
||||
if not self.__args.remaining:
|
||||
error("An <app_cmd> is required to run.\nomniperf profile -n test -- <app_cmd>")
|
||||
#TODO: Add an equivelent of characterize_app() to run profiling directly out of this module
|
||||
|
||||
error(
|
||||
"An <app_cmd> is required to run.\nomniperf profile -n test -- <app_cmd>"
|
||||
)
|
||||
# TODO: Add an equivelent of characterize_app() to run profiling directly out of this module
|
||||
|
||||
elif self.__args.no_roof:
|
||||
logging.info("[roofline] Skipping roofline.")
|
||||
else:
|
||||
mibench(self.__args)
|
||||
|
||||
#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
|
||||
# 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
|
||||
@abstractmethod
|
||||
def post_processing(self):
|
||||
if self.__run_parameters['is_standalone']:
|
||||
if self.__run_parameters["is_standalone"]:
|
||||
self.standalone_roofline()
|
||||
|
||||
|
||||
|
||||
def to_int(a):
|
||||
if str(type(a)) == "<class 'NoneType'>":
|
||||
return np.nan
|
||||
else:
|
||||
return int(a)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+62
-35
@@ -34,6 +34,7 @@ import pandas as pd
|
||||
|
||||
MAX_SERVER_SEL_DELAY = 5000 # 5 sec connection timeout
|
||||
|
||||
|
||||
class DatabaseConnector:
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
@@ -45,17 +46,22 @@ class DatabaseConnector:
|
||||
"port": str(self.args.port),
|
||||
"team": self.args.team,
|
||||
"workload": self.args.workload,
|
||||
"db": None
|
||||
"db": None,
|
||||
}
|
||||
self.interaction_type: str = None #set to 'import' or 'remove' based on user arguments
|
||||
self.interaction_type: str = (
|
||||
None # set to 'import' or 'remove' based on user arguments
|
||||
)
|
||||
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)
|
||||
self.connection_info["workload"] = os.path.join(
|
||||
self.connection_info["workload"], self.args.target
|
||||
)
|
||||
|
||||
# Extract SoC and workload name from sysinfo.csv
|
||||
sys_info = os.path.join(self.connection_info['workload'], "sysinfo.csv")
|
||||
sys_info = os.path.join(self.connection_info["workload"], "sysinfo.csv")
|
||||
if os.path.isfile(sys_info):
|
||||
sys_info = pd.read_csv(sys_info)
|
||||
soc = sys_info["name"][0]
|
||||
@@ -63,7 +69,9 @@ class DatabaseConnector:
|
||||
else:
|
||||
error("[database] Unable to parse SoC and/or workload name from sysinfo.csv")
|
||||
|
||||
self.connection_info["db"] = "omniperf_" + str(self.args.team) + "_" + str(name) + "_" + str(soc)
|
||||
self.connection_info["db"] = (
|
||||
"omniperf_" + str(self.args.team) + "_" + str(name) + "_" + str(soc)
|
||||
)
|
||||
|
||||
@demarcate
|
||||
def db_import(self):
|
||||
@@ -72,7 +80,11 @@ class DatabaseConnector:
|
||||
file = "blank"
|
||||
for file in tqdm(os.listdir(self.connection_info["workload"])):
|
||||
if file.endswith(".csv"):
|
||||
logging.info("[database] Uploading: %s" % self.connection_info["workload"] + "/" + file)
|
||||
logging.info(
|
||||
"[database] Uploading: %s" % self.connection_info["workload"]
|
||||
+ "/"
|
||||
+ file
|
||||
)
|
||||
try:
|
||||
fileName = file[0 : file.find(".")]
|
||||
cmd = (
|
||||
@@ -101,69 +113,85 @@ class DatabaseConnector:
|
||||
|
||||
@demarcate
|
||||
def db_remove(self):
|
||||
db_to_remove = self.client[self.connection_info['workload']]
|
||||
db_to_remove = self.client[self.connection_info["workload"]]
|
||||
|
||||
# check the collection names on the database
|
||||
col_list = db_to_remove.list_collection_names()
|
||||
self.client.drop_database(db_to_remove)
|
||||
db = self.client["workload_names"]
|
||||
col = db["names"]
|
||||
col.delete_many({"name": self.connection_info['workload']})
|
||||
|
||||
logging.info("[database] Successfully removed %s" % self.connection_info['workload'])
|
||||
col.delete_many({"name": self.connection_info["workload"]})
|
||||
|
||||
logging.info(
|
||||
"[database] Successfully removed %s" % self.connection_info["workload"]
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def pre_processing(self):
|
||||
"""Perform any pre-processing steps prior to database conncetion.
|
||||
"""
|
||||
"""Perform any pre-processing steps prior to database conncetion."""
|
||||
logging.debug("[database] pre-processing database connection")
|
||||
if not self.args.remove and not self.args.upload:
|
||||
error("Either -i/--import or -r/--remove is required in database mode")
|
||||
self.interaction_type = 'import' if self.args.upload else 'remove'
|
||||
self.interaction_type = "import" if self.args.upload else "remove"
|
||||
|
||||
# Detect interaction type
|
||||
if self.interaction_type == 'remove':
|
||||
if self.interaction_type == "remove":
|
||||
logging.debug("[database] validating arguments for --remove workflow")
|
||||
is_full_workload_name = self.args.workload.count("_") >= 3
|
||||
if not is_full_workload_name:
|
||||
error("-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. omniperf_asw_vcopy_mi200)")
|
||||
error(
|
||||
"-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. omniperf_asw_vcopy_mi200)"
|
||||
)
|
||||
|
||||
if self.connection_info['host'] == None or self.connection_info['username'] == None:
|
||||
error("-H/--host and -u/--username are required when interaction type is set to %s" % self.interaction_type)
|
||||
if self.connection_info['workload'] == "admin" or self.connection_info['workload'] == "local":
|
||||
error("Cannot remove %s. Try again." % self.connection_info['workload'])
|
||||
if (
|
||||
self.connection_info["host"] == None
|
||||
or self.connection_info["username"] == None
|
||||
):
|
||||
error(
|
||||
"-H/--host and -u/--username are required when interaction type is set to %s"
|
||||
% self.interaction_type
|
||||
)
|
||||
if (
|
||||
self.connection_info["workload"] == "admin"
|
||||
or self.connection_info["workload"] == "local"
|
||||
):
|
||||
error("Cannot remove %s. Try again." % self.connection_info["workload"])
|
||||
else:
|
||||
logging.debug("[database] validating arguments for --import workflow")
|
||||
if (
|
||||
self.connection_info['host'] == None
|
||||
or self.connection_info['team'] == None
|
||||
or self.connection_info['username'] == None
|
||||
or self.connection_info['workload'] == None
|
||||
self.connection_info["host"] == None
|
||||
or self.connection_info["team"] == None
|
||||
or self.connection_info["username"] == None
|
||||
or self.connection_info["workload"] == None
|
||||
):
|
||||
error("-H/--host, -w/--workload, -u/--username, and -t/--team are all required when interaction type is set to %s" % self.interaction_type)
|
||||
error(
|
||||
"-H/--host, -w/--workload, -u/--username, and -t/--team are all required when interaction type is set to %s"
|
||||
% self.interaction_type
|
||||
)
|
||||
|
||||
if os.path.isdir(os.path.abspath(self.connection_info['workload'])):
|
||||
is_workload_empty(self.connection_info['workload'])
|
||||
if os.path.isdir(os.path.abspath(self.connection_info["workload"])):
|
||||
is_workload_empty(self.connection_info["workload"])
|
||||
else:
|
||||
error("--workload is invalid. Please pass path to a valid directory.")
|
||||
|
||||
if len(self.args.team) > 13:
|
||||
error("--team exceeds 13 character limit. Try again.")
|
||||
|
||||
|
||||
# format path properly
|
||||
self.connection_info['workload'] = os.path.abspath(self.connection_info['workload'])
|
||||
self.connection_info["workload"] = os.path.abspath(
|
||||
self.connection_info["workload"]
|
||||
)
|
||||
|
||||
# Detect password
|
||||
if self.connection_info['password'] == "":
|
||||
if self.connection_info["password"] == "":
|
||||
try:
|
||||
self.connection_info['password'] = getpass.getpass()
|
||||
self.connection_info["password"] = getpass.getpass()
|
||||
except Exception as e:
|
||||
error("[database] PASSWORD ERROR %s" % e)
|
||||
else:
|
||||
logging.info("[database] Password recieved")
|
||||
else:
|
||||
password = self.connection_info['password']
|
||||
password = self.connection_info["password"]
|
||||
|
||||
# Establish client connection
|
||||
connection_str = (
|
||||
@@ -177,11 +205,10 @@ class DatabaseConnector:
|
||||
+ self.connection_info["port"]
|
||||
+ "/?authSource=admin"
|
||||
)
|
||||
self.client = MongoClient(connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY)
|
||||
self.client = MongoClient(
|
||||
connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY
|
||||
)
|
||||
try:
|
||||
self.client.server_info()
|
||||
except:
|
||||
error("[database] Unable to connect to the DB server.")
|
||||
|
||||
|
||||
|
||||
@@ -50,11 +50,12 @@ top_stats_build_in_config = {
|
||||
"id": 1,
|
||||
"title": "Dispatch List",
|
||||
"data source": [{"raw_csv_table": {"id": 2, "source": "pmc_dispatch_info.csv"}}],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
time_units = {"s": 10**9, "ms": 10**6, "us": 10**3, "ns": 1}
|
||||
|
||||
|
||||
def load_sys_info(f):
|
||||
"""
|
||||
Load sys running info from csv file to a df.
|
||||
@@ -231,4 +232,4 @@ def is_single_panel_config(root_dir, supported_archs):
|
||||
return False
|
||||
else:
|
||||
logging.error("Found multiple panel config sets but incomplete for all archs!")
|
||||
sys.exit(1)
|
||||
sys.exit(1)
|
||||
|
||||
+28
-27
@@ -34,7 +34,8 @@ pd.set_option(
|
||||
"mode.chained_assignment", None
|
||||
) # ignore SettingWithCopyWarning pandas warning
|
||||
|
||||
IS_DARK = True #TODO: Remove hardcoded in favor of class property
|
||||
IS_DARK = True # TODO: Remove hardcoded in favor of class property
|
||||
|
||||
|
||||
##################
|
||||
# HELPER FUNCTIONS
|
||||
@@ -168,31 +169,31 @@ def build_bar_chart(display_df, table_config, barchart_elements, norm_filt):
|
||||
)
|
||||
# L2 Cache per channel
|
||||
# elif table_config["id"] in barchart_elements["l2_cache_per_chan"]:
|
||||
# nested_bar = {}
|
||||
# channels = []
|
||||
# for colName, colData in display_df.items():
|
||||
# if colName == "Channel":
|
||||
# channels = list(colData.values)
|
||||
# else:
|
||||
# display_df[colName] = [
|
||||
# x.astype(float) if x != "" and x != None else float(0)
|
||||
# for x in display_df[colName]
|
||||
# ]
|
||||
# nested_bar[colName] = list(display_df[colName])
|
||||
# for group, metric in nested_bar.items():
|
||||
# d_figs.append(
|
||||
# px.bar(
|
||||
# title=group[0 : group.rfind("(")],
|
||||
# x=channels,
|
||||
# y=metric,
|
||||
# labels={
|
||||
# "x": "Channel",
|
||||
# "y": group[group.rfind("(") + 1 : len(group) - 1].replace(
|
||||
# "per", norm_filt
|
||||
# ),
|
||||
# },
|
||||
# ).update_yaxes(rangemode="nonnegative")
|
||||
# )
|
||||
# nested_bar = {}
|
||||
# channels = []
|
||||
# for colName, colData in display_df.items():
|
||||
# if colName == "Channel":
|
||||
# channels = list(colData.values)
|
||||
# else:
|
||||
# display_df[colName] = [
|
||||
# x.astype(float) if x != "" and x != None else float(0)
|
||||
# for x in display_df[colName]
|
||||
# ]
|
||||
# nested_bar[colName] = list(display_df[colName])
|
||||
# for group, metric in nested_bar.items():
|
||||
# d_figs.append(
|
||||
# px.bar(
|
||||
# title=group[0 : group.rfind("(")],
|
||||
# x=channels,
|
||||
# y=metric,
|
||||
# labels={
|
||||
# "x": "Channel",
|
||||
# "y": group[group.rfind("(") + 1 : len(group) - 1].replace(
|
||||
# "per", norm_filt
|
||||
# ),
|
||||
# },
|
||||
# ).update_yaxes(rangemode="nonnegative")
|
||||
# )
|
||||
|
||||
# Speed-of-light bar chart
|
||||
elif table_config["id"] in barchart_elements["sol"]:
|
||||
@@ -376,4 +377,4 @@ def build_table_chart(
|
||||
# print("DATA: \n", display_df.to_dict('records'))
|
||||
d_figs.append(d_t)
|
||||
return d_figs
|
||||
# print(d_t.columns)
|
||||
# print(d_t.columns)
|
||||
|
||||
@@ -52,9 +52,9 @@ def insert_chart_data(mem_data, base_data):
|
||||
return G(
|
||||
className="data",
|
||||
children=[
|
||||
# ----------------------------------------
|
||||
# Instr Buff Block
|
||||
#TODO: double check wave_occupancy
|
||||
# ----------------------------------------
|
||||
# Instr Buff Block
|
||||
# TODO: double check wave_occupancy
|
||||
Text(
|
||||
x="52",
|
||||
y="313",
|
||||
@@ -73,8 +73,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontWeight="bold",
|
||||
children=memchart_values["Wave Life"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Instr Dispatch Block
|
||||
# ----------------------------------------
|
||||
# Instr Dispatch Block
|
||||
Text(
|
||||
x="386",
|
||||
y="46",
|
||||
@@ -139,8 +139,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["BR"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Exec Block
|
||||
# ----------------------------------------
|
||||
# Exec Block
|
||||
Text(
|
||||
x="480",
|
||||
y="99",
|
||||
@@ -198,8 +198,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["Workgroups"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# LDS Block
|
||||
# ----------------------------------------
|
||||
# LDS Block
|
||||
Text(
|
||||
x="723",
|
||||
y="78",
|
||||
@@ -224,8 +224,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["LDS Latency"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Vector L1 Cache Block
|
||||
# ----------------------------------------
|
||||
# Vector L1 Cache Block
|
||||
Text(
|
||||
x="708",
|
||||
y="204",
|
||||
@@ -306,8 +306,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["VL1_L2 Atomic"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Scalar L1D Cache Block
|
||||
# ----------------------------------------
|
||||
# Scalar L1D Cache Block
|
||||
Text(
|
||||
x="709",
|
||||
y="384",
|
||||
@@ -356,8 +356,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["VL1D_L2 Atomic"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Instr L1 Cache Block
|
||||
# ----------------------------------------
|
||||
# Instr L1 Cache Block
|
||||
Text(
|
||||
x="492",
|
||||
y="498",
|
||||
@@ -390,8 +390,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["IL1_L2 Rd"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# L2 Cache Block(inside)
|
||||
# ----------------------------------------
|
||||
# L2 Cache Block(inside)
|
||||
Text(
|
||||
x="1145",
|
||||
y="213",
|
||||
@@ -440,8 +440,8 @@ def insert_chart_data(mem_data, base_data):
|
||||
fontSize="12px",
|
||||
children=memchart_values["L2 Wr Lat"],
|
||||
),
|
||||
# ----------------------------------------
|
||||
# Fabric Block
|
||||
# ----------------------------------------
|
||||
# Fabric Block
|
||||
Text(
|
||||
x="1317",
|
||||
y="243",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import glob
|
||||
import glob
|
||||
import re
|
||||
import subprocess
|
||||
import pandas as pd
|
||||
@@ -34,6 +34,7 @@ from utils.utils import error
|
||||
|
||||
cache = dict()
|
||||
|
||||
|
||||
# Note: shortener is now dependent on a rocprof install with llvm
|
||||
def kernel_name_shortener(workload_dir, level):
|
||||
def shorten_file(df, level):
|
||||
@@ -134,6 +135,8 @@ def kernel_name_shortener(workload_dir, level):
|
||||
modified_df = shorten_file(orig_df, level)
|
||||
modified_df.to_csv(fpath, index=False)
|
||||
except pd.errors.EmptyDataError:
|
||||
logging.debug("[profiling] Skipping shortening on empty csv: %s" % str(fpath))
|
||||
logging.debug(
|
||||
"[profiling] Skipping shortening on empty csv: %s" % str(fpath)
|
||||
)
|
||||
|
||||
logging.info("[profiling] Kernel_Name shortening complete.")
|
||||
logging.info("[profiling] Kernel_Name shortening complete.")
|
||||
|
||||
@@ -1039,4 +1039,4 @@ if __name__ == "__main__":
|
||||
|
||||
arch = ""
|
||||
normal_unit = "per_kernel"
|
||||
print(plot_mem_chart(arch, normal_unit, metric_dict))
|
||||
print(plot_mem_chart(arch, normal_unit, metric_dict))
|
||||
|
||||
+19
-15
@@ -174,6 +174,7 @@ def to_round(a, b):
|
||||
else:
|
||||
return round(a, b)
|
||||
|
||||
|
||||
def to_quantile(a, b):
|
||||
if a is None:
|
||||
return None
|
||||
@@ -182,6 +183,7 @@ def to_quantile(a, b):
|
||||
else:
|
||||
raise Exception("to_quantile: unsupported type.")
|
||||
|
||||
|
||||
def to_mod(a, b):
|
||||
if isinstance(a, pd.core.series.Series):
|
||||
return a.mod(b)
|
||||
@@ -402,6 +404,7 @@ def gen_counter_list(formula):
|
||||
|
||||
return visited, counters
|
||||
|
||||
|
||||
def calc_builtin_var(var, sys_info):
|
||||
"""
|
||||
Calculate build-in variable based on sys_info:
|
||||
@@ -414,6 +417,7 @@ def calc_builtin_var(var, sys_info):
|
||||
print("Don't support", var)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
"""
|
||||
- Build dataframe for each type of data source within each panel.
|
||||
@@ -447,7 +451,6 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
type == "metric_table"
|
||||
and "metric" in data_config
|
||||
and "placeholder_range" in data_config["metric"]
|
||||
|
||||
):
|
||||
# print(data_config["metric"])
|
||||
new_metrics = {}
|
||||
@@ -475,16 +478,14 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
data_config["metric"] = new_metrics
|
||||
# print(data_config)
|
||||
# print(data_config["metric"])
|
||||
|
||||
|
||||
for panel_id, panel in archConfigs.panel_configs.items():
|
||||
for data_source in panel["data source"]:
|
||||
for type, data_config in data_source.items():
|
||||
if type == "metric_table":
|
||||
headers = ["Metric_ID"]
|
||||
data_source_idx = str(data_config["id"] // 100)
|
||||
if (data_source_idx != 0 or
|
||||
data_source_idx in filter_metrics
|
||||
):
|
||||
if data_source_idx != 0 or data_source_idx in filter_metrics:
|
||||
metric_list[data_source_idx] = panel["title"]
|
||||
if (
|
||||
"cli_style" in data_config
|
||||
@@ -506,9 +507,9 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
headers.append("coll_level")
|
||||
if "tips" in data_config["header"].keys():
|
||||
headers.append(data_config["header"]["tips"])
|
||||
|
||||
|
||||
df = pd.DataFrame(columns=headers)
|
||||
|
||||
|
||||
i = 0
|
||||
for key, entries in data_config["metric"].items():
|
||||
data_source_idx = (
|
||||
@@ -532,7 +533,7 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
):
|
||||
values.append(metric_idx)
|
||||
values.append(key)
|
||||
|
||||
|
||||
metric_list[data_source_idx] = data_config["title"]
|
||||
|
||||
if (
|
||||
@@ -687,9 +688,9 @@ def eval_metric(dfs, dfs_type, sys_info, soc_spec, raw_pmc_df, debug):
|
||||
ammolite__numWavesPerCU = sys_info.maxWavesPerCU # 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 = soc_spec[
|
||||
"LDSBanks"
|
||||
] # todo: eventually switch this over to sys_info. its a new spec so trying not to break compatibility
|
||||
ammolite__freq = sys_info.cur_sclk # todo: check do we still need it
|
||||
ammolite__mclk = sys_info.cur_mclk
|
||||
ammolite__sclk = sys_info.sclk
|
||||
@@ -910,7 +911,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"
|
||||
)
|
||||
elif "from_csv_columnwise" in df.columns:
|
||||
# NB:
|
||||
# Another way might be doing transpose in tty like metric_table.
|
||||
@@ -923,7 +926,9 @@ def load_kernel_top(workload, dir):
|
||||
# so tty could detect them and show them correctly in comparison.
|
||||
tmp[id].columns = ["Info"]
|
||||
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"
|
||||
)
|
||||
workload.dfs.update(tmp)
|
||||
|
||||
|
||||
@@ -957,6 +962,7 @@ def build_comparable_columns(time_unit):
|
||||
|
||||
return comparable_columns
|
||||
|
||||
|
||||
def correct_sys_info(df, specs_correction):
|
||||
"""
|
||||
Correct system spec items manually
|
||||
@@ -1012,5 +1018,3 @@ def correct_sys_info(df, specs_correction):
|
||||
df[name_map[k]] = v
|
||||
|
||||
return df
|
||||
|
||||
|
||||
|
||||
+43
-21
@@ -96,35 +96,36 @@ def get_color(catagory):
|
||||
# Plot BW at each cache level
|
||||
# -------------------------------------------------------------------------------------
|
||||
def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
"""Given benchmarking data, calculate ceilings (or peak performance) for empirical roofline
|
||||
"""
|
||||
"""Given benchmarking data, calculate ceilings (or peak performance) for empirical roofline"""
|
||||
# TODO: This is where filtering by memory level will need to occur for standalone
|
||||
graphPoints = {"hbm": [], "l2": [], "l1": [], "lds": [], "valu": [], "mfma": []}
|
||||
|
||||
if roofline_parameters['mem_level'] == "ALL":
|
||||
if roofline_parameters["mem_level"] == "ALL":
|
||||
cacheHierarchy = ["HBM", "L2", "L1", "LDS"]
|
||||
else:
|
||||
cacheHierarchy = roofline_parameters['mem_level']
|
||||
cacheHierarchy = roofline_parameters["mem_level"]
|
||||
|
||||
x1 = y1 = x2 = y2 = -1
|
||||
x1_mfma = y1_mfma = x2_mfma = y2_mfma = -1
|
||||
target_precision = dtype[2:]
|
||||
|
||||
if dtype != "FP16" and dtype != "I8":
|
||||
peakOps = float(
|
||||
benchmark_data[dtype + "Flops"][roofline_parameters['device_id']]
|
||||
)
|
||||
peakOps = float(benchmark_data[dtype + "Flops"][roofline_parameters["device_id"]])
|
||||
for i in range(0, len(cacheHierarchy)):
|
||||
# Plot BW line
|
||||
# Plot BW line
|
||||
logging.debug("[roofline] Current cache level is %s" % cacheHierarchy[i])
|
||||
curr_bw = cacheHierarchy[i] + "Bw"
|
||||
peakBw = float(benchmark_data[curr_bw][roofline_parameters['device_id']])
|
||||
peakBw = float(benchmark_data[curr_bw][roofline_parameters["device_id"]])
|
||||
|
||||
if dtype == "I8":
|
||||
peakMFMA = float(benchmark_data["MFMAI8Ops"][roofline_parameters['device_id']])
|
||||
peakMFMA = float(
|
||||
benchmark_data["MFMAI8Ops"][roofline_parameters["device_id"]]
|
||||
)
|
||||
else:
|
||||
peakMFMA = float(
|
||||
benchmark_data["MFMAF{}Flops".format(target_precision)][roofline_parameters['device_id']]
|
||||
benchmark_data["MFMAF{}Flops".format(target_precision)][
|
||||
roofline_parameters["device_id"]
|
||||
]
|
||||
)
|
||||
|
||||
x1 = float(XMIN)
|
||||
@@ -173,7 +174,9 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
if x2_mfma < x0_mfma:
|
||||
x0_mfma = x2_mfma
|
||||
|
||||
logging.debug("MFMA ROOF [{}, {}], [{},{}]".format(x0_mfma, XMAX, peakMFMA, peakMFMA))
|
||||
logging.debug(
|
||||
"MFMA ROOF [{}, {}], [{},{}]".format(x0_mfma, XMAX, peakMFMA, peakMFMA)
|
||||
)
|
||||
graphPoints["mfma"].append([x0_mfma, XMAX])
|
||||
graphPoints["mfma"].append([peakMFMA, peakMFMA])
|
||||
graphPoints["mfma"].append(peakMFMA)
|
||||
@@ -186,8 +189,7 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
# -------------------------------------------------------------------------------------
|
||||
# Calculate relevant metrics for ai calculation
|
||||
def calc_ai(sort_type, ret_df):
|
||||
"""Given counter data, calculate arithmetic intensity for each kernel in the application.
|
||||
"""
|
||||
"""Given counter data, calculate arithmetic intensity for each kernel in the application."""
|
||||
df = ret_df["pmc_perf"]
|
||||
# Sort by top kernels or top dispatches?
|
||||
df = df.sort_values(by=["Kernel_Name"])
|
||||
@@ -261,7 +263,11 @@ def calc_ai(sort_type, ret_df):
|
||||
+ (df["SQ_INSTS_VALU_MFMA_MOPS_F64"][idx] * 512)
|
||||
)
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped total_flops at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped total_flops at index {}".format(
|
||||
kernelName[:35], idx
|
||||
)
|
||||
)
|
||||
pass
|
||||
try:
|
||||
valu_flops += (
|
||||
@@ -288,7 +294,9 @@ def calc_ai(sort_type, ret_df):
|
||||
)
|
||||
)
|
||||
except KeyError:
|
||||
logging.debug("{}: Skipped valu_flops at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"{}: Skipped valu_flops at index {}".format(kernelName[:35], idx)
|
||||
)
|
||||
pass
|
||||
|
||||
try:
|
||||
@@ -298,7 +306,9 @@ def calc_ai(sort_type, ret_df):
|
||||
mfma_flops_f64 += df["SQ_INSTS_VALU_MFMA_MOPS_F64"][idx] * 512
|
||||
mfma_iops_i8 += df["SQ_INSTS_VALU_MFMA_MOPS_I8"][idx] * 512
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped mfma ops at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped mfma ops at index {}".format(kernelName[:35], idx)
|
||||
)
|
||||
pass
|
||||
|
||||
try:
|
||||
@@ -308,13 +318,19 @@ def calc_ai(sort_type, ret_df):
|
||||
* L2_BANKS
|
||||
) # L2_BANKS = 32 (since assuming mi200)
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped lds_data at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped lds_data at index {}".format(kernelName[:35], idx)
|
||||
)
|
||||
pass
|
||||
|
||||
try:
|
||||
L1cache_data += df["TCP_TOTAL_CACHE_ACCESSES_sum"][idx] * 64
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped L1cache_data at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped L1cache_data at index {}".format(
|
||||
kernelName[:35], idx
|
||||
)
|
||||
)
|
||||
pass
|
||||
|
||||
try:
|
||||
@@ -325,7 +341,11 @@ def calc_ai(sort_type, ret_df):
|
||||
+ df["TCP_TCC_READ_REQ_sum"][idx] * 64
|
||||
)
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped L2cache_data at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped L2cache_data at index {}".format(
|
||||
kernelName[:35], idx
|
||||
)
|
||||
)
|
||||
pass
|
||||
try:
|
||||
hbm_data += (
|
||||
@@ -335,7 +355,9 @@ def calc_ai(sort_type, ret_df):
|
||||
+ ((df["TCC_EA_WRREQ_sum"][idx] - df["TCC_EA_WRREQ_64B_sum"][idx]) * 32)
|
||||
)
|
||||
except KeyError:
|
||||
logging.debug("[roofline] {}: Skipped hbm_data at index {}".format(kernelName[:35], idx))
|
||||
logging.debug(
|
||||
"[roofline] {}: Skipped hbm_data at index {}".format(kernelName[:35], idx)
|
||||
)
|
||||
pass
|
||||
|
||||
totalDuration += df["End_Timestamp"][idx] - df["Start_Timestamp"][idx]
|
||||
|
||||
+61
-61
@@ -37,6 +37,7 @@ from pathlib import Path as path
|
||||
from textwrap import dedent
|
||||
from utils.utils import error, get_hbm_stack_num
|
||||
|
||||
|
||||
@dataclass
|
||||
class MachineSpecs:
|
||||
hostname: str
|
||||
@@ -135,7 +136,7 @@ def gpuinfo():
|
||||
|
||||
# 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)
|
||||
gpu_info["max_mclk"] = search(r"(\d+)Mhz\s*$", rocm_smi_mclk)
|
||||
|
||||
# Fixme: find better way to differentiate cards, GPU vs APU, etc.
|
||||
rocminfo_full = run(["rocminfo"])
|
||||
@@ -151,81 +152,85 @@ def gpuinfo():
|
||||
if not gpu_arch in SUPPORTED_ARCHS.keys():
|
||||
return gpu_info
|
||||
|
||||
gpu_info['L1'], gpu_info['L1'] = "", ""
|
||||
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
|
||||
gpu_info["L1"] = key
|
||||
continue
|
||||
|
||||
key = search(r"^\s*L2:\s+ ([a-zA-Z0-9]+)\s*", linetext)
|
||||
if key != None:
|
||||
gpu_info['L2'] = key
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
gpu_info["max_waves_per_cu"] = key
|
||||
break
|
||||
|
||||
try:
|
||||
soc_module = importlib.import_module('omniperf_soc.soc_'+gpu_arch)
|
||||
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))
|
||||
|
||||
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'])
|
||||
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))\
|
||||
|
||||
error(
|
||||
"Incomplete class definition for %s. Expected a field for %s in SOC_PARAM."
|
||||
% (gpu_arch, e)
|
||||
)
|
||||
# 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):
|
||||
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'] = ""
|
||||
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():
|
||||
@@ -235,7 +240,7 @@ def gpuinfo():
|
||||
return gpu_info
|
||||
|
||||
|
||||
def run(cmd,exit_on_error=False):
|
||||
def run(cmd, exit_on_error=False):
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
if exit_on_error:
|
||||
@@ -255,24 +260,18 @@ def search(pattern, string):
|
||||
return m.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def total_l2_banks(archname, L2Banks, memory_partition):
|
||||
# Fixme: support all supported partitioning mode
|
||||
# Fixme: "name" is a bad name!
|
||||
totalL2Banks = L2Banks
|
||||
if (
|
||||
archname.lower() == "mi300a_a0"
|
||||
or archname.lower() == "mi300a_a1"
|
||||
):
|
||||
totalL2Banks = L2Banks * get_hbm_stack_num(
|
||||
archname, memory_partition)
|
||||
elif (
|
||||
archname.lower() == "mi300x_a0"
|
||||
or archname.lower() == "mi300x_a1"
|
||||
):
|
||||
totalL2Banks = L2Banks * get_hbm_stack_num(
|
||||
archname, memory_partition)
|
||||
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()
|
||||
@@ -339,8 +338,8 @@ def get_machine_specs(devicenum):
|
||||
|
||||
# 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']
|
||||
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))
|
||||
@@ -358,15 +357,16 @@ def get_machine_specs(devicenum):
|
||||
memory_partition = "NA"
|
||||
|
||||
totalL2Banks = total_l2_banks(
|
||||
gpu_info['gpu_name'], int(gpu_info['L2Banks']), memory_partition)
|
||||
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"
|
||||
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)
|
||||
hbmBW = str(int(gpu_info["max_mclk"]) / 1000 * 32 * hbmchannels)
|
||||
totalL2Banks = str(totalL2Banks)
|
||||
|
||||
return MachineSpecs(
|
||||
@@ -377,26 +377,26 @@ def get_machine_specs(devicenum):
|
||||
ram,
|
||||
distro,
|
||||
rocm_version,
|
||||
gpu_info['gpu_name'],
|
||||
gpu_info['gpu_arch'],
|
||||
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'],
|
||||
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'],
|
||||
gpu_info["max_waves_per_cu"],
|
||||
gpu_info["L2Banks"],
|
||||
totalL2Banks,
|
||||
gpu_info['LDSBanks'],
|
||||
gpu_info['numSQC'],
|
||||
gpu_info['numPipes'],
|
||||
gpu_info["LDSBanks"],
|
||||
gpu_info["numSQC"],
|
||||
gpu_info["numPipes"],
|
||||
hbmBW,
|
||||
compute_partition,
|
||||
memory_partition,
|
||||
|
||||
+6
-5
@@ -201,9 +201,9 @@ def show_all(args, runs, archConfigs, output):
|
||||
)
|
||||
|
||||
# Only show top N kernels (as specified in --max-kernel-num) in "Top Stats" section
|
||||
if(
|
||||
type == "raw_csv_table"
|
||||
and (table_config["source"] == "pmc_kernel_top.csv" or table_config["source"] == "pmc_dispatch_info.csv")
|
||||
if type == "raw_csv_table" and (
|
||||
table_config["source"] == "pmc_kernel_top.csv"
|
||||
or table_config["source"] == "pmc_dispatch_info.csv"
|
||||
):
|
||||
df = df.head(args.max_stat_num)
|
||||
# NB:
|
||||
@@ -251,7 +251,9 @@ def show_kernel_stats(args, runs, archConfigs, output):
|
||||
# sorted when load_table_data.
|
||||
if table_config["id"] == 1:
|
||||
print("\n" + "-" * 80, file=output)
|
||||
print("Detected Kernels (sorted decending by duration)", file=output)
|
||||
print(
|
||||
"Detected Kernels (sorted decending by duration)", file=output
|
||||
)
|
||||
df = pd.concat([df, single_df["Kernel_Name"]], axis=1)
|
||||
|
||||
if table_config["id"] == 2:
|
||||
@@ -268,4 +270,3 @@ def show_kernel_stats(args, runs, archConfigs, output):
|
||||
),
|
||||
file=output,
|
||||
)
|
||||
|
||||
|
||||
@@ -358,7 +358,10 @@ def baseline_compare_metric(test_name, workload_dir, args=[]):
|
||||
)
|
||||
|
||||
isValid = (
|
||||
(abs(absolute_diff) <= METRIC_THRESHOLDS[metric_idx]["absolute"])
|
||||
(
|
||||
abs(absolute_diff)
|
||||
<= METRIC_THRESHOLDS[metric_idx]["absolute"]
|
||||
)
|
||||
if (threshold_type == "absolute")
|
||||
else (
|
||||
abs(relative_diff)
|
||||
|
||||
Reference in New Issue
Block a user