diff options
author | Ryan Prichard <ryan.prichard@gmail.com> | 2022-02-01 08:25:05 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-01 17:25:05 +0100 |
commit | 5f5e6d620f67063651a511afbf72439888fe3bf2 (patch) | |
tree | 7ab618920000b1c1105bde442caf7a4b0be2a1ca | |
parent | f1801f0ca1550c1e86425e0b44022a17d0916523 (diff) | |
download | cpu_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.c | 8 | ||||
-rw-r--r-- | src/impl_arm_linux_or_android.c | 15 | ||||
-rw-r--r-- | test/cpuinfo_arm_test.cc | 18 |
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. |