forked from OSchip/llvm-project
280 lines
9.0 KiB
Python
Executable File
280 lines
9.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import sys
|
|
from json import loads
|
|
from subprocess import Popen, PIPE
|
|
|
|
# Holds code regions statistics.
|
|
class Summary:
|
|
def __init__(
|
|
self,
|
|
name,
|
|
block_rthroughput,
|
|
dispatch_width,
|
|
ipc,
|
|
instructions,
|
|
iterations,
|
|
total_cycles,
|
|
total_uops,
|
|
uops_per_cycle,
|
|
iteration_resource_pressure,
|
|
name_target_info_resources,
|
|
):
|
|
self.name = name
|
|
self.block_rthroughput = block_rthroughput
|
|
self.dispatch_width = dispatch_width
|
|
self.ipc = ipc
|
|
self.instructions = instructions
|
|
self.iterations = iterations
|
|
self.total_cycles = total_cycles
|
|
self.total_uops = total_uops
|
|
self.uops_per_cycle = uops_per_cycle
|
|
self.iteration_resource_pressure = iteration_resource_pressure
|
|
self.name_target_info_resources = name_target_info_resources
|
|
|
|
|
|
# Parse the program arguments.
|
|
def parse_program_args(parser):
|
|
parser.add_argument(
|
|
"file_names",
|
|
nargs="+",
|
|
type=str,
|
|
help="Names of files which llvm-mca tool process.",
|
|
)
|
|
parser.add_argument(
|
|
"--llvm-mca-binary",
|
|
nargs=1,
|
|
required=True,
|
|
type=str,
|
|
action="store",
|
|
metavar="[=<path to llvm-mca>]",
|
|
help="Specified relative path to binary of llvm-mca.",
|
|
)
|
|
parser.add_argument(
|
|
"--args",
|
|
nargs=1,
|
|
type=str,
|
|
action="store",
|
|
metavar="[='-option1=<arg> -option2=<arg> ...']",
|
|
default=["-"],
|
|
help="Forward options to lvm-mca tool.",
|
|
)
|
|
parser.add_argument(
|
|
"-v",
|
|
action="store_true",
|
|
default=False,
|
|
help="More details about the running lvm-mca tool.",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
# 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("/")
|
|
return path[(index_of_slash + 1) : len(path)]
|
|
|
|
|
|
# Returns the results of the running llvm-mca tool for the input file.
|
|
def run_llvm_mca_tool(opts, file_name):
|
|
# Get the path of the llvm-mca binary file.
|
|
llvm_mca_cmd = opts.llvm_mca_binary[0]
|
|
|
|
# The statistics llvm-mca options.
|
|
if opts.args[0] != "-":
|
|
llvm_mca_cmd += " " + opts.args[0]
|
|
llvm_mca_cmd += " -json"
|
|
|
|
# Set file which llvm-mca tool will process.
|
|
llvm_mca_cmd += " " + file_name
|
|
|
|
if opts.v:
|
|
print("run: $ " + llvm_mca_cmd + "\n")
|
|
|
|
# Generate the stats with the llvm-mca.
|
|
subproc = Popen(
|
|
llvm_mca_cmd.split(" "),
|
|
stdin=PIPE,
|
|
stdout=PIPE,
|
|
stderr=PIPE,
|
|
universal_newlines=True,
|
|
)
|
|
|
|
cmd_stdout, cmd_stderr = subproc.communicate()
|
|
|
|
try:
|
|
json_parsed = loads(cmd_stdout)
|
|
except:
|
|
print("error: No valid llvm-mca statistics found.")
|
|
print(cmd_stderr)
|
|
sys.exit(1)
|
|
|
|
if opts.v:
|
|
print("Simulation Parameters: ")
|
|
simulation_parameters = json_parsed["SimulationParameters"]
|
|
for key in simulation_parameters:
|
|
print(key, ":", simulation_parameters[key])
|
|
print("\n")
|
|
|
|
code_regions_len = len(json_parsed["CodeRegions"])
|
|
array_of_code_regions = [None] * code_regions_len
|
|
|
|
for i in range(code_regions_len):
|
|
code_region_instructions_len = len(
|
|
json_parsed["CodeRegions"][i]["Instructions"]
|
|
)
|
|
target_info_resources_len = len(json_parsed["TargetInfo"]["Resources"])
|
|
iteration_resource_pressure = ["-" for k in range(target_info_resources_len)]
|
|
resource_pressure_info = json_parsed["CodeRegions"][i]["ResourcePressureView"][
|
|
"ResourcePressureInfo"
|
|
]
|
|
|
|
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]
|
|
if (
|
|
obj_of_resource_pressure_info["InstructionIndex"]
|
|
== code_region_instructions_len
|
|
):
|
|
iteration_resource_pressure[
|
|
obj_of_resource_pressure_info["ResourceIndex"]
|
|
] = str(round(obj_of_resource_pressure_info["ResourceUsage"], 2))
|
|
|
|
array_of_code_regions[i] = Summary(
|
|
file_name,
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["BlockRThroughput"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["DispatchWidth"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["IPC"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["Instructions"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["Iterations"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["TotalCycles"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["TotaluOps"],
|
|
json_parsed["CodeRegions"][i]["SummaryView"]["uOpsPerCycle"],
|
|
iteration_resource_pressure,
|
|
name_target_info_resources,
|
|
)
|
|
|
|
return array_of_code_regions
|
|
|
|
|
|
# Print statistics in console for single file or for multiple files.
|
|
def console_print_results(matrix_of_code_regions, opts):
|
|
try:
|
|
import termtables as tt
|
|
except ImportError:
|
|
print("error: termtables not found.")
|
|
sys.exit(1)
|
|
|
|
headers_names = [None] * (len(opts.file_names) + 1)
|
|
headers_names[0] = " "
|
|
|
|
max_code_regions = 0
|
|
|
|
print("Input files:")
|
|
for i in range(len(matrix_of_code_regions)):
|
|
if max_code_regions < len(matrix_of_code_regions[i]):
|
|
max_code_regions = len(matrix_of_code_regions[i])
|
|
print("[f" + str(i + 1) + "]: " + get_filename_from_path(opts.file_names[i]))
|
|
headers_names[i + 1] = "[f" + str(i + 1) + "]: "
|
|
|
|
print("\nITERATIONS: " + str(matrix_of_code_regions[0][0].iterations) + "\n")
|
|
|
|
for i in range(max_code_regions):
|
|
|
|
print(
|
|
"\n-----------------------------------------\nCode region: "
|
|
+ str(i + 1)
|
|
+ "\n"
|
|
)
|
|
|
|
table_values = [
|
|
[[None] for i in range(len(matrix_of_code_regions) + 1)] for j in range(7)
|
|
]
|
|
|
|
table_values[0][0] = "Instructions: "
|
|
table_values[1][0] = "Total Cycles: "
|
|
table_values[2][0] = "Total uOps: "
|
|
table_values[3][0] = "Dispatch Width: "
|
|
table_values[4][0] = "uOps Per Cycle: "
|
|
table_values[5][0] = "IPC: "
|
|
table_values[6][0] = "Block RThroughput: "
|
|
|
|
for j in range(len(matrix_of_code_regions)):
|
|
if len(matrix_of_code_regions[j]) > i:
|
|
table_values[0][j + 1] = str(matrix_of_code_regions[j][i].instructions)
|
|
table_values[1][j + 1] = str(matrix_of_code_regions[j][i].total_cycles)
|
|
table_values[2][j + 1] = str(matrix_of_code_regions[j][i].total_uops)
|
|
table_values[3][j + 1] = str(
|
|
matrix_of_code_regions[j][i].dispatch_width
|
|
)
|
|
table_values[4][j + 1] = str(
|
|
round(matrix_of_code_regions[j][i].uops_per_cycle, 2)
|
|
)
|
|
table_values[5][j + 1] = str(round(matrix_of_code_regions[j][i].ipc, 2))
|
|
table_values[6][j + 1] = str(
|
|
round(matrix_of_code_regions[j][i].block_rthroughput, 2)
|
|
)
|
|
else:
|
|
table_values[0][j + 1] = "-"
|
|
table_values[1][j + 1] = "-"
|
|
table_values[2][j + 1] = "-"
|
|
table_values[3][j + 1] = "-"
|
|
table_values[4][j + 1] = "-"
|
|
table_values[5][j + 1] = "-"
|
|
table_values[6][j + 1] = "-"
|
|
|
|
tt.print(
|
|
table_values,
|
|
header=headers_names,
|
|
style=tt.styles.ascii_thin_double,
|
|
padding=(0, 1),
|
|
)
|
|
|
|
print("\nResource pressure per iteration: \n")
|
|
|
|
table_values = [
|
|
[
|
|
[None]
|
|
for i in range(
|
|
len(matrix_of_code_regions[0][0].iteration_resource_pressure) + 1
|
|
)
|
|
]
|
|
for j in range(len(matrix_of_code_regions) + 1)
|
|
]
|
|
|
|
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:
|
|
table_values[j + 1] = [
|
|
"[f" + str(j + 1) + "]: "
|
|
] + matrix_of_code_regions[j][i].iteration_resource_pressure
|
|
else:
|
|
table_values[j + 1] = ["[f" + str(j + 1) + "]: "] + len(
|
|
matrix_of_code_regions[0][0].iteration_resource_pressure
|
|
) * ["-"]
|
|
|
|
tt.print(
|
|
table_values,
|
|
style=tt.styles.ascii_thin_double,
|
|
padding=(0, 1),
|
|
)
|
|
print("\n")
|
|
|
|
|
|
def Main():
|
|
parser = argparse.ArgumentParser()
|
|
opts = parse_program_args(parser)
|
|
|
|
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 __name__ == "__main__":
|
|
Main()
|
|
sys.exit(0)
|