7 from subprocess
import Popen
, PIPE
9 # Holds code regions statistics.
22 iteration_resource_pressure
,
23 name_target_info_resources
,
26 self
.block_rthroughput
= block_rthroughput
27 self
.dispatch_width
= dispatch_width
29 self
.instructions
= instructions
30 self
.iterations
= iterations
31 self
.total_cycles
= total_cycles
32 self
.total_uops
= total_uops
33 self
.uops_per_cycle
= uops_per_cycle
34 self
.iteration_resource_pressure
= iteration_resource_pressure
35 self
.name_target_info_resources
= name_target_info_resources
38 # Parse the program arguments.
39 def parse_program_args(parser
):
44 help="Names of files which llvm-mca tool process.",
52 metavar
="[=<path to llvm-mca>]",
53 help="Specified relative path to binary of llvm-mca.",
60 metavar
="[='-option1=<arg> -option2=<arg> ...']",
62 help="Forward options to lvm-mca tool.",
68 help="Draw plots of statistics for input files.",
71 "-plot-resource-pressure",
74 help="Draw plots of resource pressure per iterations for input files.",
83 help="Specify relative path where you want to save the plots.",
89 help="More details about the running lvm-mca tool.",
91 return parser
.parse_args()
94 # Verify that the program inputs meet the requirements.
95 def verify_program_inputs(opts
):
96 if opts
.plot_path
[0] != "-" and not opts
.plot
and not opts
.plot_resource_pressure
:
98 "error: Please specify --plot-path only with the -plot or -plot-resource-pressure options."
105 # Returns the name of the file to be analyzed from the path it is on.
106 def get_filename_from_path(path
):
107 index_of_slash
= path
.rfind("/")
108 return path
[(index_of_slash
+ 1) : len(path
)]
111 # Returns the results of the running llvm-mca tool for the input file.
112 def run_llvm_mca_tool(opts
, file_name
):
113 # Get the path of the llvm-mca binary file.
114 llvm_mca_cmd
= opts
.llvm_mca_binary
[0]
116 # The statistics llvm-mca options.
117 if opts
.args
[0] != "-":
118 llvm_mca_cmd
+= " " + opts
.args
[0]
119 llvm_mca_cmd
+= " -json"
121 # Set file which llvm-mca tool will process.
122 llvm_mca_cmd
+= " " + file_name
125 print("run: $ " + llvm_mca_cmd
+ "\n")
127 # Generate the stats with the llvm-mca.
129 llvm_mca_cmd
.split(" "),
133 universal_newlines
=True,
136 cmd_stdout
, cmd_stderr
= subproc
.communicate()
139 json_parsed
= loads(cmd_stdout
)
141 print("error: No valid llvm-mca statistics found.")
146 print("Simulation Parameters: ")
147 simulation_parameters
= json_parsed
["SimulationParameters"]
148 for key
in simulation_parameters
:
149 print(key
, ":", simulation_parameters
[key
])
152 code_regions_len
= len(json_parsed
["CodeRegions"])
153 array_of_code_regions
= [None] * code_regions_len
155 for i
in range(code_regions_len
):
156 code_region_instructions_len
= len(
157 json_parsed
["CodeRegions"][i
]["Instructions"]
159 target_info_resources_len
= len(json_parsed
["TargetInfo"]["Resources"])
160 iteration_resource_pressure
= ["-" for k
in range(target_info_resources_len
)]
161 resource_pressure_info
= json_parsed
["CodeRegions"][i
]["ResourcePressureView"][
162 "ResourcePressureInfo"
165 name_target_info_resources
= json_parsed
["TargetInfo"]["Resources"]
167 for s
in range(len(resource_pressure_info
)):
168 obj_of_resource_pressure_info
= resource_pressure_info
[s
]
170 obj_of_resource_pressure_info
["InstructionIndex"]
171 == code_region_instructions_len
173 iteration_resource_pressure
[
174 obj_of_resource_pressure_info
["ResourceIndex"]
175 ] = str(round(obj_of_resource_pressure_info
["ResourceUsage"], 2))
177 array_of_code_regions
[i
] = Summary(
179 json_parsed
["CodeRegions"][i
]["SummaryView"]["BlockRThroughput"],
180 json_parsed
["CodeRegions"][i
]["SummaryView"]["DispatchWidth"],
181 json_parsed
["CodeRegions"][i
]["SummaryView"]["IPC"],
182 json_parsed
["CodeRegions"][i
]["SummaryView"]["Instructions"],
183 json_parsed
["CodeRegions"][i
]["SummaryView"]["Iterations"],
184 json_parsed
["CodeRegions"][i
]["SummaryView"]["TotalCycles"],
185 json_parsed
["CodeRegions"][i
]["SummaryView"]["TotaluOps"],
186 json_parsed
["CodeRegions"][i
]["SummaryView"]["uOpsPerCycle"],
187 iteration_resource_pressure
,
188 name_target_info_resources
,
191 return array_of_code_regions
194 # Print statistics in console for single file or for multiple files.
195 def console_print_results(matrix_of_code_regions
, opts
):
197 import termtables
as tt
199 print("error: termtables not found.")
202 headers_names
= [None] * (len(opts
.file_names
) + 1)
203 headers_names
[0] = " "
207 print("Input files:")
208 for i
in range(len(matrix_of_code_regions
)):
209 if max_code_regions
< len(matrix_of_code_regions
[i
]):
210 max_code_regions
= len(matrix_of_code_regions
[i
])
211 print("[f" + str(i
+ 1) + "]: " + get_filename_from_path(opts
.file_names
[i
]))
212 headers_names
[i
+ 1] = "[f" + str(i
+ 1) + "]: "
214 print("\nITERATIONS: " + str(matrix_of_code_regions
[0][0].iterations
) + "\n")
216 for i
in range(max_code_regions
):
219 "\n-----------------------------------------\nCode region: "
225 [[None] for i
in range(len(matrix_of_code_regions
) + 1)] for j
in range(7)
228 table_values
[0][0] = "Instructions: "
229 table_values
[1][0] = "Total Cycles: "
230 table_values
[2][0] = "Total uOps: "
231 table_values
[3][0] = "Dispatch Width: "
232 table_values
[4][0] = "uOps Per Cycle: "
233 table_values
[5][0] = "IPC: "
234 table_values
[6][0] = "Block RThroughput: "
236 for j
in range(len(matrix_of_code_regions
)):
237 if len(matrix_of_code_regions
[j
]) > i
:
238 table_values
[0][j
+ 1] = str(matrix_of_code_regions
[j
][i
].instructions
)
239 table_values
[1][j
+ 1] = str(matrix_of_code_regions
[j
][i
].total_cycles
)
240 table_values
[2][j
+ 1] = str(matrix_of_code_regions
[j
][i
].total_uops
)
241 table_values
[3][j
+ 1] = str(
242 matrix_of_code_regions
[j
][i
].dispatch_width
244 table_values
[4][j
+ 1] = str(
245 round(matrix_of_code_regions
[j
][i
].uops_per_cycle
, 2)
247 table_values
[5][j
+ 1] = str(round(matrix_of_code_regions
[j
][i
].ipc
, 2))
248 table_values
[6][j
+ 1] = str(
249 round(matrix_of_code_regions
[j
][i
].block_rthroughput
, 2)
252 table_values
[0][j
+ 1] = "-"
253 table_values
[1][j
+ 1] = "-"
254 table_values
[2][j
+ 1] = "-"
255 table_values
[3][j
+ 1] = "-"
256 table_values
[4][j
+ 1] = "-"
257 table_values
[5][j
+ 1] = "-"
258 table_values
[6][j
+ 1] = "-"
262 header
=headers_names
,
263 style
=tt
.styles
.ascii_thin_double
,
267 print("\nResource pressure per iteration: \n")
273 len(matrix_of_code_regions
[0][0].iteration_resource_pressure
) + 1
276 for j
in range(len(matrix_of_code_regions
) + 1)
279 table_values
[0] = [" "] + matrix_of_code_regions
[0][
281 ].name_target_info_resources
283 for j
in range(len(matrix_of_code_regions
)):
284 if len(matrix_of_code_regions
[j
]) > i
:
285 table_values
[j
+ 1] = [
286 "[f" + str(j
+ 1) + "]: "
287 ] + matrix_of_code_regions
[j
][i
].iteration_resource_pressure
289 table_values
[j
+ 1] = ["[f" + str(j
+ 1) + "]: "] + len(
290 matrix_of_code_regions
[0][0].iteration_resource_pressure
295 style
=tt
.styles
.ascii_thin_double
,
301 # Based on the obtained results (summary view) of llvm-mca tool, draws plots for multiple input files.
302 def draw_plot_files_summary(array_of_summary
, opts
):
304 import matplotlib
.pyplot
as plt
306 print("error: matplotlib.pyplot not found.")
309 from matplotlib
.cm
import get_cmap
311 print("error: get_cmap (matplotlib.cm) not found.")
324 rows
, cols
= (len(opts
.file_names
), 7)
326 values
= [[0 for x
in range(cols
)] for y
in range(rows
)]
328 for i
in range(len(opts
.file_names
)):
329 values
[i
][0] = array_of_summary
[i
].block_rthroughput
330 values
[i
][1] = array_of_summary
[i
].dispatch_width
331 values
[i
][2] = array_of_summary
[i
].ipc
332 values
[i
][3] = array_of_summary
[i
].uops_per_cycle
333 values
[i
][4] = array_of_summary
[i
].instructions
334 values
[i
][5] = array_of_summary
[i
].total_cycles
335 values
[i
][6] = array_of_summary
[i
].total_uops
337 fig
, axs
= plt
.subplots(4, 2)
339 "Machine code statistics", fontsize
=20, fontweight
="bold", color
="black"
345 cmap
= get_cmap("tab20")
347 if not (x
== 0 and y
== 1) and i
< 7:
348 axs
[x
][y
].grid(True, color
="grey", linestyle
="--")
351 for j
in range(len(opts
.file_names
)):
352 if maxValue
< values
[j
][i
]:
353 maxValue
= values
[j
][i
]
359 label
=get_filename_from_path(opts
.file_names
[j
]),
362 for j
in range(len(opts
.file_names
)):
363 if maxValue
< values
[j
][i
]:
364 maxValue
= values
[j
][i
]
365 axs
[x
][y
].bar(0.3 * j
, values
[j
][i
], width
=0.1, color
=colors
[j
])
366 axs
[x
][y
].set_axisbelow(True)
367 axs
[x
][y
].set_xlim([-0.3, len(opts
.file_names
) / 3])
368 axs
[x
][y
].set_ylim([0, maxValue
+ (maxValue
/ 2)])
369 axs
[x
][y
].set_title(names
[i
], fontsize
=15, fontweight
="bold")
370 axs
[x
][y
].axes
.xaxis
.set_visible(False)
371 for j
in range(len(opts
.file_names
)):
374 values
[j
][i
] + (maxValue
/ 40),
382 axs
[0][1].set_visible(False)
383 fig
.legend(prop
={"size": 15})
385 figg
.set_size_inches((25, 15), forward
=False)
386 if opts
.plot_path
[0] == "-":
387 plt
.savefig("llvm-mca-plot.png", dpi
=500)
388 print("The plot was saved within llvm-mca-plot.png")
391 os
.path
.normpath(os
.path
.join(opts
.plot_path
[0], "llvm-mca-plot.png")),
395 "The plot was saved within {}.".format(
396 os
.path
.normpath(os
.path
.join(opts
.plot_path
[0], "llvm-mca-plot.png"))
401 # Calculates the average value (summary view) per region.
402 def summary_average_code_region(array_of_code_regions
, file_name
):
403 summary
= Summary(file_name
, 0, 0, 0, 0, 0, 0, 0, 0, None, None)
404 for i
in range(len(array_of_code_regions
)):
405 summary
.block_rthroughput
+= array_of_code_regions
[i
].block_rthroughput
406 summary
.dispatch_width
+= array_of_code_regions
[i
].dispatch_width
407 summary
.ipc
+= array_of_code_regions
[i
].ipc
408 summary
.instructions
+= array_of_code_regions
[i
].instructions
409 summary
.iterations
+= array_of_code_regions
[i
].iterations
410 summary
.total_cycles
+= array_of_code_regions
[i
].total_cycles
411 summary
.total_uops
+= array_of_code_regions
[i
].total_uops
412 summary
.uops_per_cycle
+= array_of_code_regions
[i
].uops_per_cycle
413 summary
.block_rthroughput
= round(
414 summary
.block_rthroughput
/ len(array_of_code_regions
), 2
416 summary
.dispatch_width
= round(
417 summary
.dispatch_width
/ len(array_of_code_regions
), 2
419 summary
.ipc
= round(summary
.ipc
/ len(array_of_code_regions
), 2)
420 summary
.instructions
= round(summary
.instructions
/ len(array_of_code_regions
), 2)
421 summary
.iterations
= round(summary
.iterations
/ len(array_of_code_regions
), 2)
422 summary
.total_cycles
= round(summary
.total_cycles
/ len(array_of_code_regions
), 2)
423 summary
.total_uops
= round(summary
.total_uops
/ len(array_of_code_regions
), 2)
424 summary
.uops_per_cycle
= round(
425 summary
.uops_per_cycle
/ len(array_of_code_regions
), 2
430 # Based on the obtained results (resource pressure per iter) of llvm-mca tool, draws plots for multiple input files.
431 def draw_plot_resource_pressure(
432 array_average_resource_pressure_per_file
, opts
, name_target_info_resources
435 import matplotlib
.pyplot
as plt
437 print("error: matplotlib.pyplot not found.")
440 from matplotlib
.cm
import get_cmap
442 print("error: get_cmap (matplotlib.cm) not found.")
445 fig
, axs
= plt
.subplots()
447 "Resource pressure per iterations",
454 for j
in range(len(opts
.file_names
)):
455 if maxValue
< max(array_average_resource_pressure_per_file
[j
]):
456 maxValue
= max(array_average_resource_pressure_per_file
[j
])
458 cmap
= get_cmap("tab20")
461 xticklabels
= [None] * len(opts
.file_names
) * len(name_target_info_resources
)
464 for j
in range(len(name_target_info_resources
)):
465 for i
in range(len(opts
.file_names
)):
468 j
* len(opts
.file_names
) * 10 + i
* 10,
469 array_average_resource_pressure_per_file
[i
][j
],
472 label
=name_target_info_resources
[j
],
476 j
* len(opts
.file_names
) * 10 + i
* 10,
477 array_average_resource_pressure_per_file
[i
][j
],
482 j
* len(opts
.file_names
) * 10 + i
* 10,
483 array_average_resource_pressure_per_file
[i
][j
] + (maxValue
/ 40),
484 s
=str(array_average_resource_pressure_per_file
[i
][j
]),
489 xticklabels
[index
] = opts
.file_names
[i
]
494 j
* len(opts
.file_names
) * 10 + i
* 10
495 for j
in range(len(name_target_info_resources
))
496 for i
in range(len(opts
.file_names
))
499 axs
.set_xticklabels(xticklabels
, rotation
=65)
501 axs
.set_axisbelow(True)
502 axs
.set_xlim([-0.5, len(opts
.file_names
) * len(name_target_info_resources
) * 10])
503 axs
.set_ylim([0, maxValue
+ maxValue
/ 10])
505 fig
.legend(prop
={"size": 15})
507 figg
.set_size_inches((25, 15), forward
=False)
508 if opts
.plot_path
[0] == "-":
509 plt
.savefig("llvm-mca-plot-resource-pressure.png", dpi
=500)
510 print("The plot was saved within llvm-mca-plot-resource-pressure.png")
514 os
.path
.join(opts
.plot_path
[0], "llvm-mca-plot-resource-pressure.png")
519 "The plot was saved within {}.".format(
522 opts
.plot_path
[0], "llvm-mca-plot-resource-pressure.png"
529 # Calculates the average value (resource pressure per iter) per region.
530 def average_code_region_resource_pressure(array_of_code_regions
, file_name
):
531 resource_pressure_per_iter_one_file
= [0] * len(
532 array_of_code_regions
[0].iteration_resource_pressure
534 for i
in range(len(array_of_code_regions
)):
535 for j
in range(len(array_of_code_regions
[i
].iteration_resource_pressure
)):
536 if array_of_code_regions
[i
].iteration_resource_pressure
[j
] != "-":
537 resource_pressure_per_iter_one_file
[j
] += float(
538 array_of_code_regions
[i
].iteration_resource_pressure
[j
]
540 for i
in range(len(resource_pressure_per_iter_one_file
)):
541 resource_pressure_per_iter_one_file
[i
] = round(
542 resource_pressure_per_iter_one_file
[i
] / len(array_of_code_regions
), 2
544 return resource_pressure_per_iter_one_file
548 parser
= argparse
.ArgumentParser()
549 opts
= parse_program_args(parser
)
551 if not verify_program_inputs(opts
):
555 matrix_of_code_regions
= [None] * len(opts
.file_names
)
557 for i
in range(len(opts
.file_names
)):
558 matrix_of_code_regions
[i
] = run_llvm_mca_tool(opts
, opts
.file_names
[i
])
559 if not opts
.plot
and not opts
.plot_resource_pressure
:
560 console_print_results(matrix_of_code_regions
, opts
)
563 array_average_summary_per_file
= [None] * len(matrix_of_code_regions
)
564 for j
in range(len(matrix_of_code_regions
)):
565 array_average_summary_per_file
[j
] = summary_average_code_region(
566 matrix_of_code_regions
[j
], opts
.file_names
[j
]
568 draw_plot_files_summary(array_average_summary_per_file
, opts
)
569 if opts
.plot_resource_pressure
:
570 array_average_resource_pressure_per_file
= [None] * len(
571 matrix_of_code_regions
573 for j
in range(len(matrix_of_code_regions
)):
574 array_average_resource_pressure_per_file
[
576 ] = average_code_region_resource_pressure(
577 matrix_of_code_regions
[j
], opts
.file_names
[j
]
579 draw_plot_resource_pressure(
580 array_average_resource_pressure_per_file
,
582 matrix_of_code_regions
[0][0].name_target_info_resources
,
586 if __name__
== "__main__":