From 510aa1345d4ac2c61e9fc3b0ab145a1ba5178dd6 Mon Sep 17 00:00:00 2001 From: "binh.ampere" <138732269+binh-ampere@users.noreply.github.com> Date: Tue, 14 May 2024 14:45:45 +0800 Subject: [PATCH] Support for AmpereOne family (#6) * add detect software built for the Arm Neoverse series of processors and recommend options for AmpereOne support. * detects build files for missing AmpereOne support * update UT cases for neoverse/ampere1 build flag detection * support scanning makefiles with arm64/aarch64 as file extension in filename * extend other arch list to reduce noise during assembly code detection --- .../constants/arch_specific_options.py | 13 +++- src/advisor/constants/arch_strings.py | 10 +-- src/advisor/helpers/find_port.py | 5 +- .../arch_specific_build_option_issue.py | 18 ++++- src/advisor/scanners/cmake_scanner.py | 34 +++++++-- src/advisor/scanners/makefile_scanner.py | 36 +++++++++- src/advisor/scanners/meson_scanner.py | 72 +++++++++++++++++++ src/advisor/scanners/scanners.py | 4 +- unittest/test_cmake_scanner.py | 12 ++++ unittest/test_makefile_scanner.py | 12 ++++ unittest/test_meson_scanner.py | 70 ++++++++++++++++++ 11 files changed, 269 insertions(+), 17 deletions(-) create mode 100644 src/advisor/scanners/meson_scanner.py create mode 100644 unittest/test_meson_scanner.py diff --git a/src/advisor/constants/arch_specific_options.py b/src/advisor/constants/arch_specific_options.py index 19697eb..f6ff60c 100644 --- a/src/advisor/constants/arch_specific_options.py +++ b/src/advisor/constants/arch_specific_options.py @@ -1,7 +1,16 @@ """ SPDX-License-Identifier: Apache-2.0 -Copyright (c) 2023, Ampere Computing LLC +Copyright (c) 2024, Ampere Computing LLC """ -ARCH_SPECIFIC_OPTS = ['mmx', 'sse', 'sse2', 'sse3', 'ssse3', 'sse4', 'sse4a', 'sse4.1', 'sse4.2', 'avx', 'avx2', 'avx512f', 'avx512pf', 'avx512er', 'avx512cd', 'avx512vl', 'avx512bw', 'avx512dq', 'avx512ifma', 'avx512vbmi', 'sha', 'aes', 'pclmul', 'clflushopt', 'clwb', 'fsgsbase', 'ptwrite', 'rdrnd', 'f16c', 'fma', 'pconfig', 'wbnoinvd', 'fma4', 'prfchw', 'rdpid', 'prefetchwt1', 'rdseed', 'sgx', 'xop', 'lwp', '3dnow', '3dnowa', 'popcnt', 'abm', 'adx', 'bmi', 'bmi2', 'lzcnt', 'fxsr', 'xsave', 'xsaveopt', 'xsavec', 'xsaves', 'rtm', 'hle', 'tbm', 'mwaitx', 'clzero', 'pku', 'avx512vbmi2', 'avx512bf16', 'avx512fp16', 'gfni', 'vaes', 'waitpkg', 'vpclmulqdq', 'avx512bitalg', 'movdiri', 'movdir64b', 'enqcmd', 'uintr', 'tsxldtrk', 'avx512vpopcntdq', 'avx512vp2intersect', 'avx5124fmaps', 'avx512vnni', 'avxvnni', 'avx5124vnniw', 'cldemote', 'serialize', 'amx-tile', 'amx-int8', 'amx-bf16', 'hreset', 'kl', 'widekl', 'avxifma', 'avxvnniint8', 'avxneconvert', 'cmpccxadd', 'amx-fp16', 'prefetchi', 'raoint', 'amx-complex'] +X86_SPECIFIC_OPTS = ['mmx', 'sse', 'sse2', 'sse3', 'ssse3', 'sse4', 'sse4a', 'sse4.1', 'sse4.2', 'avx', 'avx2', 'avx512f', 'avx512pf', 'avx512er', 'avx512cd', 'avx512vl', 'avx512bw', 'avx512dq', 'avx512ifma', 'avx512vbmi', 'sha', 'aes', 'pclmul', 'clflushopt', 'clwb', 'fsgsbase', 'ptwrite', 'rdrnd', 'f16c', 'fma', 'pconfig', 'wbnoinvd', 'fma4', 'prfchw', 'rdpid', 'prefetchwt1', 'rdseed', 'sgx', 'xop', 'lwp', '3dnow', '3dnowa', 'popcnt', 'abm', 'adx', 'bmi', 'bmi2', 'lzcnt', 'fxsr', 'xsave', 'xsaveopt', 'xsavec', 'xsaves', 'rtm', 'hle', 'tbm', 'mwaitx', 'clzero', 'pku', 'avx512vbmi2', 'avx512bf16', 'avx512fp16', 'gfni', 'vaes', 'waitpkg', 'vpclmulqdq', 'avx512bitalg', 'movdiri', 'movdir64b', 'enqcmd', 'uintr', 'tsxldtrk', 'avx512vpopcntdq', 'avx512vp2intersect', 'avx5124fmaps', 'avx512vnni', 'avxvnni', 'avx5124vnniw', 'cldemote', 'serialize', 'amx-tile', 'amx-int8', 'amx-bf16', 'hreset', 'kl', 'widekl', 'avxifma', 'avxvnniint8', 'avxneconvert', 'cmpccxadd', 'amx-fp16', 'prefetchi', 'raoint', 'amx-complex'] """Options that are not available on aarch64.""" + +NEOVERSE_SPECIFIC_OPTS = ['neoverse-'] +"""Options for Arm Neoverse are not appropriate for AmpereOne family.""" + +AMPEREONE_SPECIFIC_OPTS = ['ampere1', 'ampere1a', 'ampere1b'] +"""Options for AmpereOne family.""" + +ARCH_SPECIFIC_IN_BUILD_FILES = ['meson.build', 'CMakeLists.txt', 'Makefile.in', 'Makefile.am', 'Makefile.arm64', 'Makefile.aarch64'] +"""Build files in aarch64 port dir can't be filter out as they might missing support for ampere1.""" diff --git a/src/advisor/constants/arch_strings.py b/src/advisor/constants/arch_strings.py index 87beda9..3684509 100644 --- a/src/advisor/constants/arch_strings.py +++ b/src/advisor/constants/arch_strings.py @@ -19,11 +19,11 @@ AARCH64_ARCHS = ['arm', 'aarch64', 'arm64', 'neon', 'sve'] NON_AARCH64_ARCHS = ['alpha', 'altivec', 'amd64', 'avx', 'avx512', 'hppa', - 'i386', 'i586', 'i686', 'ia64', 'intel', 'intel64', 'ix86', - 'm68k', 'microblaze', 'mips', 'nios2', 'otherarch', 'power', - 'powerpc', 'powerpc32', 'powerpc64', 'ppc', 'ppc64', - 'ppc64le', 's390', 'sh', 'sparc', 'sse', 'sse2', 'sse3', - 'tile', 'x64', 'x86', 'x86_64'] + 'i386', 'i586', 'i686', 'ia64', 'intel', 'intel64', 'ix86', 'loongarch64', + 'm68k', 'microblaze', 'mips', 'nios2', 'otherarch', 'penryn', 'power', + 'powerpc', 'powerpc32', 'powerpc64', 'ppc', 'ppc64', 'ppc64le', 'riscv64', + 'sandybridge', 's390', 'sh', 'sifive_x280', 'sparc', 'sse', 'sse2', 'sse3', + 'tile', 'x64', 'x86', 'x86_64', 'zarch', 'zen', 'zen2', 'zen3'] COMPILERS = ['clang', 'cray', 'flang', 'gcc', 'gfortran', 'gnuc', 'gnug', 'ibmcpp', 'ibmxl', 'icc', 'ifort', 'intel', 'intel_compiler', 'llvm', 'pathscale', 'pgi', 'pgic', 'sunpro', 'xlc', 'xlf'] diff --git a/src/advisor/helpers/find_port.py b/src/advisor/helpers/find_port.py index 2450521..fa7bde1 100644 --- a/src/advisor/helpers/find_port.py +++ b/src/advisor/helpers/find_port.py @@ -19,6 +19,7 @@ import os import re from ..constants.arch_strings import AARCH64_ARCHS, NON_AARCH64_ARCHS +from ..constants.arch_specific_options import ARCH_SPECIFIC_IN_BUILD_FILES def port_filenames(filename): @@ -41,7 +42,7 @@ def port_filenames(filename): filename = ''.join(parts[:i]) + \ arm_arch + ''.join(parts[(i + 1):]) ret.append(filename) - elif part in AARCH64_ARCHS: + elif part in AARCH64_ARCHS and filename not in ARCH_SPECIFIC_IN_BUILD_FILES: ret.append(filename) return ret @@ -105,7 +106,7 @@ def find_port_file(filename, other_files, other_files_dirs=None): for file in other_files: other_files_dirs.add(os.path.dirname(file)) port_dir = find_port_dir(head, other_files_dirs) - if port_dir: + if port_dir and tail not in ARCH_SPECIFIC_IN_BUILD_FILES: return os.path.join(port_dir, tail) return None diff --git a/src/advisor/reports/issues/arch_specific_build_option_issue.py b/src/advisor/reports/issues/arch_specific_build_option_issue.py index e75143c..2c346db 100644 --- a/src/advisor/reports/issues/arch_specific_build_option_issue.py +++ b/src/advisor/reports/issues/arch_specific_build_option_issue.py @@ -1,10 +1,11 @@ """ SPDX-License-Identifier: Apache-2.0 -Copyright (c) 2023, Ampere Computing LLC +Copyright (c) 2024, Ampere Computing LLC """ from .issue import Issue from ..localization import _ +from ..report_item import ReportItem class ArchSpecificBuildOptionIssue(Issue): @@ -13,3 +14,18 @@ def __init__(self, filename, lineno, opt_name): opt_name super().__init__(description=description, filename=filename, lineno=lineno) + +class NeoverseSpecificBuildOptionIssue(Issue): + def __init__(self, filename, lineno, opt_name, opt_value): + description = (_("neoverse-specific build option may not appropriate for AmpereOne: " + "-m%s=%s, see https://amperecomputing.com/tutorials/gcc-guide-ampere-processors for more details.") \ + % (opt_name, opt_value)) + super().__init__(description=description, filename=filename, + lineno=lineno, item_type=ReportItem.NEUTRAL) + +class AmpereoneSpecificBuildOptionIssue(Issue): + def __init__(self, filename, lineno): + description = (_("Missing build option for AmpereOne, see " + "https://amperecomputing.com/tutorials/gcc-guide-ampere-processors for more details.")) + super().__init__(description=description, filename=filename, + lineno=lineno, item_type=ReportItem.NEUTRAL) diff --git a/src/advisor/scanners/cmake_scanner.py b/src/advisor/scanners/cmake_scanner.py index 94521f2..52e85ff 100644 --- a/src/advisor/scanners/cmake_scanner.py +++ b/src/advisor/scanners/cmake_scanner.py @@ -1,16 +1,20 @@ """ SPDX-License-Identifier: Apache-2.0 -Copyright (c) 2023, Ampere Computing LLC +Copyright (c) 2024, Ampere Computing LLC """ import os import re from ..constants.arch_strings import AARCH64_ARCHS, NON_AARCH64_ARCHS from ..constants.arch_specific_libs import ARCH_SPECIFIC_LIBS -from ..constants.arch_specific_options import ARCH_SPECIFIC_OPTS +from ..constants.arch_specific_options import X86_SPECIFIC_OPTS +from ..constants.arch_specific_options import NEOVERSE_SPECIFIC_OPTS +from ..constants.arch_specific_options import AMPEREONE_SPECIFIC_OPTS from ..parsers.continuation_parser import ContinuationParser from ..reports.issues.arch_specific_library_issue import ArchSpecificLibraryIssue from ..reports.issues.arch_specific_build_option_issue import ArchSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import NeoverseSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import AmpereoneSpecificBuildOptionIssue from ..reports.issues.define_other_arch_issue import DefineOtherArchIssue from .scanner import Scanner @@ -20,10 +24,14 @@ class CMakeScanner(Scanner): CMAKE_NAMES = ['CMakeLists.txt'] - ARCH_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(%s)' % - '|'.join([(r'%s\b' % x) for x in ARCH_SPECIFIC_OPTS])) + X86_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(%s)' % + '|'.join([(r'%s\b' % x) for x in X86_SPECIFIC_OPTS])) ARCH_SPECIFIC_LIBS_RE_PROG = re.compile(r'(?:find_package|find_library)\((%s)' % '|'.join([(r'%s\b' % x) for x in ARCH_SPECIFIC_LIBS])) + NEOVERSE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in NEOVERSE_SPECIFIC_OPTS])) + AMPEREONE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in AMPEREONE_SPECIFIC_OPTS])) OTHER_ARCH_CPU_LINE_RE_PROG = re.compile(r'(?:CMAKE_SYSTEM_PROCESSOR).*(%s)' % '|'.join(NON_AARCH64_ARCHS)) AARCH64_CPU_LINE_RE_PROG = re.compile(r'(?:CMAKE_SYSTEM_PROCESSOR).*(%s)' % @@ -37,6 +45,8 @@ def scan_file_object(self, filename, file, report): continuation_parser = ContinuationParser() other_arch_cpu_condition = None seen_aarch64_cpu_condition = False + seen_neoverse_build_flag = False + seen_ampere1_build_flag = False for lineno, line in enumerate(file, 1): line = continuation_parser.parse_line(line) @@ -49,11 +59,23 @@ def scan_file_object(self, filename, file, report): lib_name = match.group(1) report.add_issue(ArchSpecificLibraryIssue( filename, lineno + 1, lib_name)) - match = CMakeScanner.ARCH_SPECIFIC_OPTS_RE_PROG.search(line) + match = CMakeScanner.X86_SPECIFIC_OPTS_RE_PROG.search(line) if match: opt_name = match.group(1) report.add_issue(ArchSpecificBuildOptionIssue( filename, lineno + 1, opt_name)) + match = CMakeScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_aarch64_cpu_condition = True + seen_neoverse_build_flag = True + opt_name = match.group(1) + opt_value = match.group(2) + report.add_issue(NeoverseSpecificBuildOptionIssue( + filename, lineno + 1, opt_name, opt_value)) + match = CMakeScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_aarch64_cpu_condition = True + seen_ampere1_build_flag = True match = CMakeScanner.OTHER_ARCH_CPU_LINE_RE_PROG.search(line) if match: other_arch_cpu_condition = line @@ -62,3 +84,5 @@ def scan_file_object(self, filename, file, report): seen_aarch64_cpu_condition = True if other_arch_cpu_condition and not seen_aarch64_cpu_condition: report.add_issue(DefineOtherArchIssue(filename, lineno + 1, other_arch_cpu_condition)) + if seen_neoverse_build_flag and not seen_ampere1_build_flag: + report.add_issue(AmpereoneSpecificBuildOptionIssue(filename, lineno + 1)) diff --git a/src/advisor/scanners/makefile_scanner.py b/src/advisor/scanners/makefile_scanner.py index b94f7aa..d6bbdee 100644 --- a/src/advisor/scanners/makefile_scanner.py +++ b/src/advisor/scanners/makefile_scanner.py @@ -20,23 +20,36 @@ import re from ..constants.arch_strings import AARCH64_ARCHS, NON_AARCH64_ARCHS from ..constants.arch_specific_libs import ARCH_SPECIFIC_LIBS +from ..constants.arch_specific_options import X86_SPECIFIC_OPTS +from ..constants.arch_specific_options import NEOVERSE_SPECIFIC_OPTS +from ..constants.arch_specific_options import AMPEREONE_SPECIFIC_OPTS from ..parsers.continuation_parser import ContinuationParser from ..reports.issues.arch_specific_library_issue import ArchSpecificLibraryIssue from ..reports.issues.build_command_issue import BuildCommandIssue from ..reports.issues.define_other_arch_issue import DefineOtherArchIssue from ..reports.issues.host_cpu_detection_issue import HostCpuDetectionIssue +from ..reports.issues.arch_specific_build_option_issue import ArchSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import NeoverseSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import AmpereoneSpecificBuildOptionIssue from ..reports.issues.old_crt_issue import OldCrtIssue + from .scanner import Scanner class MakefileScanner(Scanner): """Scanner that scans Makefiles.""" - MAKEFILE_NAMES = ['Makefile.in', 'Makefile.am'] + MAKEFILE_NAMES = ['Makefile.in', 'Makefile.am', 'Makefile.arm64', 'Makefile.aarch64'] MAKEFILE_NAMES_CASE_INSENSITIVE = ['makefile', 'nmakefile', 'makefile.mk'] ARCH_SPECIFIC_LIBS_RE_PROG = re.compile(r'-l(%s)' % '|'.join([(r'%s\b' % x) for x in ARCH_SPECIFIC_LIBS])) + X86_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(%s)' % + '|'.join([(r'%s\b' % x) for x in X86_SPECIFIC_OPTS])) + NEOVERSE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in NEOVERSE_SPECIFIC_OPTS])) + AMPEREONE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in AMPEREONE_SPECIFIC_OPTS])) OLD_CRT_RE_PROG = re.compile(r'(libcmt[a-z]*\.lib)', re.IGNORECASE) UCRT_RE_PROG = re.compile(r'(libucrt[a-z]*\.lib)', re.IGNORECASE) OTHER_ARCH_CPU_LINE_RE_PROG = re.compile(r'\$\((?:CPU|PROCESSOR_ARCHITECTURE)\).*(%s)' % @@ -72,6 +85,8 @@ def scan_file_object(self, filename, file, report): seen_ucrt = False other_arch_cpu_condition = None seen_aarch64_cpu_condition = False + seen_neoverse_build_flag = False + seen_ampere1_build_flag = False d_other_arch = None seen_d_aarch64 = False targets = set() @@ -90,6 +105,23 @@ def scan_file_object(self, filename, file, report): lib_name = match.group(1) report.add_issue(ArchSpecificLibraryIssue( filename, lineno + 1, lib_name)) + match = MakefileScanner.X86_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + opt_name = match.group(1) + report.add_issue(ArchSpecificBuildOptionIssue( + filename, lineno + 1, opt_name)) + match = MakefileScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_aarch64_cpu_condition = True + seen_neoverse_build_flag = True + opt_name = match.group(1) + opt_value = match.group(2) + report.add_issue(NeoverseSpecificBuildOptionIssue( + filename, lineno + 1, opt_name, opt_value)) + match = MakefileScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_aarch64_cpu_condition = True + seen_ampere1_build_flag = True match = MakefileScanner.OLD_CRT_RE_PROG.search(line) if match: old_crt_lib_name = match.group(1) @@ -139,3 +171,5 @@ def scan_file_object(self, filename, file, report): report.add_issue(BuildCommandIssue(filename, lineno + 1, command)) if d_other_arch and not seen_d_aarch64: report.add_issue(DefineOtherArchIssue(filename, lineno + 1, d_other_arch)) + if seen_neoverse_build_flag and not seen_ampere1_build_flag: + report.add_issue(AmpereoneSpecificBuildOptionIssue(filename, lineno + 1)) diff --git a/src/advisor/scanners/meson_scanner.py b/src/advisor/scanners/meson_scanner.py new file mode 100644 index 0000000..b5c2006 --- /dev/null +++ b/src/advisor/scanners/meson_scanner.py @@ -0,0 +1,72 @@ +""" +SPDX-License-Identifier: Apache-2.0 +Copyright (c) 2024, Ampere Computing LLC +""" + +import os +import re +from ..constants.arch_strings import AARCH64_ARCHS, NON_AARCH64_ARCHS +from ..constants.arch_specific_libs import ARCH_SPECIFIC_LIBS +from ..constants.arch_specific_options import X86_SPECIFIC_OPTS +from ..constants.arch_specific_options import NEOVERSE_SPECIFIC_OPTS +from ..constants.arch_specific_options import AMPEREONE_SPECIFIC_OPTS +from ..parsers.continuation_parser import ContinuationParser +from ..reports.issues.arch_specific_library_issue import ArchSpecificLibraryIssue +from ..reports.issues.arch_specific_build_option_issue import ArchSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import NeoverseSpecificBuildOptionIssue +from ..reports.issues.arch_specific_build_option_issue import AmpereoneSpecificBuildOptionIssue +from ..reports.issues.define_other_arch_issue import DefineOtherArchIssue +from .scanner import Scanner + + +class MesonScanner(Scanner): + """Scanner that scans Meson builds""" + + MESON_NAMES = ['meson.build'] + + X86_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(%s)' % + '|'.join([(r'%s\b' % x) for x in X86_SPECIFIC_OPTS])) + ARCH_SPECIFIC_LIBS_RE_PROG = re.compile(r'(?:find_library)\(\'(%s)' % + '|'.join([(r'%s\b' % x) for x in ARCH_SPECIFIC_LIBS])) + NEOVERSE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in NEOVERSE_SPECIFIC_OPTS])) + AMPEREONE_SPECIFIC_OPTS_RE_PROG = re.compile(r'-m(cpu|tune)=(%s)' % + '|'.join([(r'%s\b' % x) for x in AMPEREONE_SPECIFIC_OPTS])) + + def accepts_file(self, filename): + basename = os.path.basename(filename) + return basename in MesonScanner.MESON_NAMES + + def scan_file_object(self, filename, file, report): + continuation_parser = ContinuationParser() + seen_neoverse_build_flag = False + seen_ampere1_build_flag = False + + for lineno, line in enumerate(file, 1): + line = continuation_parser.parse_line(line) + + if not line: + continue + + match = MesonScanner.ARCH_SPECIFIC_LIBS_RE_PROG.search(line) + if match: + lib_name = match.group(1) + report.add_issue(ArchSpecificLibraryIssue( + filename, lineno + 1, lib_name)) + match = MesonScanner.X86_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + opt_name = match.group(1) + report.add_issue(ArchSpecificBuildOptionIssue( + filename, lineno + 1, opt_name)) + match = MesonScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_neoverse_build_flag = True + opt_name = match.group(1) + opt_value = match.group(2) + report.add_issue(NeoverseSpecificBuildOptionIssue( + filename, lineno + 1, opt_name, opt_value)) + match = MesonScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search(line) + if match: + seen_ampere1_build_flag = True + if seen_neoverse_build_flag and not seen_ampere1_build_flag: + report.add_issue(AmpereoneSpecificBuildOptionIssue(filename, lineno + 1)) diff --git a/src/advisor/scanners/scanners.py b/src/advisor/scanners/scanners.py index 827d7b2..060f3a2 100644 --- a/src/advisor/scanners/scanners.py +++ b/src/advisor/scanners/scanners.py @@ -26,6 +26,7 @@ from .java_scanner import JavaScanner from .makefile_scanner import MakefileScanner from .cmake_scanner import CMakeScanner +from .meson_scanner import MesonScanner from .python_scanner import PythonScanner from .source_scanner import SourceScanner @@ -49,7 +50,8 @@ def __init__(self, issue_type_config, filter_ported_code=True): AsmSourceScanner(), ConfigGuessScanner(), MakefileScanner(), - CMakeScanner()] + CMakeScanner(), + MesonScanner()] self.filters = [PortFilter()] if filter_ported_code else [] self.filters += [IssueTypeFilter(issue_type_config), TargetOsFilter(), diff --git a/unittest/test_cmake_scanner.py b/unittest/test_cmake_scanner.py index 00f2312..8fe1856 100644 --- a/unittest/test_cmake_scanner.py +++ b/unittest/test_cmake_scanner.py @@ -74,3 +74,15 @@ def test_continuation(self): cmake_scanner.scan_file_object( 'CMakeLists.txt', io_object, report) self.assertEqual(len(report.issues), 1) + + def test_neoverse_specific_opts_line_re(self): + match = CMakeScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search('ADD_CXX_FLAGS("-mtune=ampere1a")') + self.assertIsNone(match) + match = CMakeScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search('ADD_CXX_FLAGS("-mtune=neoverse-n2")') + self.assertIsNotNone(match) + + def test_ampereone_specific_opts_line_re(self): + match = CMakeScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search('ADD_CXX_FLAGS("-mcpu=neoverse-v2")') + self.assertIsNone(match) + match = CMakeScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search('ADD_CXX_FLAGS("-mcpu=ampere1b")') + self.assertIsNotNone(match) diff --git a/unittest/test_makefile_scanner.py b/unittest/test_makefile_scanner.py index bc0814a..8e05a72 100644 --- a/unittest/test_makefile_scanner.py +++ b/unittest/test_makefile_scanner.py @@ -300,3 +300,15 @@ def test_continuation(self): makefile_scanner.scan_file_object( 'Makefile', io_object, report) self.assertEqual(len(report.issues), 1) + + def test_neoverse_specific_opts_line_re(self): + match = MakefileScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search('CFLAGS = -mtune=ampere1a') + self.assertIsNone(match) + match = MakefileScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search('CFLAGS = -mtune=neoverse-n2') + self.assertIsNotNone(match) + + def test_ampereone_specific_opts_line_re(self): + match = MakefileScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search('CFLAGS = -mcpu=neoverse-v2') + self.assertIsNone(match) + match = MakefileScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search('CFLAGS = -mcpu=ampere1b') + self.assertIsNotNone(match) diff --git a/unittest/test_meson_scanner.py b/unittest/test_meson_scanner.py new file mode 100644 index 0000000..4bea301 --- /dev/null +++ b/unittest/test_meson_scanner.py @@ -0,0 +1,70 @@ +""" +SPDX-License-Identifier: Apache-2.0 +Copyright (c) 2024, Ampere Computing LLC +""" + +import io +import unittest +from src.advisor.reports.report import Report +from src.advisor.scanners.meson_scanner import MesonScanner + + +class TestMesonScanner(unittest.TestCase): + def test_accepts_file(self): + meson_scanner = MesonScanner() + self.assertFalse(meson_scanner.accepts_file('test')) + self.assertTrue(meson_scanner.accepts_file('meson.build')) + + def test_scan_file_object(self): + meson_scanner = MesonScanner() + report = Report('/root') + io_object = io.StringIO('xxx') + meson_scanner.scan_file_object( + 'meson.build', io_object, report) + self.assertEqual(len(report.issues), 0) + + + def test_arch_specific_libs_re(self): + match = MesonScanner.ARCH_SPECIFIC_LIBS_RE_PROG.search("cc.find_library('foo')") + self.assertIsNone(match) + match = MesonScanner.ARCH_SPECIFIC_LIBS_RE_PROG.search("cc.find_library('otherarch')") + self.assertIsNotNone(match) + self.assertEqual(match.group(1), "otherarch") + + def test_arch_specific_libs(self): + meson_scanner = MesonScanner() + report = Report('/root') + io_object = io.StringIO("cc.find_library('otherarch')") + meson_scanner.scan_file_object( + 'meson.build', io_object, report) + self.assertEqual(len(report.issues), 1) + + def test_neoverse_specific_opts_line_re(self): + match = MesonScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=ampere1a'],") + self.assertIsNone(match) + match = MesonScanner.NEOVERSE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=neoverse-n2'],") + self.assertIsNotNone(match) + + def test_ampereone_specific_opts_line_re(self): + match = MesonScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=neoverse-n2'],") + self.assertIsNone(match) + match = MesonScanner.AMPEREONE_SPECIFIC_OPTS_RE_PROG.search("'compiler_options': ['-mcpu=ampere1a'],") + self.assertIsNotNone(match) + + def test_neoverse_specific_opts_line(self): + meson_scanner = MesonScanner() + + report = Report('/root') + io_object = io.StringIO("'compiler_options': ['-mcpu=neoverse-n2'],") + meson_scanner.scan_file_object( + 'meson.build', io_object, report) + # Should report 2 issues, one for neoverse flag indication, another for ampereone flag missing. + self.assertEqual(len(report.issues), 2) + + report = Report('/root') + io_object = io.StringIO("'compiler_options': ['-mcpu=ampere1a'],\n'compiler_options': ['-mtune=ampere1a'],\n'compiler_options': ['-mcpu=neoverse-v2'],\n'compiler_options': ['-mtune=neoverse-v2'],\n") + meson_scanner.scan_file_object( + 'meson.build', io_object, report) + self.assertEqual(len(report.issues), 2) + +