[llvm] 402f91b - [llvm-mca] Plot as result of comparing multiple files

Djordje Todorovic via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 28 04:05:44 PST 2022


Author: Milica Matic
Date: 2022-01-28T13:04:52+01:00
New Revision: 402f91bcbb5157a122b92366b0f5f9a917df06a3

URL: https://github.com/llvm/llvm-project/commit/402f91bcbb5157a122b92366b0f5f9a917df06a3
DIFF: https://github.com/llvm/llvm-project/commit/402f91bcbb5157a122b92366b0f5f9a917df06a3.diff

LOG: [llvm-mca] Plot as result of comparing multiple files

This patch introduces a new options for script llvm-mca-compare.py
(-plot-resource-pressure, -plot) to draw plots for llvm-mca tool
statistics and option (--plot-path) to specify relative path where
you want to save the plots.

Differential Revision: https://reviews.llvm.org/D115718

Added: 
    

Modified: 
    llvm/utils/llvm-mca-compare.py

Removed: 
    


################################################################################
diff  --git a/llvm/utils/llvm-mca-compare.py b/llvm/utils/llvm-mca-compare.py
index 72c875d42442..ca69bc945af1 100755
--- a/llvm/utils/llvm-mca-compare.py
+++ b/llvm/utils/llvm-mca-compare.py
@@ -2,6 +2,7 @@
 
 import argparse
 import sys
+import os
 from json import loads
 from subprocess import Popen, PIPE
 
@@ -60,6 +61,27 @@ def parse_program_args(parser):
         default=["-"],
         help="Forward options to lvm-mca tool.",
     )
+    parser.add_argument(
+        "-plot",
+        action="store_true",
+        default=False,
+        help="Draw plots of statistics for input files.",
+    )
+    parser.add_argument(
+        "-plot-resource-pressure",
+        action="store_true",
+        default=False,
+        help="Draw plots of resource pressure per iterations for input files.",
+    )
+    parser.add_argument(
+        "--plot-path",
+        nargs=1,
+        type=str,
+        action="store",
+        metavar="[=<path>]",
+        default=["-"],
+        help="Specify relative path where you want to save the plots.",
+    )
     parser.add_argument(
         "-v",
         action="store_true",
@@ -69,6 +91,17 @@ def parse_program_args(parser):
     return parser.parse_args()
 
 
+# Verify that the program inputs meet the requirements.
+def verify_program_inputs(opts):
+    if opts.plot_path[0] != "-" and not opts.plot and not opts.plot_resource_pressure:
+        print(
+            "error: Please specify --plot-path only with the -plot or -plot-resource-pressure options."
+        )
+        return False
+
+    return True
+
+
 # Returns the name of the file to be analyzed from the path it is on.
 def get_filename_from_path(path):
     index_of_slash = path.rfind("/")
@@ -129,7 +162,7 @@ def run_llvm_mca_tool(opts, file_name):
             "ResourcePressureInfo"
         ]
 
-        name_target_info_resources = [" "] + json_parsed["TargetInfo"]["Resources"]
+        name_target_info_resources = json_parsed["TargetInfo"]["Resources"]
 
         for s in range(len(resource_pressure_info)):
             obj_of_resource_pressure_info = resource_pressure_info[s]
@@ -243,7 +276,9 @@ def console_print_results(matrix_of_code_regions, opts):
             for j in range(len(matrix_of_code_regions) + 1)
         ]
 
-        table_values[0] = matrix_of_code_regions[0][0].name_target_info_resources
+        table_values[0] = [" "] + matrix_of_code_regions[0][
+            0
+        ].name_target_info_resources
 
         for j in range(len(matrix_of_code_regions)):
             if len(matrix_of_code_regions[j]) > i:
@@ -263,15 +298,289 @@ def console_print_results(matrix_of_code_regions, opts):
         print("\n")
 
 
