Skip to content

Commit 98ab0fd

Browse files
[mca] update_mca_test_checks.py helpers to manage llvm-mca -scheduling-info new option
When using llvm-mca -scheduling-info and if assembly test contains comments with reference values of scheduling info: <MicroOps> <Latency> <Forward Latency> <Throughput> <Units> To check coherency between llvm-mca -scheduling-info output and scheduling references in comment, use --check-sched-info. Exit with error if found deferences and report them. This is usefull to check new scheduling info patches as we can specify source documentation references for each instructions and so be able to understand easier differences. Example of comment in AArch64/Neoverse/V1-scheduling-info.s: abs D15, D23 // ABS <V><d>, <V><n> \\ ASIMD arith, basic \\ 1 2 2 4.0 V1UnitV llvm-mca -scheduling-info output: 1 2 2 4.00 - ABSv1i64 V1UnitSVE01, V1UnitV, abs d15, d23 // ABS <V><d>, <V><n> \\ ASIMD arith, basic \\ 1 2 2 4.0 V1UnitV update_mca_test_checks.py is searching for 4 values at the begining and after comment // and compare these values. Values order must be the same as llvm-mca output. And it will check that all resources in comment (reference) is included in llvm-mca output. It is possible to update source test scheduling information references using -update-sched-info option. If you want to update test source references and llvm-mca output references, you have to run two times update_mca_test_checks.py -update-sched-info. First time to update scheduling information references and second time to update llvm-mca new output reference.
1 parent 1f2ab0d commit 98ab0fd

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

llvm/utils/update_mca_test_checks.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import os
1313
import sys
1414
import warnings
15+
import re
1516

1617
from UpdateTestChecks import common
1718

@@ -64,6 +65,16 @@ def _get_parser():
6465
default="llvm-mca",
6566
help="the binary to use to generate the test case " "(default: llvm-mca)",
6667
)
68+
parser.add_argument(
69+
"--check-sched-info", action="store_true",
70+
help="check scheduling info if references are given "
71+
"in comment after each instruction"
72+
)
73+
parser.add_argument(
74+
"--update-sched-info", action="store_true",
75+
help="updating scheduling info references given "
76+
"in comment after each instruction"
77+
)
6778
parser.add_argument("tests", metavar="<test-path>", nargs="+")
6879
return parser
6980

@@ -244,6 +255,146 @@ def _align_matching_blocks(all_blocks, farthest_indexes):
244255

245256
return False
246257

