From 022598d94f2cd718f62b2b9ed02edee86757dbd1 Mon Sep 17 00:00:00 2001 From: JanLJL Date: Thu, 29 Oct 2020 13:00:02 +0100 Subject: [PATCH] autodetect ISA and default uarch for ISA --- osaca/osaca.py | 21 ++++++++++++++++----- osaca/parser/base_parser.py | 20 +++++++++++++++++++- tests/test_base_parser.py | 12 ++++++++++++ tests/test_cli.py | 14 ++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/osaca/osaca.py b/osaca/osaca.py index 656ad88..9c82f3c 100755 --- a/osaca/osaca.py +++ b/osaca/osaca.py @@ -31,6 +31,10 @@ SUPPORTED_ARCHS = [ 'N1', 'A64FX', ] +DEFAULT_ARCHS = { + 'aarch64': 'A64FX', + 'x86': 'ICL', +} # Stolen from pip @@ -85,7 +89,7 @@ def create_parser(parser=None): '--arch', type=str, help='Define architecture (SNB, IVB, HSW, BDW, SKX, CSX, ICL, ZEN1, ZEN2, TX2, N1, ' - 'A64FX).', + 'A64FX). If no architecture is given, OSACA assumes a default uarch for x86/AArch64.', ) parser.add_argument( '--fixed', @@ -164,7 +168,12 @@ def check_arguments(args, parser): """ supported_import_files = ['ibench', 'asmbench'] - if 'arch' in args and (args.arch is None or args.arch.upper() not in SUPPORTED_ARCHS): + if args.arch is None and (args.check_db or 'import_data' in args): + parser.error( + 'DB check and data import cannot work with a default microarchitecture. ' + 'Please see --help for all valid architecture codes.' + ) + elif args.arch is not None and args.arch.upper() not in SUPPORTED_ARCHS: parser.error( 'Microarchitecture not supported. Please see --help for all valid architecture codes.' ) @@ -241,13 +250,15 @@ def inspect(args, output_file=sys.stdout): :param output_file: Define the stream for output, defaults to :class:`sys.stdout` :type output_file: stream, optional """ - arch = args.arch + # Read file + code = args.file.read() + + # Detect ISA if necessary + arch = args.arch if args.arch is not None else DEFAULT_ARCHS[BaseParser.detect_ISA(code)] isa = MachineModel.get_isa_for_arch(arch) verbose = args.verbose ignore_unknown = args.ignore_unknown - # Read file - code = args.file.read() # Parse file parser = get_asm_parser(arch) parsed_code = parser.parse_file(code) diff --git a/osaca/parser/base_parser.py b/osaca/parser/base_parser.py index 2706e04..f2b8fe9 100755 --- a/osaca/parser/base_parser.py +++ b/osaca/parser/base_parser.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Parser superclass of specific parsers.""" - +import operator +import re class BaseParser(object): # Identifiers for operand types @@ -18,6 +19,23 @@ class BaseParser(object): def __init__(self): self.construct_parser() + @staticmethod + def detect_ISA(file_content): + """Detect the ISA of the assembly based on the used registers and return the ISA code.""" + # Check for the amount of registers in the code to determine the ISA + # 1) Check for xmm, ymm, zmm, rax, rbx, rcx, and rdx registers in x86 + heuristics_x86ATT = [r'%[xyz]mm[0-9]', r'%r[abcd]x[0-9]'] + # 2) check for v and z vector registers and x/w general-purpose registers + heuristics_aarch64 = [r'[vz][0-9][0-9]?\.[0-9][0-9]?[bhsd]', r'[wx][0-9]'] + matches = {'x86': 0, 'aarch64': 0} + + for h in heuristics_x86ATT: + matches['x86'] += len(re.findall(h, file_content)) + for h in heuristics_aarch64: + matches['aarch64'] += len(re.findall(h, file_content)) + + return max(matches.items(), key=operator.itemgetter(1))[0] + def parse_file(self, file_content, start_line=0): """ Parse assembly file. This includes *not* extracting of the marked kernel and diff --git a/tests/test_base_parser.py b/tests/test_base_parser.py index 7465c05..4d76352 100755 --- a/tests/test_base_parser.py +++ b/tests/test_base_parser.py @@ -18,6 +18,12 @@ class TestBaseParser(unittest.TestCase): pass with open(self._find_file('triad_x86_iaca.s')) as f: self.triad_code = f.read() + with open(self._find_file('triad_arm_iaca.s')) as f: + self.triad_code_arm = f.read() + with open(self._find_file('kernel_x86.s')) as f: + self.x86_code = f.read() + with open(self._find_file('kernel_aarch64.s')) as f: + self.aarch64_code = f.read() ################## # Test @@ -59,6 +65,12 @@ class TestBaseParser(unittest.TestCase): with self.assertRaises(NotImplementedError): self.parser.normalize_imd(imd_hex_1) + def test_detect_ISA(self): + self.assertEqual(BaseParser.detect_ISA(self.triad_code), 'x86') + self.assertEqual(BaseParser.detect_ISA(self.triad_code_arm), 'aarch64') + self.assertEqual(BaseParser.detect_ISA(self.x86_code), 'x86') + self.assertEqual(BaseParser.detect_ISA(self.aarch64_code), 'aarch64') + ################## # Helper functions ################## diff --git a/tests/test_cli.py b/tests/test_cli.py index 8e44a2e..5030b36 100755 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -153,6 +153,20 @@ class TestCLI(unittest.TestCase): output = StringIO() osaca.run(args, output_file=output) + def test_without_arch(self): + # Run test kernels without --arch flag + parser = osaca.create_parser() + # x86 + kernel_x86 = 'kernel_x86.s' + args = parser.parse_args([self._find_test_file(kernel_x86)]) + output = StringIO() + osaca.run(args, output_file=output) + # AArch64 + kernel_aarch64 = 'kernel_aarch64.s' + args = parser.parse_args([self._find_test_file(kernel_aarch64)]) + osaca.run(args, output_file=output) + + ################## # Helper functions ##################