diff options
Diffstat (limited to 'lldb/packages/Python/lldbsuite')
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/cpu_feature.py | 75 | ||||
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/decorators.py | 24 | ||||
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/lldbtest.py | 66 |
3 files changed, 103 insertions, 62 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/cpu_feature.py b/lldb/packages/Python/lldbsuite/test/cpu_feature.py new file mode 100644 index 0000000..3f43cbb --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/cpu_feature.py @@ -0,0 +1,75 @@ +""" +Platform-agnostic helper to query for CPU features. +""" + +import re + + +class CPUFeature: + def __init__(self, linux_cpu_info_flag: str = None, darwin_sysctl_key: str = None): + self.cpu_info_flag = linux_cpu_info_flag + self.sysctl_key = darwin_sysctl_key + + def __str__(self): + for arch_class in ALL_ARCHS: + for feat_var in dir(arch_class): + if self == getattr(arch_class, feat_var): + return f"{arch_class.__name__}.{feat_var}" + raise AssertionError("unreachable") + + def is_supported(self, triple, cmd_runner): + if re.match(".*-.*-linux", triple): + err_msg, res = self._is_supported_linux(cmd_runner) + elif re.match(".*-apple-.*", triple): + err_msg, res = self._is_supported_darwin(cmd_runner) + else: + err_msg, res = None, False + + if err_msg: + print(f"CPU feature check failed: {err_msg}") + + return res + + def _is_supported_linux(self, cmd_runner): + if not self.cpu_info_flag: + return f"Unspecified cpuinfo flag for {self}", False + + cmd = "cat /proc/cpuinfo" + err, retcode, output = cmd_runner(cmd) + if err.Fail() or retcode != 0: + return output, False + + # FIXME: simple substring match, e.g., test for 'sme' will be true if + # 'sme2' or 'smefa64' is present + return None, (self.cpu_info_flag in output) + + def _is_supported_darwin(self, cmd_runner): + if not self.sysctl_key: + return f"Unspecified sysctl key for {self}", False + + cmd = f"sysctl -n {self.sysctl_key}" + err, retcode, output = cmd_runner(cmd) + if err.Fail() or retcode != 0: + return output, False + + return None, (output.strip() == "1") + + +class AArch64: + FPMR = CPUFeature("fpmr") + GCS = CPUFeature("gcs") + MTE = CPUFeature("mte") + MTE_STORE_ONLY = CPUFeature("mtestoreonly") + PTR_AUTH = CPUFeature("paca", "hw.optional.arm.FEAT_PAuth2") + SME = CPUFeature("sme", "hw.optional.arm.FEAT_SME") + SME_FA64 = CPUFeature("smefa64") + SME2 = CPUFeature("sme2", "hw.optional.arm.FEAT_SME2") + SVE = CPUFeature("sve") + + +class Loong: + LASX = CPUFeature("lasx") + LSX = CPUFeature("lsx") + + +ALL_ARCHS = [AArch64, Loong] diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 16a58cf..454196e 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -27,6 +27,7 @@ from lldbsuite.support import funcutils from lldbsuite.support import temp_file from lldbsuite.test import lldbplatform from lldbsuite.test import lldbplatformutil +from lldbsuite.test.cpu_feature import CPUFeature class DecorateMode: @@ -1131,24 +1132,13 @@ def skipIfLLVMTargetMissing(target): return unittest.skipIf(not found, "requires " + target) -# Call sysctl on darwin to see if a specified hardware feature is available on this machine. -def skipUnlessFeature(feature): - def is_feature_enabled(): - if platform.system() == "Darwin": - try: - output = subprocess.check_output( - ["/usr/sbin/sysctl", feature], stderr=subprocess.DEVNULL - ).decode("utf-8") - # If 'feature: 1' was output, then this feature is available and - # the test should not be skipped. - if re.match(r"%s: 1\s*" % feature, output): - return None - else: - return "%s is not supported on this system." % feature - except subprocess.CalledProcessError: - return "%s is not supported on this system." % feature +def skipUnlessFeature(cpu_feature: CPUFeature): + def hasFeature(test_case): + if not test_case.isSupported(cpu_feature): + return f"Unsupported CPU feature: {cpu_feature}" + return None - return skipTestIfFn(is_feature_enabled) + return skipTestIfFn(hasFeature) def skipIfBuildType(types: list[str]): diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index b7077f8..8074922 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -48,6 +48,7 @@ import unittest # LLDB modules import lldb from . import configuration +from . import cpu_feature from . import decorators from . import lldbplatformutil from . import lldbtest_config @@ -1315,39 +1316,6 @@ class Base(unittest.TestCase): return True return False - def getCPUInfo(self): - triple = self.dbg.GetSelectedPlatform().GetTriple() - - # TODO other platforms, please implement this function - if not re.match(".*-.*-linux", triple): - return "" - - # Need to do something different for non-Linux/Android targets - cpuinfo_path = self.getBuildArtifact("cpuinfo") - if configuration.lldb_platform_name: - self.runCmd( - 'platform get-file "/proc/cpuinfo" ' + cpuinfo_path, check=False - ) - if not self.res.Succeeded(): - if self.TraceOn(): - print( - 'Failed to get /proc/cpuinfo from remote: "{}"'.format( - self.res.GetOutput().strip() - ) - ) - print("All cpuinfo feature checks will fail.") - return "" - else: - cpuinfo_path = "/proc/cpuinfo" - - try: - with open(cpuinfo_path, "r") as f: - cpuinfo = f.read() - except: - return "" - - return cpuinfo - def isAArch64(self): """Returns true if the architecture is AArch64.""" arch = self.getArchitecture().lower() @@ -1360,39 +1328,47 @@ class Base(unittest.TestCase): self.getArchitecture().lower().startswith("arm") ) + def isSupported(self, cpu_feature: cpu_feature.CPUFeature): + triple = self.dbg.GetSelectedPlatform().GetTriple() + cmd_runner = self.run_platform_command + return cpu_feature.is_supported(triple, cmd_runner) + def isAArch64SVE(self): - return self.isAArch64() and "sve" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SVE) def isAArch64SME(self): - return self.isAArch64() and "sme" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SME) def isAArch64SME2(self): # If you have sme2, you also have sme. - return self.isAArch64() and "sme2" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.SME2) def isAArch64SMEFA64(self): # smefa64 allows the use of the full A64 instruction set in streaming # mode. This is required by certain test programs to setup register # state. - cpuinfo = self.getCPUInfo() - return self.isAArch64() and "sme" in cpuinfo and "smefa64" in cpuinfo + return ( + self.isAArch64() + and self.isSupported(cpu_feature.AArch64.SME) + and self.isSupported(cpu_feature.AArch64.SME_FA64) + ) def isAArch64MTE(self): - return self.isAArch64() and "mte" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.MTE) def isAArch64MTEStoreOnly(self): - return self.isAArch64() and "mtestoreonly" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.MTE_STORE_ONLY) def isAArch64GCS(self): - return self.isAArch64() and "gcs" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.GCS) def isAArch64PAuth(self): if self.getArchitecture() == "arm64e": return True - return self.isAArch64() and "paca" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.PTR_AUTH) def isAArch64FPMR(self): - return self.isAArch64() and "fpmr" in self.getCPUInfo() + return self.isAArch64() and self.isSupported(cpu_feature.AArch64.FPMR) def isAArch64Windows(self): """Returns true if the architecture is AArch64 and platform windows.""" @@ -1407,10 +1383,10 @@ class Base(unittest.TestCase): return arch in ["loongarch64", "loongarch32"] def isLoongArchLSX(self): - return self.isLoongArch() and "lsx" in self.getCPUInfo() + return self.isLoongArch() and self.isSupported(cpu_feature.Loong.LSX) def isLoongArchLASX(self): - return self.isLoongArch() and "lasx" in self.getCPUInfo() + return self.isLoongArch() and self.isSupported(cpu_feature.Loong.LASX) def isRISCV(self): """Returns true if the architecture is RISCV64 or RISCV32.""" |