aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Prichard <ryan.prichard@gmail.com>2022-02-01 08:25:05 -0800
committerGitHub <noreply@github.com>2022-02-01 17:25:05 +0100
commit5f5e6d620f67063651a511afbf72439888fe3bf2 (patch)
tree7ab618920000b1c1105bde442caf7a4b0be2a1ca
parentf1801f0ca1550c1e86425e0b44022a17d0916523 (diff)
downloadcpu_features-5f5e6d620f67063651a511afbf72439888fe3bf2.tar.gz
Fix a getauxval comment and expand the Krait idiv workaround (#206)
* Fix getauxval comment (API 18 not 20) getauxval is available in Android starting with API 18, not 20. The comment about __ANDROID_API__ appears to have been copied from the NDK's cpufeatures, which always uses dlopen/dlsym and doesn't assume it can directly call getauxval, even if __ANDROID_API__ is new enough. With this project, though, when __ANDROID_API__ is 18 or up, the CMakeLists.txt file would detect that getauxval is available and define HAVE_STRONG_GETAUXVAL. * Broaden Qualcomm Krait idiv workaround Some Qualcomm Krait CPUs have IDIV support but the kernel doesn't report it. Previously, this code looked for two CPUs: - 0x510006F2 (0x51/'Q', variant 0, part 0x06f, rev 2) - 0x510006F3 (0x51/'Q', variant 0, part 0x06f, rev 3) This check misses my 2013 Nexus 7 device, which has this CPU ID: - 0x511006f0 (0x51/'Q', variant 1, part 0x06f, rev 0) My Nexus 7 device doesn't report idiv through AT_HWCAP or through /proc/cpuinfo (AT_HWCAP is 0x1b0d7). Expand the check to anything with: - implementer 0x51 - architecture 7 - part 0x4d or 0x6f Part 0x4d appears to be a dual-core Krait (e.g. see https://crbug.com/341598#c43). This new matching behavior is a subset of what the upstream kernel does (patch[1] contributed by CodeAurora), and also closely matches the behavior of pytorch/cpuinfo. [1] https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b
-rw-r--r--src/hwcaps.c8
-rw-r--r--src/impl_arm_linux_or_android.c15
-rw-r--r--test/cpuinfo_arm_test.cc18
3 files changed, 27 insertions, 14 deletions
diff --git a/src/hwcaps.c b/src/hwcaps.c
index 605f892..f44f6c3 100644
--- a/src/hwcaps.c
+++ b/src/hwcaps.c
@@ -68,13 +68,7 @@ static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
#elif defined(HAVE_DLFCN_H)
// On Android we probe the system's C library for a 'getauxval' function and
// call it if it exits, or return 0 for failure. This function is available
-// since API level 20.
-//
-// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
-// case where some NDK developers use headers for a platform that is newer than
-// the one really targetted by their application. This is typically done to use
-// newer native APIs only when running on more recent Android versions, and
-// requires careful symbol management.
+// since API level 18.
//
// Note that getauxval() can't really be re-implemented here, because its
// implementation does not parse /proc/self/auxv. Instead it depends on values
diff --git a/src/impl_arm_linux_or_android.c b/src/impl_arm_linux_or_android.c
index d110a15..997ef93 100644
--- a/src/impl_arm_linux_or_android.c
+++ b/src/impl_arm_linux_or_android.c
@@ -152,13 +152,14 @@ static void FixErrors(ArmInfo* const info,
// https://crbug.com/341598.
info->features.neon = false;
break;
- case 0x510006F2:
- case 0x510006F3:
- // The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
- // IDIV support.
- info->features.idiva = true;
- info->features.idivt = true;
- break;
+ }
+
+ // Some Qualcomm Krait kernels forget to report IDIV support.
+ // https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b
+ if (info->implementer == 0x51 && info->architecture == 7 &&
+ (info->part == 0x4d || info->part == 0x6f)) {
+ info->features.idiva = true;
+ info->features.idivt = true;
}
// Propagate cpu features.
diff --git a/test/cpuinfo_arm_test.cc b/test/cpuinfo_arm_test.cc
index 85ee7fb..ad7f4e8 100644
--- a/test/cpuinfo_arm_test.cc
+++ b/test/cpuinfo_arm_test.cc
@@ -327,6 +327,24 @@ CPU revision : 3)");
EXPECT_EQ(GetArmCpuId(&info), 0x510006f3);
}
+// The 2013 Nexus 7 (Qualcomm Krait) kernel configuration forgets to report IDIV
+// support.
+TEST(CpuinfoArmTest, Nexus7_2013_0x511006f0) {
+ ResetHwcaps();
+ auto& fs = GetEmptyFilesystem();
+ fs.CreateFile("/proc/cpuinfo",
+ R"(CPU implementer : 0x51
+CPU architecture: 7
+CPU variant : 0x1
+CPU part : 0x06f
+CPU revision : 0)");
+ const auto info = GetArmInfo();
+ EXPECT_TRUE(info.features.idiva);
+ EXPECT_TRUE(info.features.idivt);
+
+ EXPECT_EQ(GetArmCpuId(&info), 0x511006f0);
+}
+
// The emulator-specific Android 4.2 kernel fails to report support for the
// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual
// CPU implemented by the emulator.