2025-08-01 10:14:39 -06:00
|
|
|
##############################################################################
|
2023-12-04 15:47:03 -06:00
|
|
|
# MIT License
|
|
|
|
|
#
|
2025-01-23 13:09:32 -06:00
|
|
|
# Copyright (c) 2021 - 2025 Advanced Micro Devices, Inc. All Rights Reserved.
|
2023-12-04 15:47:03 -06:00
|
|
|
#
|
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
# in the Software without restriction, including without limitation the rights
|
|
|
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
|
#
|
2025-08-01 10:14:39 -06:00
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
|
|
|
# all copies or substantial portions of the Software.
|
2023-12-04 15:47:03 -06:00
|
|
|
#
|
|
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
2025-08-01 10:14:39 -06:00
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
2023-12-04 15:47:03 -06:00
|
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
2025-08-01 10:14:39 -06:00
|
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
# THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
##############################################################################
|
|
|
|
|
|
2025-01-02 13:29:47 -08:00
|
|
|
import copy
|
2025-07-25 14:01:34 -04:00
|
|
|
import textwrap
|
2023-12-04 15:47:03 -06:00
|
|
|
from pathlib import Path
|
2025-01-02 13:29:47 -08:00
|
|
|
|
|
|
|
|
import pandas as pd
|
2023-12-04 15:47:03 -06:00
|
|
|
from tabulate import tabulate
|
|
|
|
|
|
2025-07-24 12:15:52 -04:00
|
|
|
import config
|
2025-06-06 16:15:56 -06:00
|
|
|
from utils import mem_chart, parser
|
2025-07-15 12:42:27 -04:00
|
|
|
from utils.logger import console_error, console_log, console_warning
|
2025-07-23 16:16:29 -04:00
|
|
|
from utils.utils import convert_metric_id_to_panel_info
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def string_multiple_lines(source, width, max_rows):
|
|
|
|
|
"""
|
|
|
|
|
Adjust string with multiple lines by inserting '\n'
|
|
|
|
|
"""
|
|
|
|
|
idx = 0
|
|
|
|
|
lines = []
|
|
|
|
|
while idx < len(source) and len(lines) < max_rows:
|
|
|
|
|
lines.append(source[idx : idx + width])
|
|
|
|
|
idx += width
|
|
|
|
|
|
|
|
|
|
if idx < len(source):
|
|
|
|
|
last = lines[-1]
|
|
|
|
|
lines[-1] = last[0:-3] + "..."
|
|
|
|
|
return "\n".join(lines)
|
|
|
|
|
|
|
|
|
|
|
2024-02-29 10:21:29 -05:00
|
|
|
def get_table_string(df, transpose=False, decimal=2):
|
2025-07-25 14:01:34 -04:00
|
|
|
"""
|
|
|
|
|
Convert DataFrame to a formatted table string, wrapping specified columns.
|
|
|
|
|
"""
|
|
|
|
|
df_to_show = df.transpose() if transpose else df
|
|
|
|
|
wrap_columns = ["Description"]
|
|
|
|
|
wrap_width = 40
|
|
|
|
|
for col in wrap_columns:
|
|
|
|
|
if col in df_to_show.columns:
|
|
|
|
|
df_to_show[col] = (
|
|
|
|
|
df_to_show[col]
|
|
|
|
|
.astype(str)
|
|
|
|
|
.apply(lambda x: textwrap.fill(x, width=wrap_width))
|
|
|
|
|
)
|
2024-03-01 11:52:31 -06:00
|
|
|
return tabulate(
|
2025-07-25 14:01:34 -04:00
|
|
|
df_to_show,
|
2024-03-01 11:52:31 -06:00
|
|
|
headers="keys",
|
|
|
|
|
tablefmt="fancy_grid",
|
|
|
|
|
floatfmt="." + str(decimal) + "f",
|
|
|
|
|
)
|
2024-02-29 10:21:29 -05:00
|
|
|
|
|
|
|
|
|
2025-07-24 12:15:52 -04:00
|
|
|
def convert_time_columns(df, time_unit):
|
|
|
|
|
"""
|
|
|
|
|
Convert time column values based on the specified time unit.
|
|
|
|
|
Uses the Unit column to identify which columns contain time data.
|
|
|
|
|
"""
|
|
|
|
|
if time_unit not in config.TIME_UNITS or "Unit" not in df.columns:
|
|
|
|
|
return df
|
|
|
|
|
|
|
|
|
|
# Avoid modifying the original
|
|
|
|
|
df_copy = df.copy()
|
|
|
|
|
|
|
|
|
|
time_rows = df_copy["Unit"].str.lower().str.contains("ns", na=False)
|
|
|
|
|
|
|
|
|
|
time_value_columns = ["Avg", "Min", "Max"]
|
|
|
|
|
|
|
|
|
|
for col in time_value_columns:
|
|
|
|
|
if col in df_copy.columns:
|
|
|
|
|
mask = time_rows
|
|
|
|
|
if mask.any():
|
|
|
|
|
try:
|
|
|
|
|
numeric_values = pd.to_numeric(
|
|
|
|
|
df_copy.loc[mask, col], errors="coerce"
|
|
|
|
|
)
|
2025-08-08 15:32:30 -04:00
|
|
|
df_copy.loc[mask, col] = (
|
|
|
|
|
numeric_values / config.TIME_UNITS[time_unit]
|
|
|
|
|
)
|
|
|
|
|
except Exception:
|
2025-07-24 12:15:52 -04:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Update the Unit column
|
|
|
|
|
if time_rows.any():
|
|
|
|
|
df_copy.loc[time_rows, "Unit"] = time_unit
|
|
|
|
|
|
|
|
|
|
return df_copy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def has_time_data(df):
|
|
|
|
|
"""
|
|
|
|
|
Check if the dataframe contains time data by looking at the Unit column.
|
|
|
|
|
"""
|
|
|
|
|
if "Unit" not in df.columns:
|
|
|
|
|
return False
|
|
|
|
|
# NOTE: "ns" / "NS" / "nS" / "Ns" are reserved for Nanosec time unit
|
|
|
|
|
return df["Unit"].str.lower().str.contains("ns", na=False).any()
|
|
|
|
|
|
|
|
|
|
|
2025-06-18 13:19:58 -04:00
|
|
|
def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
2023-12-04 15:47:03 -06:00
|
|
|
"""
|
|
|
|
|
Show all panels with their data in plain text mode.
|
|
|
|
|
"""
|
|
|
|
|
comparable_columns = parser.build_comparable_columns(args.time_unit)
|
2025-07-21 09:37:35 -04:00
|
|
|
filter_panel_ids = profiling_config.get("filter_blocks", [])
|
|
|
|
|
if isinstance(filter_panel_ids, dict):
|
|
|
|
|
# For backward compatibility
|
|
|
|
|
filter_panel_ids = [
|
|
|
|
|
name for name, type in filter_panel_ids.items() if type == "metric_id"
|
2025-03-10 14:42:56 -04:00
|
|
|
]
|
2025-07-21 09:37:35 -04:00
|
|
|
filter_panel_ids = [
|
2025-07-23 16:16:29 -04:00
|
|
|
int(convert_metric_id_to_panel_info(metric_id)[0])
|
|
|
|
|
for metric_id in filter_panel_ids
|
2025-03-10 14:42:56 -04:00
|
|
|
]
|
2025-07-25 14:01:34 -04:00
|
|
|
if args.include_cols:
|
|
|
|
|
hidden_cols = list(set(config.HIDDEN_COLUMNS_CLI) - set(args.include_cols))
|
|
|
|
|
else:
|
|
|
|
|
hidden_cols = config.HIDDEN_COLUMNS_CLI
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
for panel_id, panel in archConfigs.panel_configs.items():
|
|
|
|
|
# Skip panels that don't support baseline comparison
|
2025-07-24 12:15:52 -04:00
|
|
|
if len(args.path) > 1 and panel_id in config.HIDDEN_SECTIONS:
|
2023-12-04 15:47:03 -06:00
|
|
|
continue
|
2025-07-15 12:42:27 -04:00
|
|
|
ss = "" # store content of all data_source from one panel
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
for data_source in panel["data source"]:
|
|
|
|
|
for type, table_config in data_source.items():
|
2025-08-08 15:32:30 -04:00
|
|
|
# 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.
|
2025-03-10 14:42:56 -04:00
|
|
|
if (
|
|
|
|
|
not args.filter_metrics
|
|
|
|
|
and filter_panel_ids
|
|
|
|
|
and table_config["id"] not in filter_panel_ids
|
|
|
|
|
and panel_id not in filter_panel_ids
|
|
|
|
|
and panel_id > 100
|
|
|
|
|
):
|
|
|
|
|
table_id_str = (
|
|
|
|
|
str(table_config["id"] // 100)
|
|
|
|
|
+ "."
|
|
|
|
|
+ str(table_config["id"] % 100)
|
|
|
|
|
)
|
|
|
|
|
console_log(
|
2025-08-08 15:32:30 -04:00
|
|
|
f"Not showing table not selected during profiling: "
|
|
|
|
|
f"{table_id_str} "
|
|
|
|
|
f"{table_config['title']}"
|
2025-03-10 14:42:56 -04:00
|
|
|
)
|
|
|
|
|
continue
|
2025-07-15 12:42:27 -04:00
|
|
|
|
|
|
|
|
# Show roofline
|
|
|
|
|
# Check if we have filter_metrics for analyze stage:
|
2025-08-08 15:32:30 -04:00
|
|
|
# no filter_metrics = show all,
|
|
|
|
|
# filter_metrics containing "4" = user requesting roofline chart
|
2025-07-15 12:42:27 -04:00
|
|
|
if panel_id == 400 and (
|
|
|
|
|
not args.filter_metrics or "4" in args.filter_metrics
|
|
|
|
|
):
|
|
|
|
|
show_roof_plot(roof_plot)
|
|
|
|
|
continue
|
|
|
|
|
|
2025-07-24 11:49:02 -04:00
|
|
|
# Metrics baseline comparison mode
|
2025-08-08 15:32:30 -04:00
|
|
|
# We cannot guarantee that all runs have the same metrics.
|
|
|
|
|
# Only show common metrics.
|
2025-07-24 11:49:02 -04:00
|
|
|
if (
|
|
|
|
|
type == "metric_table"
|
|
|
|
|
and "Metric" in table_config["header"].values()
|
|
|
|
|
and len(runs) > 1
|
|
|
|
|
):
|
|
|
|
|
# Common metrics across all runs
|
|
|
|
|
common_metrics = set()
|
|
|
|
|
for _, data in runs.items():
|
|
|
|
|
if not common_metrics:
|
|
|
|
|
common_metrics = set(data.dfs[table_config["id"]]["Metric"])
|
|
|
|
|
else:
|
2025-08-08 15:32:30 -04:00
|
|
|
common_metrics &= set(
|
|
|
|
|
data.dfs[table_config["id"]]["Metric"]
|
|
|
|
|
)
|
2025-07-24 11:49:02 -04:00
|
|
|
# Apply common metrics across all runs
|
|
|
|
|
# Reindex all runs based on first run
|
|
|
|
|
initial_index = None
|
|
|
|
|
for key in runs.keys():
|
|
|
|
|
runs[key].dfs[table_config["id"]] = (
|
|
|
|
|
runs[key]
|
|
|
|
|
.dfs[table_config["id"]]
|
|
|
|
|
.loc[lambda d: d["Metric"].isin(common_metrics)]
|
|
|
|
|
)
|
|
|
|
|
if initial_index is None:
|
2025-07-24 12:15:52 -04:00
|
|
|
initial_index = runs[key].dfs[table_config["id"]].index
|
2025-07-24 11:49:02 -04:00
|
|
|
else:
|
|
|
|
|
runs[key].dfs[table_config["id"]].index = initial_index
|
|
|
|
|
|
2023-12-04 15:47:03 -06:00
|
|
|
# take the 1st run as baseline
|
|
|
|
|
base_run, base_data = next(iter(runs.items()))
|
|
|
|
|
base_df = base_data.dfs[table_config["id"]]
|
|
|
|
|
|
2025-07-24 12:15:52 -04:00
|
|
|
if args.time_unit and has_time_data(base_df):
|
|
|
|
|
base_df = convert_time_columns(base_df, args.time_unit)
|
|
|
|
|
|
2023-12-04 15:47:03 -06:00
|
|
|
df = pd.DataFrame(index=base_df.index)
|
|
|
|
|
|
|
|
|
|
for header in list(base_df.keys()):
|
2025-07-25 14:01:34 -04:00
|
|
|
# For raw csv table, columns cannot be filtered
|
2025-08-08 15:32:30 -04:00
|
|
|
# If columns are filtered, then skip the headers not in
|
|
|
|
|
# filtered columns
|
2023-12-04 15:47:03 -06:00
|
|
|
if (
|
2025-07-25 14:01:34 -04:00
|
|
|
type == "raw_csv_table"
|
|
|
|
|
or not args.cols
|
|
|
|
|
or base_df.columns.get_loc(header) in args.cols
|
2023-12-04 15:47:03 -06:00
|
|
|
):
|
2025-07-25 14:01:34 -04:00
|
|
|
if header in hidden_cols:
|
2023-12-04 15:47:03 -06:00
|
|
|
pass
|
|
|
|
|
elif header not in comparable_columns:
|
|
|
|
|
if (
|
|
|
|
|
type == "raw_csv_table"
|
2024-05-22 16:35:16 +00:00
|
|
|
and (
|
|
|
|
|
table_config["source"] == "pmc_kernel_top.csv"
|
|
|
|
|
or table_config["source"] == "pmc_dispatch_info.csv"
|
|
|
|
|
)
|
2024-01-19 13:46:01 -06:00
|
|
|
and header == "Kernel_Name"
|
2023-12-04 15:47:03 -06:00
|
|
|
):
|
2025-08-08 15:32:30 -04:00
|
|
|
# NB: the width of kernel name might depend
|
|
|
|
|
# on the header of the table.
|
2024-05-22 16:35:16 +00:00
|
|
|
if table_config["source"] == "pmc_kernel_top.csv":
|
|
|
|
|
adjusted_name = base_df["Kernel_Name"].apply(
|
|
|
|
|
lambda x: string_multiple_lines(x, 40, 3)
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
adjusted_name = base_df["Kernel_Name"].apply(
|
|
|
|
|
lambda x: string_multiple_lines(x, 80, 4)
|
|
|
|
|
)
|
2023-12-04 15:47:03 -06:00
|
|
|
df = pd.concat([df, adjusted_name], axis=1)
|
|
|
|
|
elif type == "raw_csv_table" and header == "Info":
|
|
|
|
|
for run, data in runs.items():
|
|
|
|
|
cur_df = data.dfs[table_config["id"]]
|
|
|
|
|
df = pd.concat([df, cur_df[header]], axis=1)
|
|
|
|
|
else:
|
|
|
|
|
df = pd.concat([df, base_df[header]], axis=1)
|
|
|
|
|
else:
|
|
|
|
|
for run, data in runs.items():
|
|
|
|
|
cur_df = data.dfs[table_config["id"]]
|
2025-07-24 12:15:52 -04:00
|
|
|
|
|
|
|
|
if args.time_unit and has_time_data(base_df):
|
2025-08-08 15:32:30 -04:00
|
|
|
cur_df = convert_time_columns(
|
|
|
|
|
cur_df, args.time_unit
|
|
|
|
|
)
|
2025-07-24 12:15:52 -04:00
|
|
|
|
2023-12-04 15:47:03 -06:00
|
|
|
if (type == "raw_csv_table") or (
|
2025-08-08 15:32:30 -04:00
|
|
|
type == "metric_table"
|
|
|
|
|
and (not header in hidden_cols)
|
2023-12-04 15:47:03 -06:00
|
|
|
):
|
|
|
|
|
if run != base_run:
|
|
|
|
|
# calc percentage over the baseline
|
|
|
|
|
base_df[header] = [
|
|
|
|
|
float(x) if x != "" else float(0)
|
|
|
|
|
for x in base_df[header]
|
|
|
|
|
]
|
|
|
|
|
cur_df[header] = [
|
|
|
|
|
float(x) if x != "" else float(0)
|
|
|
|
|
for x in cur_df[header]
|
|
|
|
|
]
|
|
|
|
|
t_df = pd.concat(
|
|
|
|
|
[
|
|
|
|
|
base_df[header],
|
|
|
|
|
cur_df[header],
|
|
|
|
|
],
|
|
|
|
|
axis=1,
|
|
|
|
|
)
|
2023-12-13 14:50:22 -06:00
|
|
|
absolute_diff = (
|
|
|
|
|
t_df.iloc[:, 1] - t_df.iloc[:, 0]
|
|
|
|
|
).round(args.decimal)
|
|
|
|
|
t_df = absolute_diff / t_df.iloc[:, 0].replace(
|
|
|
|
|
0, 1
|
|
|
|
|
)
|
2023-12-04 15:47:03 -06:00
|
|
|
if args.verbose >= 2:
|
2024-01-30 17:25:16 -06:00
|
|
|
console_log("---------", header, t_df)
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
t_df_pretty = (
|
|
|
|
|
t_df.astype(float)
|
|
|
|
|
.mul(100)
|
|
|
|
|
.round(args.decimal)
|
|
|
|
|
)
|
|
|
|
|
# show value + percentage
|
|
|
|
|
# TODO: better alignment
|
|
|
|
|
t_df = (
|
|
|
|
|
cur_df[header]
|
|
|
|
|
.astype(float)
|
|
|
|
|
.round(args.decimal)
|
|
|
|
|
.map(str)
|
2024-03-22 11:29:36 -04:00
|
|
|
.astype(str)
|
2023-12-04 15:47:03 -06:00
|
|
|
+ " ("
|
|
|
|
|
+ t_df_pretty.map(str)
|
|
|
|
|
+ "%)"
|
|
|
|
|
)
|
|
|
|
|
df = pd.concat([df, t_df], axis=1)
|
|
|
|
|
# DEBUG: When in a CI setting and flag is set,
|
2025-08-08 15:32:30 -04:00
|
|
|
# then verify metrics meet threshold
|
|
|
|
|
# requirement
|
2024-06-28 15:23:22 -05:00
|
|
|
if (
|
|
|
|
|
header in ["Value", "Count", "Avg"]
|
|
|
|
|
and t_df_pretty.abs()
|
|
|
|
|
.gt(args.report_diff)
|
|
|
|
|
.any()
|
|
|
|
|
):
|
|
|
|
|
df["Abs Diff"] = absolute_diff
|
|
|
|
|
if args.report_diff:
|
2023-12-13 14:50:22 -06:00
|
|
|
violation_idx = t_df_pretty.index[
|
|
|
|
|
t_df_pretty.abs() > args.report_diff
|
|
|
|
|
]
|
2024-03-04 12:57:25 -06:00
|
|
|
console_warning(
|
2025-08-08 15:32:30 -04:00
|
|
|
"Dataframe diff exceeds %s "
|
|
|
|
|
"threshold requirement\n"
|
|
|
|
|
"See metric %s"
|
2024-03-04 12:57:25 -06:00
|
|
|
% (
|
|
|
|
|
str(args.report_diff) + "%",
|
|
|
|
|
violation_idx.to_numpy(),
|
|
|
|
|
)
|
|
|
|
|
)
|
2024-01-30 17:25:16 -06:00
|
|
|
console_warning(df)
|
2023-12-04 15:47:03 -06:00
|
|
|
else:
|
|
|
|
|
cur_df_copy = copy.deepcopy(cur_df)
|
|
|
|
|
cur_df_copy[header] = [
|
2024-02-22 15:40:02 -06:00
|
|
|
(
|
|
|
|
|
round(float(x), args.decimal)
|
|
|
|
|
if x != ""
|
|
|
|
|
else x
|
|
|
|
|
)
|
2023-12-04 15:47:03 -06:00
|
|
|
for x in base_df[header]
|
|
|
|
|
]
|
2025-08-08 15:32:30 -04:00
|
|
|
df = pd.concat(
|
|
|
|
|
[df, cur_df_copy[header]], axis=1
|
|
|
|
|
)
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
if not df.empty:
|
|
|
|
|
# subtitle for each table in a panel if existing
|
|
|
|
|
table_id_str = (
|
|
|
|
|
str(table_config["id"] // 100)
|
|
|
|
|
+ "."
|
|
|
|
|
+ str(table_config["id"] % 100)
|
|
|
|
|
)
|
|
|
|
|
|
2025-03-10 14:42:56 -04:00
|
|
|
# Check if any column in df is empty
|
2025-08-08 15:32:30 -04:00
|
|
|
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()
|
|
|
|
|
])
|
2025-03-10 14:42:56 -04:00
|
|
|
# Do not print the table if any column is empty
|
|
|
|
|
if is_empty_columns_exist:
|
2025-03-28 16:51:49 -06:00
|
|
|
if "title" in table_config:
|
|
|
|
|
console_log(
|
2025-08-08 15:32:30 -04:00
|
|
|
f"Not showing table with empty column(s): "
|
|
|
|
|
f"{table_id_str} "
|
|
|
|
|
f"{table_config['title']}"
|
2025-03-28 16:51:49 -06:00
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
console_log(
|
2025-08-08 15:32:30 -04:00
|
|
|
f"Not showing table with empty column(s): "
|
|
|
|
|
f"{table_id_str}"
|
2025-03-28 16:51:49 -06:00
|
|
|
)
|
2025-03-10 14:42:56 -04:00
|
|
|
if (
|
|
|
|
|
"title" in table_config
|
|
|
|
|
and table_config["title"]
|
|
|
|
|
and not is_empty_columns_exist
|
|
|
|
|
):
|
2023-12-04 15:47:03 -06:00
|
|
|
ss += table_id_str + " " + table_config["title"] + "\n"
|
|
|
|
|
|
|
|
|
|
if args.df_file_dir:
|
|
|
|
|
p = Path(args.df_file_dir)
|
|
|
|
|
if not p.exists():
|
|
|
|
|
p.mkdir()
|
|
|
|
|
if p.is_dir():
|
|
|
|
|
if "title" in table_config and table_config["title"]:
|
|
|
|
|
table_id_str += "_" + table_config["title"]
|
|
|
|
|
df.to_csv(
|
|
|
|
|
p.joinpath(table_id_str.replace(" ", "_") + ".csv"),
|
|
|
|
|
index=False,
|
|
|
|
|
)
|
2025-08-08 15:32:30 -04:00
|
|
|
# Only show top N kernels (as specified in --max-kernel-num)
|
|
|
|
|
# in "Top Stats" section
|
2024-02-16 15:34:28 -06:00
|
|
|
if type == "raw_csv_table" and (
|
|
|
|
|
table_config["source"] == "pmc_kernel_top.csv"
|
|
|
|
|
or table_config["source"] == "pmc_dispatch_info.csv"
|
2024-02-13 19:17:41 -06:00
|
|
|
):
|
|
|
|
|
df = df.head(args.max_stat_num)
|
2023-12-04 15:47:03 -06:00
|
|
|
# NB:
|
|
|
|
|
# "columnwise: True" is a special attr of a table/df
|
|
|
|
|
# For raw_csv_table, such as system_info, we transpose the
|
|
|
|
|
# df when load it, because we need those items in column.
|
|
|
|
|
# For metric_table, we only need to show the data in column
|
|
|
|
|
# fash for now.
|
2024-03-01 11:52:31 -06:00
|
|
|
transpose = (
|
|
|
|
|
type != "raw_csv_table"
|
2024-02-29 10:21:29 -05:00
|
|
|
and "columnwise" in table_config
|
2025-08-08 15:32:30 -04:00
|
|
|
and table_config["columnwise"]
|
2024-03-01 11:52:31 -06:00
|
|
|
)
|
2025-03-10 14:42:56 -04:00
|
|
|
if not is_empty_columns_exist:
|
2025-06-06 16:15:56 -06:00
|
|
|
# enable mem_chart only with single run
|
|
|
|
|
if (
|
|
|
|
|
"cli_style" in table_config
|
|
|
|
|
and table_config["cli_style"] == "mem_chart"
|
|
|
|
|
and len(runs) == 1
|
|
|
|
|
):
|
2025-08-08 15:32:30 -04:00
|
|
|
# NB: to avoid broken test with
|
|
|
|
|
# arbitrary number with "--cols" option
|
2025-06-12 19:45:24 -04:00
|
|
|
if "Metric" in df.columns and "Value" in df.columns:
|
|
|
|
|
ss += mem_chart.plot_mem_chart(
|
|
|
|
|
"",
|
|
|
|
|
args.normal_unit,
|
|
|
|
|
pd.DataFrame([df["Metric"], df["Value"]])
|
|
|
|
|
.transpose()
|
|
|
|
|
.set_index("Metric")
|
|
|
|
|
.to_dict()["Value"],
|
|
|
|
|
)
|
2025-06-18 13:19:58 -04:00
|
|
|
ss += "\n"
|
2025-06-06 16:15:56 -06:00
|
|
|
else:
|
|
|
|
|
ss += (
|
|
|
|
|
get_table_string(
|
|
|
|
|
df, transpose=transpose, decimal=args.decimal
|
|
|
|
|
)
|
|
|
|
|
+ "\n"
|
2025-03-10 14:42:56 -04:00
|
|
|
)
|
2023-12-04 15:47:03 -06:00
|
|
|
|
|
|
|
|
if ss:
|
|
|
|
|
print("\n" + "-" * 80, file=output)
|
|
|
|
|
print(str(panel_id // 100) + ". " + panel["title"], file=output)
|
|
|
|
|
print(ss, file=output)
|
|
|
|
|
|
|
|
|
|
|
2025-06-18 13:19:58 -04:00
|
|
|
def show_roof_plot(roof_plot):
|
|
|
|
|
# TODO: short term solution to display roofline plot
|
|
|
|
|
print("\n" + "-" * 80)
|
|
|
|
|
print("4. Roofline")
|
|
|
|
|
print("4.1 Roofline")
|
2025-07-15 12:42:27 -04:00
|
|
|
if roof_plot:
|
|
|
|
|
print(roof_plot)
|
|
|
|
|
else:
|
|
|
|
|
console_error(
|
2025-08-08 15:32:30 -04:00
|
|
|
"Cannot create roofline plot for CLI with incomplete/missing "
|
|
|
|
|
"roofline profiling data.",
|
2025-07-15 12:42:27 -04:00
|
|
|
exit=False,
|
|
|
|
|
)
|
2025-06-18 13:19:58 -04:00
|
|
|
|
|
|
|
|
|
2024-02-13 19:17:41 -06:00
|
|
|
def show_kernel_stats(args, runs, archConfigs, output):
|
2023-12-04 15:47:03 -06:00
|
|
|
"""
|
2024-02-13 19:17:41 -06:00
|
|
|
Show the kernels and dispatches from "Top Stats" section.
|
2023-12-04 15:47:03 -06:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
df = pd.DataFrame()
|
|
|
|
|
for panel_id, panel in archConfigs.panel_configs.items():
|
|
|
|
|
for data_source in panel["data source"]:
|
|
|
|
|
for type, table_config in data_source.items():
|
|
|
|
|
for run, data in runs.items():
|
2024-02-13 19:17:41 -06:00
|
|
|
df = pd.DataFrame()
|
2023-12-04 15:47:03 -06:00
|
|
|
single_df = data.dfs[table_config["id"]]
|
|
|
|
|
# NB:
|
|
|
|
|
# For pmc_kernel_top.csv, have to sort here if not
|
|
|
|
|
# sorted when load_table_data.
|
2024-02-13 19:17:41 -06:00
|
|
|
if table_config["id"] == 1:
|
|
|
|
|
print("\n" + "-" * 80, file=output)
|
2024-02-16 15:34:28 -06:00
|
|
|
print(
|
2024-03-26 12:54:51 -05:00
|
|
|
"Detected Kernels (sorted descending by duration)",
|
|
|
|
|
file=output,
|
2024-02-16 15:34:28 -06:00
|
|
|
)
|
2024-02-13 19:17:41 -06:00
|
|
|
df = pd.concat([df, single_df["Kernel_Name"]], axis=1)
|
|
|
|
|
|
|
|
|
|
if table_config["id"] == 2:
|
|
|
|
|
print("\n" + "-" * 80, file=output)
|
|
|
|
|
print("Dispatch list", file=output)
|
|
|
|
|
df = single_df
|
|
|
|
|
|
|
|
|
|
print(
|
2024-02-29 12:35:52 -05:00
|
|
|
get_table_string(df, transpose=False, decimal=args.decimal),
|
2024-02-13 19:17:41 -06:00
|
|
|
file=output,
|
|
|
|
|
)
|