Format source code to PEP8 using Ruff (#36)
* added ruff docs * style: Run ruff and black before yapf pass * yapf -r -i (23 fixes) * fixed conf.py and ran ruff format . * fixed conf.py 2 * formatted argparser.py * formatted src/rocprof_compute_analyze * formatted src/rocprof_compute_profile * formatted soc_base.py * formatted rocprof_compute_tui * formatted gui_components * formatted src/utils * formatted tests/ * format extra files * cleanup * fix test_utils.py * fixed typos * Update pyproject.toml * Update README.md * Update test_utils.py --------- Signed-off-by: jamessiddeley-amd <James.Siddeley@amd.com> Co-authored-by: James Siddeley <James.Siddeley@amd.com> Co-authored-by: systems-assistant[bot] <systems-assistant[bot]@users.noreply.github.com>
This commit is contained in:
zatwierdzone przez
GitHub
rodzic
d3f9ab25eb
commit
58d2a016ce
@@ -23,10 +23,9 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import getpass
|
||||
import os
|
||||
from abc import ABC, abstractmethod
|
||||
from abc import abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
import pandas as pd
|
||||
@@ -75,7 +74,8 @@ class DatabaseConnector:
|
||||
name = sys_info["workload_name"][0].strip()
|
||||
except KeyError as e:
|
||||
console_error(
|
||||
f"Outdated workload. Cannot find {e} field. Please reprofile to update."
|
||||
f"Outdated workload. "
|
||||
f"Cannot find {e} field. Please reprofile to update."
|
||||
)
|
||||
else:
|
||||
console_error(
|
||||
@@ -140,7 +140,6 @@ class DatabaseConnector:
|
||||
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"]
|
||||
@@ -166,15 +165,17 @@ class DatabaseConnector:
|
||||
is_full_workload_name = self.args.workload.count("_") >= 3
|
||||
if not is_full_workload_name:
|
||||
console_error(
|
||||
"-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. rocprofiler-compute_asw_vcopy_mi200)"
|
||||
"-w/--workload is not valid. Please use full workload name "
|
||||
"as seen in GUI when removing (i.e. "
|
||||
"rocprofiler-compute_asw_vcopy_mi200)"
|
||||
)
|
||||
if (
|
||||
self.connection_info["host"] == None
|
||||
or self.connection_info["username"] == None
|
||||
):
|
||||
console_error(
|
||||
"-H/--host and -u/--username are required when interaction type is set to %s"
|
||||
% self.interaction_type
|
||||
"-H/--host and -u/--username are required when "
|
||||
"interaction type is set to %s" % self.interaction_type
|
||||
)
|
||||
if (
|
||||
self.connection_info["workload"] == "admin"
|
||||
@@ -192,7 +193,8 @@ class DatabaseConnector:
|
||||
or self.connection_info["workload"] == None
|
||||
):
|
||||
console_error(
|
||||
"-H/--host, -w/--workload, -u/--username, and -t/--team are all required when interaction type is set to %s"
|
||||
"-H/--host, -w/--workload, -u/--username, and -t/--team are all "
|
||||
"required when interaction type is set to %s"
|
||||
% self.interaction_type
|
||||
)
|
||||
|
||||
@@ -220,7 +222,7 @@ class DatabaseConnector:
|
||||
else:
|
||||
console_log("database", "Password received")
|
||||
else:
|
||||
password = self.connection_info["password"]
|
||||
pass
|
||||
|
||||
# Establish client connection
|
||||
connection_str = (
|
||||
@@ -239,5 +241,5 @@ class DatabaseConnector:
|
||||
)
|
||||
try:
|
||||
self.client.server_info()
|
||||
except:
|
||||
except Exception:
|
||||
console_error("database", "Unable to connect to the DB server.")
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
@@ -50,7 +49,9 @@ top_stats_build_in_config = {
|
||||
1: {
|
||||
"id": 1,
|
||||
"title": "Dispatch List",
|
||||
"data source": [{"raw_csv_table": {"id": 2, "source": "pmc_dispatch_info.csv"}}],
|
||||
"data source": [
|
||||
{"raw_csv_table": {"id": 2, "source": "pmc_dispatch_info.csv"}}
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,7 +73,8 @@ def load_panel_configs(dir):
|
||||
if f.endswith(".yaml"):
|
||||
with open(str(Path(root).joinpath(f))) as file:
|
||||
config = 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["Panel Config"]["data source"]:
|
||||
metric_table = data_source.get("metric_table")
|
||||
@@ -80,7 +82,8 @@ def load_panel_configs(dir):
|
||||
metric_table["metric"] = {}
|
||||
d[config["Panel Config"]["id"]] = config["Panel Config"]
|
||||
|
||||
# TODO: sort metrics as the header order in case they are not defined in the same order
|
||||
# TODO: sort metrics as the header order in case they-
|
||||
# are not defined in the same order
|
||||
|
||||
od = OrderedDict(sorted(d.items()))
|
||||
# for key, value in od.items():
|
||||
@@ -157,9 +160,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 = [
|
||||
@@ -205,8 +208,8 @@ def create_df_pmc(
|
||||
dfs = []
|
||||
coll_levels = []
|
||||
|
||||
df = pd.DataFrame()
|
||||
new_df = pd.DataFrame()
|
||||
df = pd.DataFrame() # noqa: F841
|
||||
new_df = pd.DataFrame() # noqa: F841
|
||||
for root, dirs, files in os.walk(raw_data_dir):
|
||||
for f in files:
|
||||
# print("file ", f)
|
||||
@@ -250,7 +253,9 @@ def create_df_pmc(
|
||||
else:
|
||||
# regular single node case
|
||||
if nodes is None:
|
||||
return create_single_df_pmc(raw_data_root_dir, None, kernel_verbose, verbose)
|
||||
return create_single_df_pmc(
|
||||
raw_data_root_dir, None, kernel_verbose, verbose
|
||||
)
|
||||
|
||||
# "empty list" means all nodes
|
||||
elif not nodes:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import colorlover
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
@@ -87,23 +86,21 @@ def discrete_background_color_bins(df, n_bins=5, columns="all"):
|
||||
color = "white" if i > len(bounds) / 2.0 else "inherit"
|
||||
|
||||
for column in df_numeric_columns:
|
||||
styles.append(
|
||||
{
|
||||
"if": {
|
||||
"filter_query": (
|
||||
"{{{column}}} >= {min_bound}"
|
||||
+ (
|
||||
" && {{{column}}} < {max_bound}"
|
||||
if (i < len(bounds) - 1)
|
||||
else ""
|
||||
)
|
||||
).format(column=column, min_bound=min_bound, max_bound=max_bound),
|
||||
"column_id": column,
|
||||
},
|
||||
"backgroundColor": backgroundColor,
|
||||
"color": color,
|
||||
}
|
||||
)
|
||||
styles.append({
|
||||
"if": {
|
||||
"filter_query": (
|
||||
"{{{column}}} >= {min_bound}"
|
||||
+ (
|
||||
" && {{{column}}} < {max_bound}"
|
||||
if (i < len(bounds) - 1)
|
||||
else ""
|
||||
)
|
||||
).format(column=column, min_bound=min_bound, max_bound=max_bound),
|
||||
"column_id": column,
|
||||
},
|
||||
"backgroundColor": backgroundColor,
|
||||
"color": color,
|
||||
})
|
||||
legend.append(
|
||||
html.Div(
|
||||
style={"display": "inline-block", "width": "60px"},
|
||||
@@ -203,7 +200,9 @@ def build_bar_chart(display_df, table_config, barchart_elements, norm_filt):
|
||||
|
||||
# Speed-of-light bar chart
|
||||
elif table_config["id"] in barchart_elements["sol"]:
|
||||
display_df["Avg"] = [float(x) if x != "" else float(0) for x in display_df["Avg"]]
|
||||
display_df["Avg"] = [
|
||||
float(x) if x != "" else float(0) for x in display_df["Avg"]
|
||||
]
|
||||
if table_config["id"] == 1701:
|
||||
# special layout for L2 Cache SOL
|
||||
d_figs.append(
|
||||
@@ -265,7 +264,9 @@ def build_bar_chart(display_df, table_config, barchart_elements, norm_filt):
|
||||
).update_xaxes(range=[0, 110])
|
||||
)
|
||||
else:
|
||||
console_error("Table id %s. Cannot determine barchart type." % table_config["id"])
|
||||
console_error(
|
||||
"Table id %s. Cannot determine barchart type." % table_config["id"]
|
||||
)
|
||||
|
||||
# update layout for each of the charts
|
||||
for fig in d_figs:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import dash_bootstrap_components as dbc
|
||||
from dash import dcc, html
|
||||
|
||||
@@ -67,7 +66,9 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
children=[
|
||||
dbc.DropdownMenu(
|
||||
[
|
||||
dbc.DropdownMenuItem("Overview", header=True),
|
||||
dbc.DropdownMenuItem(
|
||||
"Overview", header=True
|
||||
),
|
||||
dbc.DropdownMenuItem(
|
||||
"Roofline",
|
||||
href="#roofline",
|
||||
@@ -88,7 +89,9 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
href="#system_speed-of-light",
|
||||
external_link=True,
|
||||
),
|
||||
dbc.DropdownMenuItem("Compute", header=True),
|
||||
dbc.DropdownMenuItem(
|
||||
"Compute", header=True
|
||||
),
|
||||
dbc.DropdownMenuItem(
|
||||
"Command Processor (CPF/CPC)",
|
||||
href="#command_processor_cpccpf",
|
||||
@@ -131,8 +134,14 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
external_link=True,
|
||||
),
|
||||
dbc.DropdownMenuItem(
|
||||
"Address Processing Unit and Data Return Path (TA/TD)",
|
||||
href="#address_processing_unit_and_data_return_path_tatd",
|
||||
(
|
||||
"Address Processing Unit and "
|
||||
"Data Return Path (TA/TD)"
|
||||
),
|
||||
href=(
|
||||
"#address_processing_unit_and"
|
||||
"_data_return_path_tatd"
|
||||
),
|
||||
external_link=True,
|
||||
),
|
||||
dbc.DropdownMenuItem(
|
||||
@@ -199,9 +208,9 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
), # list avail gcd ids
|
||||
id="gcd-filt",
|
||||
multi=True,
|
||||
value=input_filters[
|
||||
"gpu"
|
||||
], # default to any gpu filters passed as args
|
||||
# default to any gpu filters
|
||||
# passed as args
|
||||
value=input_filters["gpu"],
|
||||
placeholder="ALL",
|
||||
clearable=False,
|
||||
style={"width": "60px"},
|
||||
@@ -230,9 +239,9 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
),
|
||||
id="disp-filt",
|
||||
multi=True,
|
||||
value=input_filters[
|
||||
"dispatch"
|
||||
], # default to any dispatch filters passed as args
|
||||
# default to any dispatch
|
||||
# filters passed as args
|
||||
value=input_filters["dispatch"],
|
||||
placeholder="ALL",
|
||||
style={"width": "150px"},
|
||||
),
|
||||
@@ -254,7 +263,8 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
id="top-n-filt",
|
||||
value=input_filters[
|
||||
"top_n"
|
||||
], # default to any dispatch filters passed as args
|
||||
], # default to any dispatch filters
|
||||
# passed as args
|
||||
clearable=False,
|
||||
style={"width": "50px"},
|
||||
),
|
||||
@@ -287,7 +297,9 @@ def get_header(raw_pmc, input_filters, kernel_names):
|
||||
optionHeight=150,
|
||||
placeholder="ALL",
|
||||
style={
|
||||
"width": "600px", # TODO: Change these widths to % rather than fixed value
|
||||
"width": "600px",
|
||||
# TODO: Change these widths to
|
||||
# % rather than fixed value
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
from dash import html
|
||||
from dash_svg import G, Path, Rect, Svg, Text
|
||||
|
||||
@@ -580,21 +579,31 @@ def get_memchart(mem_data, base_data):
|
||||
Rect(x="319", y="329.5", rx="3", ry="3"),
|
||||
Rect(x="319", y="382", rx="3", ry="3"),
|
||||
Rect(x="1367.69", y="271", rx="3", ry="3"),
|
||||
Rect(x="1367.69", y="296.5", rx="3", ry="3"),
|
||||
Rect(x="1367.69", y="322.5", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="1367.69", y="296.5", rx="3", ry="3"
|
||||
),
|
||||
Rect(
|
||||
x="1367.69", y="322.5", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="1078", y="199", rx="3", ry="3"),
|
||||
Rect(x="1078", y="224.5", rx="3", ry="3"),
|
||||
Rect(x="1078", y="250.5", rx="3", ry="3"),
|
||||
Rect(x="771.44", y="103", rx="3", ry="3"),
|
||||
Rect(x="770.44", y="358.75", rx="3", ry="3"),
|
||||
Rect(x="770.44", y="390.25", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="770.44", y="358.75", rx="3", ry="3"
|
||||
),
|
||||
Rect(
|
||||
x="770.44", y="390.25", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="769.44", y="477", rx="3", ry="3"),
|
||||
Rect(x="769.44", y="508.5", rx="3", ry="3"),
|
||||
Rect(x="1078", y="278", rx="3", ry="3"),
|
||||
Rect(x="1078", y="342.5", rx="3", ry="3"),
|
||||
Rect(x="1078", y="368.5", rx="3", ry="3"),
|
||||
Rect(x="772.44", y="179", rx="3", ry="3"),
|
||||
Rect(x="772.44", y="210.18", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="772.44", y="210.18", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="771.44", y="71.28", rx="3", ry="3"),
|
||||
Rect(x="772.44", y="242", rx="3", ry="3"),
|
||||
Rect(x="770.44", y="274.5", rx="3", ry="3"),
|
||||
@@ -617,21 +626,31 @@ def get_memchart(mem_data, base_data):
|
||||
className="val-3",
|
||||
children=[
|
||||
Rect(x="1410.69", y="271", rx="3", ry="3"),
|
||||
Rect(x="1410.69", y="296.5", rx="3", ry="3"),
|
||||
Rect(x="1410.69", y="322.5", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="1410.69", y="296.5", rx="3", ry="3"
|
||||
),
|
||||
Rect(
|
||||
x="1410.69", y="322.5", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="1121", y="199", rx="3", ry="3"),
|
||||
Rect(x="1121", y="224.5", rx="3", ry="3"),
|
||||
Rect(x="1121", y="250.5", rx="3", ry="3"),
|
||||
Rect(x="814.44", y="103", rx="3", ry="3"),
|
||||
Rect(x="813.44", y="358.75", rx="3", ry="3"),
|
||||
Rect(x="813.44", y="390.25", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="813.44", y="358.75", rx="3", ry="3"
|
||||
),
|
||||
Rect(
|
||||
x="813.44", y="390.25", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="812.44", y="477", rx="3", ry="3"),
|
||||
Rect(x="812.44", y="508.5", rx="3", ry="3"),
|
||||
Rect(x="1121", y="278", rx="3", ry="3"),
|
||||
Rect(x="1121", y="342.5", rx="3", ry="3"),
|
||||
Rect(x="1121", y="368.5", rx="3", ry="3"),
|
||||
Rect(x="815.44", y="179", rx="3", ry="3"),
|
||||
Rect(x="815.44", y="210.18", rx="3", ry="3"),
|
||||
Rect(
|
||||
x="815.44", y="210.18", rx="3", ry="3"
|
||||
),
|
||||
Rect(x="814.44", y="71.28", rx="3", ry="3"),
|
||||
Rect(x="815.44", y="242", rx="3", ry="3"),
|
||||
Rect(x="813.44", y="274.5", rx="3", ry="3"),
|
||||
@@ -694,7 +713,8 @@ def get_memchart(mem_data, base_data):
|
||||
children=[
|
||||
Path(
|
||||
id="p1",
|
||||
d="M 100 243.72 L 120 220.28 L 475 220.28 L 495 243.72 Z",
|
||||
d="M 100 243.72 L 120 220.28 L "
|
||||
"475 220.28 L 495 243.72 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -744,7 +764,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 62 L 411.89 65.51 L 413.63 62.01 L 411.88 58.51 Z",
|
||||
d="M 418.88 62 L 411.89 65.51 L "
|
||||
"413.63 62.01 L 411.88 58.51 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -754,7 +775,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 112 L 411.88 115.49 L 413.63 112 L 411.88 108.49 Z",
|
||||
d="M 418.88 112 L 411.88 115.49 L "
|
||||
"413.63 112 L 411.88 108.49 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -764,7 +786,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 162 L 411.88 165.51 L 413.63 162 L 411.88 158.51 Z",
|
||||
d="M 418.88 162 L 411.88 165.51 L "
|
||||
"413.63 162 L 411.88 158.51 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -774,7 +797,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 212 L 411.88 215.5 L 413.63 212 L 411.88 208.5 Z",
|
||||
d="M 418.88 212 L 411.88 215.5 "
|
||||
"L 413.63 212 L 411.88 208.5 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -784,7 +808,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 262 L 411.88 265.5 L 413.63 262 L 411.88 258.5 Z",
|
||||
d="M 418.88 262 L 411.88 265.5 L "
|
||||
"413.63 262 L 411.88 258.5 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -794,7 +819,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 312 L 411.89 315.51 L 413.63 312.01 L 411.88 308.51 Z",
|
||||
d="M 418.88 312 L 411.89 315.51 L "
|
||||
"413.63 312.01 L 411.88 308.51 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -804,7 +830,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 362 L 411.88 365.5 L 413.63 362 L 411.88 358.5 Z",
|
||||
d="M 418.88 362 L 411.88 365.5 L "
|
||||
"413.63 362 L 411.88 358.5 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -814,7 +841,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#ff8000",
|
||||
),
|
||||
Path(
|
||||
d="M 418.88 409 L 411.87 412.47 L 413.63 408.97 L 411.9 405.47 Z",
|
||||
d="M 418.88 409 L 411.87 412.47 L "
|
||||
"413.63 408.97 L 411.9 405.47 Z",
|
||||
fill="#ff8000",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -824,7 +852,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 647.12 207 L 654.12 203.5 L 652.37 207 L 654.12 210.5 Z",
|
||||
d="M 647.12 207 L 654.12 203.5 L "
|
||||
"652.37 207 L 654.12 210.5 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -834,17 +863,20 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 748.88 236.01 L 741.9 239.54 L 743.63 236.03 L 741.86 232.54 Z",
|
||||
d="M 748.88 236.01 L 741.9 239.54 L "
|
||||
"743.63 236.03 L 741.86 232.54 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 750 502 L 110 502 Q 100 502 100 492 L 100 468.37",
|
||||
d="M 750 502 L 110 502 Q 100 "
|
||||
"502 100 492 L 100 468.37",
|
||||
fill="none",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 100 463.12 L 103.5 470.12 L 100 468.37 L 96.5 470.12 Z",
|
||||
d="M 100 463.12 L 103.5 470.12 L "
|
||||
"100 468.37 L 96.5 470.12 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -854,7 +886,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 937.12 504 L 944.12 500.5 L 942.37 504 L 944.12 507.5 Z",
|
||||
d="M 937.12 504 L 944.12 500.5 L "
|
||||
"942.37 504 L 944.12 507.5 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -864,7 +897,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1528.81 242.93 L 1535.81 239.43 L 1534.06 242.93 L 1535.81 246.43 Z",
|
||||
d="M 1528.81 242.93 L 1535.81 239.43 L "
|
||||
"1534.06 242.93 L 1535.81 246.43 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -874,7 +908,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1596.57 274.64 L 1589.57 278.14 L 1591.32 274.64 L 1589.57 271.14 Z",
|
||||
d="M 1596.57 274.64 L 1589.57 278.14 L "
|
||||
"1591.32 274.64 L 1589.57 271.14 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -884,7 +919,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1413 127.12 L 1416.5 134.12 L 1413 132.37 L 1409.5 134.12 Z",
|
||||
d="M 1413 127.12 L 1416.5 134.12 L "
|
||||
"1413 132.37 L 1409.5 134.12 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -894,7 +930,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1443 194.88 L 1439.5 187.88 L 1443 189.63 L 1446.5 187.88 Z",
|
||||
d="M 1443 194.88 L 1439.5 187.88 L "
|
||||
"1443 189.63 L 1446.5 187.88 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -904,7 +941,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1413.01 372.12 L 1416.54 379.1 L 1413.03 377.37 L 1409.54 379.14 Z",
|
||||
d="M 1413.01 372.12 L 1416.54 379.1 L "
|
||||
"1413.03 377.37 L 1409.54 379.14 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -914,12 +952,14 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1443.35 437.38 L 1439.82 430.4 L 1443.33 432.13 L 1446.82 430.36 Z",
|
||||
d="M 1443.35 437.38 L 1439.82 430.4 L "
|
||||
"1443.33 432.13 L 1446.82 430.36 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1145.25 341.38 L 1141.75 334.38 L 1145.25 336.13 L 1148.75 334.38 Z",
|
||||
d="M 1145.25 341.38 L 1141.75 334.38 L "
|
||||
"1145.25 336.13 L 1148.75 334.38 Z",
|
||||
fill="rgb(0, 0, 0)",
|
||||
stroke="rgb(0, 0, 0)",
|
||||
),
|
||||
@@ -929,7 +969,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 647.12 82 L 654.12 78.5 L 652.37 82 L 654.12 85.5 Z",
|
||||
d="M 647.12 82 L 654.12 78.5 L 652.37 "
|
||||
"82 L 654.12 85.5 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -939,7 +980,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 651.12 386.75 L 658.12 383.25 L 656.37 386.75 L 658.12 390.25 Z",
|
||||
d="M 651.12 386.75 L 658.12 383.25 L "
|
||||
"656.37 386.75 L 658.12 390.25 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -949,12 +991,14 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 646.12 269 L 653.12 265.5 L 651.37 269 L 653.12 272.5 Z",
|
||||
d="M 646.12 269 L 653.12 265.5 L "
|
||||
"651.37 269 L 653.12 272.5 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 748.88 269 L 741.88 272.5 L 743.63 269 L 741.88 265.5 Z",
|
||||
d="M 748.88 269 L 741.88 272.5 L "
|
||||
"743.63 269 L 741.88 265.5 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -964,7 +1008,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 939.12 206.41 L 946.12 202.91 L 944.37 206.41 L 946.12 209.91 Z",
|
||||
d="M 939.12 206.41 L 946.12 202.91 L "
|
||||
"944.37 206.41 L 946.12 209.91 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -974,7 +1019,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1040.88 235.42 L 1033.9 238.95 L 1035.63 235.44 L 1033.86 231.95 Z",
|
||||
d="M 1040.88 235.42 L 1033.9 238.95 L "
|
||||
"1035.63 235.44 L 1033.86 231.95 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -984,12 +1030,14 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 938.12 268.41 L 945.12 264.91 L 943.37 268.41 L 945.12 271.91 Z",
|
||||
d="M 938.12 268.41 L 945.12 264.91 L "
|
||||
"943.37 268.41 L 945.12 271.91 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1040.88 268.41 L 1033.88 271.91 L 1035.63 268.41 L 1033.88 264.91 Z",
|
||||
d="M 1040.88 268.41 L 1033.88 271.91 L "
|
||||
"1035.63 268.41 L 1033.88 264.91 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -999,7 +1047,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 939.12 354.32 L 946.12 350.82 L 944.37 354.32 L 946.12 357.82 Z",
|
||||
d="M 939.12 354.32 L 946.12 350.82 L "
|
||||
"944.37 354.32 L 946.12 357.82 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -1009,7 +1058,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1040.88 383.33 L 1033.9 386.86 L 1035.63 383.35 L 1033.86 379.86 Z",
|
||||
d="M 1040.88 383.33 L 1033.9 386.86 L "
|
||||
"1035.63 383.35 L 1033.86 379.86 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -1019,12 +1069,14 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 938.12 416.32 L 945.12 412.82 L 943.37 416.32 L 945.12 419.82 Z",
|
||||
d="M 938.12 416.32 L 945.12 412.82 L "
|
||||
"943.37 416.32 L 945.12 419.82 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1040.88 416.32 L 1033.88 419.82 L 1035.63 416.32 L 1033.88 412.82 Z",
|
||||
d="M 1040.88 416.32 L 1033.88 419.82 L "
|
||||
"1035.63 416.32 L 1033.88 412.82 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -1034,7 +1086,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1252.12 245.75 L 1259.12 242.25 L 1257.37 245.75 L 1259.12 249.25 Z",
|
||||
d="M 1252.12 245.75 L 1259.12 242.25 L "
|
||||
"1257.37 245.75 L 1259.12 249.25 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -1044,7 +1097,8 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1353.88 274.76 L 1346.9 278.29 L 1348.63 274.78 L 1346.86 271.29 Z",
|
||||
d="M 1353.88 274.76 L 1346.9 278.29 L "
|
||||
"1348.63 274.78 L 1346.86 271.29 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
@@ -1054,18 +1108,21 @@ def get_memchart(mem_data, base_data):
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1251.12 307.75 L 1258.12 304.25 L 1256.37 307.75 L 1258.12 311.25 Z",
|
||||
d="M 1251.12 307.75 L 1258.12 304.25 L "
|
||||
"1256.37 307.75 L 1258.12 311.25 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
d="M 1353.88 307.75 L 1346.88 311.25 L 1348.63 307.75 L 1346.88 304.25 Z",
|
||||
d="M 1353.88 307.75 L 1346.88 311.25 L "
|
||||
"1348.63 307.75 L 1346.88 304.25 Z",
|
||||
fill="#00cccc",
|
||||
stroke="#00cccc",
|
||||
),
|
||||
Path(
|
||||
id="p2",
|
||||
d="M 235 67 L 245 57 L 265 57 L 275 67 Z",
|
||||
d="M 235 67 L 245 57 L "
|
||||
"265 57 L 275 67 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1091,7 +1148,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p3",
|
||||
d="M 235 117 L 245 107 L 265 107 L 275 117 Z",
|
||||
d="M 235 117 L 245 107 L 265 "
|
||||
"107 L 275 117 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1117,7 +1175,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p4",
|
||||
d="M 235 167 L 245 157 L 265 157 L 275 167 Z",
|
||||
d="M 235 167 L 245 157 L "
|
||||
"265 157 L 275 167 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1143,7 +1202,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p5",
|
||||
d="M 235 217 L 245 207 L 265 207 L 275 217 Z",
|
||||
d="M 235 217 L 245 207 L "
|
||||
"265 207 L 275 217 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1169,7 +1229,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p6",
|
||||
d="M 235 267 L 245 257 L 265 257 L 275 267 Z",
|
||||
d="M 235 267 L 245 257 L "
|
||||
"265 257 L 275 267 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1195,7 +1256,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p7",
|
||||
d="M 235 317 L 245 307 L 265 307 L 275 317 Z",
|
||||
d="M 235 317 L 245 307 L "
|
||||
"265 307 L 275 317 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1221,7 +1283,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p8",
|
||||
d="M 235 367 L 245 357 L 265 357 L 275 367 Z",
|
||||
d="M 235 367 L 245 357 L "
|
||||
"265 357 L 275 367 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1247,7 +1310,8 @@ def get_memchart(mem_data, base_data):
|
||||
),
|
||||
Path(
|
||||
id="p9",
|
||||
d="M 235 417 L 245 407 L 265 407 L 275 417 Z",
|
||||
d="M 235 417 L 245 407 L "
|
||||
"265 407 L 275 417 Z",
|
||||
fill="#ffffff",
|
||||
stroke="#ff8000",
|
||||
),
|
||||
@@ -1986,11 +2050,11 @@ def format_value_for_display(value, max_length=6):
|
||||
if isinstance(value, (int, float)):
|
||||
value = abs(value)
|
||||
if value >= 1000000000:
|
||||
value = f"{value/1000000000:.1f}B"
|
||||
value = f"{value / 1000000000:.1f}B"
|
||||
elif value >= 1000000:
|
||||
value = f"{value/1000000:.1f}M"
|
||||
value = f"{value / 1000000:.1f}M"
|
||||
elif value >= 1000:
|
||||
value = f"{value/1000:.1f}K"
|
||||
value = f"{value / 1000:.1f}K"
|
||||
elif value == int(value):
|
||||
value = str(int(value))
|
||||
else:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
@@ -70,7 +69,8 @@ def kernel_name_shortener(df, level):
|
||||
r"(?P<name>[( )A-Za-z0-9_]+)([ ,*<>()]+)(::)?"
|
||||
)
|
||||
|
||||
# works for name Kokkos::namespace::init_lock_array_kernel_threadid(int) [clone .kd]
|
||||
# works for name:
|
||||
# Kokkos::namespace::init_lock_array_kernel_threadid(int) [clone .kd]
|
||||
if names_and_args.search(demangled_name):
|
||||
matches = names_and_args.findall(demangled_name)
|
||||
else:
|
||||
@@ -82,7 +82,8 @@ def kernel_name_shortener(df, level):
|
||||
|
||||
current_level = 0
|
||||
for name in matches:
|
||||
##can cause errors if a function name or argument is equal to 'clone'
|
||||
# can cause errors if a function name-
|
||||
# or argument is equal to 'clone'
|
||||
if name[0] == "clone":
|
||||
continue
|
||||
if len(name) == 3:
|
||||
@@ -101,7 +102,8 @@ def kernel_name_shortener(df, level):
|
||||
current_level += name[1].count("<")
|
||||
|
||||
curr_index = 0
|
||||
# cases include '>' '> >, ' have to go in depth here to not lose account of commas and current level
|
||||
# cases include '>' '> >, ' have to go in depth here to-
|
||||
# not lose account of commas and current level
|
||||
while name[1].count(">") > 0 and curr_index < len(name[1]):
|
||||
if current_level < level:
|
||||
new_name += name[1][curr_index:]
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
@@ -97,7 +96,9 @@ class ColoredFormatter(logging.Formatter):
|
||||
def format(self, record):
|
||||
levelname = record.levelname
|
||||
if levelname in COLORS:
|
||||
levelname_color = COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
|
||||
levelname_color = (
|
||||
COLOR_SEQ % (30 + COLORS[levelname]) + levelname + RESET_SEQ
|
||||
)
|
||||
record.levelname = levelname_color
|
||||
return logging.Formatter.format(self, record)
|
||||
|
||||
@@ -107,9 +108,12 @@ class ColoredFormatterAll(logging.Formatter):
|
||||
levelname = record.levelname
|
||||
if levelname in COLORS:
|
||||
if levelname == "INFO":
|
||||
log_fmt = f"%(message)s"
|
||||
log_fmt = "%(message)s"
|
||||
else:
|
||||
log_fmt = f"{COLOR_SEQ % (30 + COLORS[levelname])}%(levelname)s: %(message)s{RESET_SEQ}"
|
||||
log_fmt = (
|
||||
f"{COLOR_SEQ % (30 + COLORS[levelname])}"
|
||||
f"%(levelname)s: %(message)s{RESET_SEQ}"
|
||||
)
|
||||
formatter = logging.Formatter(log_fmt)
|
||||
return formatter.format(record)
|
||||
|
||||
@@ -171,7 +175,6 @@ def setup_file_handler(loglevel, workload_dir):
|
||||
|
||||
# Setup logger priority - called after argument parsing
|
||||
def setup_logging_priority(verbosity, quietmode, appmode, guimode):
|
||||
|
||||
# set loglevel based on selected verbosity and quietmode
|
||||
levels = [logging.INFO, logging.DEBUG, logging.TRACE]
|
||||
|
||||
@@ -197,7 +200,9 @@ def setup_logging_priority(verbosity, quietmode, appmode, guimode):
|
||||
elif loglevel in {"ERROR", "error"}:
|
||||
loglevel = logging.ERROR
|
||||
else:
|
||||
print("Ignoring unsupported ROCPROFCOMPUTE_LOGLEVEL setting (%s)" % loglevel)
|
||||
print(
|
||||
"Ignoring unsupported ROCPROFCOMPUTE_LOGLEVEL setting (%s)" % loglevel
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
# update console loglevel based on command-line args/env settings
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from decimal import Decimal
|
||||
from types import SimpleNamespace as NS
|
||||
from typing import Dict, Generator, List, Mapping
|
||||
from typing import Dict
|
||||
|
||||
from plotille import Canvas
|
||||
|
||||
@@ -60,7 +59,8 @@ def make_format_spec(num, align=">"):
|
||||
|
||||
def is_value_valid(value):
|
||||
"""
|
||||
Check if a value is valid and display N/A if not(to be valid, it needs to be not None, and be int or float)
|
||||
Check if a value is valid and display N/A if not
|
||||
(to be valid, it needs to be not None, and be int or float)
|
||||
"""
|
||||
if value is None:
|
||||
return False
|
||||
@@ -82,7 +82,8 @@ def format_text(
|
||||
value_align=">",
|
||||
):
|
||||
"""
|
||||
Format a text string for canvas to display according to input key value pair and make proper aligment
|
||||
Format a text string for canvas to display according to
|
||||
input key value pair and make proper aligment
|
||||
For invalid value, it displays N/A
|
||||
All strings to be displayed on Canvas need to use this method
|
||||
"""
|
||||
@@ -102,12 +103,16 @@ def format_text(
|
||||
value_str = f"{'N/A':{align}{width}}"
|
||||
|
||||
key_format = (
|
||||
make_format_spec(key_step_prec_leftalign, key_align) if key is not None else None
|
||||
make_format_spec(key_step_prec_leftalign, key_align)
|
||||
if key is not None
|
||||
else None
|
||||
)
|
||||
key_str = (
|
||||
"{key:{key_format}}".format(key=key, key_format=key_format)
|
||||
if key and isinstance(key, (int, float))
|
||||
else str(key) if key else None
|
||||
else str(key)
|
||||
if key
|
||||
else None
|
||||
)
|
||||
|
||||
unit_string = post_description_with_space if not "N/A" in value_str else ""
|
||||
@@ -913,7 +918,9 @@ class Fabric(RectFrame):
|
||||
canvas.rect(self.x_min, self.y_min, self.x_max, self.y_max)
|
||||
canvas.text(self.x_min + 6.0, self.y_max - 2.0, " " + self.label)
|
||||
canvas.text(self.x_min + 2.0, self.y_max - 4.0, "Latency (cycles)")
|
||||
canvas.rect(self.x_min + 2.0, self.y_max - 9, self.x_max - 2.0, self.y_max - 4.5)
|
||||
canvas.rect(
|
||||
self.x_min + 2.0, self.y_max - 9, self.x_max - 2.0, self.y_max - 4.5
|
||||
)
|
||||
|
||||
i = 1
|
||||
for k, v in self.lat.items():
|
||||
@@ -960,7 +967,9 @@ class Wire_Fabric_HBM(RectFrame):
|
||||
value_step_prec_rightalign=4.0,
|
||||
),
|
||||
)
|
||||
canvas.text(self.x_min + self.text_x_offset - 2, self.y_max - 1.0, "<-----------")
|
||||
canvas.text(
|
||||
self.x_min + self.text_x_offset - 2, self.y_max - 1.0, "<-----------"
|
||||
)
|
||||
canvas.text(
|
||||
self.x_min + self.text_x_offset,
|
||||
self.y_max - 2.0,
|
||||
@@ -971,7 +980,9 @@ class Wire_Fabric_HBM(RectFrame):
|
||||
value_step_prec_rightalign=4.0,
|
||||
),
|
||||
)
|
||||
canvas.text(self.x_min + self.text_x_offset - 2, self.y_max - 3.0, "----------->")
|
||||
canvas.text(
|
||||
self.x_min + self.text_x_offset - 2, self.y_max - 3.0, "----------->"
|
||||
)
|
||||
|
||||
|
||||
# HBM
|
||||
@@ -1001,7 +1012,7 @@ class MemChart:
|
||||
# Fixme: this is temp solution to filter out non-numeric string
|
||||
for k, v in metric_dict.items():
|
||||
# print(k, type(v))
|
||||
metric_dict[k] = None if type(v) == str else v
|
||||
metric_dict[k] = None if isinstance(v, str) else v
|
||||
|
||||
# Typically, the drawing order would be: left->right, top->down
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict
|
||||
@@ -48,7 +47,6 @@ MI_CONSTANS = {
|
||||
MI350: "mi350",
|
||||
}
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# Data Class handling to preserve the hierarchical gpu information
|
||||
# ----------------------------
|
||||
@@ -64,9 +62,9 @@ class MIGPUSpecs:
|
||||
_chip_id_dict = {} # key: chip_id (int)
|
||||
_perfmon_config = {} # key: gpu_arch
|
||||
|
||||
_gpu_arch_to_compute_partition_dict = (
|
||||
{}
|
||||
) # key: gpu_arch, used for gpu archs containing only one gpu model and thus one compute partition
|
||||
_gpu_arch_to_compute_partition_dict = {} # key: gpu_arch, used for gpu archs
|
||||
# containing only one gpu model and
|
||||
# thus one compute partition
|
||||
|
||||
_initialized = False
|
||||
|
||||
@@ -109,7 +107,8 @@ class MIGPUSpecs:
|
||||
console_error(f"Error parsing YAML file '{file_path}': {exc}")
|
||||
except Exception as e:
|
||||
console_error(
|
||||
f"An unexpected error occurred while loading YAML file '{file_path}': {e}"
|
||||
f"An unexpected error occurred while loading YAML "
|
||||
f"file '{file_path}': {e}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -152,9 +151,13 @@ class MIGPUSpecs:
|
||||
.get("num_xcds", {})
|
||||
)
|
||||
if "chip_ids" in models and "physical" in models["chip_ids"]:
|
||||
cls._chip_id_dict[models["chip_ids"]["physical"]] = curr_gpu_model
|
||||
cls._chip_id_dict[models["chip_ids"]["physical"]] = (
|
||||
curr_gpu_model
|
||||
)
|
||||
if "chip_ids" in models and "virtual" in models["chip_ids"]:
|
||||
cls._chip_id_dict[models["chip_ids"]["virtual"]] = curr_gpu_model
|
||||
cls._chip_id_dict[models["chip_ids"]["virtual"]] = (
|
||||
curr_gpu_model
|
||||
)
|
||||
|
||||
# detect gpu arch to compute partition relationships
|
||||
cls._populate_gpu_arch_to_compute_partition_dict()
|
||||
@@ -171,10 +174,12 @@ class MIGPUSpecs:
|
||||
compute_partition = cls._num_xcds_dict.get(single_model)
|
||||
|
||||
if compute_partition is not None:
|
||||
cls._gpu_arch_to_compute_partition_dict[gpu_arch] = compute_partition
|
||||
cls._gpu_arch_to_compute_partition_dict[gpu_arch] = (
|
||||
compute_partition
|
||||
)
|
||||
console_debug(
|
||||
"[populate_single_arch_partition_dict] Single model arch found: "
|
||||
"%s -> %s (partition: %s)"
|
||||
"[populate_single_arch_partition_dict] Single model "
|
||||
"arch found: %s -> %s (partition: %s)"
|
||||
% (gpu_arch, single_model, compute_partition)
|
||||
)
|
||||
|
||||
@@ -254,14 +259,16 @@ class MIGPUSpecs:
|
||||
@classmethod
|
||||
def set_default_gpu_settings(self, gpu_arch, gpu_model, compute_partition):
|
||||
"""
|
||||
Set default GPU settings when model is unknown or cannot be determined.
|
||||
NOTE: This is a fallback to gfx942 settings - consider making this architecture-specific.
|
||||
Set default GPU settings when model is unknown or cannot be
|
||||
determined. NOTE: This is a fallback to gfx942 settings -
|
||||
consider making this architecture-specific.
|
||||
"""
|
||||
DEFAULT_COMPUTE_PARTITION = "SPX"
|
||||
DEFAULT_NUM_XCD = 8
|
||||
console_warning(
|
||||
f"Unable to determine xcd count from:\n\t"
|
||||
f"GPU arch: '{gpu_arch}', model: '{gpu_model}', partition: '{compute_partition}'"
|
||||
"Unable to determine xcd count from:\n\t"
|
||||
f"GPU arch: '{gpu_arch}', model: '{gpu_model}',\n\t"
|
||||
f"partition: '{compute_partition}'"
|
||||
)
|
||||
console_warning(
|
||||
f"Applying default gfx942 settings:\n"
|
||||
@@ -276,7 +283,8 @@ class MIGPUSpecs:
|
||||
cls, gpu_arch: str = None, gpu_model: str = None, compute_partition: str = None
|
||||
):
|
||||
"""
|
||||
Retrieve the number of XCDs based on GPU architecture, model, and compute partition.
|
||||
Retrieve the number of XCDs based on GPU architecture, model,
|
||||
and compute partition.
|
||||
|
||||
Priority order:
|
||||
1. Legacy GPU check (returns 1 XCD for older architectures/models)
|
||||
@@ -307,7 +315,8 @@ class MIGPUSpecs:
|
||||
return num_xcds
|
||||
else:
|
||||
console_warning(
|
||||
f"No compute partition data found for architecture '{gpu_arch.upper()}'"
|
||||
f"No compute partition data found for "
|
||||
f"architecture '{gpu_arch.upper()}'"
|
||||
)
|
||||
|
||||
# 3. Fall back to model + partition-based lookup
|
||||
@@ -315,7 +324,8 @@ class MIGPUSpecs:
|
||||
# Validate XCD dictionary is populated
|
||||
if not hasattr(cls, "_num_xcds_dict") or not cls._num_xcds_dict:
|
||||
console_error(
|
||||
"mi300_num_xcds_dict not populated. Did you run parse_mi_gpu_spec()?"
|
||||
"mi300_num_xcds_dict not populated. "
|
||||
"Did you run parse_mi_gpu_spec()?"
|
||||
)
|
||||
elif gpu_model_norm not in cls._num_xcds_dict:
|
||||
console_warning(
|
||||
@@ -330,7 +340,9 @@ class MIGPUSpecs:
|
||||
)
|
||||
elif partition_norm not in model_dict:
|
||||
console_warning(
|
||||
f"Unknown compute partition '{compute_partition}' for model '{gpu_model}'"
|
||||
f"Unknown compute partition "
|
||||
f"'{compute_partition}' for model "
|
||||
f"'{gpu_model}'"
|
||||
)
|
||||
else:
|
||||
num_xcds = model_dict[partition_norm]
|
||||
@@ -338,8 +350,10 @@ class MIGPUSpecs:
|
||||
return num_xcds
|
||||
else:
|
||||
console_warning(
|
||||
f"Unknown compute partition found for {compute_partition} / {gpu_model}"
|
||||
"Unknown compute partition found "
|
||||
f"for {compute_partition} / {gpu_model}"
|
||||
)
|
||||
|
||||
else:
|
||||
console_warning("No gpu model provided for num xcds lookup.")
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import ast
|
||||
import json
|
||||
import re
|
||||
@@ -66,10 +65,9 @@ pmc_kernel_top_table_id = 1
|
||||
# },
|
||||
# {
|
||||
# "case": { "$eq": [ $normUnit, "per Sec"]} ,
|
||||
# "then": {"$divide":[{"$subtract": ["&End_Timestamp", "&Start_Timestamp" ]}, 1000000000]}
|
||||
# }
|
||||
# ],
|
||||
# "default": 1
|
||||
# "then": {"$divide":[{"$subtract": ["&End_Timestamp",
|
||||
# "&Start_Timestamp" ]},
|
||||
# 1000000000]}
|
||||
# }
|
||||
# }
|
||||
supported_denom = {
|
||||
@@ -84,16 +82,19 @@ build_in_vars = {
|
||||
"GRBM_GUI_ACTIVE_PER_XCD": "(GRBM_GUI_ACTIVE / $num_xcd)",
|
||||
"GRBM_COUNT_PER_XCD": "(GRBM_COUNT / $num_xcd)",
|
||||
"GRBM_SPI_BUSY_PER_XCD": "(GRBM_SPI_BUSY / $num_xcd)",
|
||||
"numActiveCUs": "TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / $GRBM_GUI_ACTIVE_PER_XCD)), \
|
||||
0) / $max_waves_per_cu) * 8) + MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) \
|
||||
/ $GRBM_GUI_ACTIVE_PER_XCD)), 0), $max_waves_per_cu), 8)), $cu_per_gpu))",
|
||||
"kernelBusyCycles": "ROUND(AVG((((End_Timestamp - Start_Timestamp) / 1000) * $max_sclk)), 0)",
|
||||
"numActiveCUs": "TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / \
|
||||
$GRBM_GUI_ACTIVE_PER_XCD)), 0) / $max_waves_per_cu) * 8) + \
|
||||
MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / \
|
||||
$GRBM_GUI_ACTIVE_PER_XCD)), 0), $max_waves_per_cu), 8)), $cu_per_gpu))",
|
||||
"kernelBusyCycles": "ROUND(AVG((((End_Timestamp - Start_Timestamp) / \
|
||||
1000) * $max_sclk)), 0)",
|
||||
"hbmBandwidth": "($max_mclk / 1000 * 32 * $num_hbm_channels)",
|
||||
}
|
||||
|
||||
supported_call = {
|
||||
# If the below has single arg, like(expr), it is a aggr, in which turn to a pd function.
|
||||
# If it has args like list [], in which turn to a python function.
|
||||
# If the below has a single arg, like(expr), it is an aggr,
|
||||
# in which case it turns into a pandas function.
|
||||
# If it has args like a list [], it turns into a Python function.
|
||||
"MIN": "to_min",
|
||||
"MAX": "to_max",
|
||||
# simple aggr
|
||||
@@ -243,11 +244,18 @@ class CodeTransformer(ast.NodeTransformer):
|
||||
|
||||
def visit_IfExp(self, node):
|
||||
self.generic_visit(node)
|
||||
# print("visit_IfExp", type(node.test), type(node.body), type(node.orelse), dir(node))
|
||||
# print(
|
||||
# "visit_IfExp",
|
||||
# type(node.test),
|
||||
# type(node.body),
|
||||
# type(node.orelse),
|
||||
# dir(node),
|
||||
# )
|
||||
|
||||
if isinstance(node.body, ast.Num):
|
||||
raise Exception(
|
||||
"Don't support body of IF with number only! Has to be expr with df['column']."
|
||||
"Don't support body of IF with number only! Has to be expr with "
|
||||
"df['column']."
|
||||
)
|
||||
|
||||
new_node = ast.Expr(
|
||||
@@ -289,19 +297,58 @@ class CodeTransformer(ast.NodeTransformer):
|
||||
|
||||
def build_eval_string(equation, coll_level, config):
|
||||
"""
|
||||
Convert user defined equation string to eval executable string
|
||||
Convert user defined equation string to eval executable string.
|
||||
For example,
|
||||
input: AVG(100 * SQ_ACTIVE_INST_SCA / ( GRBM_GUI_ACTIVE * $numCU ))
|
||||
output: to_avg(100 * raw_pmc_df["pmc_perf"]["SQ_ACTIVE_INST_SCA"] / \
|
||||
(raw_pmc_df["pmc_perf"]["GRBM_GUI_ACTIVE"] * numCU))
|
||||
input: AVG(((TCC_EA_RDREQ_LEVEL_31 / TCC_EA_RDREQ_31) if (TCC_EA_RDREQ_31 != 0) else (0)))
|
||||
output: to_avg((raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_LEVEL_31"] / raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"]).where(raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"] != 0, 0))
|
||||
We can not handle the below for now,
|
||||
input: AVG((0 if (TCC_EA_RDREQ_31 == 0) else (TCC_EA_RDREQ_LEVEL_31 / TCC_EA_RDREQ_31)))
|
||||
But potential workaound is,
|
||||
output: to_avg(raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"].where(raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"] == 0, raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_LEVEL_31"] / raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"]))
|
||||
input:
|
||||
AVG(100 * SQ_ACTIVE_INST_SCA / ( GRBM_GUI_ACTIVE * $numCU ))
|
||||
output:
|
||||
to_avg(
|
||||
100 * raw_pmc_df["pmc_perf"]["SQ_ACTIVE_INST_SCA"] /
|
||||
(
|
||||
raw_pmc_df["pmc_perf"]["GRBM_GUI_ACTIVE"] *
|
||||
numCU
|
||||
)
|
||||
)
|
||||
input:
|
||||
AVG(
|
||||
(
|
||||
TCC_EA_RDREQ_LEVEL_31 / TCC_EA_RDREQ_31
|
||||
)
|
||||
if (TCC_EA_RDREQ_31 != 0)
|
||||
else (0)
|
||||
)
|
||||
output:
|
||||
to_avg(
|
||||
(
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_LEVEL_31"] /
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"]
|
||||
).where(
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"] != 0,
|
||||
0
|
||||
)
|
||||
)
|
||||
We can not handle the below for now:
|
||||
input:
|
||||
AVG(
|
||||
(
|
||||
0
|
||||
if (TCC_EA_RDREQ_31 == 0)
|
||||
else (
|
||||
TCC_EA_RDREQ_LEVEL_31 /
|
||||
TCC_EA_RDREQ_31
|
||||
)
|
||||
)
|
||||
)
|
||||
But potential workaround is:
|
||||
output:
|
||||
to_avg(
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"].where(
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"] == 0,
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_LEVEL_31"] /
|
||||
raw_pmc_df["pmc_perf"]["TCC_EA_RDREQ_31"]
|
||||
)
|
||||
)
|
||||
"""
|
||||
|
||||
if coll_level is None:
|
||||
raise Exception("Error: coll_level can not be None.")
|
||||
|
||||
@@ -333,7 +380,7 @@ def build_eval_string(equation, coll_level, config):
|
||||
# apply coll_level
|
||||
if config.get("format_rocprof_output") == "rocpd":
|
||||
# Replace SQ_ACCUM_PREV_HIRES with coll_level_ACCUM then ignore coll_level df
|
||||
s = re.sub(f"SQ_ACCUM_PREV_HIRES", f"{coll_level}_ACCUM", s)
|
||||
s = re.sub("SQ_ACCUM_PREV_HIRES", f"{coll_level}_ACCUM", s)
|
||||
s = re.sub(
|
||||
r"raw_pmc_df", "raw_pmc_df.get('" + schema.pmc_perf_file_prefix + "')", s
|
||||
)
|
||||
@@ -420,21 +467,24 @@ def gen_counter_list(formula):
|
||||
.replace("$denom", "SQ_WAVES")
|
||||
.replace(
|
||||
"$numActiveCUs",
|
||||
"TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / $GRBM_GUI_ACTIVE_PER_XCD})), \
|
||||
0) / $maxWavesPerCU) * 8) + MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) \
|
||||
/ $GRBM_GUI_ACTIVE_PER_XCD)), 0), $maxWavesPerCU), 8)), $numCU))",
|
||||
"TO_INT(MIN((((ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / "
|
||||
"$GRBM_GUI_ACTIVE_PER_XCD})), 0) / $maxWavesPerCU) * 8) + "
|
||||
"MIN(MOD(ROUND(AVG(((4 * SQ_BUSY_CU_CYCLES) / "
|
||||
"$GRBM_GUI_ACTIVE_PER_XCD)), 0), $maxWavesPerCU), 8)), $numCU))",
|
||||
)
|
||||
.replace("$", "")
|
||||
)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Name):
|
||||
val = str(node.id)[:-4] if str(node.id).endswith("_sum") else str(node.id)
|
||||
val = (
|
||||
str(node.id)[:-4] if str(node.id).endswith("_sum") else str(node.id)
|
||||
)
|
||||
if val.isupper() and val not in function_filter:
|
||||
counters.append(val)
|
||||
visited = True
|
||||
if val in built_in_counter:
|
||||
visited = True
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return visited, counters
|
||||
@@ -645,10 +695,7 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
|
||||
or (data_source_idx == "0") # no filter
|
||||
or (data_source_idx in filter_metrics)
|
||||
):
|
||||
if (
|
||||
"columnwise" in data_config
|
||||
and data_config["columnwise"] == True
|
||||
):
|
||||
if "columnwise" in data_config and data_config["columnwise"]:
|
||||
df = pd.DataFrame(
|
||||
[data_config["source"]], columns=["from_csv_columnwise"]
|
||||
)
|
||||
@@ -726,79 +773,93 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
ammolite__se_per_gpu = int(sys_info.se_per_gpu)
|
||||
if np.isnan(ammolite__se_per_gpu) or ammolite__se_per_gpu == 0:
|
||||
console_warning(
|
||||
"se_per_gpu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"se_per_gpu is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__pipes_per_gpu = int(sys_info.pipes_per_gpu)
|
||||
if np.isnan(ammolite__pipes_per_gpu) or ammolite__pipes_per_gpu == 0:
|
||||
console_warning(
|
||||
"pipes_per_gpu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"pipes_per_gpu is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__cu_per_gpu = int(sys_info.cu_per_gpu)
|
||||
if np.isnan(ammolite__cu_per_gpu) or ammolite__cu_per_gpu == 0:
|
||||
console_warning(
|
||||
"cu_per_gpu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"cu_per_gpu is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__simd_per_cu = int(sys_info.simd_per_cu) # not used
|
||||
if np.isnan(ammolite__simd_per_cu) or ammolite__simd_per_cu == 0:
|
||||
console_warning(
|
||||
"simd_per_cu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"simd_per_cu is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__sqc_per_gpu = int(sys_info.sqc_per_gpu)
|
||||
if np.isnan(ammolite__sqc_per_gpu) or ammolite__sqc_per_gpu == 0:
|
||||
console_warning(
|
||||
"sqc_per_gpu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"sqc_per_gpu is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__lds_banks_per_cu = int(sys_info.lds_banks_per_cu)
|
||||
if np.isnan(ammolite__lds_banks_per_cu) or ammolite__lds_banks_per_cu == 0:
|
||||
console_warning(
|
||||
"lds_banks_per_cu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"lds_banks_per_cu is not available in sysinfo.csv, please provide the "
|
||||
"correct value using --specs-correction"
|
||||
)
|
||||
ammolite__cur_sclk = float(sys_info.cur_sclk) # not used
|
||||
if np.isnan(ammolite__cur_sclk) or ammolite__cur_sclk == 0:
|
||||
console_warning(
|
||||
"cur_sclk is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"cur_sclk is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__cur_mclk = float(sys_info.cur_mclk) # not used
|
||||
if np.isnan(ammolite__cur_mclk) or ammolite__cur_mclk == 0:
|
||||
console_warning(
|
||||
"cur_mclk is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"cur_mclk is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__max_mclk = float(sys_info.max_mclk)
|
||||
if np.isnan(ammolite__max_mclk) or ammolite__max_mclk == 0:
|
||||
console_warning(
|
||||
"max_mclk is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"max_mclk is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__max_sclk = float(sys_info.max_sclk)
|
||||
if np.isnan(ammolite__max_sclk) or ammolite__max_sclk == 0:
|
||||
console_warning(
|
||||
"max_sclk is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"max_sclk is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__max_waves_per_cu = int(sys_info.max_waves_per_cu)
|
||||
if np.isnan(ammolite__max_waves_per_cu) or ammolite__max_waves_per_cu == 0:
|
||||
console_warning(
|
||||
"max_waver_per_cu is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"max_waver_per_cu is not available in sysinfo.csv, please provide the "
|
||||
"correct value using --specs-correction"
|
||||
)
|
||||
ammolite__num_hbm_channels = float(sys_info.num_hbm_channels)
|
||||
if np.isnan(ammolite__num_hbm_channels) or ammolite__num_hbm_channels == 0:
|
||||
console_warning(
|
||||
"num_hbm_channels is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"num_hbm_channels is not available in sysinfo.csv, please provide the "
|
||||
"correct value using --specs-correction"
|
||||
)
|
||||
ammolite__total_l2_chan = calc_builtin_var("$total_l2_chan", sys_info)
|
||||
if np.isnan(ammolite__total_l2_chan) or ammolite__total_l2_chan == 0:
|
||||
console_warning(
|
||||
"total_l2_chan is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"total_l2_chan is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__num_xcd = int(sys_info.num_xcd)
|
||||
if np.isnan(ammolite__num_xcd) or ammolite__num_xcd == 0:
|
||||
console_warning(
|
||||
"num_xcd is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"num_xcd is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
ammolite__wave_size = int(sys_info.wave_size)
|
||||
if np.isnan(ammolite__wave_size) or ammolite__wave_size == 0:
|
||||
console_warning(
|
||||
"wave_size is not available in sysinfo.csv, please provide the correct value using --specs-correction"
|
||||
"wave_size is not available in sysinfo.csv, please provide the correct "
|
||||
"value using --specs-correction"
|
||||
)
|
||||
|
||||
# TODO: fix all $normUnit in Unit column or title
|
||||
|
||||
# build and eval all derived build-in global variables
|
||||
@@ -817,9 +878,9 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
except AttributeError as ae:
|
||||
if ae == "'NoneType' object has no attribute 'get'":
|
||||
ammolite__build_in[key] = None
|
||||
ammolite__GRBM_GUI_ACTIVE_PER_XCD = ammolite__build_in["GRBM_GUI_ACTIVE_PER_XCD"]
|
||||
ammolite__GRBM_COUNT_PER_XCD = ammolite__build_in["GRBM_COUNT_PER_XCD"]
|
||||
ammolite__GRBM_SPI_BUSY_PER_XCD = ammolite__build_in["GRBM_SPI_BUSY_PER_XCD"]
|
||||
ammolite__GRBM_GUI_ACTIVE_PER_XCD = ammolite__build_in["GRBM_GUI_ACTIVE_PER_XCD"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
ammolite__GRBM_COUNT_PER_XCD = ammolite__build_in["GRBM_COUNT_PER_XCD"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
ammolite__GRBM_SPI_BUSY_PER_XCD = ammolite__build_in["GRBM_SPI_BUSY_PER_XCD"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
|
||||
for key, value in build_in_vars.items():
|
||||
# next pass, we evaluate the builtins the depend on the per-XCD values
|
||||
@@ -834,12 +895,16 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
except AttributeError as ae:
|
||||
if ae == "'NoneType' object has no attribute 'get'":
|
||||
ammolite__build_in[key] = None
|
||||
ammolite__numActiveCUs = ammolite__build_in["numActiveCUs"]
|
||||
ammolite__kernelBusyCycles = ammolite__build_in["kernelBusyCycles"]
|
||||
ammolite__hbmBandwidth = ammolite__build_in["hbmBandwidth"]
|
||||
ammolite__numActiveCUs = ammolite__build_in["numActiveCUs"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
ammolite__kernelBusyCycles = ammolite__build_in["kernelBusyCycles"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
ammolite__hbmBandwidth = ammolite__build_in["hbmBandwidth"] # noqa: F841 - Ruff: var utilized during runtime
|
||||
|
||||
# Hmmm... apply + lambda should just work
|
||||
# df['Value'] = df['Value'].apply(lambda s: eval(compile(str(s), '<string>', 'eval')))
|
||||
# df['Value'] = df['Value'].apply(
|
||||
# lambda s: eval(
|
||||
# compile(str(s), '<string>', 'eval')
|
||||
# )
|
||||
# )
|
||||
for id, df in dfs.items():
|
||||
if dfs_type[id] == "metric_table":
|
||||
for idx, row in df.iterrows():
|
||||
@@ -851,7 +916,9 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
print("~" * 40 + "\nExpression:")
|
||||
print(expr, "=", row[expr])
|
||||
print("Inputs:")
|
||||
matched_vars = re.findall(r"ammolite__\w+", row[expr])
|
||||
matched_vars = re.findall(
|
||||
r"ammolite__\w+", row[expr]
|
||||
)
|
||||
if matched_vars:
|
||||
for v in matched_vars:
|
||||
print(
|
||||
@@ -868,7 +935,7 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
m = re.match(
|
||||
r"raw_pmc_df\['(\w+)'\]\['(\w+)'\]", c
|
||||
)
|
||||
t = raw_pmc_df[m.group(1)][
|
||||
t = raw_pmc_df[m.group(1)][ # noqa: F841
|
||||
m.group(2)
|
||||
].to_list()
|
||||
print(c)
|
||||
@@ -890,19 +957,22 @@ def eval_metric(dfs, dfs_type, sys_info, raw_pmc_df, debug, config):
|
||||
print("~" * 40)
|
||||
except TypeError:
|
||||
console_warning(
|
||||
"Skipping entry. Encountered a missing counter\n{} has been assigned to None\n{}".format(
|
||||
expr, np.nan
|
||||
"Skipping entry. Encountered a missing "
|
||||
"counter\n{} has been assigned to None\n{}"
|
||||
.format(
|
||||
expr,
|
||||
np.nan,
|
||||
)
|
||||
)
|
||||
except AttributeError as ae:
|
||||
if (
|
||||
str(ae)
|
||||
== "'NoneType' object has no attribute 'get'"
|
||||
== "'NoneType' object has no attribute "
|
||||
"'get'"
|
||||
):
|
||||
console_warning(
|
||||
"Skipping entry. Encountered a missing csv\n{}".format(
|
||||
np.nan
|
||||
)
|
||||
"Skipping entry. Encountered a missing "
|
||||
"csv\n{}".format(np.nan)
|
||||
)
|
||||
else:
|
||||
console_error("analysis", str(ae))
|
||||
@@ -967,14 +1037,16 @@ def apply_filters(workload, dir, is_gui, debug):
|
||||
# We pick up kernel names from kerne ids first.
|
||||
# Then filter valid entries with kernel names.
|
||||
if workload.filter_kernel_ids:
|
||||
if all(type(kid) == int for kid in workload.filter_kernel_ids):
|
||||
if all(isinstance(kid, int) for kid in workload.filter_kernel_ids):
|
||||
# Verify valid kernel filter
|
||||
kernels_df = pd.read_csv(str(Path(dir).joinpath("pmc_kernel_top.csv")))
|
||||
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(
|
||||
kernel_id, len(kernels_df["Kernel_Name"]) - 1
|
||||
"{} is an invalid kernel id. Please enter an id between 0-{}"
|
||||
.format(
|
||||
kernel_id,
|
||||
len(kernels_df["Kernel_Name"]) - 1,
|
||||
)
|
||||
)
|
||||
kernels = []
|
||||
@@ -992,7 +1064,7 @@ def apply_filters(workload, dir, is_gui, debug):
|
||||
ret_df = ret_df.loc[
|
||||
ret_df[schema.pmc_perf_file_prefix]["Kernel_Name"].isin(kernels)
|
||||
]
|
||||
elif all(type(kid) == str for kid in workload.filter_kernel_ids):
|
||||
elif all(isinstance(kid, str) for kid in workload.filter_kernel_ids):
|
||||
df_cleaned = ret_df[schema.pmc_perf_file_prefix]["Kernel_Name"].apply(
|
||||
lambda x: x.strip() if isinstance(x, str) else x
|
||||
)
|
||||
@@ -1028,7 +1100,8 @@ def apply_filters(workload, dir, is_gui, debug):
|
||||
|
||||
def find_key_recursively(data, search_key):
|
||||
"""
|
||||
Recursively search for the search_key in the given data (which can be a dict or list).
|
||||
Recursively search for the search_key in the given data
|
||||
(which can be a dict or list).
|
||||
If the key is found, returns the value as a DataFrame.
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
@@ -1050,7 +1123,6 @@ def find_key_recursively(data, search_key):
|
||||
|
||||
|
||||
def search_key_in_json(file_path, search_key):
|
||||
|
||||
# FIXME:
|
||||
# Load the entire JSON into memory.
|
||||
# Should not use for large file.
|
||||
@@ -1081,14 +1153,18 @@ def search_pc_sampling_record(records):
|
||||
"inst_index": None,
|
||||
"stall_reason": {
|
||||
"NONE": 0,
|
||||
"NO_INSTRUCTION_AVAILABLE": 0, # No instruction available in the instruction cache.
|
||||
# No instruction available in the instruction cache.
|
||||
"NO_INSTRUCTION_AVAILABLE": 0,
|
||||
"ALU_DEPENDENCY": 0, # ALU dependency not resolved.
|
||||
"WAITCNT": 0,
|
||||
"INTERNAL_INSTRUCTION": 0, # Wave executes an internal instruction.
|
||||
"BARRIER_WAIT": 0,
|
||||
"ARBITER_NOT_WIN": 0, # The instruction did not win the arbiter.
|
||||
"ARBITER_WIN_EX_STALL": 0, # Arbiter issued an instruction, but the execution pipe pushed it back from execution.
|
||||
"OTHER_WAIT": 0, # Other types of wait (e.g., wait for XNACK acknowledgment).
|
||||
"ARBITER_WIN_EX_STALL": 0,
|
||||
# Arbiter issued an instruction, but the execution pipe
|
||||
# pushed it back from execution.
|
||||
"OTHER_WAIT": 0,
|
||||
# Other types of wait (e.g., wait for XNACK acknowledgment).
|
||||
"SLEEP_WAIT": 0,
|
||||
"LAST": 0,
|
||||
},
|
||||
@@ -1116,14 +1192,19 @@ def search_pc_sampling_record(records):
|
||||
and inst_index is not None
|
||||
):
|
||||
grouped_data[code_object_id][code_object_offset]["count"] += 1
|
||||
# NB: the write here could be duplicated. If there is perf issue, We might want to opt it.
|
||||
# NB: the write here could be duplicated. If there is perf issue,
|
||||
# We might want to opt it.
|
||||
grouped_data[code_object_id][code_object_offset]["inst_index"] = inst_index
|
||||
|
||||
if len(snapshot):
|
||||
if issued:
|
||||
grouped_data[code_object_id][code_object_offset]["count_issued"] += 1
|
||||
grouped_data[code_object_id][code_object_offset][
|
||||
"count_issued"
|
||||
] += 1
|
||||
else:
|
||||
grouped_data[code_object_id][code_object_offset]["count_stalled"] += 1
|
||||
grouped_data[code_object_id][code_object_offset][
|
||||
"count_stalled"
|
||||
] += 1
|
||||
grouped_data[code_object_id][code_object_offset]["stall_reason"][
|
||||
snapshot.get("stall_reason")[rocp_inst_not_issued_prefix_len:]
|
||||
] += 1
|
||||
@@ -1138,7 +1219,8 @@ def search_pc_sampling_record(records):
|
||||
|
||||
# print(grouped_data)
|
||||
|
||||
# Convert to sorted list of tuples (code_object_id, inst_index, code_object_offset, count)
|
||||
# Convert to sorted list of tuples:
|
||||
# (code_object_id, inst_index, code_object_offset, count)
|
||||
sorted_counts = sorted(
|
||||
[
|
||||
(
|
||||
@@ -1148,7 +1230,8 @@ def search_pc_sampling_record(records):
|
||||
info["count"],
|
||||
info["count_issued"],
|
||||
info["count_stalled"],
|
||||
# For info["stall_reason"], remove the zero entries, sorting the remaining items by their values in descending order
|
||||
# For info["stall_reason"], remove the zero entries,
|
||||
# sorting the remaining items by their values in descending order
|
||||
sorted(
|
||||
((k, v) for k, v in info["stall_reason"].items() if v > 0),
|
||||
key=lambda item: item[1],
|
||||
@@ -1173,7 +1256,8 @@ def load_pc_sampling_data_per_kernel(
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Load PC sampling raw data from json file with given method and kernel name,
|
||||
count pc sampling and sort it in the order of compiled asm and associate with kernel source code if available,
|
||||
count pc sampling and sort it in the order of compiled asm and associate with
|
||||
kernel source code if available,
|
||||
then return df.
|
||||
|
||||
:param method: "host_trap" or "stochastic".
|
||||
@@ -1258,11 +1342,25 @@ def load_pc_sampling_data_per_kernel(
|
||||
(df["code_object_id"] == kernel_info["code_object_id"])
|
||||
& (df["offset"] > kernel_info["entry_byte_offset"])
|
||||
& (df["offset"] < kernel_info["potential_end_offset"])
|
||||
][["inst_index", "offset", "count", "count_issued", "count_stalled", "stall_reason"]]
|
||||
][
|
||||
[
|
||||
"inst_index",
|
||||
"offset",
|
||||
"count",
|
||||
"count_issued",
|
||||
"count_stalled",
|
||||
"stall_reason",
|
||||
]
|
||||
]
|
||||
|
||||
df["offset"] = df["offset"].apply(lambda x: hex(x))
|
||||
|
||||
# df["stall_reason"] = df["stall_reason"].apply(lambda x: ', '.join(f"{k}: {v}" for k, v in x))
|
||||
# df["stall_reason"] = df["stall_reason"].apply(
|
||||
# lambda x: ', '.join(
|
||||
# f"{k}: {v}"
|
||||
# for k, v in x
|
||||
# )
|
||||
# )
|
||||
|
||||
pc_sample_instructions = search_key_in_json(file_name, "pc_sample_instructions")
|
||||
# print(pc_sample_instructions)
|
||||
@@ -1334,7 +1432,9 @@ def load_pc_sampling_data(workload, dir, file_prefix, sorting_type):
|
||||
# - The default file name is subject to changes from rocprofv3
|
||||
# - Prioritize stochastic
|
||||
# - Alternatively, we could check pc_sampling_method in json
|
||||
csv_file_path = Path.joinpath(Path(dir), file_prefix + "_pc_sampling_stochastic.csv")
|
||||
csv_file_path = Path.joinpath(
|
||||
Path(dir), file_prefix + "_pc_sampling_stochastic.csv"
|
||||
)
|
||||
if csv_file_path.exists():
|
||||
pc_sampling_method = "stochastic"
|
||||
else:
|
||||
@@ -1352,7 +1452,6 @@ def load_pc_sampling_data(workload, dir, file_prefix, sorting_type):
|
||||
|
||||
# No kernel filter, return grouped and sorted csv directly
|
||||
if not workload.filter_kernel_ids:
|
||||
|
||||
df = pd.read_csv(csv_file_path)
|
||||
# Group by 'Instruction_Comment' and count occurrences
|
||||
grouped_counts = (
|
||||
@@ -1379,7 +1478,8 @@ def load_pc_sampling_data(workload, dir, file_prefix, sorting_type):
|
||||
|
||||
elif len(workload.filter_kernel_ids) > 1:
|
||||
console_error(
|
||||
"PC sampling supports single kernel only! Please specify -k with single kernel."
|
||||
"PC sampling supports single kernel only! Please specify -k with "
|
||||
"single kernel."
|
||||
)
|
||||
return pd.DataFrame()
|
||||
|
||||
@@ -1409,7 +1509,8 @@ def load_pc_sampling_data(workload, dir, file_prefix, sorting_type):
|
||||
@demarcate
|
||||
def load_kernel_top(workload, dir, args):
|
||||
# NB:
|
||||
# - Do pmc_kernel_top.csv loading before eval_metric because we need the kernel names.
|
||||
# - Do pmc_kernel_top.csv loading before eval_metric because we need the
|
||||
# kernel names.
|
||||
# - There might be a better way/timing to load raw_csv_table.
|
||||
|
||||
# FIXME:
|
||||
@@ -1427,9 +1528,11 @@ def load_kernel_top(workload, dir, args):
|
||||
tmp[id] = pd.read_csv(file)
|
||||
else:
|
||||
console_warning(
|
||||
f"Couldn't load {file.name}. This may result in missing analysis data."
|
||||
f"Couldn't load {file.name}. "
|
||||
"This may result in missing analysis data."
|
||||
)
|
||||
# NB: Special case for sysinfo. Probably room for improvement in this whole function design
|
||||
# NB: Special case for sysinfo. Probably room for improvement in this whole
|
||||
# function design
|
||||
elif "from_csv_columnwise" in df.columns and id == 101:
|
||||
tmp[id] = workload.sys_info.transpose()
|
||||
# All transposed columns should be marked with a general header
|
||||
@@ -1447,7 +1550,8 @@ def load_kernel_top(workload, dir, args):
|
||||
tmp[id].columns = ["Info"]
|
||||
else:
|
||||
console_warning(
|
||||
f"Couldn't load {file.name}. This may result in missing analysis data."
|
||||
f"Couldn't load {file.name}. "
|
||||
"This may result in missing analysis data."
|
||||
)
|
||||
elif "from_pc_sampling" in df.columns:
|
||||
tmp[id] = load_pc_sampling_data(
|
||||
@@ -1513,7 +1617,8 @@ def correct_sys_info(mspec, specs_correction: dict):
|
||||
if not hasattr(mspec, str(k)):
|
||||
console_error(
|
||||
"analyze",
|
||||
f"Invalid specs correction '{k}'. Please use --specs option to peak valid specs",
|
||||
f"Invalid specs correction '{k}'. Please use --specs option "
|
||||
f"to peak valid specs",
|
||||
)
|
||||
setattr(mspec, str(k), v)
|
||||
return mspec.get_class_members()
|
||||
|
||||
@@ -4,7 +4,8 @@ from contextlib import closing
|
||||
|
||||
from utils.logger import console_error
|
||||
|
||||
# From schema definition in source/share/rocprofiler-sdk-rocpd/data_views.sql in rocprofiler-sdk repository
|
||||
# From schema definition in source/share/rocprofiler-sdk-rocpd/data_views.sql
|
||||
# in rocprofiler-sdk repository
|
||||
COUNTERS_COLLECTION_QUERY = """
|
||||
SELECT
|
||||
agent_id as GPU_ID,
|
||||
@@ -39,9 +40,9 @@ def convert_db_to_csv(
|
||||
with closing(conn.execute(COUNTERS_COLLECTION_QUERY)) as cursor:
|
||||
with open(csv_file_path, "w", newline="") as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
writer.writerow(
|
||||
[description[0] for description in cursor.description]
|
||||
)
|
||||
writer.writerow([
|
||||
description[0] for description in cursor.description
|
||||
])
|
||||
for row in cursor:
|
||||
writer.writerow(row)
|
||||
except (sqlite3.DatabaseError, IOError) as e:
|
||||
@@ -50,22 +51,21 @@ def convert_db_to_csv(
|
||||
|
||||
def process_rocpd_csv(df):
|
||||
"""
|
||||
Merge counters across unique dispatches from the input dataframe and return processed dataframe.
|
||||
Merge counters across unique dispatches from the
|
||||
input dataframe and return processed dataframe.
|
||||
"""
|
||||
# Only import pandas if needed
|
||||
import pandas as pd
|
||||
|
||||
data = list()
|
||||
# Group by unique kernel and merge into a single row
|
||||
for _, group_df in df.groupby(
|
||||
[
|
||||
"Dispatch_ID",
|
||||
"Kernel_Name",
|
||||
"Grid_Size",
|
||||
"Workgroup_Size",
|
||||
"LDS_Per_Workgroup",
|
||||
]
|
||||
):
|
||||
for _, group_df in df.groupby([
|
||||
"Dispatch_ID",
|
||||
"Kernel_Name",
|
||||
"Grid_Size",
|
||||
"Workgroup_Size",
|
||||
"LDS_Per_Workgroup",
|
||||
]):
|
||||
row = {
|
||||
"GPU_ID": group_df["GPU_ID"].iloc[0],
|
||||
"Grid_Size": group_df["Grid_Size"].iloc[0],
|
||||
@@ -80,7 +80,8 @@ def process_rocpd_csv(df):
|
||||
}
|
||||
# Each counter will become its own column
|
||||
row.update(dict(zip(group_df["Counter_Name"], group_df["Counter_Value"])))
|
||||
# Replace end timestamp with median of durations of group, start timestamp is set to 0
|
||||
# Replace end timestamp with median of durations of group,
|
||||
# start timestamp is set to 0
|
||||
row["End_Timestamp"] = (
|
||||
group_df["End_Timestamp"] - group_df["Start_Timestamp"]
|
||||
).median()
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import csv
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
@@ -155,7 +154,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": []}
|
||||
|
||||
@@ -186,7 +186,7 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
|
||||
if dtype in PEAK_OPS_DATATYPES:
|
||||
x2 = peakOps / peakBw
|
||||
y2 = peakOps
|
||||
y2 = peakOps # noqa: F841
|
||||
|
||||
# Plot MFMA lines (NOTE: Assuming MI200 soc)
|
||||
x1_mfma = peakOps / peakBw
|
||||
@@ -220,9 +220,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
|
||||
@@ -255,7 +255,8 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
|
||||
# -------------------------------------------------------------------------------------
|
||||
# Calculate relevant metrics for ai calculation
|
||||
def calc_ai(mspec, 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"])
|
||||
@@ -442,7 +443,10 @@ def calc_ai(mspec, sort_type, ret_df):
|
||||
* 64
|
||||
)
|
||||
+ (
|
||||
(df["TCC_EA0_WRREQ_sum"][idx] - df["TCC_EA0_WRREQ_64B_sum"][idx])
|
||||
(
|
||||
df["TCC_EA0_WRREQ_sum"][idx]
|
||||
- df["TCC_EA0_WRREQ_64B_sum"][idx]
|
||||
)
|
||||
* 32
|
||||
)
|
||||
+ (df["TCC_EA0_WRREQ_64B_sum"][idx] * 64)
|
||||
@@ -459,7 +463,7 @@ def calc_ai(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,
|
||||
@@ -534,9 +538,8 @@ def calc_ai(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
|
||||
)
|
||||
"No flops counted for {}, arithmetic intensities will not "
|
||||
"display on plots.".format(myList[i].KernelName)
|
||||
)
|
||||
|
||||
kernelNames.append(myList[i].KernelName)
|
||||
@@ -545,28 +548,40 @@ def calc_ai(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")
|
||||
# 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")
|
||||
# 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")
|
||||
# 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")
|
||||
|
||||
i += 1
|
||||
|
||||
@@ -575,7 +590,7 @@ def calc_ai(mspec, sort_type, ret_df):
|
||||
for i in intensities:
|
||||
values = intensities[i]
|
||||
|
||||
color = get_color(i)
|
||||
color = get_color(i) # noqa: F841
|
||||
x = []
|
||||
y = []
|
||||
for entryIndx in range(0, len(values)):
|
||||
@@ -607,9 +622,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:
|
||||
@@ -627,7 +641,7 @@ def constuct_roof(roofline_parameters, dtype):
|
||||
|
||||
rowCount += 1
|
||||
csvfile.close()
|
||||
except:
|
||||
except Exception:
|
||||
graphPoints = {
|
||||
"hbm": [None, None, None],
|
||||
"l2": [None, None, None],
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
#
|
||||
# Define all common data storage classes,
|
||||
# predifned dict and global functions.
|
||||
@@ -31,7 +30,7 @@
|
||||
|
||||
from collections import OrderedDict
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Dict, Generator, List, Mapping
|
||||
from typing import Dict, List
|
||||
|
||||
import pandas as pd
|
||||
|
||||
|
||||
@@ -22,16 +22,13 @@
|
||||
# THE SOFTWARE.
|
||||
|
||||
##############################################################################
|
||||
|
||||
"""Get host/gpu specs."""
|
||||
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass, field, fields
|
||||
from datetime import datetime
|
||||
from math import ceil
|
||||
@@ -103,17 +100,19 @@ def kw_only(cls):
|
||||
|
||||
|
||||
def generate_machine_specs(args, sysinfo: dict = None):
|
||||
if not sysinfo is None:
|
||||
if sysinfo is not None:
|
||||
try:
|
||||
sysinfo_ver = str(sysinfo["version"])
|
||||
except KeyError:
|
||||
console_error(
|
||||
"Detected mismatch in sysinfo versioning. You need to reprofile to update data."
|
||||
"Detected mismatch in sysinfo versioning. You need to reprofile "
|
||||
"to update data."
|
||||
)
|
||||
version = get_version(config.rocprof_compute_home)["version"]
|
||||
if sysinfo_ver != version[: version.find(".")]:
|
||||
console_warning(
|
||||
"Detected mismatch in sysinfo versioning. You need to reprofile to update data."
|
||||
"Detected mismatch in sysinfo versioning. You need to reprofile "
|
||||
"to update data."
|
||||
)
|
||||
return MachineSpecs(**sysinfo)
|
||||
# read timestamp info
|
||||
@@ -127,7 +126,8 @@ def generate_machine_specs(args, sysinfo: dict = None):
|
||||
# set specs version
|
||||
vData = get_version(config.rocprof_compute_home)
|
||||
version = vData["version"]
|
||||
# NB: Just taking major as specs version. May want to make this more specific in the future
|
||||
# NB: Just taking major as specs version.
|
||||
# May want to make this more specific in the future
|
||||
specs_version = version[
|
||||
: version.find(".")
|
||||
] # version will always follow 'major.minor.patch' format
|
||||
@@ -173,8 +173,8 @@ def generate_machine_specs(args, sysinfo: dict = None):
|
||||
|
||||
# Apply default compute partition is above fails
|
||||
if compute_partition is None:
|
||||
console_warning(f"Can not detect compute/accelerator partition from amd-smi.")
|
||||
console_warning(f"Applying default compute partition: SPX")
|
||||
console_warning("Can not detect compute/accelerator partition from amd-smi.")
|
||||
console_warning("Applying default compute partition: SPX")
|
||||
compute_partition = "SPX"
|
||||
|
||||
memory_partition = search(memory_partition_pattern, amd_smi_output)
|
||||
@@ -218,14 +218,16 @@ def generate_machine_specs(args, sysinfo: dict = None):
|
||||
|
||||
# Load above SoC specs via module import
|
||||
try:
|
||||
soc_module = importlib.import_module("rocprof_compute_soc.soc_" + specs.gpu_arch)
|
||||
soc_module = importlib.import_module(
|
||||
"rocprof_compute_soc.soc_" + specs.gpu_arch
|
||||
)
|
||||
except ModuleNotFoundError as e:
|
||||
console_error(
|
||||
"Arch %s marked as supported, but couldn't find class implementation %s."
|
||||
% (specs.gpu_arch, e)
|
||||
)
|
||||
soc_class = getattr(soc_module, specs.gpu_arch + "_soc")
|
||||
soc_obj = soc_class(args, specs)
|
||||
soc_obj = soc_class(args, specs) # noqa: F841
|
||||
# Update arch specific specs
|
||||
specs.gpu_model = mi_gpu_specs.get_gpu_model(specs.gpu_arch, specs.gpu_chip_id)
|
||||
specs.num_xcd = mi_gpu_specs.get_num_xcds(
|
||||
@@ -332,7 +334,10 @@ class MachineSpecs:
|
||||
amd_gpu_kernel_version: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The version of the AMDGPU driver installed on the machine. Unimplemented.",
|
||||
"doc": (
|
||||
"[RESERVED] The version of the AMDGPU driver installed on the machine. "
|
||||
"Unimplemented."
|
||||
),
|
||||
"name": "AMD GPU Kernel Version",
|
||||
},
|
||||
)
|
||||
@@ -347,7 +352,10 @@ class MachineSpecs:
|
||||
gpu_memory: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The total amount of memory available to accelerators/GPUs in the system. Unimplemented.",
|
||||
"doc": (
|
||||
"[RESERVED] The total amount of memory available to accelerators/GPUs "
|
||||
"in the system. Unimplemented."
|
||||
),
|
||||
"unit": "KB",
|
||||
"name": "GPU Memory",
|
||||
},
|
||||
@@ -369,14 +377,20 @@ class MachineSpecs:
|
||||
compute_partition: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The compute partitioning mode active on the accelerators/GPUs in the system (MI300 only).",
|
||||
"doc": (
|
||||
"The compute partitioning mode active on the accelerators/GPUs in the "
|
||||
"system (MI300 only)."
|
||||
),
|
||||
"name": "Compute Partition",
|
||||
},
|
||||
)
|
||||
memory_partition: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The memory partitioning mode active on the accelerators/GPUs in the system (MI300 only).",
|
||||
"doc": (
|
||||
"The memory partitioning mode active on the accelerators/GPUs in the "
|
||||
"system (MI300 only)."
|
||||
),
|
||||
"name": "Memory Partition",
|
||||
},
|
||||
)
|
||||
@@ -417,7 +431,10 @@ class MachineSpecs:
|
||||
gpu_l1: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs.",
|
||||
"doc": (
|
||||
"The size of the vL1D cache (per compute-unit) on the "
|
||||
"accelerators/GPUs."
|
||||
),
|
||||
"name": "GPU L1",
|
||||
"unit": "KiB",
|
||||
},
|
||||
@@ -425,7 +442,10 @@ class MachineSpecs:
|
||||
gpu_l2: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The size of the vL1D cache (per compute-unit) on the accelerators/GPUs.",
|
||||
"doc": (
|
||||
"The size of the vL1D cache (per compute-unit) on the "
|
||||
"accelerators/GPUs."
|
||||
),
|
||||
"name": "GPU L2",
|
||||
"unit": "KiB",
|
||||
},
|
||||
@@ -433,52 +453,72 @@ class MachineSpecs:
|
||||
cu_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The total number of compute units per accelerator/GPU in the system. On systems with configurable\n"
|
||||
"partitioning, (e.g., MI300) this is the total number of compute units in a partition.",
|
||||
"doc": (
|
||||
"The total number of compute units per accelerator/GPU in the system. "
|
||||
"On systems with configurable partitioning, (e.g., MI300) this is "
|
||||
"the total number of compute units in a partition."
|
||||
),
|
||||
"name": "CU per GPU",
|
||||
},
|
||||
)
|
||||
simd_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of SIMD processors in a compute unit for the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The number of SIMD processors in a compute unit for the "
|
||||
"accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "SIMD per CU",
|
||||
},
|
||||
)
|
||||
se_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of shader engines on the accelerators/GPUs in the system. On systems with configurable\n"
|
||||
"partitioning, (e.g., MI300) this is the total number of shader engines in a partition.",
|
||||
"doc": (
|
||||
"The number of shader engines on the accelerators/GPUs in the system. "
|
||||
"On systems with configurable partitioning, (e.g., MI300) this is "
|
||||
"the total number of shader engines in a partition."
|
||||
),
|
||||
"name": "SE per GPU",
|
||||
},
|
||||
)
|
||||
wave_size: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number work-items in a wavefront on the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The number work-items in a wavefront on the accelerators/GPUs in "
|
||||
"the system."
|
||||
),
|
||||
"name": "Wave Size",
|
||||
},
|
||||
)
|
||||
workgroup_max_size: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of work-items in a workgroup on the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The maximum number of work-items in a workgroup on the "
|
||||
"accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "Workgroup Max Size",
|
||||
},
|
||||
)
|
||||
max_waves_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of wavefronts that can be resident on a compute unit on the\n"
|
||||
"accelerators/GPUs in the system",
|
||||
"doc": (
|
||||
"The maximum number of wavefronts that can be resident on a "
|
||||
"compute unit on the accelerators/GPUs in the system"
|
||||
),
|
||||
"name": "Max Waves per CU",
|
||||
},
|
||||
)
|
||||
max_sclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum engine (compute-unit) clock rate of the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The maximum engine (compute-unit) clock rate of the "
|
||||
"accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "Max SCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
@@ -486,7 +526,9 @@ class MachineSpecs:
|
||||
max_mclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum memory clock rate of the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The maximum memory clock rate of the accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "Max MCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
@@ -494,7 +536,10 @@ class MachineSpecs:
|
||||
cur_sclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The current engine (compute unit) clock rate of the accelerators/GPUs in the system. Unused.",
|
||||
"doc": (
|
||||
"[RESERVED] The current engine (compute unit) clock rate of the "
|
||||
"accelerators/GPUs in the system. Unused."
|
||||
),
|
||||
"name": "Cur SCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
@@ -502,54 +547,75 @@ class MachineSpecs:
|
||||
cur_mclk: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "[RESERVED] The current memory clock rate of the accelerators/GPUs in the system. Unused.",
|
||||
"doc": (
|
||||
"[RESERVED] The current memory clock rate of the accelerators/GPUs "
|
||||
"in the system. Unused."
|
||||
),
|
||||
"name": "Cur MCLK",
|
||||
"unit": "MHz",
|
||||
},
|
||||
)
|
||||
_l2_banks: str = None # NB: This only used in flatten_tcc_info_across_hbm_stacks()
|
||||
_l2_banks: str = None # NB: Only used in flatten_tcc_info_across_hbm_stacks()
|
||||
total_l2_chan: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The maximum number of L2 cache channels on the accelerators/GPUs in the system. On systems with\n"
|
||||
"configurable partitioning, (e.g., MI300) this is the total number of L2 cache channels in a partition.",
|
||||
"doc": (
|
||||
"The maximum number of L2 cache channels on the accelerators/GPUs "
|
||||
"in the system. On systems with configurable partitioning, "
|
||||
"(e.g., MI300) this is the total number of L2 cache channels "
|
||||
"in a partition."
|
||||
),
|
||||
"name": "Total L2 Channels",
|
||||
},
|
||||
)
|
||||
lds_banks_per_cu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of banks in the LDS for a compute unit on the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The number of banks in the LDS for a compute unit on the "
|
||||
"accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "LDS Banks per CU",
|
||||
},
|
||||
)
|
||||
sqc_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of L1I/sL1D caches on the accelerators/GPUs in the system. On systems with\n"
|
||||
"configurable partitioning, (e.g., MI300) this is the total number of L1I/sL1D caches in a partition.",
|
||||
"doc": (
|
||||
"The number of L1I/sL1D caches on the accelerators/GPUs in the "
|
||||
"system. On systems with configurable partitioning, (e.g., MI300) "
|
||||
"this is the total number of L1I/sL1D caches in a partition."
|
||||
),
|
||||
"name": "SQC per GPU",
|
||||
},
|
||||
)
|
||||
pipes_per_gpu: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The number of scheduler-pipes on the accelerators/GPUs in the system.",
|
||||
"doc": (
|
||||
"The number of scheduler-pipes on the accelerators/GPUs in the system."
|
||||
),
|
||||
"name": "Pipes per GPU",
|
||||
},
|
||||
)
|
||||
num_xcd: str = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"doc": "The total number of accelerator complex dies in a compute partition on the accelerators/GPUs in the\n"
|
||||
"system. For accelerators without partitioning (i.e., pre-MI300), this is considered to be one.",
|
||||
"doc": (
|
||||
"The total number of accelerator complex dies in a compute partition "
|
||||
"on the accelerators/GPUs in the system. For accelerators without "
|
||||
"partitioning (i.e., pre-MI300), this is considered to be one."
|
||||
),
|
||||
"name": "Num XCDs",
|
||||
"unit": "XCDs",
|
||||
},
|
||||
)
|
||||
num_hbm_channels: str = field(
|
||||
default=None,
|
||||
metadata={"doc": "Number of HBM channels", "name": "HBM channels"},
|
||||
metadata={
|
||||
"doc": "Number of HBM channels",
|
||||
"name": "HBM channels",
|
||||
},
|
||||
)
|
||||
|
||||
def get_hbm_channels(self):
|
||||
@@ -567,16 +633,16 @@ class MachineSpecs:
|
||||
all_populated = True
|
||||
data = {}
|
||||
# dataclass uses an OrderedDict for member variables, ensuring order consistency
|
||||
for field in fields(self):
|
||||
name = field.name
|
||||
for class_field in fields(self):
|
||||
name = class_field.name
|
||||
if not name.startswith("_"):
|
||||
value = getattr(self, name)
|
||||
if value is None:
|
||||
# check if we've marked it optional
|
||||
if (
|
||||
field.metadata
|
||||
and "optional" in field.metadata
|
||||
and field.metadata["optional"]
|
||||
class_field.metadata
|
||||
and "optional" in class_field.metadata
|
||||
and class_field.metadata["optional"]
|
||||
):
|
||||
pass
|
||||
else:
|
||||
@@ -592,27 +658,35 @@ class MachineSpecs:
|
||||
return pd.DataFrame(data, index=[0])
|
||||
|
||||
def __repr__(self):
|
||||
topstr = "Machine Specifications: describing the state of the machine that ROCm Compute Profiler data was collected on.\n"
|
||||
topstr = (
|
||||
"Machine Specifications: describing the state of the machine that "
|
||||
"ROCm Compute Profiler data was collected on.\n"
|
||||
)
|
||||
data = []
|
||||
for field in fields(self):
|
||||
name = field.name
|
||||
for class_field in fields(self):
|
||||
name = class_field.name
|
||||
if not name.startswith("_"):
|
||||
_data = {}
|
||||
value = getattr(self, name)
|
||||
if field.metadata:
|
||||
if class_field.metadata:
|
||||
# check out of table before any re-naming for pretty-printing
|
||||
if "intable" in field.metadata and not field.metadata["intable"]:
|
||||
if (
|
||||
"intable" in class_field.metadata
|
||||
and not class_field.metadata["intable"]
|
||||
):
|
||||
if name == "version":
|
||||
topstr += f"Output version: {value}\n"
|
||||
else:
|
||||
console_error(f"Unknown out of table printing field: {name}")
|
||||
console_error(
|
||||
f"Unknown out of table printing field: {name}"
|
||||
)
|
||||
continue
|
||||
if "name" in field.metadata:
|
||||
name = field.metadata["name"]
|
||||
if "unit" in field.metadata:
|
||||
_data["Unit"] = field.metadata["unit"]
|
||||
if "doc" in field.metadata:
|
||||
_data["Description"] = field.metadata["doc"]
|
||||
if "name" in class_field.metadata:
|
||||
name = class_field.metadata["name"]
|
||||
if "unit" in class_field.metadata:
|
||||
_data["Unit"] = class_field.metadata["unit"]
|
||||
if "doc" in class_field.metadata:
|
||||
_data["Description"] = class_field.metadata["doc"]
|
||||
_data["Spec"] = name
|
||||
_data["Value"] = value
|
||||
data.append(_data)
|
||||
@@ -660,7 +734,10 @@ def run(cmd, exit_on_error=False):
|
||||
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except FileNotFoundError as e:
|
||||
console_error(
|
||||
f"Unable to parse specs. Can't find ROCm asset: {e.filename}\nTry passing a path to an existing workload results in 'analyze' mode."
|
||||
(
|
||||
f"Unable to parse specs. Can't find ROCm asset: {e.filename}\n"
|
||||
"Try passing a path to an existing workload results in 'analyze' mode."
|
||||
)
|
||||
)
|
||||
|
||||
if exit_on_error:
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import copy
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
@@ -98,8 +97,10 @@ def convert_time_columns(df, time_unit):
|
||||
numeric_values = pd.to_numeric(
|
||||
df_copy.loc[mask, col], errors="coerce"
|
||||
)
|
||||
df_copy.loc[mask, col] = numeric_values / config.TIME_UNITS[time_unit]
|
||||
except:
|
||||
df_copy.loc[mask, col] = (
|
||||
numeric_values / config.TIME_UNITS[time_unit]
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Update the Unit column
|
||||
@@ -147,11 +148,11 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
|
||||
for data_source in panel["data source"]:
|
||||
for type, table_config in data_source.items():
|
||||
# If block filtering was used during analysis, then dont use profiling config
|
||||
# If block filtering was used in profiling config, only show those panels
|
||||
# If block filtering not used in profiling config, show all panels
|
||||
# Skip this table if table id or panel id is not present in block filters
|
||||
# However, always show panel id <= 100
|
||||
# If block filtering was used during analysis, then don't use profiling
|
||||
# config. If block filtering was used in profiling config, only show
|
||||
# those panels. If block filtering not used in profiling config, show
|
||||
# all panels. Skip this table if table id or panel id is not present
|
||||
# in block filters. However, always show panel id <= 100.
|
||||
if (
|
||||
not args.filter_metrics
|
||||
and filter_panel_ids
|
||||
@@ -165,13 +166,16 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
+ str(table_config["id"] % 100)
|
||||
)
|
||||
console_log(
|
||||
f"Not showing table not selected during profiling: {table_id_str} {table_config['title']}"
|
||||
f"Not showing table not selected during profiling: "
|
||||
f"{table_id_str} "
|
||||
f"{table_config['title']}"
|
||||
)
|
||||
continue
|
||||
|
||||
# Show roofline
|
||||
# Check if we have filter_metrics for analyze stage:
|
||||
# no filter_metrics = show all, filter_metrics containing "4" = user requesting roofline chart
|
||||
# no filter_metrics = show all,
|
||||
# filter_metrics containing "4" = user requesting roofline chart
|
||||
if panel_id == 400 and (
|
||||
not args.filter_metrics or "4" in args.filter_metrics
|
||||
):
|
||||
@@ -179,7 +183,8 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
continue
|
||||
|
||||
# Metrics baseline comparison mode
|
||||
# We cannot guarantee that all runs have the same metrics. Only show common metrics.
|
||||
# We cannot guarantee that all runs have the same metrics.
|
||||
# Only show common metrics.
|
||||
if (
|
||||
type == "metric_table"
|
||||
and "Metric" in table_config["header"].values()
|
||||
@@ -191,7 +196,9 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
if not common_metrics:
|
||||
common_metrics = set(data.dfs[table_config["id"]]["Metric"])
|
||||
else:
|
||||
common_metrics &= set(data.dfs[table_config["id"]]["Metric"])
|
||||
common_metrics &= set(
|
||||
data.dfs[table_config["id"]]["Metric"]
|
||||
)
|
||||
# Apply common metrics across all runs
|
||||
# Reindex all runs based on first run
|
||||
initial_index = None
|
||||
@@ -217,7 +224,8 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
|
||||
for header in list(base_df.keys()):
|
||||
# For raw csv table, columns cannot be filtered
|
||||
# If columns are filtered, then skip the headers not in filtered columns
|
||||
# If columns are filtered, then skip the headers not in
|
||||
# filtered columns
|
||||
if (
|
||||
type == "raw_csv_table"
|
||||
or not args.cols
|
||||
@@ -234,7 +242,8 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
)
|
||||
and header == "Kernel_Name"
|
||||
):
|
||||
# NB: the width of kernel name might depend on the header of the table.
|
||||
# NB: the width of kernel name might depend
|
||||
# on the header of the table.
|
||||
if table_config["source"] == "pmc_kernel_top.csv":
|
||||
adjusted_name = base_df["Kernel_Name"].apply(
|
||||
lambda x: string_multiple_lines(x, 40, 3)
|
||||
@@ -255,10 +264,13 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
cur_df = data.dfs[table_config["id"]]
|
||||
|
||||
if args.time_unit and has_time_data(base_df):
|
||||
cur_df = convert_time_columns(cur_df, args.time_unit)
|
||||
cur_df = convert_time_columns(
|
||||
cur_df, args.time_unit
|
||||
)
|
||||
|
||||
if (type == "raw_csv_table") or (
|
||||
type == "metric_table" and (not header in hidden_cols)
|
||||
type == "metric_table"
|
||||
and (not header in hidden_cols)
|
||||
):
|
||||
if run != base_run:
|
||||
# calc percentage over the baseline
|
||||
@@ -304,9 +316,9 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
+ "%)"
|
||||
)
|
||||
df = pd.concat([df, t_df], axis=1)
|
||||
|
||||
# DEBUG: When in a CI setting and flag is set,
|
||||
# then verify metrics meet threshold requirement
|
||||
# then verify metrics meet threshold
|
||||
# requirement
|
||||
if (
|
||||
header in ["Value", "Count", "Avg"]
|
||||
and t_df_pretty.abs()
|
||||
@@ -319,14 +331,15 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
t_df_pretty.abs() > args.report_diff
|
||||
]
|
||||
console_warning(
|
||||
"Dataframe diff exceeds %s threshold requirement\nSee metric %s"
|
||||
"Dataframe diff exceeds %s "
|
||||
"threshold requirement\n"
|
||||
"See metric %s"
|
||||
% (
|
||||
str(args.report_diff) + "%",
|
||||
violation_idx.to_numpy(),
|
||||
)
|
||||
)
|
||||
console_warning(df)
|
||||
|
||||
else:
|
||||
cur_df_copy = copy.deepcopy(cur_df)
|
||||
cur_df_copy[header] = [
|
||||
@@ -337,7 +350,9 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
)
|
||||
for x in base_df[header]
|
||||
]
|
||||
df = pd.concat([df, cur_df_copy[header]], axis=1)
|
||||
df = pd.concat(
|
||||
[df, cur_df_copy[header]], axis=1
|
||||
)
|
||||
|
||||
if not df.empty:
|
||||
# subtitle for each table in a panel if existing
|
||||
@@ -348,22 +363,23 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
)
|
||||
|
||||
# Check if any column in df is empty
|
||||
is_empty_columns_exist = any(
|
||||
[
|
||||
df.columns[col_idx]
|
||||
for col_idx in range(len(df.columns))
|
||||
if df.replace("", None).iloc[:, col_idx].isnull().all()
|
||||
]
|
||||
)
|
||||
is_empty_columns_exist = any([
|
||||
df.columns[col_idx]
|
||||
for col_idx in range(len(df.columns))
|
||||
if df.replace("", None).iloc[:, col_idx].isnull().all()
|
||||
])
|
||||
# Do not print the table if any column is empty
|
||||
if is_empty_columns_exist:
|
||||
if "title" in table_config:
|
||||
console_log(
|
||||
f"Not showing table with empty column(s): {table_id_str} {table_config['title']}"
|
||||
f"Not showing table with empty column(s): "
|
||||
f"{table_id_str} "
|
||||
f"{table_config['title']}"
|
||||
)
|
||||
else:
|
||||
console_log(
|
||||
f"Not showing table with empty column(s): {table_id_str}"
|
||||
f"Not showing table with empty column(s): "
|
||||
f"{table_id_str}"
|
||||
)
|
||||
if (
|
||||
"title" in table_config
|
||||
@@ -383,7 +399,8 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
p.joinpath(table_id_str.replace(" ", "_") + ".csv"),
|
||||
index=False,
|
||||
)
|
||||
# Only show top N kernels (as specified in --max-kernel-num) in "Top Stats" section
|
||||
# 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"
|
||||
@@ -398,17 +415,17 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
transpose = (
|
||||
type != "raw_csv_table"
|
||||
and "columnwise" in table_config
|
||||
and table_config["columnwise"] == True
|
||||
and table_config["columnwise"]
|
||||
)
|
||||
if not is_empty_columns_exist:
|
||||
|
||||
# enable mem_chart only with single run
|
||||
if (
|
||||
"cli_style" in table_config
|
||||
and table_config["cli_style"] == "mem_chart"
|
||||
and len(runs) == 1
|
||||
):
|
||||
# NB: to avoid broken test with arbitrary number with "--cols" option
|
||||
# NB: to avoid broken test with
|
||||
# arbitrary number with "--cols" option
|
||||
if "Metric" in df.columns and "Value" in df.columns:
|
||||
ss += mem_chart.plot_mem_chart(
|
||||
"",
|
||||
@@ -442,7 +459,8 @@ def show_roof_plot(roof_plot):
|
||||
print(roof_plot)
|
||||
else:
|
||||
console_error(
|
||||
"Cannot create roofline plot for CLI with incomplete/missing roofline profiling data.",
|
||||
"Cannot create roofline plot for CLI with incomplete/missing "
|
||||
"roofline profiling data.",
|
||||
exit=False,
|
||||
)
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
##############################################################################
|
||||
|
||||
|
||||
import glob
|
||||
import io
|
||||
import json
|
||||
@@ -74,7 +73,8 @@ def add_counter_extra_config_input_yaml(
|
||||
"""
|
||||
Add a new counter to the rocprofiler-sdk dictionary.
|
||||
Initialize missing parts if data is empty or incomplete.
|
||||
Enforces that 'architectures' and 'properties' are lists for correct YAML list serialization.
|
||||
Enforces that 'architectures' and 'properties' are lists
|
||||
for correct YAML list serialization.
|
||||
Overwrites the counter if it already exists.
|
||||
|
||||
Args:
|
||||
@@ -189,7 +189,7 @@ def get_version(rocprof_compute_home) -> dict:
|
||||
found = True
|
||||
versionDir = dir
|
||||
break
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
if not found:
|
||||
console_error("Cannot find VERSION file at {}".format(searchDirs))
|
||||
@@ -204,7 +204,7 @@ def get_version(rocprof_compute_home) -> dict:
|
||||
MODE = "dev"
|
||||
else:
|
||||
raise Exception(output)
|
||||
except:
|
||||
except Exception:
|
||||
try:
|
||||
shaFile = path(versionDir).joinpath("VERSION.sha").absolute().resolve()
|
||||
with open(shaFile, "r") as file:
|
||||
@@ -263,7 +263,10 @@ def detect_rocprof(args):
|
||||
rocprof_path = shutil.which(rocprof_cmd)
|
||||
if not rocprof_path:
|
||||
console_error(
|
||||
"Please verify installation or set ROCPROF environment variable with full path."
|
||||
(
|
||||
"Please verify installation or set ROCPROF environment variable "
|
||||
"with full path."
|
||||
)
|
||||
)
|
||||
else:
|
||||
# Resolve any sym links in file path
|
||||
@@ -271,7 +274,8 @@ def detect_rocprof(args):
|
||||
console_debug("ROC Profiler: " + str(rocprof_path))
|
||||
|
||||
console_debug("rocprof_cmd is {}".format(str(rocprof_cmd)))
|
||||
return rocprof_cmd # TODO: Do we still need to return this? It's not being used in the function call
|
||||
# TODO: Do we still need to return this? It's not being used in the function call
|
||||
return rocprof_cmd
|
||||
|
||||
|
||||
def store_app_cmd(args):
|
||||
@@ -364,14 +368,12 @@ def get_agent_dict(data):
|
||||
# Returns a dictionary that maps agent ID to GPU ID
|
||||
# starting at 0.
|
||||
def get_gpuid_dict(data):
|
||||
|
||||
agents = data["rocprofiler-sdk-tool"][0]["agents"]
|
||||
|
||||
agent_list = []
|
||||
|
||||
# Get agent ID and node_id for GPU agents only
|
||||
for agent in agents:
|
||||
|
||||
if agent["type"] == 2:
|
||||
agent_id = agent["id"]["handle"]
|
||||
node_id = agent["node_id"]
|
||||
@@ -419,12 +421,13 @@ def v3_json_get_dispatches(data):
|
||||
|
||||
|
||||
def v3_json_to_csv(json_file_path, csv_file_path):
|
||||
|
||||
f = open(json_file_path, "rt")
|
||||
data = json.load(f)
|
||||
|
||||
dispatch_records = v3_json_get_dispatches(data)
|
||||
dispatches = data["rocprofiler-sdk-tool"][0]["callback_records"]["counter_collection"]
|
||||
dispatches = data["rocprofiler-sdk-tool"][0]["callback_records"][
|
||||
"counter_collection"
|
||||
]
|
||||
kernel_symbols = data["rocprofiler-sdk-tool"][0]["kernel_symbols"]
|
||||
agents = get_agent_dict(data)
|
||||
pid = data["rocprofiler-sdk-tool"][0]["metadata"]["pid"]
|
||||
@@ -434,33 +437,30 @@ def v3_json_to_csv(json_file_path, csv_file_path):
|
||||
counter_info = v3_json_get_counters(data)
|
||||
|
||||
# CSV headers. If there are no dispatches we still end up with a valid CSV file.
|
||||
csv_data = dict.fromkeys(
|
||||
[
|
||||
"Dispatch_ID",
|
||||
"GPU_ID",
|
||||
"Queue_ID",
|
||||
"PID",
|
||||
"TID",
|
||||
"Grid_Size",
|
||||
"Workgroup_Size",
|
||||
"LDS_Per_Workgroup",
|
||||
"Scratch_Per_Workitem",
|
||||
"Arch_VGPR",
|
||||
"Accum_VGPR",
|
||||
"SGPR",
|
||||
"Wave_Size",
|
||||
"Kernel_Name",
|
||||
"Start_Timestamp",
|
||||
"End_Timestamp",
|
||||
"Correlation_ID",
|
||||
]
|
||||
)
|
||||
csv_data = dict.fromkeys([
|
||||
"Dispatch_ID",
|
||||
"GPU_ID",
|
||||
"Queue_ID",
|
||||
"PID",
|
||||
"TID",
|
||||
"Grid_Size",
|
||||
"Workgroup_Size",
|
||||
"LDS_Per_Workgroup",
|
||||
"Scratch_Per_Workitem",
|
||||
"Arch_VGPR",
|
||||
"Accum_VGPR",
|
||||
"SGPR",
|
||||
"Wave_Size",
|
||||
"Kernel_Name",
|
||||
"Start_Timestamp",
|
||||
"End_Timestamp",
|
||||
"Correlation_ID",
|
||||
])
|
||||
|
||||
for key in csv_data:
|
||||
csv_data[key] = []
|
||||
|
||||
for d in dispatches:
|
||||
|
||||
dispatch_info = d["dispatch_data"]["dispatch_info"]
|
||||
|
||||
agent_id = dispatch_info["agent_id"]["handle"]
|
||||
@@ -542,7 +542,8 @@ def v3_json_to_csv(json_file_path, csv_file_path):
|
||||
|
||||
def v3_counter_csv_to_v2_csv(counter_file, agent_info_filepath, converted_csv_file):
|
||||
"""
|
||||
Convert the counter file of csv output for a certain csv from rocprofv3 format to rocprfv2 format.
|
||||
Convert the counter file of csv output for a certain csv from rocprofv3 format
|
||||
to rocprfv2 format.
|
||||
This function is not for use of other csv out file such as kernel trace file.
|
||||
"""
|
||||
pd_counter_collections = pd.read_csv(counter_file)
|
||||
@@ -576,7 +577,8 @@ def v3_counter_csv_to_v2_csv(counter_file, agent_info_filepath, converted_csv_fi
|
||||
values="Counter_Value",
|
||||
).reset_index()
|
||||
|
||||
# NB: Agent_Id is int in older rocporfv3, now switched to string with prefix "Agent ". We need to make sure handle both cases.
|
||||
# NB: Agent_Id is int in older rocporfv3, now switched to string with prefix
|
||||
# "Agent ". We need to make sure handle both cases.
|
||||
console_debug(
|
||||
"The type of Agent ID from counter csv file is {}".format(
|
||||
result["Agent_Id"].dtype
|
||||
@@ -592,9 +594,10 @@ def v3_counter_csv_to_v2_csv(counter_file, agent_info_filepath, converted_csv_fi
|
||||
)
|
||||
except Exception as e:
|
||||
console_error(
|
||||
'Parsing rocprofv3 csv output: Error of getting "Agent_Id", the error message "{}"'.format(
|
||||
e
|
||||
)
|
||||
(
|
||||
'Parsing rocprofv3 csv output: Error of getting "Agent_Id", '
|
||||
'the error message "{}"'
|
||||
).format(e)
|
||||
)
|
||||
|
||||
# Grab the Wave_Front_Size column from agent info
|
||||
@@ -762,7 +765,10 @@ def run_prof(
|
||||
# Set counter definitions
|
||||
new_env["ROCPROFILER_METRICS_PATH"] = str(tmpfile_path.parent)
|
||||
console_debug(
|
||||
f"Adding env var for counter definitions: ROCPROFILER_METRICS_PATH={new_env['ROCPROFILER_METRICS_PATH']}"
|
||||
(
|
||||
"Adding env var for counter definitions: "
|
||||
f"ROCPROFILER_METRICS_PATH={new_env['ROCPROFILER_METRICS_PATH']}"
|
||||
)
|
||||
)
|
||||
|
||||
# set required env var for >= mi300
|
||||
@@ -836,7 +842,10 @@ def run_prof(
|
||||
return
|
||||
else:
|
||||
console_error(
|
||||
"rocpd output format is only supported with rocprofiler-sdk or rocprofv3."
|
||||
(
|
||||
"rocpd output format is only supported with "
|
||||
"rocprofiler-sdk or rocprofv3."
|
||||
)
|
||||
)
|
||||
elif rocprof_cmd.endswith("v2"):
|
||||
# rocprofv2 has separate csv files for each process
|
||||
@@ -863,12 +872,14 @@ def run_prof(
|
||||
)
|
||||
|
||||
if rocprof_cmd == "rocprofiler-sdk":
|
||||
# TODO: as rocprofv3 --kokkos-trace feature improves, rocprof-compute should make updates accordingly
|
||||
# TODO: as rocprofv3 --kokkos-trace feature improves,
|
||||
# rocprof-compute should make updates accordingly
|
||||
if "ROCPROF_HIP_RUNTIME_API_TRACE" in options:
|
||||
process_hip_trace_output(workload_dir, fbase)
|
||||
else:
|
||||
if "--kokkos-trace" in options:
|
||||
# TODO: as rocprofv3 --kokkos-trace feature improves, rocprof-compute should make updates accordingly
|
||||
# TODO: as rocprofv3 --kokkos-trace feature improves,
|
||||
# rocprof-compute should make updates accordingly
|
||||
process_kokkos_trace_output(workload_dir, fbase)
|
||||
elif "--hip-trace" in options:
|
||||
process_hip_trace_output(workload_dir, fbase)
|
||||
@@ -880,7 +891,10 @@ def run_prof(
|
||||
)
|
||||
else:
|
||||
console_warning(
|
||||
f"Cannot write results for {fbase}.csv due to no counter csv files generated."
|
||||
(
|
||||
f"Cannot write results for {fbase}.csv due to no counter "
|
||||
"csv files generated."
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
@@ -976,7 +990,9 @@ def pc_sampling_prof(
|
||||
for key, value in options.items():
|
||||
new_env[key] = value
|
||||
console_debug("pc sampling rocprof sdk env vars: {}".format(new_env))
|
||||
console_debug("pc sampling rocprof sdk user provided command: {}".format(appcmd))
|
||||
console_debug(
|
||||
"pc sampling rocprof sdk user provided command: {}".format(appcmd)
|
||||
)
|
||||
success, output = capture_subprocess_output(
|
||||
appcmd, new_env=new_env, profileMode=True
|
||||
)
|
||||
@@ -1011,7 +1027,8 @@ def pc_sampling_prof(
|
||||
def process_rocprofv3_output(rocprof_output, workload_dir, is_timestamps):
|
||||
"""
|
||||
rocprofv3 specific output processing.
|
||||
takes care of json or csv formats, for csv format, additional processing is performed.
|
||||
takes care of json or csv formats, for csv format,
|
||||
additional processing is performed.
|
||||
"""
|
||||
results_files_csv = {}
|
||||
|
||||
@@ -1059,12 +1076,15 @@ def process_rocprofv3_output(rocprof_output, workload_dir, is_timestamps):
|
||||
|
||||
results_files_csv = glob.glob(workload_dir + "/out/pmc_1/*/*_converted.csv")
|
||||
elif is_timestamps:
|
||||
# when the input is timestamps, we know counter csv file is not generated and will instead parse kernel trace file
|
||||
# when the input is timestamps, we know counter csv file
|
||||
# is not generated and will instead parse kernel trace file
|
||||
results_files_csv = glob.glob(
|
||||
workload_dir + "/out/pmc_1/*/*_kernel_trace.csv"
|
||||
)
|
||||
else:
|
||||
# when the input is not for timestamps, and counter csv file is not generated, we assume failed rocprof run and will completely bypass the file generation and merging for current pmc
|
||||
# when the input is not for timestamps, and counter csv file
|
||||
# is not generated, we assume failed rocprof run and will completely
|
||||
# bypass the file generation and merging for current pmc
|
||||
results_files_csv = []
|
||||
else:
|
||||
console_error("The output file of rocprofv3 can only support json or csv!!!")
|
||||
@@ -1121,7 +1141,6 @@ def process_hip_trace_output(workload_dir, fbase):
|
||||
|
||||
|
||||
def replace_timestamps(workload_dir):
|
||||
|
||||
if not path(workload_dir, "timestamps.csv").is_file():
|
||||
return
|
||||
|
||||
@@ -1173,7 +1192,9 @@ def detect_roofline(mspec):
|
||||
if "ROOFLINE_BIN" in os.environ.keys():
|
||||
rooflineBinary = os.environ["ROOFLINE_BIN"]
|
||||
if path(rooflineBinary).exists():
|
||||
msg = "Detected user-supplied binary --> ROOFLINE_BIN = %s\n" % rooflineBinary
|
||||
msg = (
|
||||
"Detected user-supplied binary --> ROOFLINE_BIN = %s\n" % rooflineBinary
|
||||
)
|
||||
console_warning("roofline", msg)
|
||||
# distro stays marked as override and path value is substituted in
|
||||
target_binary["path"] = rooflineBinary
|
||||
@@ -1196,7 +1217,7 @@ def detect_roofline(mspec):
|
||||
|
||||
# Must be a valid SLES machine
|
||||
elif (
|
||||
(type(sles_distro) == str and len(sles_distro) >= 3)
|
||||
(isinstance(sles_distro, str) and len(sles_distro) >= 3)
|
||||
and sles_distro[:2] == "15" # confirm string and len
|
||||
and int(sles_distro[3]) >= 6 # SLES15 and SP >= 6
|
||||
):
|
||||
@@ -1208,7 +1229,9 @@ def detect_roofline(mspec):
|
||||
distro = "22.04"
|
||||
|
||||
else:
|
||||
console_error("roofline", "Cannot find a valid binary for your operating system")
|
||||
console_error(
|
||||
"roofline", "Cannot find a valid binary for your operating system"
|
||||
)
|
||||
|
||||
# distro gets assigned, to follow default roofline bin location and nomenclature
|
||||
target_binary["distro"] = distro
|
||||
@@ -1250,14 +1273,16 @@ def mibench(args, mspec):
|
||||
|
||||
# Distro is valid but cant find rocm ver
|
||||
found = False
|
||||
for path in binary_paths:
|
||||
if pathlib.Path(path).exists():
|
||||
for binary_path in binary_paths:
|
||||
if pathlib.Path(binary_path).exists():
|
||||
found = True
|
||||
path_to_binary = path
|
||||
path_to_binary = binary_path
|
||||
break
|
||||
|
||||
if not found:
|
||||
console_error("roofline", "Unable to locate expected binary (%s)." % binary_paths)
|
||||
console_error(
|
||||
"roofline", "Unable to locate expected binary (%s)." % binary_paths
|
||||
)
|
||||
|
||||
my_args = [
|
||||
path_to_binary,
|
||||
@@ -1303,7 +1328,7 @@ def flatten_tcc_info_across_xcds(file, xcds, tcc_channel_per_xcd):
|
||||
# filter the channel index only
|
||||
p = re.compile(r"\[(\d+)\]")
|
||||
# pick up the 1st element only
|
||||
r = (
|
||||
r = ( # noqa: E731
|
||||
lambda match: "["
|
||||
+ str(int(match.group(1)) + i * tcc_channel_per_xcd)
|
||||
+ "]"
|
||||
@@ -1434,7 +1459,10 @@ def reverse_multi_index_df_pmc(final_df):
|
||||
|
||||
def merge_counters_spatial_multiplex(df_multi_index):
|
||||
"""
|
||||
For spatial multiplexing, this merges counter values for the same kernel that runs on different devices. For time stamp, start time stamp will use median while for end time stamp, it will be equal to the summation between median start stamp and median delta time.
|
||||
For spatial multiplexing, this merges counter values for the same kernel that
|
||||
runs on different devices. For time stamp, start time stamp will use median
|
||||
while for end time stamp, it will be equal to the summation between median
|
||||
start stamp and median delta time.
|
||||
"""
|
||||
non_counter_column_index = [
|
||||
"Dispatch_ID",
|
||||
@@ -1467,7 +1495,8 @@ def merge_counters_spatial_multiplex(df_multi_index):
|
||||
|
||||
result_dfs = []
|
||||
|
||||
# TODO: will need optimize to avoid this convertion to single index format and do merge directly on multi-index dataframe
|
||||
# TODO: will need to optimize to avoid this conversion to single index format
|
||||
# and do merge directly on multi-index dataframe
|
||||
dfs, coll_levels = reverse_multi_index_df_pmc(df_multi_index)
|
||||
|
||||
for df in dfs:
|
||||
@@ -1490,7 +1519,9 @@ def merge_counters_spatial_multiplex(df_multi_index):
|
||||
|
||||
# Process non-counter columns
|
||||
for col in [
|
||||
col for col in non_counter_column_index if col not in expired_column_index
|
||||
col
|
||||
for col in non_counter_column_index
|
||||
if col not in expired_column_index
|
||||
]:
|
||||
if col == "Start_Timestamp":
|
||||
# For Start_Timestamp, take the median
|
||||
@@ -1504,7 +1535,8 @@ def merge_counters_spatial_multiplex(df_multi_index):
|
||||
# For other non-counter columns, take the first occurrence (0th row)
|
||||
merged_row[col] = group.iloc[0][col]
|
||||
|
||||
# Process counter columns (assumed to be all columns not in non_counter_column_index)
|
||||
# Process counter columns (assumed to be all columns not in
|
||||
# non_counter_column_index)
|
||||
counter_columns = [
|
||||
col for col in group.columns if col not in non_counter_column_index
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user