diff --git a/include/cpu_features_macros.h b/include/cpu_features_macros.h index d4771674..6a2f76af 100644 --- a/include/cpu_features_macros.h +++ b/include/cpu_features_macros.h @@ -239,4 +239,11 @@ #define CPU_FEATURES_UNREACHABLE() #endif +// Communicates to the compiler that the function is now deprecated +#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC) +#define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message))) +#else +#define CPU_FEATURES_DEPRECATED(message) +#endif + #endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_ diff --git a/include/cpuinfo_x86.h b/include/cpuinfo_x86.h index adb11896..69173a9d 100644 --- a/include/cpuinfo_x86.h +++ b/include/cpuinfo_x86.h @@ -103,7 +103,8 @@ typedef struct { int family; int model; int stepping; - char vendor[13]; // 0 terminated string + char vendor[13]; // 0 terminated string + char brand_string[49]; // 0 terminated string } X86Info; // Calls cpuid and returns an initialized X86info. @@ -170,6 +171,7 @@ X86Microarchitecture GetX86Microarchitecture(const X86Info* info); // Calls cpuid and fills the brand_string. // - brand_string *must* be of size 49 (beware of array decaying). // - brand_string will be zero terminated. +CPU_FEATURES_DEPRECATED("brand_string is now embedded in X86Info by default") void FillX86BrandString(char brand_string[49]); //////////////////////////////////////////////////////////////////////////////// diff --git a/src/impl_x86__base_implementation.inl b/src/impl_x86__base_implementation.inl index e1b8f825..184c35a5 100644 --- a/src/impl_x86__base_implementation.inl +++ b/src/impl_x86__base_implementation.inl @@ -184,6 +184,7 @@ static int IsVendorByX86Info(const X86Info* info, const char* const name) { return equals(info->vendor, name, sizeof(info->vendor)); } +// TODO: Remove when deprecation period is over, void FillX86BrandString(char brand_string[49]) { const Leaves leaves = ReadLeaves(); const Leaf packed[3] = { @@ -202,31 +203,33 @@ void FillX86BrandString(char brand_string[49]) { // CpuId //////////////////////////////////////////////////////////////////////////////// -static bool HasSecondFMA(uint32_t model) { +static bool HasSecondFMA(const X86Info* info) { // Skylake server - if (model == 0x55) { - char proc_name[49] = {0}; - FillX86BrandString(proc_name); + if (info->model == 0x55) { // detect Xeon - if (proc_name[9] == 'X') { + if (info->brand_string[9] == 'X') { // detect Silver or Bronze - if (proc_name[17] == 'S' || proc_name[17] == 'B') return false; + if (info->brand_string[17] == 'S' || info->brand_string[17] == 'B') + return false; // detect Gold 5_20 and below, except for Gold 53__ - if (proc_name[17] == 'G' && proc_name[22] == '5') - return ((proc_name[23] == '3') || - (proc_name[24] == '2' && proc_name[25] == '2')); + if (info->brand_string[17] == 'G' && info->brand_string[22] == '5') + return ( + (info->brand_string[23] == '3') || + (info->brand_string[24] == '2' && info->brand_string[25] == '2')); // detect Xeon W 210x - if (proc_name[17] == 'W' && proc_name[21] == '0') return false; + if (info->brand_string[17] == 'W' && info->brand_string[21] == '0') + return false; // detect Xeon D 2xxx - if (proc_name[17] == 'D' && proc_name[19] == '2' && proc_name[20] == '1') + if (info->brand_string[17] == 'D' && info->brand_string[19] == '2' && + info->brand_string[20] == '1') return false; } return true; } // Cannon Lake client - if (model == 0x66) return false; + if (info->model == 0x66) return false; // Ice Lake client - if (model == 0x7d || model == 0x7e) return false; + if (info->model == 0x7d || info->model == 0x7e) return false; // This is the right default... return true; } @@ -263,10 +266,24 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, X86Features* const features = &info->features; + // Fill Family, Model and Stepping. info->family = extended_family + family; info->model = (extended_model << 4) + model; info->stepping = ExtractBitRange(leaf_1.eax, 3, 0); + // Fill Brand String. + const Leaf packed[3] = { + leaves->leaf_80000002, + leaves->leaf_80000003, + leaves->leaf_80000004, + }; +#if __STDC_VERSION__ >= 201112L + _Static_assert(sizeof(packed) == 48, "Leaves must be packed"); +#endif + copy(info->brand_string, (const char*)(packed), 48); + info->brand_string[48] = '\0'; + + // Fill cpu features. features->fpu = IsBitSet(leaf_1.edx, 0); features->tsc = IsBitSet(leaf_1.edx, 4); features->cx8 = IsBitSet(leaf_1.edx, 8); @@ -341,7 +358,7 @@ static void ParseCpuId(const Leaves* leaves, X86Info* info, features->avx512vpopcntdq = IsBitSet(leaf_7.ecx, 14); features->avx512_4vnniw = IsBitSet(leaf_7.edx, 2); features->avx512_4vbmi2 = IsBitSet(leaf_7.edx, 3); - features->avx512_second_fma = HasSecondFMA(info->model); + features->avx512_second_fma = HasSecondFMA(info); features->avx512_4fmaps = IsBitSet(leaf_7.edx, 3); features->avx512_bf16 = IsBitSet(leaf_7_1.eax, 5); features->avx512_vp2intersect = IsBitSet(leaf_7.edx, 8); diff --git a/test/cpuinfo_x86_test.cc b/test/cpuinfo_x86_test.cc index 889190ec..0972c085 100644 --- a/test/cpuinfo_x86_test.cc +++ b/test/cpuinfo_x86_test.cc @@ -414,6 +414,8 @@ TEST_F(CpuidX86Test, AMD_K15_EXCAVATOR_STONEY_RIDGE) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x70); + EXPECT_STREQ(info.brand_string, + "AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_EXCAVATOR); @@ -439,6 +441,8 @@ TEST_F(CpuidX86Test, AMD_K15_PILEDRIVER_ABU_DHABI) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x02); + EXPECT_STREQ(info.brand_string, + "AMD Opteron(tm) Processor 6376 "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PILEDRIVER); @@ -512,6 +516,8 @@ TEST_F(CpuidX86Test, AMD_K15_BULLDOZER_INTERLAGOS) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x01); + EXPECT_STREQ(info.brand_string, + "AMD Opteron(TM) Processor 6238 "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_BULLDOZER); @@ -539,6 +545,8 @@ TEST_F(CpuidX86Test, AMD_K15_STREAMROLLER_GODAVARI) { EXPECT_EQ(info.family, 0x15); EXPECT_EQ(info.model, 0x38); EXPECT_EQ(info.stepping, 0x01); + EXPECT_STREQ(info.brand_string, + "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_STREAMROLLER); @@ -564,6 +572,8 @@ TEST_F(CpuidX86Test, AMD_K16_JAGUAR_KABINI) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x16); EXPECT_EQ(info.model, 0x00); + EXPECT_STREQ(info.brand_string, + "AMD A4-5000 APU with Radeon(TM) HD Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_JAGUAR); char brand_string[49]; @@ -588,6 +598,8 @@ TEST_F(CpuidX86Test, AMD_K16_PUMA_BEEMA) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x16); EXPECT_EQ(info.model, 0x30); + EXPECT_STREQ(info.brand_string, + "AMD A6-6310 APU with AMD Radeon R4 Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_PUMA); char brand_string[49]; @@ -612,6 +624,8 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_DALI) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x20); + EXPECT_STREQ(info.brand_string, + "AMD 3020e with Radeon Graphics "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN); char brand_string[49]; @@ -636,6 +650,8 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN_PLUS_PINNACLE_RIDGE) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x08); + EXPECT_STREQ(info.brand_string, + "AMD Ryzen 7 2700X Eight-Core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN_PLUS); char brand_string[49]; @@ -660,6 +676,7 @@ TEST_F(CpuidX86Test, AMD_K17_ZEN2_XBOX_SERIES_X) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x17); EXPECT_EQ(info.model, 0x47); + EXPECT_STREQ(info.brand_string, "AMD 4700S 8-Core Processor Desktop Kit"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN2); char brand_string[49]; @@ -684,6 +701,8 @@ TEST_F(CpuidX86Test, AMD_K18_ZEN_DHYANA) { EXPECT_STREQ(info.vendor, "HygonGenuine"); EXPECT_EQ(info.family, 0x18); EXPECT_EQ(info.model, 0x00); + EXPECT_STREQ(info.brand_string, + "Hygon C86 3185 8-core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN); char brand_string[49]; @@ -756,6 +775,8 @@ TEST_F(CpuidX86Test, AMD_K19_ZEN3_VERMEER) { EXPECT_STREQ(info.vendor, "AuthenticAMD"); EXPECT_EQ(info.family, 0x19); EXPECT_EQ(info.model, 0x21); + EXPECT_STREQ(info.brand_string, + "AMD Ryzen 9 5900X 12-Core Processor "); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::AMD_ZEN3); char brand_string[49]; @@ -827,6 +848,8 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x1A); EXPECT_EQ(info.stepping, 0x02); + EXPECT_STREQ(info.brand_string, + "Genuine Intel(R) CPU @ 0000 @ 1.87GHz"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM); char brand_string[49]; @@ -908,6 +931,8 @@ flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2 EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x37); EXPECT_EQ(info.stepping, 0x03); + EXPECT_STREQ(info.brand_string, + " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz"); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_ATOM_SMT); @@ -1014,6 +1039,7 @@ flags : fpu mmx sse EXPECT_EQ(info.family, 0x06); EXPECT_EQ(info.model, 0x07); EXPECT_EQ(info.stepping, 0x03); + EXPECT_STREQ(info.brand_string, ""); EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN); char brand_string[49];