258+
def _check_sched_values(line,scheds,units,err,updates):
259+
"""Check for scheduling values differences
260+
between values reported by llvm-mca with -scheduling-info option
261+
and values in comment at the end of assembly instruction line (//).
262+
Reference units must be included in the list reported by llvm-mca.
263+
"""
264+
265+
_err = []
266+
# Got zip of llvm output and values from comment
267+
infos = ["MicroOps","Latency","Forward latency","Throughput"]
268+
sched_info = zip(infos,scheds[0].split(),scheds[1].split())
269+
for si in sched_info:
270+
if float(si[1]) != float(si[2]):
271+
updates.add("sched")
272+
_err.append(
273+
"\t=> {} LLVM value {} != reference value in comment {}\n".
274+
format(si[0],si[1],si[2]))
275+
276+
for u in units[1]:
277+
if not u in units[0]:
278+
updates.add("units")
279+
_err.append(
280+
"\t=> LLVM units {} != reference units in comment {}\n".
281+
format(units[0],units[1]))
282+
break
283+
284+
if len(_err) > 0:
285+
err.append("{}\n{}".format(line,"".join(_err)))
286+
return True
287+
288+
return False
289+
290+
def _replace_values(oldvalue,newvalue):
291+
"""Replacing values with the same format (spaces)
292+
than oldvalue
293+
"""
294+
295+
fmt = re.sub("[0-9.]+","{}", oldvalue)
296+
return fmt.format(*newvalue.split())
297+
298+
def _has_comment(line,cmt_format):
299+
"""Returns True if line contains C++ or C style
300+
comment. Set cmt_format first and optional second
301+
comment caracters.
302+
"""
303+
304+
cpp_comment = re.search("\/\/",line)
305+
c_comment = re.search("\/\*",line)
306+
if "//" in line:
307+
cmt_format.append("//")
308+
return True
309+
310+
if "/*" in line:
311+
cmt_format.append("/*")
312+
cmt_format.append("*/")
313+
return True
314+
315+
return False
316+
317+
def _sched_info(raw_tool_output, test_path,
318+
check_sched_info, update_sched_info):
319+
"""Check scheduling info if passed in assembly comment after each
320+
instructions.
321+
322+
Recognized form is:
323+
1 | 2 | 2 | 4.00 | ABSv1i64 | V1UnitV, | abs d15, d23
324+
// ABS <V><d>, <V><n> \\ ASIMD arith, basic \\ 1 2 2 4.0 V1UnitV
325+
326+
Format:
327+
[1] // [2] \\ [3] \\ [4]
328+
[1]: <llvm-mca output> <asm instruction>
329+
[2]: <Architecture description>
330+
[3]: <Scheduling info reference>
331+
[4]: <micro ops> <latency> <forward latency> <throughput> <units>
332+
333+
<llvm-mca output> with -scheduling-info option:
334+
<MicroOps> | <latency> | <fwd latency> | <throughput> |
335+
<side effect> | <llvm opcode> <units>
336+
337+
The goal is to check [4] regarding llvm-mca output with -scheduling-info [1]
338+
option. It will allow to check scheduling info easily when
339+
doing code review of scheduling info merge requests.
340+
If a difference is found, the comment should be fixed and checked
341+
against documentation.
342+
"""
343+
344+
scheduling_info = re.compile("(^\s+|\\\\\s+)([0-9]+[\s|]+[0-9]+"
345+
"[\s|]+[0-9]+[\s|]+\s+[0-9.]+)")
346+
units_info = re.compile("(^\s+|\\\\\s+)[0-9]+[\s|]+[0-9]+"
347+
"[\s|]+[0-9]+[\s|]+\s+[0-9.]+[\s|]+([^|*/]+)")
348+
349+
fixes = {}
350+
err = []
351+
instr_idx = 0
352+
for b in raw_tool_output.split("\n\n"):
353+
for line in b.splitlines():
354+
cmt_format = []
355+
if _has_comment(line,cmt_format):
356+
scheds = scheduling_info.findall(line)
357+
scheds = [s[1].replace("|","") for s in scheds]
358+
if len(scheds) == 2:
359+
cmt = cmt_format[0] + line.split(cmt_format[0])[1]
360+
units = units_info.findall(line)
361+
c_units = [re.sub("\s","",u[1]).split(",") for u in units]
362+
updates = set()
363+
if _check_sched_values(line,scheds,c_units,err,updates):
364+
if update_sched_info:
365+
if "sched" in updates:
366+
cmt = cmt.replace(scheds[1],
367+
_replace_values(scheds[1],scheds[0]))
368+
if "units" in updates:
369+
cmt = cmt.replace(units[1][1],units[0][1])
370+
371+
fixes[instr_idx] = cmt
372+
instr_idx = instr_idx + 1
373+
374+
if update_sched_info:
375+
with open(test_path) as f:
376+
# Overwrite test with new fixed comments if any.
377+
# Test file will be read again just before writing final checking
378+
output_lines = []
379+
instr_idx = 0
380+
381+
for line in f:
382+
out = line.rstrip()
383+
cmt_format = []
384+
if _has_comment(line,cmt_format) and not re.match("^#",line):
385+
if fixes.get(instr_idx) is not None:
386+
out = line.split(cmt_format[0])[0] + fixes[instr_idx]
387+
388+
instr_idx = instr_idx + 1
389+
390+
output_lines.append(out)
391+
392+
with open(test_path, "wb") as f:
393+
f.writelines(["{}\n".format(l).encode("utf-8") for l in output_lines])
394+
395+
if check_sched_info:
396+
if len(err) > 0:
397+
raise Error("{}".format("".join(err)))
247398

248399
def _get_block_infos(run_infos, test_path, args, common_prefix): # noqa
249400
"""For each run line, run the tool with the specified args and collect the
@@ -289,6 +440,17 @@ def _block_key(tool_args, prefixes):
289440
line if line.strip() else "" for line in raw_tool_output.splitlines()
290441
)
291442

443+
# Check if -scheduling-info passed to llvm-mca to check comments if any
444+
if "-scheduling-info" in tool_args:
445+
_sched_info(raw_tool_output, test_path,
446+
args.check_sched_info, args.update_sched_info)
447+
else:
448+
if args.check_sched_info:
449+
_warn("--check-sched-info: ignored: need llvm-mca -scheduling-info")
450+
if args.update_sched_info:
451+
_warn("--update-sched-info: ignored: need llvm-mca -scheduling-info")
452+
453+
292454
# Split blocks, stripping all trailing whitespace, but keeping preceding
293455
# whitespace except for newlines so that columns will line up visually.
294456
all_blocks[key] = [
@@ -550,6 +712,12 @@ def update_test_file(args, test_path, autogenerated_note):
550712
run_infos = _get_run_infos(run_lines, args)
551713
common_prefix, prefix_pad = _get_useful_prefix_info(run_infos)
552714
block_infos = _get_block_infos(run_infos, test_path, args, common_prefix)
715+
716+
if args.update_sched_info:
717+
# Read again input lines in case of changes (scheduling info updates in comments)
718+
with open(test_path) as f:
719+
input_lines = [l.rstrip() for l in f]
720+
553721
_write_output(
554722
test_path,
555723
input_lines,

0 commit comments

Comments
 (0)