1
0
mirror of https://github.com/google/cpu_features.git synced 2025-05-02 17:23:36 +02:00

Support disabling of extensions

Fixes #101
This commit is contained in:
Guillaume Chatelet 2020-01-17 16:53:37 +01:00
parent 24b8a1de17
commit eb59787849
5 changed files with 70 additions and 0 deletions

View File

@ -8,6 +8,7 @@ instructions) at runtime.
- [Design Rationale](#rationale) - [Design Rationale](#rationale)
- [Code samples](#codesample) - [Code samples](#codesample)
- [Running sample code](#usagesample) - [Running sample code](#usagesample)
- [Mocking the library](#mock)
- [What's supported](#support) - [What's supported](#support)
- [Android NDK's drop in replacement](#ndk) - [Android NDK's drop in replacement](#ndk)
- [License](#license) - [License](#license)
@ -130,6 +131,28 @@ flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]} {"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
``` ```
<a name="mock"></a>
### Mocking the library
When testing code depending on `cpu_features` it may be interesting to disable
support for a particular extension (e.g. test `sse4` support on a `Skylake`
machine).
It is easily done by setting up an interceptor callback.
```C++
TEST(X86Test, TestOnlySSE4) {
RegisterX86InfoInterceptor([](X86Info* info) {
info->features = X86Features{};
info->features.sse4 = true;
});
// 1. Call code that uses GetX86Info(),
// 2. Check the expected values,
// 3. Don't forget to cancel.
RegisterX86InfoInterceptor(NULL);
}
```
<a name="support"></a> <a name="support"></a>
## What's supported ## What's supported

View File

@ -140,4 +140,22 @@
#define CPU_FEATURES_COMPILED_MIPS_MSA defined(__mips_msa) #define CPU_FEATURES_COMPILED_MIPS_MSA defined(__mips_msa)
#endif #endif
////////////////////////////////////////////////////////////////////////////////
// Miscellaneous
////////////////////////////////////////////////////////////////////////////////
#ifndef thread_local
#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
#define thread_local _Thread_local
#elif defined _WIN32 && (defined _MSC_VER || defined __ICL || \
defined __DMC__ || defined __BORLANDC__)
#define thread_local __declspec(thread)
/* note that ICC (linux) and Clang are covered by __GNUC__ */
#elif defined __GNUC__ || defined __SUNPRO_C || defined __xlC__
#define thread_local __thread
#else
#error "Cannot define thread_local"
#endif
#endif
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ #endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_

View File

@ -201,6 +201,8 @@ const char* GetX86FeaturesEnumName(X86FeaturesEnum);
const char* GetX86MicroarchitectureName(X86Microarchitecture); const char* GetX86MicroarchitectureName(X86Microarchitecture);
void RegisterX86InfoInterceptor(void (*)(X86Info*));
CPU_FEATURES_END_CPP_NAMESPACE CPU_FEATURES_END_CPP_NAMESPACE
#if !defined(CPU_FEATURES_ARCH_X86) #if !defined(CPU_FEATURES_ARCH_X86)

View File

@ -23,6 +23,12 @@
#error "Cannot compile cpuinfo_x86 on a non x86 platform." #error "Cannot compile cpuinfo_x86 on a non x86 platform."
#endif #endif
thread_local void (*X86InfoInterceptor)(X86Info*) = NULL;
void RegisterX86InfoInterceptor(void (*ptr)(X86Info*)) {
X86InfoInterceptor = ptr;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Definitions for CpuId and GetXCR0Eax. // Definitions for CpuId and GetXCR0Eax.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -615,6 +621,7 @@ X86Info GetX86Info(void) {
if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD")) { if (IsVendor(leaf_0, "GenuineIntel") || IsVendor(leaf_0, "AuthenticAMD")) {
ParseCpuId(max_cpuid_leaf, &info); ParseCpuId(max_cpuid_leaf, &info);
} }
if (X86InfoInterceptor) X86InfoInterceptor(&info);
return info; return info;
} }

View File

@ -101,6 +101,26 @@ TEST(CpuidX86Test, SandyBridge) {
EXPECT_FALSE(features.rdrnd); EXPECT_FALSE(features.rdrnd);
} }
TEST(CpuidX86Test, ForgingCpuWithInterceptor) {
RegisterX86InfoInterceptor([](X86Info* info) {
memcpy(info->vendor, "TEST", sizeof("TEST"));
info->features = X86Features{};
info->features.erms = true;
});
const auto info = GetX86Info();
EXPECT_STREQ(info.vendor, "GenuineIntel");
const auto& features = info.features;
for (size_t i = 0; i < X86_LAST_; ++i)
if (i == X86_ERMS)
EXPECT_TRUE(GetX86FeaturesEnumValue(&features, (X86FeaturesEnum)i));
else
EXPECT_FALSE(GetX86FeaturesEnumValue(&features, (X86FeaturesEnum)i));
RegisterX86InfoInterceptor(NULL);
EXPECT_STREQ(GetX86Info().vendor, "GenuineIntel");
}
const int KiB = 1024; const int KiB = 1024;
const int MiB = 1024 * KiB; const int MiB = 1024 * KiB;