+# Based on the obtained results (summary view) of llvm-mca tool, draws plots for multiple input files.
+def draw_plot_files_summary(array_of_summary, opts):
+    try:
+        import matplotlib.pyplot as plt
+    except ImportError:
+        print("error: matplotlib.pyplot not found.")
+        sys.exit(1)
+    try:
+        from matplotlib.cm import get_cmap
+    except ImportError:
+        print("error: get_cmap (matplotlib.cm) not found.")
+        sys.exit(1)
+
+    names = [
+        "Block RThroughput",
+        "Dispatch Width",
+        "IPC",
+        "uOps Per Cycle",
+        "Instructions",
+        "Total Cycles",
+        "Total uOps",
+    ]
+
+    rows, cols = (len(opts.file_names), 7)
+
+    values = [[0 for x in range(cols)] for y in range(rows)]
+
+    for i in range(len(opts.file_names)):
+        values[i][0] = array_of_summary[i].block_rthroughput
+        values[i][1] = array_of_summary[i].dispatch_width
+        values[i][2] = array_of_summary[i].ipc
+        values[i][3] = array_of_summary[i].uops_per_cycle
+        values[i][4] = array_of_summary[i].instructions
+        values[i][5] = array_of_summary[i].total_cycles
+        values[i][6] = array_of_summary[i].total_uops
+
+    fig, axs = plt.subplots(4, 2)
+    fig.suptitle(
+        "Machine code statistics", fontsize=20, fontweight="bold", color="black"
+    )
+    i = 0
+
+    for x in range(4):
+        for y in range(2):
+            cmap = get_cmap("tab20")
+            colors = cmap.colors
+            if not (x == 0 and y == 1) and i < 7:
+                axs[x][y].grid(True, color="grey", linestyle="--")
+                maxValue = 0
+                if i == 0:
+                    for j in range(len(opts.file_names)):
+                        if maxValue < values[j][i]:
+                            maxValue = values[j][i]
+                        axs[x][y].bar(
+                            0.3 * j,
+                            values[j][i],
+                            width=0.1,
+                            color=colors[j],
+                            label=get_filename_from_path(opts.file_names[j]),
+                        )
+                else:
+                    for j in range(len(opts.file_names)):
+                        if maxValue < values[j][i]:
+                            maxValue = values[j][i]
+                        axs[x][y].bar(0.3 * j, values[j][i], width=0.1, color=colors[j])
+                axs[x][y].set_axisbelow(True)
+                axs[x][y].set_xlim([-0.3, len(opts.file_names) / 3])
+                axs[x][y].set_ylim([0, maxValue + (maxValue / 2)])
+                axs[x][y].set_title(names[i], fontsize=15, fontweight="bold")
+                axs[x][y].axes.xaxis.set_visible(False)
+                for j in range(len(opts.file_names)):
+                    axs[x][y].text(
+                        0.3 * j,
+                        values[j][i] + (maxValue / 40),
+                        s=str(values[j][i]),
+                        color="black",
+                        fontweight="bold",
+                        fontsize=4,
+                    )
+                i = i + 1
+
+    axs[0][1].set_visible(False)
+    fig.legend(prop={"size": 15})
+    figg = plt.gcf()
+    figg.set_size_inches((25, 15), forward=False)
+    if opts.plot_path[0] == "-":
+        plt.savefig("llvm-mca-plot.png", dpi=500)
+        print("The plot was saved within llvm-mca-plot.png")
+    else:
+        plt.savefig(
+            os.path.normpath(os.path.join(opts.plot_path[0], "llvm-mca-plot.png")),
+            dpi=500,
+        )
+        print(
+            "The plot was saved within {}.".format(
+                os.path.normpath(os.path.join(opts.plot_path[0], "llvm-mca-plot.png"))
+            )
+        )
+
+
+# Calculates the average value (summary view) per region.
+def summary_average_code_region(array_of_code_regions, file_name):
+    summary = Summary(file_name, 0, 0, 0, 0, 0, 0, 0, 0, None, None)
+    for i in range(len(array_of_code_regions)):
+        summary.block_rthroughput += array_of_code_regions[i].block_rthroughput
+        summary.dispatch_width += array_of_code_regions[i].dispatch_width
+        summary.ipc += array_of_code_regions[i].ipc
+        summary.instructions += array_of_code_regions[i].instructions
+        summary.iterations += array_of_code_regions[i].iterations
+        summary.total_cycles += array_of_code_regions[i].total_cycles
+        summary.total_uops += array_of_code_regions[i].total_uops
+        summary.uops_per_cycle += array_of_code_regions[i].uops_per_cycle
+    summary.block_rthroughput = round(
+        summary.block_rthroughput / len(array_of_code_regions), 2
+    )
+    summary.dispatch_width = round(
+        summary.dispatch_width / len(array_of_code_regions), 2
+    )
+    summary.ipc = round(summary.ipc / len(array_of_code_regions), 2)
+    summary.instructions = round(summary.instructions / len(array_of_code_regions), 2)
+    summary.iterations = round(summary.iterations / len(array_of_code_regions), 2)
+    summary.total_cycles = round(summary.total_cycles / len(array_of_code_regions), 2)
+    summary.total_uops = round(summary.total_uops / len(array_of_code_regions), 2)
+    summary.uops_per_cycle = round(
+        summary.uops_per_cycle / len(array_of_code_regions), 2
+    )
+    return summary
+
+
+# Based on the obtained results (resource pressure per iter) of llvm-mca tool, draws plots for multiple input files.
+def draw_plot_resource_pressure(
+    array_average_resource_pressure_per_file, opts, name_target_info_resources
+):
+    try:
+        import matplotlib.pyplot as plt
+    except ImportError:
+        print("error: matplotlib.pyplot not found.")
+        sys.exit(1)
+    try:
+        from matplotlib.cm import get_cmap
+    except ImportError:
+        print("error: get_cmap (matplotlib.cm) not found.")
+        sys.exit(1)
+
+    fig, axs = plt.subplots()
+    fig.suptitle(
+        "Resource pressure per iterations",
+        fontsize=20,
+        fontweight="bold",
+        color="black",
+    )
+
+    maxValue = 0
+    for j in range(len(opts.file_names)):
+        if maxValue < max(array_average_resource_pressure_per_file[j]):
+            maxValue = max(array_average_resource_pressure_per_file[j])
+
+    cmap = get_cmap("tab20")
+    colors = cmap.colors
+
+    xticklabels = [None] * len(opts.file_names) * len(name_target_info_resources)
+    index = 0
+
+    for j in range(len(name_target_info_resources)):
+        for i in range(len(opts.file_names)):
+            if i == 0:
+                axs.bar(
+                    j * len(opts.file_names) * 10 + i * 10,
+                    array_average_resource_pressure_per_file[i][j],
+                    width=1,
+                    color=colors[j],
+                    label=name_target_info_resources[j],
+                )
+            else:
+                axs.bar(
+                    j * len(opts.file_names) * 10 + i * 10,
+                    array_average_resource_pressure_per_file[i][j],
+                    width=1,
+                    color=colors[j],
+                )
+            axs.text(
+                j * len(opts.file_names) * 10 + i * 10,
+                array_average_resource_pressure_per_file[i][j] + (maxValue / 40),
+                s=str(array_average_resource_pressure_per_file[i][j]),
+                color=colors[j],
+                fontweight="bold",
+                fontsize=3,
+            )
+            xticklabels[index] = opts.file_names[i]
+            index = index + 1
+
+    axs.set_xticks(
+        [
+            j * len(opts.file_names) * 10 + i * 10
+            for j in range(len(name_target_info_resources))
+            for i in range(len(opts.file_names))
+        ]
+    )
+    axs.set_xticklabels(xticklabels, rotation=65)
+
+    axs.set_axisbelow(True)
+    axs.set_xlim([-0.5, len(opts.file_names) * len(name_target_info_resources) * 10])
+    axs.set_ylim([0, maxValue + maxValue / 10])
+
+    fig.legend(prop={"size": 15})
+    figg = plt.gcf()
+    figg.set_size_inches((25, 15), forward=False)
+    if opts.plot_path[0] == "-":
+        plt.savefig("llvm-mca-plot-resource-pressure.png", dpi=500)
+        print("The plot was saved within llvm-mca-plot-resource-pressure.png")
+    else:
+        plt.savefig(
+            os.path.normpath(
+                os.path.join(opts.plot_path[0], "llvm-mca-plot-resource-pressure.png")
+            ),
+            dpi=500,
+        )
+        print(
+            "The plot was saved within {}.".format(
+                os.path.normpath(
+                    os.path.join(
+                        opts.plot_path[0], "llvm-mca-plot-resource-pressure.png"
+                    )
+                )
+            )
+        )
+
+
+# Calculates the average value (resource pressure per iter) per region.
+def average_code_region_resource_pressure(array_of_code_regions, file_name):
+    resource_pressure_per_iter_one_file = [0] * len(
+        array_of_code_regions[0].iteration_resource_pressure
+    )
+    for i in range(len(array_of_code_regions)):
+        for j in range(len(array_of_code_regions[i].iteration_resource_pressure)):
+            if array_of_code_regions[i].iteration_resource_pressure[j] != "-":
+                resource_pressure_per_iter_one_file[j] += float(
+                    array_of_code_regions[i].iteration_resource_pressure[j]
+                )
+    for i in range(len(resource_pressure_per_iter_one_file)):
+        resource_pressure_per_iter_one_file[i] = round(
+            resource_pressure_per_iter_one_file[i] / len(array_of_code_regions), 2
+        )
+    return resource_pressure_per_iter_one_file
+
+
 def Main():
     parser = argparse.ArgumentParser()
     opts = parse_program_args(parser)
 
