Add roofline cli_generate_plot method (#737)
Add option to print out roofline plot in terminal using plotext. Takes in one datatype and returns the str from plot.build() which contains the visual plot of roofline analysis for said datatype. --------- Signed-off-by: Carrie Fallows <Carrie.Fallows@amd.com>
This commit is contained in:
+219
-1
@@ -30,10 +30,17 @@ from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import plotext as plt
|
||||
import plotly.graph_objects as go
|
||||
from dash import dcc, html
|
||||
|
||||
from utils.logger import console_debug, console_error, console_log, demarcate
|
||||
from utils.logger import (
|
||||
console_debug,
|
||||
console_error,
|
||||
console_log,
|
||||
console_warning,
|
||||
demarcate,
|
||||
)
|
||||
from utils.roofline_calc import (
|
||||
MFMA_DATATYPES,
|
||||
PEAK_OPS_DATATYPES,
|
||||
@@ -408,6 +415,217 @@ class Roofline:
|
||||
|
||||
return fig
|
||||
|
||||
@demarcate
|
||||
def cli_generate_plot(self, dtype):
|
||||
"""
|
||||
Plot CLI mode roofline analysis in terminal using plotext
|
||||
|
||||
:param dtype: The datatype to be profiled
|
||||
:type method: str
|
||||
:return: Build the current figure using plot.build(), or None if datatype is not valid for the architecture
|
||||
:rtype: str or None
|
||||
"""
|
||||
console_debug("roofline", "Generating roofline plot for CLI")
|
||||
|
||||
if not (str(dtype) in SUPPORTED_DATATYPES[self.__mspec.gpu_arch]):
|
||||
console_error(
|
||||
"{} is not a supported datatype for roofline profiling on {}".format(
|
||||
str(dtype), self.__mspec.gpu_model
|
||||
),
|
||||
exit=False,
|
||||
)
|
||||
return
|
||||
|
||||
# Check proper datatype input - takes single str
|
||||
if not isinstance(dtype, str):
|
||||
console_error("Unsupported datatype input - must be str")
|
||||
|
||||
if (
|
||||
not isinstance(self.__run_parameters["workload_dir"], list)
|
||||
and self.__run_parameters["workload_dir"] != None
|
||||
):
|
||||
self.roof_setup()
|
||||
|
||||
# Change vL1D to a interpretable str, if required
|
||||
if "vL1D" in self.__run_parameters["mem_level"]:
|
||||
self.__run_parameters["mem_level"].remove("vL1D")
|
||||
self.__run_parameters["mem_level"].append("L1")
|
||||
|
||||
app_path = str(
|
||||
Path(self.__run_parameters["workload_dir"]).joinpath("pmc_perf.csv")
|
||||
)
|
||||
roofline_exists = Path(app_path).is_file()
|
||||
if not roofline_exists:
|
||||
console_error("roofline", "{} does not exist".format(app_path))
|
||||
t_df = OrderedDict()
|
||||
t_df["pmc_perf"] = pd.read_csv(app_path)
|
||||
|
||||
color_scheme = {
|
||||
"HBM": "blue+",
|
||||
"L2": "green+",
|
||||
"L1": "red+",
|
||||
"LDS": "orange+",
|
||||
"VALU": "white",
|
||||
"MFMA": "magenta+",
|
||||
}
|
||||
|
||||
kernel_markers = {
|
||||
0: "star",
|
||||
1: "cross",
|
||||
2: "sd",
|
||||
3: "shamrock",
|
||||
4: "at",
|
||||
5: "atom",
|
||||
}
|
||||
|
||||
self.__ceiling_data = constuct_roof(
|
||||
roofline_parameters=self.__run_parameters,
|
||||
dtype=dtype,
|
||||
)
|
||||
self.__ai_data = calc_ai(self.__mspec, self.__run_parameters["sort_type"], t_df)
|
||||
|
||||
plt.clf()
|
||||
plt.plotsize(plt.tw(), plt.th())
|
||||
|
||||
ops_flops = "OP" if (dtype[:1] == "I") else "FLOP" # For printing purposes
|
||||
|
||||
# Plot BW Lines
|
||||
if self.__run_parameters["mem_level"] == "ALL":
|
||||
cache_hierarchy = ["HBM", "L2", "L1", "LDS"]
|
||||
else:
|
||||
cache_hierarchy = self.__run_parameters["mem_level"]
|
||||
|
||||
for cache_level in cache_hierarchy:
|
||||
plt.plot(
|
||||
self.__ceiling_data[cache_level.lower()][0],
|
||||
self.__ceiling_data[cache_level.lower()][1],
|
||||
label="{}-{}".format(cache_level, dtype),
|
||||
marker="braille",
|
||||
color=color_scheme[cache_level],
|
||||
)
|
||||
plt.text(
|
||||
str(round(self.__ceiling_data[cache_level.lower()][2])) + " GB/s",
|
||||
x=self.__ceiling_data[cache_level.lower()][0][0],
|
||||
y=self.__ceiling_data[cache_level.lower()][1][0],
|
||||
background="black",
|
||||
color="white",
|
||||
alignment="left",
|
||||
)
|
||||
console_debug(
|
||||
"roofline",
|
||||
cache_level
|
||||
+ ": [{},{}], [{},{}], {}".format(
|
||||
str(self.__ceiling_data[cache_level.lower()][0][0]),
|
||||
str(self.__ceiling_data[cache_level.lower()][0][1]),
|
||||
str(self.__ceiling_data[cache_level.lower()][1][0]),
|
||||
str(self.__ceiling_data[cache_level.lower()][1][1]),
|
||||
str(self.__ceiling_data[cache_level.lower()][2]),
|
||||
),
|
||||
)
|
||||
|
||||
# Plot VALU and MFMA Peak
|
||||
if dtype in PEAK_OPS_DATATYPES:
|
||||
plt.plot(
|
||||
self.__ceiling_data["valu"][0],
|
||||
[
|
||||
self.__ceiling_data["valu"][1][0] - 0.1,
|
||||
self.__ceiling_data["valu"][1][1] - 0.1,
|
||||
],
|
||||
label="Peak VALU-{}".format(dtype),
|
||||
marker="braille",
|
||||
color=color_scheme["VALU"],
|
||||
)
|
||||
plt.text(
|
||||
str(round(self.__ceiling_data["valu"][2])) + " G{}/s".format(ops_flops),
|
||||
x=self.__ceiling_data["valu"][0][1] - 800,
|
||||
y=self.__ceiling_data["valu"][1][1],
|
||||
background="black",
|
||||
color="white",
|
||||
alignment="right",
|
||||
)
|
||||
console_debug(
|
||||
"roofline",
|
||||
"VALU: [{},{}], [{},{}], {}".format(
|
||||
str(self.__ceiling_data["valu"][0][0]),
|
||||
str(self.__ceiling_data["valu"][0][1]),
|
||||
str(self.__ceiling_data["valu"][1][0]),
|
||||
str(self.__ceiling_data["valu"][1][1]),
|
||||
str(self.__ceiling_data["valu"][2]),
|
||||
),
|
||||
)
|
||||
else:
|
||||
console_warning("No PEAK measurement available for {}".format(dtype))
|
||||
|
||||
if dtype in MFMA_DATATYPES:
|
||||
plt.plot(
|
||||
self.__ceiling_data["mfma"][0],
|
||||
[
|
||||
self.__ceiling_data["mfma"][1][0] - 0.1,
|
||||
self.__ceiling_data["mfma"][1][1] - 0.1,
|
||||
],
|
||||
label="Peak MFMA-{}".format(dtype),
|
||||
marker="braille",
|
||||
color=color_scheme["MFMA"],
|
||||
)
|
||||
plt.text(
|
||||
str(round(self.__ceiling_data["mfma"][2])) + " G{}/s".format(ops_flops),
|
||||
x=self.__ceiling_data["mfma"][0][1] - 800,
|
||||
y=self.__ceiling_data["mfma"][1][1],
|
||||
background="black",
|
||||
color="white",
|
||||
alignment="right",
|
||||
)
|
||||
console_debug(
|
||||
"roofline",
|
||||
"MFMA: [{},{}], [{},{}], {}".format(
|
||||
str(self.__ceiling_data["mfma"][0][0]),
|
||||
str(self.__ceiling_data["mfma"][0][1]),
|
||||
str(self.__ceiling_data["mfma"][1][0]),
|
||||
str(self.__ceiling_data["mfma"][1][1]),
|
||||
str(self.__ceiling_data["mfma"][2]),
|
||||
),
|
||||
)
|
||||
else:
|
||||
console_warning("No MFMA measurement available for {}".format(dtype))
|
||||
|
||||
# Plot Application AI
|
||||
for cache_level in cache_hierarchy:
|
||||
key = "ai_" + cache_level.lower()
|
||||
if key in self.__ai_data:
|
||||
for i in range(len(self.__ai_data["kernelNames"])):
|
||||
# Zero intensity level means no data reported for this cache level
|
||||
if self.__ai_data[key][0][i] > 0 and self.__ai_data[key][1][i] > 0:
|
||||
plt.plot(
|
||||
[self.__ai_data[key][0][i]],
|
||||
[self.__ai_data[key][1][i]],
|
||||
label="AI_"
|
||||
+ cache_level
|
||||
+ "_{}".format(self.__ai_data["kernelNames"][i]),
|
||||
color=color_scheme[cache_level],
|
||||
marker=kernel_markers[i % len(kernel_markers)],
|
||||
)
|
||||
console_debug(
|
||||
"roofline",
|
||||
"AI_{}: {}, {}".format(
|
||||
self.__ai_data["kernelNames"][i],
|
||||
self.__ai_data[key][0][i],
|
||||
self.__ai_data[key][1][i],
|
||||
),
|
||||
)
|
||||
|
||||
plt.xlabel("Arithmetic Intensity ({})s/Byte)".format(ops_flops))
|
||||
plt.ylabel("Performance (GFLOP/sec)")
|
||||
plt.title("Roofline ({})".format(dtype))
|
||||
|
||||
# Canvas config
|
||||
plt.theme("pro")
|
||||
plt.xscale("log")
|
||||
plt.yscale("log")
|
||||
|
||||
# Build figure
|
||||
# Print plot using `plt._utility.write(self.cli_generate_plot(dtype))`
|
||||
return plt.build()
|
||||
|
||||
@demarcate
|
||||
def standalone_roofline(self):
|
||||
if (
|
||||
|
||||
مرجع در شماره جدید
Block a user