diff --git a/projects/rocprofiler-compute/src/omniperf b/projects/rocprofiler-compute/src/omniperf index dd1679afe9..72839cf0a1 100755 --- a/projects/rocprofiler-compute/src/omniperf +++ b/projects/rocprofiler-compute/src/omniperf @@ -715,7 +715,7 @@ def main(): # Setup prerequisits for roofline roof_setup(args, my_parser, VER) # Generate roofline - roofline_only(args.path, args.device, args.sort, args.mem_level, args.verbose) + roofline_only(args.path, args.device, args.sort, args.mem_level, args.kernel_names, args.verbose) # Profile only else: diff --git a/projects/rocprofiler-compute/src/omniperf_analyze/omniperf_analyze.py b/projects/rocprofiler-compute/src/omniperf_analyze/omniperf_analyze.py index 368e5c50c5..0825cbe2ef 100644 --- a/projects/rocprofiler-compute/src/omniperf_analyze/omniperf_analyze.py +++ b/projects/rocprofiler-compute/src/omniperf_analyze/omniperf_analyze.py @@ -212,7 +212,7 @@ def run_cli(args, runs): ) -def roofline_only(path_to_dir, dev_id, sort_type, mem_level, verbose): +def roofline_only(path_to_dir, dev_id, sort_type, mem_level, kernel_names, verbose): import pandas as pd from collections import OrderedDict @@ -235,6 +235,7 @@ def roofline_only(path_to_dir, dev_id, sort_type, mem_level, verbose): dev_id, # [Optional] Specify device id to collect roofline info from sort_type, # [Optional] Sort AI by top kernels or dispatches mem_level, # [Optional] Toggle particular level(s) of memory hierarchy + kernel_names, # [Optional] Toggle overlay of kernel names in plot True, # [Optional] Generate a standalone roofline analysis ) diff --git a/projects/rocprofiler-compute/src/omniperf_analyze/utils/gui_components/roofline.py b/projects/rocprofiler-compute/src/omniperf_analyze/utils/gui_components/roofline.py index 8fb6e36a74..13c6787d64 100644 --- a/projects/rocprofiler-compute/src/omniperf_analyze/utils/gui_components/roofline.py +++ b/projects/rocprofiler-compute/src/omniperf_analyze/utils/gui_components/roofline.py @@ -25,6 +25,7 @@ from omniperf_analyze.utils import roofline_calc import time +import sys import numpy as np from dash import html, dash_table @@ -32,6 +33,8 @@ from dash import dcc import plotly.graph_objects as go +SYMBOLS = [0,1,2,3,4,5,13,17,18,20] + def to_int(a): if str(type(a)) == "": return np.nan @@ -120,6 +123,7 @@ def generate_plots(roof_info, ai_data, mem_level, is_standalone, verbose, fig=No y=ai_data["ai_l1"][1], name="ai_l1", mode="markers", + marker_symbol=SYMBOLS, ) ) fig.add_trace( @@ -128,6 +132,7 @@ def generate_plots(roof_info, ai_data, mem_level, is_standalone, verbose, fig=No y=ai_data["ai_l2"][1], name="ai_l2", mode="markers", + marker_symbol=SYMBOLS, ) ) fig.add_trace( @@ -136,6 +141,7 @@ def generate_plots(roof_info, ai_data, mem_level, is_standalone, verbose, fig=No y=ai_data["ai_hbm"][1], name="ai_hbm", mode="markers", + marker_symbol=SYMBOLS, ) ) @@ -158,8 +164,13 @@ def get_roofline( dev_id=None, sort_type="kernels", mem_level="ALL", + kernel_names=False, is_standalone=False, ): + if kernel_names and (not is_standalone): + print("ERROR: --roof-only is required for --kernel-names") + sys.exit(1) + # Roofline settings fp32_details = { "path": path_to_dir, @@ -190,6 +201,18 @@ def get_roofline( ml_combo_fig = generate_plots( int8_details, ai_data, mem_level, is_standalone, verbose, fp16_fig ) + legend = go.Figure( + go.Scatter( + mode="markers", + x=[0]*10, + y=ai_data["kernelNames"], + marker_symbol=SYMBOLS, + marker_size=15, + ) + ) + legend.update_layout(title="Kernel Names and Markers", + margin=dict(b=0,r=0), xaxis_range=[-1,1], xaxis_side="top", height=400, width=1000) + legend.update_xaxes(dtick=1) if is_standalone: dev_id = "ALL" if dev_id == -1 else str(dev_id) @@ -198,12 +221,18 @@ def get_roofline( ml_combo_fig.write_image( path_to_dir + "/empirRoof_gpu-{}_fp8_fp16.pdf".format(dev_id) ) + legend.write_image( + path_to_dir + "/kernelName_legend.pdf" + ) time.sleep(1) # Re-save to remove loading MathJax pop up fp32_fig.write_image(path_to_dir + "/empirRoof_gpu-{}_fp32.pdf".format(dev_id)) ml_combo_fig.write_image( path_to_dir + "/empirRoof_gpu-{}_fp8_fp16.pdf".format(dev_id) ) + legend.write_image( + path_to_dir + "/kernelName_legend.pdf" + ) print("Empirical Roofline PDFs saved!") else: return html.Section( diff --git a/projects/rocprofiler-compute/src/omniperf_analyze/utils/roofline_calc.py b/projects/rocprofiler-compute/src/omniperf_analyze/utils/roofline_calc.py index 987b6694de..7ba4725f9e 100644 --- a/projects/rocprofiler-compute/src/omniperf_analyze/utils/roofline_calc.py +++ b/projects/rocprofiler-compute/src/omniperf_analyze/utils/roofline_calc.py @@ -44,6 +44,8 @@ FONT_WEIGHT = "bold" SUPPORTED_SOC = ["mi200"] +TOP_N = 10 + ################################################ # Helper funcs @@ -428,9 +430,11 @@ def plot_application(sortType, ret_df, verbose): # print("Top 5 intensities ('{}')...".format(roof_details["sort"])) intensities = {"ai_l1": [], "ai_l2": [], "ai_hbm": []} curr_perf = [] + kernelNames = [] i = 0 # Create list of top 5 intensities - while i <= 9 and i != len(myList): + while i < TOP_N and i != len(myList): + kernelNames.append(myList[i].KernelName) intensities["ai_l1"].append( myList[i].total_flops / myList[i].L1cache_data ) if myList[i].L1cache_data else intensities["ai_l1"].append(0) @@ -470,6 +474,9 @@ def plot_application(sortType, ret_df, verbose): intensityPoints[i].append(x) intensityPoints[i].append(y) + # Add an entry for kernel names + intensityPoints["kernelNames"] = kernelNames + return intensityPoints diff --git a/projects/rocprofiler-compute/src/parser.py b/projects/rocprofiler-compute/src/parser.py index b305b60187..061d85d438 100644 --- a/projects/rocprofiler-compute/src/parser.py +++ b/projects/rocprofiler-compute/src/parser.py @@ -234,6 +234,13 @@ def parse(my_parser): type=int, help="\t\t\tGPU device ID. (DEFAULT: ALL)", ) + roofline_group.add_argument( + "--kernel-names", + required=False, + default=False, + action="store_true", + help="\t\t\tInclude kernel names in roofline plot.", + ) # roofline_group.add_argument('-w', '--workgroups', required=False, default=-1, type=int, help="\t\t\tNumber of kernel workgroups (DEFAULT: 1024)") # roofline_group.add_argument('--wsize', required=False, default=-1, type=int, help="\t\t\tWorkgroup size (DEFAULT: 256)") # roofline_group.add_argument('--dataset', required=False, default = -1, type=int, help="\t\t\tDataset size (DEFAULT: 536M)")