code formatting updates

Signed-off-by: Karl W Schulz <karl.schulz@amd.com>


[ROCm/rocprofiler-compute commit: 79b877d679]
This commit is contained in:
Karl W Schulz
2024-02-16 15:34:28 -06:00
committed by Karl W. Schulz
parent abdaee0a2d
commit 4bfcf9b8a8
29 changed files with 896 additions and 639 deletions
@@ -34,6 +34,7 @@ import pandas as pd
MAX_SERVER_SEL_DELAY = 5000 # 5 sec connection timeout
class DatabaseConnector:
def __init__(self, args):
self.args = args
@@ -45,17 +46,22 @@ class DatabaseConnector:
"port": str(self.args.port),
"team": self.args.team,
"workload": self.args.workload,
"db": None
"db": None,
}
self.interaction_type: str = None #set to 'import' or 'remove' based on user arguments
self.interaction_type: str = (
None # set to 'import' or 'remove' based on user arguments
)
self.client: MongoClient = None
@demarcate
def prep_import(self, profile_and_export=False):
if profile_and_export:
self.connection_info['workload'] = os.path.join(self.connection_info['workload'], self.args.target)
self.connection_info["workload"] = os.path.join(
self.connection_info["workload"], self.args.target
)
# Extract SoC and workload name from sysinfo.csv
sys_info = os.path.join(self.connection_info['workload'], "sysinfo.csv")
sys_info = os.path.join(self.connection_info["workload"], "sysinfo.csv")
if os.path.isfile(sys_info):
sys_info = pd.read_csv(sys_info)
soc = sys_info["name"][0]
@@ -63,7 +69,9 @@ class DatabaseConnector:
else:
error("[database] Unable to parse SoC and/or workload name from sysinfo.csv")
self.connection_info["db"] = "omniperf_" + str(self.args.team) + "_" + str(name) + "_" + str(soc)
self.connection_info["db"] = (
"omniperf_" + str(self.args.team) + "_" + str(name) + "_" + str(soc)
)
@demarcate
def db_import(self):
@@ -72,7 +80,11 @@ class DatabaseConnector:
file = "blank"
for file in tqdm(os.listdir(self.connection_info["workload"])):
if file.endswith(".csv"):
logging.info("[database] Uploading: %s" % self.connection_info["workload"] + "/" + file)
logging.info(
"[database] Uploading: %s" % self.connection_info["workload"]
+ "/"
+ file
)
try:
fileName = file[0 : file.find(".")]
cmd = (
@@ -101,69 +113,85 @@ class DatabaseConnector:
@demarcate
def db_remove(self):
db_to_remove = self.client[self.connection_info['workload']]
db_to_remove = self.client[self.connection_info["workload"]]
# check the collection names on the database
col_list = db_to_remove.list_collection_names()
self.client.drop_database(db_to_remove)
db = self.client["workload_names"]
col = db["names"]
col.delete_many({"name": self.connection_info['workload']})
logging.info("[database] Successfully removed %s" % self.connection_info['workload'])
col.delete_many({"name": self.connection_info["workload"]})
logging.info(
"[database] Successfully removed %s" % self.connection_info["workload"]
)
@abstractmethod
def pre_processing(self):
"""Perform any pre-processing steps prior to database conncetion.
"""
"""Perform any pre-processing steps prior to database conncetion."""
logging.debug("[database] pre-processing database connection")
if not self.args.remove and not self.args.upload:
error("Either -i/--import or -r/--remove is required in database mode")
self.interaction_type = 'import' if self.args.upload else 'remove'
self.interaction_type = "import" if self.args.upload else "remove"
# Detect interaction type
if self.interaction_type == 'remove':
if self.interaction_type == "remove":
logging.debug("[database] validating arguments for --remove workflow")
is_full_workload_name = self.args.workload.count("_") >= 3
if not is_full_workload_name:
error("-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. omniperf_asw_vcopy_mi200)")
error(
"-w/--workload is not valid. Please use full workload name as seen in GUI when removing (i.e. omniperf_asw_vcopy_mi200)"
)
if self.connection_info['host'] == None or self.connection_info['username'] == None:
error("-H/--host and -u/--username are required when interaction type is set to %s" % self.interaction_type)
if self.connection_info['workload'] == "admin" or self.connection_info['workload'] == "local":
error("Cannot remove %s. Try again." % self.connection_info['workload'])
if (
self.connection_info["host"] == None
or self.connection_info["username"] == None
):
error(
"-H/--host and -u/--username are required when interaction type is set to %s"
% self.interaction_type
)
if (
self.connection_info["workload"] == "admin"
or self.connection_info["workload"] == "local"
):
error("Cannot remove %s. Try again." % self.connection_info["workload"])
else:
logging.debug("[database] validating arguments for --import workflow")
if (
self.connection_info['host'] == None
or self.connection_info['team'] == None
or self.connection_info['username'] == None
or self.connection_info['workload'] == None
self.connection_info["host"] == None
or self.connection_info["team"] == None
or self.connection_info["username"] == None
or self.connection_info["workload"] == None
):
error("-H/--host, -w/--workload, -u/--username, and -t/--team are all required when interaction type is set to %s" % self.interaction_type)
error(
"-H/--host, -w/--workload, -u/--username, and -t/--team are all required when interaction type is set to %s"
% self.interaction_type
)
if os.path.isdir(os.path.abspath(self.connection_info['workload'])):
is_workload_empty(self.connection_info['workload'])
if os.path.isdir(os.path.abspath(self.connection_info["workload"])):
is_workload_empty(self.connection_info["workload"])
else:
error("--workload is invalid. Please pass path to a valid directory.")
if len(self.args.team) > 13:
error("--team exceeds 13 character limit. Try again.")
# format path properly
self.connection_info['workload'] = os.path.abspath(self.connection_info['workload'])
self.connection_info["workload"] = os.path.abspath(
self.connection_info["workload"]
)
# Detect password
if self.connection_info['password'] == "":
if self.connection_info["password"] == "":
try:
self.connection_info['password'] = getpass.getpass()
self.connection_info["password"] = getpass.getpass()
except Exception as e:
error("[database] PASSWORD ERROR %s" % e)
else:
logging.info("[database] Password recieved")
else:
password = self.connection_info['password']
password = self.connection_info["password"]
# Establish client connection
connection_str = (
@@ -177,11 +205,10 @@ class DatabaseConnector:
+ self.connection_info["port"]
+ "/?authSource=admin"
)
self.client = MongoClient(connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY)
self.client = MongoClient(
connection_str, serverSelectionTimeoutMS=MAX_SERVER_SEL_DELAY
)
try:
self.client.server_info()
except:
error("[database] Unable to connect to the DB server.")
@@ -50,11 +50,12 @@ top_stats_build_in_config = {
"id": 1,
"title": "Dispatch List",
"data source": [{"raw_csv_table": {"id": 2, "source": "pmc_dispatch_info.csv"}}],
}
},
}
time_units = {"s": 10**9, "ms": 10**6, "us": 10**3, "ns": 1}
def load_sys_info(f):
"""
Load sys running info from csv file to a df.
@@ -231,4 +232,4 @@ def is_single_panel_config(root_dir, supported_archs):
return False
else:
logging.error("Found multiple panel config sets but incomplete for all archs!")
sys.exit(1)
sys.exit(1)
+28 -27
View File
@@ -34,7 +34,8 @@ pd.set_option(
"mode.chained_assignment", None
) # ignore SettingWithCopyWarning pandas warning
IS_DARK = True #TODO: Remove hardcoded in favor of class property
IS_DARK = True # TODO: Remove hardcoded in favor of class property
##################
# HELPER FUNCTIONS
@@ -168,31 +169,31 @@ def build_bar_chart(display_df, table_config, barchart_elements, norm_filt):
)
# L2 Cache per channel
# elif table_config["id"] in barchart_elements["l2_cache_per_chan"]:
# nested_bar = {}
# channels = []
# for colName, colData in display_df.items():
# if colName == "Channel":
# channels = list(colData.values)
# else:
# display_df[colName] = [
# x.astype(float) if x != "" and x != None else float(0)
# for x in display_df[colName]
# ]
# nested_bar[colName] = list(display_df[colName])
# for group, metric in nested_bar.items():
# d_figs.append(
# px.bar(
# title=group[0 : group.rfind("(")],
# x=channels,
# y=metric,
# labels={
# "x": "Channel",
# "y": group[group.rfind("(") + 1 : len(group) - 1].replace(
# "per", norm_filt
# ),
# },
# ).update_yaxes(rangemode="nonnegative")
# )
# nested_bar = {}
# channels = []
# for colName, colData in display_df.items():
# if colName == "Channel":
# channels = list(colData.values)
# else:
# display_df[colName] = [
# x.astype(float) if x != "" and x != None else float(0)
# for x in display_df[colName]
# ]
# nested_bar[colName] = list(display_df[colName])
# for group, metric in nested_bar.items():
# d_figs.append(
# px.bar(
# title=group[0 : group.rfind("(")],
# x=channels,
# y=metric,
# labels={
# "x": "Channel",
# "y": group[group.rfind("(") + 1 : len(group) - 1].replace(
# "per", norm_filt
# ),
# },
# ).update_yaxes(rangemode="nonnegative")
# )
# Speed-of-light bar chart
elif table_config["id"] in barchart_elements["sol"]:
@@ -376,4 +377,4 @@ def build_table_chart(
# print("DATA: \n", display_df.to_dict('records'))
d_figs.append(d_t)
return d_figs
# print(d_t.columns)
# print(d_t.columns)
@@ -52,9 +52,9 @@ def insert_chart_data(mem_data, base_data):
return G(
className="data",
children=[
# ----------------------------------------
# Instr Buff Block
#TODO: double check wave_occupancy
# ----------------------------------------
# Instr Buff Block
# TODO: double check wave_occupancy
Text(
x="52",
y="313",
@@ -73,8 +73,8 @@ def insert_chart_data(mem_data, base_data):
fontWeight="bold",
children=memchart_values["Wave Life"],
),
# ----------------------------------------
# Instr Dispatch Block
# ----------------------------------------
# Instr Dispatch Block
Text(
x="386",
y="46",
@@ -139,8 +139,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["BR"],
),
# ----------------------------------------
# Exec Block
# ----------------------------------------
# Exec Block
Text(
x="480",
y="99",
@@ -198,8 +198,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["Workgroups"],
),
# ----------------------------------------
# LDS Block
# ----------------------------------------
# LDS Block
Text(
x="723",
y="78",
@@ -224,8 +224,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["LDS Latency"],
),
# ----------------------------------------
# Vector L1 Cache Block
# ----------------------------------------
# Vector L1 Cache Block
Text(
x="708",
y="204",
@@ -306,8 +306,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["VL1_L2 Atomic"],
),
# ----------------------------------------
# Scalar L1D Cache Block
# ----------------------------------------
# Scalar L1D Cache Block
Text(
x="709",
y="384",
@@ -356,8 +356,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["VL1D_L2 Atomic"],
),
# ----------------------------------------
# Instr L1 Cache Block
# ----------------------------------------
# Instr L1 Cache Block
Text(
x="492",
y="498",
@@ -390,8 +390,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["IL1_L2 Rd"],
),
# ----------------------------------------
# L2 Cache Block(inside)
# ----------------------------------------
# L2 Cache Block(inside)
Text(
x="1145",
y="213",
@@ -440,8 +440,8 @@ def insert_chart_data(mem_data, base_data):
fontSize="12px",
children=memchart_values["L2 Wr Lat"],
),
# ----------------------------------------
# Fabric Block
# ----------------------------------------
# Fabric Block
Text(
x="1317",
y="243",
@@ -25,7 +25,7 @@
import os
import sys
import logging
import glob
import glob
import re
import subprocess
import pandas as pd
@@ -34,6 +34,7 @@ from utils.utils import error
cache = dict()
# Note: shortener is now dependent on a rocprof install with llvm
def kernel_name_shortener(workload_dir, level):
def shorten_file(df, level):
@@ -134,6 +135,8 @@ def kernel_name_shortener(workload_dir, level):
modified_df = shorten_file(orig_df, level)
modified_df.to_csv(fpath, index=False)
except pd.errors.EmptyDataError:
logging.debug("[profiling] Skipping shortening on empty csv: %s" % str(fpath))
logging.debug(
"[profiling] Skipping shortening on empty csv: %s" % str(fpath)
)
logging.info("[profiling] Kernel_Name shortening complete.")
logging.info("[profiling] Kernel_Name shortening complete.")
@@ -1039,4 +1039,4 @@ if __name__ == "__main__":
arch = ""
normal_unit = "per_kernel"
print(plot_mem_chart(arch, normal_unit, metric_dict))
print(plot_mem_chart(arch, normal_unit, metric_dict))
@@ -174,6 +174,7 @@ def to_round(a, b):
else:
return round(a, b)
def to_quantile(a, b):
if a is None:
return None
@@ -182,6 +183,7 @@ def to_quantile(a, b):
else:
raise Exception("to_quantile: unsupported type.")
def to_mod(a, b):
if isinstance(a, pd.core.series.Series):
return a.mod(b)
@@ -402,6 +404,7 @@ def gen_counter_list(formula):
return visited, counters
def calc_builtin_var(var, sys_info):
"""
Calculate build-in variable based on sys_info:
@@ -414,6 +417,7 @@ def calc_builtin_var(var, sys_info):
print("Don't support", var)
sys.exit(1)
def build_dfs(archConfigs, filter_metrics, sys_info):
"""
- Build dataframe for each type of data source within each panel.
@@ -447,7 +451,6 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
type == "metric_table"
and "metric" in data_config
and "placeholder_range" in data_config["metric"]
):
# print(data_config["metric"])
new_metrics = {}
@@ -475,16 +478,14 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
data_config["metric"] = new_metrics
# print(data_config)
# print(data_config["metric"])
for panel_id, panel in archConfigs.panel_configs.items():
for data_source in panel["data source"]:
for type, data_config in data_source.items():
if type == "metric_table":
headers = ["Metric_ID"]
data_source_idx = str(data_config["id"] // 100)
if (data_source_idx != 0 or
data_source_idx in filter_metrics
):
if data_source_idx != 0 or data_source_idx in filter_metrics:
metric_list[data_source_idx] = panel["title"]
if (
"cli_style" in data_config
@@ -506,9 +507,9 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
headers.append("coll_level")
if "tips" in data_config["header"].keys():
headers.append(data_config["header"]["tips"])
df = pd.DataFrame(columns=headers)
i = 0
for key, entries in data_config["metric"].items():
data_source_idx = (
@@ -532,7 +533,7 @@ def build_dfs(archConfigs, filter_metrics, sys_info):
):
values.append(metric_idx)
values.append(key)
metric_list[data_source_idx] = data_config["title"]
if (
@@ -687,9 +688,9 @@ def eval_metric(dfs, dfs_type, sys_info, soc_spec, raw_pmc_df, debug):
ammolite__numWavesPerCU = sys_info.maxWavesPerCU # todo: check do we still need it
ammolite__numSQC = sys_info.numSQC
ammolite__L2Banks = sys_info.L2Banks
ammolite__LDSBanks = (
soc_spec['LDSBanks']
) # todo: eventually switch this over to sys_info. its a new spec so trying not to break compatibility
ammolite__LDSBanks = soc_spec[
"LDSBanks"
] # todo: eventually switch this over to sys_info. its a new spec so trying not to break compatibility
ammolite__freq = sys_info.cur_sclk # todo: check do we still need it
ammolite__mclk = sys_info.cur_mclk
ammolite__sclk = sys_info.sclk
@@ -910,7 +911,9 @@ def load_kernel_top(workload, dir):
if file.exists():
tmp[id] = pd.read_csv(file)
else:
logging.info("Warning: Issue loading top kernels. Check pmc_kernel_top.csv")
logging.info(
"Warning: Issue loading top kernels. Check pmc_kernel_top.csv"
)
elif "from_csv_columnwise" in df.columns:
# NB:
# Another way might be doing transpose in tty like metric_table.
@@ -923,7 +926,9 @@ def load_kernel_top(workload, dir):
# so tty could detect them and show them correctly in comparison.
tmp[id].columns = ["Info"]
else:
logging.info("Warning: Issue loading top kernels. Check pmc_kernel_top.csv")
logging.info(
"Warning: Issue loading top kernels. Check pmc_kernel_top.csv"
)
workload.dfs.update(tmp)
@@ -957,6 +962,7 @@ def build_comparable_columns(time_unit):
return comparable_columns
def correct_sys_info(df, specs_correction):
"""
Correct system spec items manually
@@ -1012,5 +1018,3 @@ def correct_sys_info(df, specs_correction):
df[name_map[k]] = v
return df
@@ -96,35 +96,36 @@ def get_color(catagory):
# Plot BW at each cache level
# -------------------------------------------------------------------------------------
def calc_ceilings(roofline_parameters, dtype, benchmark_data):
"""Given benchmarking data, calculate ceilings (or peak performance) for empirical roofline
"""
"""Given benchmarking data, calculate ceilings (or peak performance) for empirical roofline"""
# TODO: This is where filtering by memory level will need to occur for standalone
graphPoints = {"hbm": [], "l2": [], "l1": [], "lds": [], "valu": [], "mfma": []}
if roofline_parameters['mem_level'] == "ALL":
if roofline_parameters["mem_level"] == "ALL":
cacheHierarchy = ["HBM", "L2", "L1", "LDS"]
else:
cacheHierarchy = roofline_parameters['mem_level']
cacheHierarchy = roofline_parameters["mem_level"]
x1 = y1 = x2 = y2 = -1
x1_mfma = y1_mfma = x2_mfma = y2_mfma = -1
target_precision = dtype[2:]
if dtype != "FP16" and dtype != "I8":
peakOps = float(
benchmark_data[dtype + "Flops"][roofline_parameters['device_id']]
)
peakOps = float(benchmark_data[dtype + "Flops"][roofline_parameters["device_id"]])
for i in range(0, len(cacheHierarchy)):
# Plot BW line
# Plot BW line
logging.debug("[roofline] Current cache level is %s" % cacheHierarchy[i])
curr_bw = cacheHierarchy[i] + "Bw"
peakBw = float(benchmark_data[curr_bw][roofline_parameters['device_id']])
peakBw = float(benchmark_data[curr_bw][roofline_parameters["device_id"]])
if dtype == "I8":
peakMFMA = float(benchmark_data["MFMAI8Ops"][roofline_parameters['device_id']])
peakMFMA = float(
benchmark_data["MFMAI8Ops"][roofline_parameters["device_id"]]
)
else:
peakMFMA = float(
benchmark_data["MFMAF{}Flops".format(target_precision)][roofline_parameters['device_id']]
benchmark_data["MFMAF{}Flops".format(target_precision)][
roofline_parameters["device_id"]
]
)
x1 = float(XMIN)
@@ -173,7 +174,9 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
if x2_mfma < x0_mfma:
x0_mfma = x2_mfma
logging.debug("MFMA ROOF [{}, {}], [{},{}]".format(x0_mfma, XMAX, peakMFMA, peakMFMA))
logging.debug(
"MFMA ROOF [{}, {}], [{},{}]".format(x0_mfma, XMAX, peakMFMA, peakMFMA)
)
graphPoints["mfma"].append([x0_mfma, XMAX])
graphPoints["mfma"].append([peakMFMA, peakMFMA])
graphPoints["mfma"].append(peakMFMA)
@@ -186,8 +189,7 @@ def calc_ceilings(roofline_parameters, dtype, benchmark_data):
# -------------------------------------------------------------------------------------
# Calculate relevant metrics for ai calculation
def calc_ai(sort_type, ret_df):
"""Given counter data, calculate arithmetic intensity for each kernel in the application.
"""
"""Given counter data, calculate arithmetic intensity for each kernel in the application."""
df = ret_df["pmc_perf"]
# Sort by top kernels or top dispatches?
df = df.sort_values(by=["Kernel_Name"])
@@ -261,7 +263,11 @@ def calc_ai(sort_type, ret_df):
+ (df["SQ_INSTS_VALU_MFMA_MOPS_F64"][idx] * 512)
)
except KeyError:
logging.debug("[roofline] {}: Skipped total_flops at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped total_flops at index {}".format(
kernelName[:35], idx
)
)
pass
try:
valu_flops += (
@@ -288,7 +294,9 @@ def calc_ai(sort_type, ret_df):
)
)
except KeyError:
logging.debug("{}: Skipped valu_flops at index {}".format(kernelName[:35], idx))
logging.debug(
"{}: Skipped valu_flops at index {}".format(kernelName[:35], idx)
)
pass
try:
@@ -298,7 +306,9 @@ def calc_ai(sort_type, ret_df):
mfma_flops_f64 += df["SQ_INSTS_VALU_MFMA_MOPS_F64"][idx] * 512
mfma_iops_i8 += df["SQ_INSTS_VALU_MFMA_MOPS_I8"][idx] * 512
except KeyError:
logging.debug("[roofline] {}: Skipped mfma ops at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped mfma ops at index {}".format(kernelName[:35], idx)
)
pass
try:
@@ -308,13 +318,19 @@ def calc_ai(sort_type, ret_df):
* L2_BANKS
) # L2_BANKS = 32 (since assuming mi200)
except KeyError:
logging.debug("[roofline] {}: Skipped lds_data at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped lds_data at index {}".format(kernelName[:35], idx)
)
pass
try:
L1cache_data += df["TCP_TOTAL_CACHE_ACCESSES_sum"][idx] * 64
except KeyError:
logging.debug("[roofline] {}: Skipped L1cache_data at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped L1cache_data at index {}".format(
kernelName[:35], idx
)
)
pass
try:
@@ -325,7 +341,11 @@ def calc_ai(sort_type, ret_df):
+ df["TCP_TCC_READ_REQ_sum"][idx] * 64
)
except KeyError:
logging.debug("[roofline] {}: Skipped L2cache_data at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped L2cache_data at index {}".format(
kernelName[:35], idx
)
)
pass
try:
hbm_data += (
@@ -335,7 +355,9 @@ def calc_ai(sort_type, ret_df):
+ ((df["TCC_EA_WRREQ_sum"][idx] - df["TCC_EA_WRREQ_64B_sum"][idx]) * 32)
)
except KeyError:
logging.debug("[roofline] {}: Skipped hbm_data at index {}".format(kernelName[:35], idx))
logging.debug(
"[roofline] {}: Skipped hbm_data at index {}".format(kernelName[:35], idx)
)
pass
totalDuration += df["End_Timestamp"][idx] - df["Start_Timestamp"][idx]
+61 -61
View File
@@ -37,6 +37,7 @@ from pathlib import Path as path
from textwrap import dedent
from utils.utils import error, get_hbm_stack_num
@dataclass
class MachineSpecs:
hostname: str
@@ -135,7 +136,7 @@ def gpuinfo():
# we get the max mclk from rocm-smi --showmclkrange
rocm_smi_mclk = run(["rocm-smi", "--showmclkrange"], exit_on_error=True)
gpu_info['max_mclk'] = search(r'(\d+)Mhz\s*$', rocm_smi_mclk)
gpu_info["max_mclk"] = search(r"(\d+)Mhz\s*$", rocm_smi_mclk)
# Fixme: find better way to differentiate cards, GPU vs APU, etc.
rocminfo_full = run(["rocminfo"])
@@ -151,81 +152,85 @@ def gpuinfo():
if not gpu_arch in SUPPORTED_ARCHS.keys():
return gpu_info
gpu_info['L1'], gpu_info['L1'] = "", ""
gpu_info["L1"], gpu_info["L1"] = "", ""
for idx2, linetext in enumerate(rocminfo[idx1 + 1 :]):
key = search(r"^\s*L1:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['L1'] = key
gpu_info["L1"] = key
continue
key = search(r"^\s*L2:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['L2'] = key
gpu_info["L2"] = key
continue
key = search(r"^\s*Max Clock Freq\. \(MHz\):\s+([0-9]+)", linetext)
if key != None:
gpu_info['max_sclk'] = key
gpu_info["max_sclk"] = key
continue
key = search(r"^\s*Compute Unit:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['num_CU'] = key
gpu_info["num_CU"] = key
continue
key = search(r"^\s*SIMDs per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['num_SIMD'] = key
gpu_info["num_SIMD"] = key
continue
key = search(r"^\s*Shader Engines:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['num_SE'] = key
gpu_info["num_SE"] = key
continue
key = search(r"^\s*Wavefront Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['wave_size'] = key
gpu_info["wave_size"] = key
continue
key = search(r"^\s*Workgroup Max Size:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['grp_size'] = key
gpu_info["grp_size"] = key
continue
key = search(r"^\s*Max Waves Per CU:\s+ ([a-zA-Z0-9]+)\s*", linetext)
if key != None:
gpu_info['max_waves_per_cu'] = key
gpu_info["max_waves_per_cu"] = key
break
try:
soc_module = importlib.import_module('omniperf_soc.soc_'+gpu_arch)
soc_module = importlib.import_module("omniperf_soc.soc_" + gpu_arch)
except ModuleNotFoundError as e:
error("Arch %s marked as supported, but couldn't find class implementation %s." % (gpu_arch, e))
error(
"Arch %s marked as supported, but couldn't find class implementation %s."
% (gpu_arch, e)
)
# load arch specific info
try:
gpu_name = list(SUPPORTED_ARCHS[gpu_arch].keys())[0].upper()
gpu_info['L2Banks'] = str(soc_module.SOC_PARAM['L2Banks'])
gpu_info['numSQC'] = str(soc_module.SOC_PARAM['numSQC'])
gpu_info['LDSBanks'] = str(soc_module.SOC_PARAM['LDSBanks'])
gpu_info['numPipes'] = str(soc_module.SOC_PARAM['numPipes'])
gpu_info["L2Banks"] = str(soc_module.SOC_PARAM["L2Banks"])
gpu_info["numSQC"] = str(soc_module.SOC_PARAM["numSQC"])
gpu_info["LDSBanks"] = str(soc_module.SOC_PARAM["LDSBanks"])
gpu_info["numPipes"] = str(soc_module.SOC_PARAM["numPipes"])
except KeyError as e:
error("Incomplete class definition for %s. Expected a field for %s in SOC_PARAM." % (gpu_arch, e))\
error(
"Incomplete class definition for %s. Expected a field for %s in SOC_PARAM."
% (gpu_arch, e)
)
# specify gpu name for gfx942 hardware
if gpu_name == "MI300":
gpu_name = list(SUPPORTED_ARCHS[gpu_arch].values())[0][0]
if (gpu_info['gpu_arch'] == "gfx942") and ("MI300A" in rocminfo_full):
if (gpu_info["gpu_arch"] == "gfx942") and ("MI300A" in rocminfo_full):
gpu_name = "MI300A_A1"
if (gpu_arch == "gfx942") and ("MI300A" not in rocminfo_full):
gpu_name = "MI300X_A1"
gpu_info['gpu_name'] = gpu_name
gpu_info['gpu_arch'] = gpu_arch
gpu_info['compute_partition'] = ""
gpu_info['memory_partition'] = ""
gpu_info["gpu_name"] = gpu_name
gpu_info["gpu_arch"] = gpu_arch
gpu_info["compute_partition"] = ""
gpu_info["memory_partition"] = ""
# verify all fields are filled
for key, value in gpu_info.items():
@@ -235,7 +240,7 @@ def gpuinfo():
return gpu_info
def run(cmd,exit_on_error=False):
def run(cmd, exit_on_error=False):
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if exit_on_error:
@@ -255,24 +260,18 @@ def search(pattern, string):
return m.group(1)
return None
def total_l2_banks(archname, L2Banks, memory_partition):
# Fixme: support all supported partitioning mode
# Fixme: "name" is a bad name!
totalL2Banks = L2Banks
if (
archname.lower() == "mi300a_a0"
or archname.lower() == "mi300a_a1"
):
totalL2Banks = L2Banks * get_hbm_stack_num(
archname, memory_partition)
elif (
archname.lower() == "mi300x_a0"
or archname.lower() == "mi300x_a1"
):
totalL2Banks = L2Banks * get_hbm_stack_num(
archname, memory_partition)
if archname.lower() == "mi300a_a0" or archname.lower() == "mi300a_a1":
totalL2Banks = L2Banks * get_hbm_stack_num(archname, memory_partition)
elif archname.lower() == "mi300x_a0" or archname.lower() == "mi300x_a1":
totalL2Banks = L2Banks * get_hbm_stack_num(archname, memory_partition)
return totalL2Banks
def get_machine_specs(devicenum):
cpuinfo = path("/proc/cpuinfo").read_text()
meminfo = path("/proc/meminfo").read_text()
@@ -339,8 +338,8 @@ def get_machine_specs(devicenum):
# these are just max's now, because the parsing was broken and this was inconsistent
# with how we use the clocks elsewhere (all max, all the time)
cur_sclk = gpu_info['max_sclk']
cur_mclk = gpu_info['max_mclk']
cur_sclk = gpu_info["max_sclk"]
cur_mclk = gpu_info["max_mclk"]
# FIXME with device
vbios = search(r"VBIOS version: (.*?)$", run(["rocm-smi", "-v"], exit_on_error=True))
@@ -358,15 +357,16 @@ def get_machine_specs(devicenum):
memory_partition = "NA"
totalL2Banks = total_l2_banks(
gpu_info['gpu_name'], int(gpu_info['L2Banks']), memory_partition)
gpu_info["gpu_name"], int(gpu_info["L2Banks"]), memory_partition
)
hbmchannels = totalL2Banks
if (
gpu_info['gpu_name'].lower() == "mi300a_a0"
or gpu_info['gpu_name'].lower() == "mi300a_a1"
gpu_info["gpu_name"].lower() == "mi300a_a0"
or gpu_info["gpu_name"].lower() == "mi300a_a1"
) and memory_partition.lower() == "nps1":
# we have an extra 32 channels for the CCD
hbmchannels += 32
hbmBW = str(int(gpu_info['max_mclk']) / 1000 * 32 * hbmchannels)
hbmBW = str(int(gpu_info["max_mclk"]) / 1000 * 32 * hbmchannels)
totalL2Banks = str(totalL2Banks)
return MachineSpecs(
@@ -377,26 +377,26 @@ def get_machine_specs(devicenum):
ram,
distro,
rocm_version,
gpu_info['gpu_name'],
gpu_info['gpu_arch'],
gpu_info["gpu_name"],
gpu_info["gpu_arch"],
vbios,
gpu_info['L1'],
gpu_info['L2'],
gpu_info['num_CU'],
gpu_info['num_SIMD'],
gpu_info['num_SE'],
gpu_info['wave_size'],
gpu_info['grp_size'],
gpu_info['max_sclk'],
gpu_info['max_mclk'],
gpu_info["L1"],
gpu_info["L2"],
gpu_info["num_CU"],
gpu_info["num_SIMD"],
gpu_info["num_SE"],
gpu_info["wave_size"],
gpu_info["grp_size"],
gpu_info["max_sclk"],
gpu_info["max_mclk"],
cur_sclk,
cur_mclk,
gpu_info['max_waves_per_cu'],
gpu_info['L2Banks'],
gpu_info["max_waves_per_cu"],
gpu_info["L2Banks"],
totalL2Banks,
gpu_info['LDSBanks'],
gpu_info['numSQC'],
gpu_info['numPipes'],
gpu_info["LDSBanks"],
gpu_info["numSQC"],
gpu_info["numPipes"],
hbmBW,
compute_partition,
memory_partition,
@@ -201,9 +201,9 @@ def show_all(args, runs, archConfigs, output):
)
# Only show top N kernels (as specified in --max-kernel-num) in "Top Stats" section
if(
type == "raw_csv_table"
and (table_config["source"] == "pmc_kernel_top.csv" or table_config["source"] == "pmc_dispatch_info.csv")
if type == "raw_csv_table" and (
table_config["source"] == "pmc_kernel_top.csv"
or table_config["source"] == "pmc_dispatch_info.csv"
):
df = df.head(args.max_stat_num)
# NB:
@@ -251,7 +251,9 @@ def show_kernel_stats(args, runs, archConfigs, output):
# sorted when load_table_data.
if table_config["id"] == 1:
print("\n" + "-" * 80, file=output)
print("Detected Kernels (sorted decending by duration)", file=output)
print(
"Detected Kernels (sorted decending by duration)", file=output
)
df = pd.concat([df, single_df["Kernel_Name"]], axis=1)
if table_config["id"] == 2:
@@ -268,4 +270,3 @@ def show_kernel_stats(args, runs, archConfigs, output):
),
file=output,
)