+    if not verify_program_inputs(opts):
+        parser.print_help()
+        sys.exit(1)
+
     matrix_of_code_regions = [None] * len(opts.file_names)
 
     for i in range(len(opts.file_names)):
         matrix_of_code_regions[i] = run_llvm_mca_tool(opts, opts.file_names[i])
-    console_print_results(matrix_of_code_regions, opts)
+    if not opts.plot and not opts.plot_resource_pressure:
+        console_print_results(matrix_of_code_regions, opts)
+    else:
+        if opts.plot:
+            array_average_summary_per_file = [None] * len(matrix_of_code_regions)
+            for j in range(len(matrix_of_code_regions)):
+                array_average_summary_per_file[j] = summary_average_code_region(
+                    matrix_of_code_regions[j], opts.file_names[j]
+                )
+            draw_plot_files_summary(array_average_summary_per_file, opts)
+        if opts.plot_resource_pressure:
+            array_average_resource_pressure_per_file = [None] * len(
+                matrix_of_code_regions
+            )
+            for j in range(len(matrix_of_code_regions)):
+                array_average_resource_pressure_per_file[
+                    j
+                ] = average_code_region_resource_pressure(
+                    matrix_of_code_regions[j], opts.file_names[j]
+                )
+            draw_plot_resource_pressure(
+                array_average_resource_pressure_per_file,
+                opts,
+                matrix_of_code_regions[0][0].name_target_info_resources,
+            )
 
 
 if __name__ == "__main__":


        


More information about the llvm-commits mailing list