[rocprof-compute] Update Formatting (#671)
* updated rocprof-compute formatting * fixed ammolite peak variables in parser.py * format parser.py * update formatting rocprof_compute_base
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e9e98daf24
Коммит
5deeea71df
@@ -228,7 +228,8 @@ Examples:
|
||||
"--set",
|
||||
default=None,
|
||||
dest="set_selected",
|
||||
help="\t\t\tProfile a set of metrics of topic of interest by collecting counters in a single pass.\n\t\t\tFor available sets, see --list-sets",
|
||||
help="\t\t\tProfile a set of metrics of topic of interest by collecting "
|
||||
"counters in a single pass.\n\t\t\tFor available sets, see --list-sets",
|
||||
)
|
||||
|
||||
profile_group.add_argument(
|
||||
|
||||
@@ -169,14 +169,17 @@ class OmniAnalyze_Base:
|
||||
if self.__args.list_metrics:
|
||||
self.list_metrics()
|
||||
|
||||
# load required configs
|
||||
for d in self.__args.path:
|
||||
sysinfo_path = (
|
||||
Path(d[0])
|
||||
def get_sysinfo_path(data_path):
|
||||
return (
|
||||
Path(data_path)
|
||||
if self.__args.nodes is None
|
||||
and self.__args.spatial_multiplexing is not True
|
||||
else file_io.find_1st_sub_dir(d[0])
|
||||
else file_io.find_1st_sub_dir(data_path)
|
||||
)
|
||||
|
||||
# load required configs
|
||||
for d in self.__args.path:
|
||||
sysinfo_path = get_sysinfo_path(d[0])
|
||||
sys_info = file_io.load_sys_info(sysinfo_path.joinpath("sysinfo.csv"))
|
||||
arch = sys_info.iloc[0]["gpu_arch"]
|
||||
args = self.__args
|
||||
@@ -196,20 +199,14 @@ class OmniAnalyze_Base:
|
||||
# For regular single node case, load sysinfo.csv directly
|
||||
# For multi-node, either the default "all", or specified some,
|
||||
# pick up the one in the 1st sub_dir. We could fix it properly later.
|
||||
sysinfo_path = (
|
||||
Path(d[0])
|
||||
if self.__args.nodes is None
|
||||
and self.__args.spatial_multiplexing is not True
|
||||
else file_io.find_1st_sub_dir(d[0])
|
||||
)
|
||||
w = schema.Workload()
|
||||
sysinfo_path = get_sysinfo_path(d[0])
|
||||
w.sys_info = file_io.load_sys_info(sysinfo_path.joinpath("sysinfo.csv"))
|
||||
|
||||
if not getattr(self.get_args(), "no_roof", False):
|
||||
try:
|
||||
roofline_path = sysinfo_path.joinpath("roofline.csv")
|
||||
roofline_df = pd.read_csv(roofline_path)
|
||||
|
||||
# use original column names from roofline.csv directly
|
||||
roofline_csv_path = sysinfo_path / "roofline.csv"
|
||||
roofline_df = pd.read_csv(roofline_csv_path)
|
||||
w.roofline_peaks = roofline_df
|
||||
|
||||
except FileNotFoundError:
|
||||
|
||||
@@ -229,9 +229,9 @@ class RocProfCompute:
|
||||
arch = self.__args.list_metrics
|
||||
if arch in self.__supported_archs.keys():
|
||||
ac = schema.ArchConfig()
|
||||
ac.panel_configs = file_io.load_panel_configs(
|
||||
[self.__args.config_dir.joinpath(arch)]
|
||||
)
|
||||
ac.panel_configs = file_io.load_panel_configs([
|
||||
self.__args.config_dir.joinpath(arch)
|
||||
])
|
||||
sys_info = self.__mspec.get_class_members().iloc[0]
|
||||
parser.build_dfs(archConfigs=ac, filter_metrics=[], sys_info=sys_info)
|
||||
for key, value in ac.metric_list.items():
|
||||
@@ -259,7 +259,8 @@ class RocProfCompute:
|
||||
|
||||
# Print header
|
||||
print(
|
||||
f"{'Set Option':<35} {'Set Title':<35} {'Metric Name':<30} {'Metric ID':<10}"
|
||||
f"{'Set Option':<35} {'Set Title':<35}"
|
||||
f" {'Metric Name':<30} {'Metric ID':<10}"
|
||||
)
|
||||
print("-" * 115)
|
||||
|
||||
@@ -279,7 +280,8 @@ class RocProfCompute:
|
||||
title_display = title if first_row else ""
|
||||
|
||||
print(
|
||||
f"{set_display:<35} {title_display:<35} {metric_name:<30} {metric_id:<10}"
|
||||
f"{set_display:<35} {title_display:<35}"
|
||||
f" {metric_name:<30} {metric_id:<10}"
|
||||
)
|
||||
first_row = False
|
||||
# Empty line between sets
|
||||
|
||||
@@ -300,7 +300,8 @@ class OmniSoC_Base:
|
||||
sets_info = parse_sets_yaml(self.__arch)
|
||||
if set_selected not in set(sets_info.keys()):
|
||||
console_error(
|
||||
f"argument --set: invalid choice: '{set_selected}' (choose from {sets_info.keys()})"
|
||||
f"argument --set: invalid choice: '{set_selected}' "
|
||||
f"(choose from {sets_info.keys()})"
|
||||
)
|
||||
self.__args.filter_blocks = [
|
||||
next(iter(metric.keys()))
|
||||
|
||||
@@ -55,7 +55,10 @@ class MainView(Horizontal):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(id="main-container")
|
||||
self.start_path = Path(DEFAULT_START_PATH) if DEFAULT_START_PATH else Path.cwd()
|
||||
self.start_path = (
|
||||
# NOTE: is cwd the best choice?
|
||||
Path.cwd() if DEFAULT_START_PATH is None else Path(DEFAULT_START_PATH)
|
||||
)
|
||||
self.logger = Logger()
|
||||
self.logger.info("MainView initialized", update_ui=False)
|
||||
|
||||
@@ -167,7 +170,9 @@ class MainView(Horizontal):
|
||||
def refresh_results(self) -> None:
|
||||
kernel_view = self.query_one("#kernel-view")
|
||||
if kernel_view:
|
||||
kernel_view.update_results(self.kernel_to_df_dict, self.top_kernel_to_df_list)
|
||||
kernel_view.update_results(
|
||||
self.kernel_to_df_dict, self.top_kernel_to_df_list
|
||||
)
|
||||
self.logger.success("Results displayed successfully.")
|
||||
else:
|
||||
self.logger.error("Kernel view not found or no data available")
|
||||
|
||||
@@ -51,7 +51,8 @@ def create_table(df: pd.DataFrame) -> DataTable:
|
||||
def create_widget_from_data(df: pd.DataFrame, tui_style: str = None, context: str = ""):
|
||||
if df is None or df.empty:
|
||||
return Label(
|
||||
f"Data not available{f' for {context}' if context else ''}", classes="warning"
|
||||
f"Data not available{f' for {context}' if context else ''}",
|
||||
classes="warning",
|
||||
)
|
||||
|
||||
match tui_style:
|
||||
@@ -100,7 +101,9 @@ def build_section_from_config(
|
||||
if isinstance(dfs, dict):
|
||||
exclude_keys = subsection_config.get("exclude_keys", [])
|
||||
for section_name, subsections in dfs.items():
|
||||
if section_name not in exclude_keys and isinstance(subsections, dict):
|
||||
if section_name not in exclude_keys and isinstance(
|
||||
subsections, dict
|
||||
):
|
||||
kernel_children = []
|
||||
for subsection_name, data in subsections.items():
|
||||
if isinstance(data, dict) and "df" in data:
|
||||
|
||||
@@ -676,7 +676,8 @@ class Roofline:
|
||||
console_log("roofline", "{} does not exist".format(roofline_csv))
|
||||
return
|
||||
|
||||
# if workload is detected, utilize Roofline yamls. If not, fallback to legacy calc_ai
|
||||
# if workload is detected, utilize Roofline yamls.
|
||||
# If not, fallback to legacy calc_ai
|
||||
if workload is not None:
|
||||
self.__ai_data = calc_ai_analyze(
|
||||
workload=workload,
|
||||
|
||||
@@ -74,7 +74,8 @@ def load_panel_configs(dirs):
|
||||
if f.endswith(".yaml"):
|
||||
with open(Path(root) / f) as file:
|
||||
config_yml = yaml.safe_load(file)
|
||||
# metric key can be None due to some metric tables not having any metrics
|
||||
# metric key can be None due to some metric-
|
||||
# tables not having any metrics
|
||||
# metric key should be empty dict instead of None
|
||||
for data_source in config_yml["Panel Config"]["data source"]:
|
||||
metric_table = data_source.get("metric_table")
|
||||
@@ -160,9 +161,9 @@ def create_df_kernel_top_stats(
|
||||
axis=1,
|
||||
)
|
||||
|
||||
grouped = time_stats.groupby(by=["Kernel_Name"]).agg(
|
||||
{"ExeTime": ["count", "sum", "mean", "median"]}
|
||||
)
|
||||
grouped = time_stats.groupby(by=["Kernel_Name"]).agg({
|
||||
"ExeTime": ["count", "sum", "mean", "median"]
|
||||
})
|
||||
|
||||
time_unit_str = "(" + time_unit + ")"
|
||||
grouped.columns = [
|
||||
|
||||
@@ -996,7 +996,8 @@ def eval_metric(dfs, dfs_type, sys_info, empirical_peaks_df, raw_pmc_df, debug,
|
||||
except TypeError:
|
||||
console_warning(
|
||||
"Skipping entry. Encountered a missing "
|
||||
"counter\n{} has been assigned to None\n{}".format(
|
||||
"counter\n"
|
||||
"{} has been assigned to None\n{}".format(
|
||||
expr,
|
||||
np.nan,
|
||||
)
|
||||
@@ -1024,11 +1025,10 @@ def eval_metric(dfs, dfs_type, sys_info, empirical_peaks_df, raw_pmc_df, debug,
|
||||
except (TypeError, NameError) as e:
|
||||
if "empirical_peak" in str(e):
|
||||
console_warning(
|
||||
f"Missing empirical peak data: {e}. Using empty value."
|
||||
f"Missing empirical peak data: {e}. "
|
||||
"Using empty value."
|
||||
)
|
||||
row[expr] = ""
|
||||
else:
|
||||
row[expr] = ""
|
||||
row[expr] = ""
|
||||
except AttributeError as ae:
|
||||
if (
|
||||
str(ae)
|
||||
@@ -1086,7 +1086,8 @@ def apply_filters(workload, dir, is_gui, debug):
|
||||
for kernel_id in workload.filter_kernel_ids:
|
||||
if kernel_id >= len(kernels_df["Kernel_Name"]):
|
||||
console_error(
|
||||
"{} is an invalid kernel id. Please enter an id between 0-{}".format(
|
||||
"{} is an invalid kernel id. "
|
||||
"Please enter an id between 0-{}".format(
|
||||
kernel_id,
|
||||
len(kernels_df["Kernel_Name"]) - 1,
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
|
||||
from utils.logger import console_debug
|
||||
from utils.logger import console_debug, console_warning
|
||||
from utils.parser import apply_filters, eval_metric
|
||||
|
||||
################################################
|
||||
@@ -158,7 +158,8 @@ 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": []}
|
||||
|
||||
@@ -189,7 +190,7 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
|
||||
if dtype in PEAK_OPS_DATATYPES:
|
||||
x2 = peakOps / peakBw
|
||||
y2 = peakOps
|
||||
y2 = peakOps # noqa
|
||||
|
||||
# Plot MFMA lines (NOTE: Assuming MI200 soc)
|
||||
x1_mfma = peakOps / peakBw
|
||||
@@ -223,9 +224,9 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
graphPoints[cacheHierarchy[i].lower()].append([y1, peakY])
|
||||
graphPoints[cacheHierarchy[i].lower()].append(peakBw)
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# ----------------------------------------------------------------------------------
|
||||
# Plot computing roof
|
||||
# -------------------------------------------------------------------------------------
|
||||
# ----------------------------------------------------------------------------------
|
||||
if dtype in PEAK_OPS_DATATYPES:
|
||||
# Plot FMA roof
|
||||
x0 = XMAX
|
||||
@@ -356,7 +357,11 @@ def calc_ai_analyze(workload, mspec, sort_type, config, arch_config):
|
||||
|
||||
console_debug(
|
||||
"roofline",
|
||||
f"Kernel {kernel_id}: AI_HBM={ai_hbm:.2f}, AI_L2={ai_l2:.2f}, AI_L1={ai_l1:.2f}, Performance={performance:.2e} GFLOP/s",
|
||||
f"Kernel {kernel_id}: "
|
||||
f"AI_HBM={ai_hbm:.2f}, "
|
||||
f"AI_L2={ai_l2:.2f}, "
|
||||
f"AI_L1={ai_l1:.2f}, "
|
||||
f"Performance={performance:.2e} GFLOP/s",
|
||||
)
|
||||
|
||||
# add to plot points if we have valid data
|
||||
@@ -393,11 +398,11 @@ def calc_ai_analyze(workload, mspec, sort_type, config, arch_config):
|
||||
|
||||
|
||||
def calc_ai_profile(mspec, sort_type, ret_df):
|
||||
"""Given counter data, calculate arithmetic intensity for each kernel in the application.
|
||||
Leverage hard-coded equations to calculate AI values.
|
||||
"""Given counter data, calculate arithmetic intensity for each kernel
|
||||
in the application. Leverage hard-coded equations to calculate AI values.
|
||||
|
||||
Used during profiling stage to generate roofline PDF, since Roofline yamls are not available
|
||||
in the profiling stage."""
|
||||
Used during profiling stage to generate roofline PDF, since Roofline yamls
|
||||
are not available in the profiling stage."""
|
||||
|
||||
console_debug(
|
||||
"calc_ai_profile: Starting legacy roofline calculation (from roofline_calc)"
|
||||
@@ -608,9 +613,7 @@ def calc_ai_profile(mspec, sort_type, ret_df):
|
||||
|
||||
calls += 1
|
||||
|
||||
if sort_type == "kernels" and (
|
||||
at_end == True or (kernelName != next_kernelName)
|
||||
):
|
||||
if sort_type == "kernels" and (at_end or (kernelName != next_kernelName)):
|
||||
myList.append(
|
||||
AI_Data(
|
||||
kernelName,
|
||||
@@ -685,9 +688,8 @@ def calc_ai_profile(mspec, sort_type, ret_df):
|
||||
while i < TOP_N and i != len(myList):
|
||||
if myList[i].total_flops == 0:
|
||||
console_debug(
|
||||
"No flops counted for {}, arithmetic intensities will not display on plots.".format(
|
||||
myList[i].KernelName
|
||||
)
|
||||
f"No flops counted for {myList[i].KernelName}, "
|
||||
"arithmetic intensities will not display on plots."
|
||||
)
|
||||
|
||||
kernelNames.append(myList[i].KernelName)
|
||||
@@ -696,28 +698,28 @@ def calc_ai_profile(mspec, sort_type, ret_df):
|
||||
if myList[i].L1cache_data
|
||||
else intensities["ai_l1"].append(0)
|
||||
)
|
||||
# print("cur_ai_L1", myList[i].total_flops/myList[i].L1cache_data) if myList[i].L1cache_data else print("null")
|
||||
# print("cur_ai_L1", myList[i].total_flops/myList[i].L1cache_data) if myList[i].L1cache_data else print("null") #noqa
|
||||
# print()
|
||||
(
|
||||
intensities["ai_l2"].append(myList[i].total_flops / myList[i].L2cache_data)
|
||||
if myList[i].L2cache_data
|
||||
else intensities["ai_l2"].append(0)
|
||||
)
|
||||
# print("cur_ai_L2", myList[i].total_flops/myList[i].L2cache_data) if myList[i].L2cache_data else print("null")
|
||||
# print("cur_ai_L2", myList[i].total_flops/myList[i].L2cache_data) if myList[i].L2cache_data else print("null") #noqa
|
||||
# print()
|
||||
(
|
||||
intensities["ai_hbm"].append(myList[i].total_flops / myList[i].hbm_data)
|
||||
if myList[i].hbm_data
|
||||
else intensities["ai_hbm"].append(0)
|
||||
)
|
||||
# print("cur_ai_hbm", myList[i].total_flops/myList[i].hbm_data) if myList[i].hbm_data else print("null")
|
||||
# print("cur_ai_hbm", myList[i].total_flops/myList[i].hbm_data) if myList[i].hbm_data else print("null") #noqa
|
||||
# print()
|
||||
(
|
||||
curr_perf.append(myList[i].total_flops / myList[i].avgDuration)
|
||||
if myList[i].avgDuration
|
||||
else curr_perf.append(0)
|
||||
)
|
||||
# print("cur_perf", myList[i].total_flops/myList[i].avgDuration) if myList[i].avgDuration else print("null")
|
||||
# print("cur_perf", myList[i].total_flops/myList[i].avgDuration) if myList[i].avgDuration else print("null") #noqa
|
||||
|
||||
i += 1
|
||||
|
||||
@@ -726,7 +728,7 @@ def calc_ai_profile(mspec, sort_type, ret_df):
|
||||
for i in intensities:
|
||||
values = intensities[i]
|
||||
|
||||
color = get_color(i)
|
||||
color = get_color(i) # noqa
|
||||
x = []
|
||||
y = []
|
||||
for entryIndx in range(0, len(values)):
|
||||
@@ -758,7 +760,8 @@ def constuct_roof(roofline_parameters, dtype):
|
||||
# -----------------------------------------------------
|
||||
# Initialize roofline data dictionary from roofline.csv
|
||||
# -----------------------------------------------------
|
||||
benchmark_data = {} # TODO: consider changing this to an ordered dict for consistency over py versions
|
||||
# TODO: consider changing this to an ordered dict for consistency over py versions
|
||||
benchmark_data = {}
|
||||
headers = []
|
||||
try:
|
||||
with open(benchmark_results, "r") as csvfile:
|
||||
@@ -776,7 +779,7 @@ def constuct_roof(roofline_parameters, dtype):
|
||||
|
||||
rowCount += 1
|
||||
csvfile.close()
|
||||
except:
|
||||
except Exception:
|
||||
graphPoints = {
|
||||
"hbm": [None, None, None],
|
||||
"l2": [None, None, None],
|
||||
|
||||
@@ -167,7 +167,8 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
and workload.roofline_metrics
|
||||
):
|
||||
print(
|
||||
"\n(4.1) Per-Kernel Roofline Metrics and (4.2) AI Plot Points",
|
||||
"\n(4.1) Per-Kernel Roofline Metrics and "
|
||||
"(4.2) AI Plot Points",
|
||||
file=output,
|
||||
)
|
||||
print("-" * 80, file=output)
|
||||
@@ -201,7 +202,9 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
else kernel_name
|
||||
)
|
||||
print(
|
||||
f"\nKernel {kernel_id}: {display_name} ({kernel_pct:.1f}%)",
|
||||
f"\nKernel {kernel_id}: "
|
||||
f"{display_name} "
|
||||
f"({kernel_pct:.1f}%)",
|
||||
file=output,
|
||||
)
|
||||
|
||||
|
||||
@@ -172,7 +172,9 @@ def get_num_pmc_file(output_dir):
|
||||
"""
|
||||
|
||||
perfmon_path = Path(output_dir) / "perfmon"
|
||||
return len([f for f in perfmon_path.iterdir() if f.is_file() and f.suffix == ".txt"])
|
||||
return len([
|
||||
f for f in perfmon_path.iterdir() if f.is_file() and f.suffix == ".txt"
|
||||
])
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -1769,8 +1771,18 @@ def test_v3_json_to_csv_complex_dispatch(tmp_path, monkeypatch):
|
||||
{
|
||||
"metadata": {"pid": 12345},
|
||||
"agents": [
|
||||
{"id": {"handle": 1}, "type": 2, "node_id": 0, "wave_front_size": 64},
|
||||
{"id": {"handle": 2}, "type": 2, "node_id": 1, "wave_front_size": 32},
|
||||
{
|
||||
"id": {"handle": 1},
|
||||
"type": 2,
|
||||
"node_id": 0,
|
||||
"wave_front_size": 64,
|
||||
},
|
||||
{
|
||||
"id": {"handle": 2},
|
||||
"type": 2,
|
||||
"node_id": 1,
|
||||
"wave_front_size": 32,
|
||||
},
|
||||
],
|
||||
"counters": [
|
||||
{
|
||||
@@ -1923,8 +1935,10 @@ def test_v3_json_to_csv_complex_dispatch(tmp_path, monkeypatch):
|
||||
|
||||
def test_v3_json_to_csv_missing_counters_handling(tmp_path, monkeypatch):
|
||||
"""
|
||||
Test v3_json_to_csv handles cases where different dispatches have different sets of counters.
|
||||
This addresses the DataFrame creation issue where arrays have different lengths.
|
||||
Test v3_json_to_csv handles cases where different
|
||||
dispatches have different sets of counters.
|
||||
This addresses the DataFrame creation issue
|
||||
where arrays have different lengths.
|
||||
|
||||
Args:
|
||||
tmp_path (pathlib.Path): Temporary directory for test files
|
||||
@@ -1936,7 +1950,12 @@ def test_v3_json_to_csv_missing_counters_handling(tmp_path, monkeypatch):
|
||||
{
|
||||
"metadata": {"pid": 12345},
|
||||
"agents": [
|
||||
{"id": {"handle": 1}, "type": 2, "node_id": 0, "wave_front_size": 64}
|
||||
{
|
||||
"id": {"handle": 1},
|
||||
"type": 2,
|
||||
"node_id": 0,
|
||||
"wave_front_size": 64,
|
||||
}
|
||||
],
|
||||
"counters": [
|
||||
{
|
||||
@@ -2072,7 +2091,8 @@ def test_v3_json_to_csv_missing_counters_handling(tmp_path, monkeypatch):
|
||||
except ValueError as e:
|
||||
if "All arrays must be of the same length" in str(e):
|
||||
pytest.skip(
|
||||
"v3_json_to_csv does not currently handle missing counters gracefully - arrays have different lengths"
|
||||
"v3_json_to_csv does not currently "
|
||||
"handle missing counters gracefully - arrays have different lengths"
|
||||
)
|
||||
else:
|
||||
raise
|
||||
|
||||
@@ -34,7 +34,11 @@ METRIC_ID_TO_NAME_MAP = {gfx_version: {} for gfx_version in GFX_VERSIONS}
|
||||
|
||||
|
||||
def get_autogen_text(config_file="utils/unified_config.yaml"):
|
||||
return f"# AUTOGENERATED FILE. Only edit for testing purposes, not for development. Generated from {config_file}. Generated by utils/split_config.py\n"
|
||||
return (
|
||||
f"# AUTOGENERATED FILE. Only edit for testing purposes, "
|
||||
f"not for development. Generated from {config_file}. "
|
||||
f"Generated by utils/split_config.py\n"
|
||||
)
|
||||
|
||||
|
||||
def update_analysis_config():
|
||||
|
||||
Ссылка в новой задаче
Block a user