From 36c3c713bdc59a44193c875d0b23c6d8c4f67d13 Mon Sep 17 00:00:00 2001 From: Robin Leroy Date: Sat, 30 Mar 2024 17:43:48 +0100 Subject: [PATCH] Make it work, update callers, log it --- base/cpuid.cpp | 5 ++-- base/cpuid.hpp | 30 +++++++++++++----------- base/cpuid_test.cpp | 9 +++++++ geometry/grassmann_test.cpp | 6 ++--- geometry/point_test.cpp | 2 +- ksp_plugin/interface.cpp | 9 +++++-- numerics/cbrt_test.cpp | 10 ++++---- numerics/fma.hpp | 2 +- numerics/fma_test.cpp | 2 +- quantities/elementary_functions_test.cpp | 2 +- 10 files changed, 47 insertions(+), 30 deletions(-) diff --git a/base/cpuid.cpp b/base/cpuid.cpp index 6ece902572..132202962a 100644 --- a/base/cpuid.cpp +++ b/base/cpuid.cpp @@ -18,7 +18,7 @@ namespace _cpuid { namespace internal { namespace { -std::vector CPUIDFlags; +std::vector CPUIDFlags; CPUIDResult CPUID(std::uint32_t const eax, std::uint32_t const ecx) { #if PRINCIPIA_COMPILER_MSVC @@ -78,7 +78,7 @@ std::string ProcessorBrandString() { } std::string CPUFeatures() { - std::string result = ""; + std::string result; for (auto const& flag : CPUIDFlags) { if (flag.IsSet()) { if (!result.empty()) { @@ -87,6 +87,7 @@ std::string CPUFeatures() { result += flag.name(); } } + return result; } } // namespace internal diff --git a/base/cpuid.hpp b/base/cpuid.hpp index 1b1920ca00..0f1a9511cf 100644 --- a/base/cpuid.hpp +++ b/base/cpuid.hpp @@ -56,28 +56,30 @@ std::string CPUFeatures(); namespace cpuid_feature_flags { // Table 3-11. PRINCIPIA_CPUID_FLAG(FPU, 0x01, EDX, 0); // x87 Floating Point Unit on chip. -PRINCIPIA_CPUID_FLAG(PSN, 0x01, EDX, 18); // Processor Serial Number. -PRINCIPIA_CPUID_FLAG(SSE, 0x01, EDX, 25); // Streaming SIMD Extensions. -PRINCIPIA_CPUID_FLAG(SSE2, 0x01, EDX, 26); // Streaming SIMD Extensions 2. -PRINCIPIA_CPUID_FLAG(SSE3, 0x01, ECX, 0); // Streaming SIMD Extensions 3. -PRINCIPIA_CPUID_FLAG(FMA, 0x01, ECX, 12); // Fused Multiply Add. + +PRINCIPIA_CPUID_FLAG(PSN, 0x01, EDX, 18); // Processor Serial Number. +PRINCIPIA_CPUID_FLAG(SSE, 0x01, EDX, 25); // Streaming SIMD Extensions. +PRINCIPIA_CPUID_FLAG(SSE2, 0x01, EDX, 26); // Streaming SIMD Extensions 2. +PRINCIPIA_CPUID_FLAG(SSE3, 0x01, ECX, 0); // Streaming SIMD Extensions 3. +PRINCIPIA_CPUID_FLAG(FMA, 0x01, ECX, 12); // Fused Multiply Add. PRINCIPIA_CPUID_FLAG(SSE4_1, 0x01, ECX, 19); // Streaming SIMD Extensions 4.1. PRINCIPIA_CPUID_FLAG(AVX, 0x01, ECX, 28); // Advanced Vector eXtensions. -// Table 3-8. + +// Table 3-8, Structured Extended Feature Flags Enumeration Leaf. PRINCIPIA_CPUID_FLAG(AVX2, 0x07, EBX, 5); // Advanced Vector eXtensions 2. PRINCIPIA_CPUID_FLAG(AVX512F, 0x07, EBX, 16); // AVX-512 Foundation. -PRINCIPIA_CPUID_FLAG(AVX512DQ, 0x07, EBX, 17); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512_IFMA, 0x07, EBX, 21); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512PF, 0x07, EBX, 26); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512ER, 0x07, EBX, 27); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512CD, 0x07, EBX, 28); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512BW, 0x07, EBX, 30); // AVX-512 . -PRINCIPIA_CPUID_FLAG(AVX512VL, 0x07, EBX, 31); // AVX-512 . +PRINCIPIA_CPUID_FLAG(AVX512DQ, 0x07, EBX, 17); // DWORD and QWORD instructions. +PRINCIPIA_CPUID_FLAG(AVX512VL, 0x07, EBX, 31); // Vector Length Extensions. +PRINCIPIA_CPUID_FLAG(AVX512_FP16, 0x07, ECX, 23); // IEEE-754 binary16. } // namespace cpuid_feature_flags } // namespace internal +#undef PRINCIPIA_CPUID_FLAG + +using internal::CPUFeatures; using internal::CPUVendorIdentificationString; -namespace cpuid_feature_flags = internal::cpuid_feature_flags +using internal::ProcessorBrandString; +namespace cpuid_feature_flags = internal::cpuid_feature_flags; } // namespace _cpuid } // namespace base diff --git a/base/cpuid_test.cpp b/base/cpuid_test.cpp index 4bd8c98232..3a6be0d9ad 100644 --- a/base/cpuid_test.cpp +++ b/base/cpuid_test.cpp @@ -7,6 +7,8 @@ namespace principia { namespace base { using ::testing::AnyOf; +using ::testing::HasSubstr; +using ::testing::Not; using ::testing::Test; using namespace principia::base::_cpuid; @@ -20,6 +22,10 @@ TEST_F(CPUIDTest, Vendor) { AnyOf("AuthenticAMD", "GenuineIntel")); } +TEST_F(CPUIDTest, Brand) { + EXPECT_THAT(ProcessorBrandString(), AnyOf(HasSubstr("Intel(R) Xeon(R)"))); +} + TEST_F(CPUIDTest, CPUFeatureFlags) { // We require Prescott or later. EXPECT_TRUE(cpuid_feature_flags::FPU.IsSet()); @@ -30,6 +36,9 @@ TEST_F(CPUIDTest, CPUFeatureFlags) { // We are not running these tests on a Pentium III, so we do not have the // Processor Serial Number feature. EXPECT_FALSE(cpuid_feature_flags::PSN.IsSet()); + EXPECT_THAT( + CPUFeatures(), + AllOf(HasSubstr("FPU"), HasSubstr("SSE2"), Not(HasSubstr("PSN")))); } } // namespace base diff --git a/geometry/grassmann_test.cpp b/geometry/grassmann_test.cpp index a0016b8465..e1a8061b8f 100644 --- a/geometry/grassmann_test.cpp +++ b/geometry/grassmann_test.cpp @@ -82,7 +82,7 @@ class GrassmannTest : public testing::Test { using GrassmannDeathTest = GrassmannTest; TEST_F(GrassmannTest, VectorFMA) { - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } Length const a = a_.x; @@ -101,7 +101,7 @@ TEST_F(GrassmannTest, VectorFMA) { } TEST_F(GrassmannTest, BivectorFMA) { - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } Length const a = a_.x; @@ -120,7 +120,7 @@ TEST_F(GrassmannTest, BivectorFMA) { } TEST_F(GrassmannTest, TrivectorFMA) { - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } Length const a = a_.x; diff --git a/geometry/point_test.cpp b/geometry/point_test.cpp index b823f7ba24..169bea09c3 100644 --- a/geometry/point_test.cpp +++ b/geometry/point_test.cpp @@ -48,7 +48,7 @@ class PointTest : public testing::Test { using PointDeathTest = PointTest; TEST_F(PointTest, FMA) { - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } EXPECT_THAT(FusedMultiplyAdd(3 * Litre, 5 * Second / Litre, mjd0), diff --git a/ksp_plugin/interface.cpp b/ksp_plugin/interface.cpp index c5e3ffde1b..9664e6ec40 100644 --- a/ksp_plugin/interface.cpp +++ b/ksp_plugin/interface.cpp @@ -23,6 +23,7 @@ #include "astronomy/time_scales.hpp" #include "base/array.hpp" #include "base/base64.hpp" +#include "base/cpuid.hpp" #include "base/encoder.hpp" #include "base/fingerprint2011.hpp" #include "base/flags.hpp" @@ -83,6 +84,7 @@ using namespace principia::astronomy::_epoch; using namespace principia::astronomy::_time_scales; using namespace principia::base::_array; using namespace principia::base::_base64; +using namespace principia::base::_cpuid; using namespace principia::base::_encoder; using namespace principia::base::_fingerprint2011; using namespace principia::base::_flags; @@ -730,8 +732,11 @@ void __cdecl principia__InitGoogleLogging() { << " built on " << BuildDate << " by " << principia::base::CompilerName << " version " << principia::base::CompilerVersion - << " for " << principia::base::OperatingSystem - << " " << principia::base::Architecture; + << " for " << principia::base::OperatingSystem << " " + << principia::base::Architecture; + LOG(ERROR) << "Running on " << ProcessorBrandString() << " (" + << CPUVendorIdentificationString() << ")"; + LOG(ERROR) << "with " << CPUFeatures(); #if OS_WIN MODULEINFO module_info; memset(&module_info, 0, sizeof(module_info)); diff --git a/numerics/cbrt_test.cpp b/numerics/cbrt_test.cpp index 74e034bacc..4f66e0037c 100644 --- a/numerics/cbrt_test.cpp +++ b/numerics/cbrt_test.cpp @@ -101,7 +101,7 @@ class CubeRootTest : public ::testing::Test { cbrt_y.rounded_to_nearest) { ++method_3²ᴄZ5¹_misroundings; } - if (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()) { EXPECT_THAT(method_5²Z4¹FMA::Cbrt(y), AnyOf(cbrt_y.rounded_down, cbrt_y.rounded_up)); EXPECT_THAT(method_5²Z4¹FMA::Cbrt(y), @@ -113,7 +113,7 @@ class CubeRootTest : public ::testing::Test { } } EXPECT_THAT(method_3²ᴄZ5¹_misroundings, Eq(expected_3²ᴄZ5¹_misroundings)); - if (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()) { EXPECT_THAT(method_5²Z4¹FMA_misroundings, Eq(expected_5²Z4¹FMA_misroundings)); } @@ -140,7 +140,7 @@ TEST_F(CubeRootTest, Rescaling) { Eq(Cbrt(2))); EXPECT_THAT(0x1p358 * method_3²ᴄZ5¹::Cbrt(0x1p-1073), Eq(Cbrt(2))); - if (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()) { EXPECT_THAT(0x1p-340 * method_5²Z4¹FMA::Cbrt(0x1p1021), Eq(Cbrt(2))); EXPECT_THAT(0x1p341 * method_5²Z4¹FMA::Cbrt(0x1p-1022), @@ -206,7 +206,7 @@ TEST_F(CubeRootTest, BoundsOfTheRescalingRange) { Eq(0x1p113 * Cbrt(4))); EXPECT_THAT(method_3²ᴄZ5¹::Cbrt(0x1.0'0000'0000'0002p341), Eq(0x1p113 * Cbrt(0x1.0'0000'0000'0002p2))); - if (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()) { EXPECT_THAT(method_5²Z4¹FMA::Cbrt(0x1p-438), Eq(0x1p-146)); EXPECT_THAT( @@ -237,7 +237,7 @@ TEST_F(CubeRootTest, ParticularlyDifficultRounding) { Eq(cbrt_y.rounded_to_nearest)); EXPECT_THAT(method_3²ᴄZ5¹::Cbrt(y), AllOf(Ne(cbrt_y.rounded_to_nearest), Eq(cbrt_y.rounded_down))); - if (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()) { EXPECT_THAT(method_5²Z4¹FMA::Cbrt(y), Eq(cbrt_y.rounded_to_nearest)); EXPECT_THAT(method_5²Z4¹FMA::Cbrt(y), diff --git a/numerics/fma.hpp b/numerics/fma.hpp index 24bea157c9..c04b1e3582 100644 --- a/numerics/fma.hpp +++ b/numerics/fma.hpp @@ -21,7 +21,7 @@ constexpr bool CanEmitFMAInstructions = false; #if PRINCIPIA_USE_FMA_IF_AVAILABLE() #define PRINCIPIA_USE_HARDWARE_FMA_DEFAULT \ - (CanEmitFMAInstructions && HasCPUFeatures(CPUFeatureFlags::FMA)); + (CanEmitFMAInstructions && cpuid_feature_flags::FPU.IsSet()); #else #define PRINCIPIA_USE_HARDWARE_FMA_DEFAULT false; #endif diff --git a/numerics/fma_test.cpp b/numerics/fma_test.cpp index 056bf5e5ce..476269c2f3 100644 --- a/numerics/fma_test.cpp +++ b/numerics/fma_test.cpp @@ -17,7 +17,7 @@ class FMATest : public testing::Test { protected: void SetUp() override { // Note that we test even if |UseHardwareFMA| is false, i.e., even in debug. - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } } diff --git a/quantities/elementary_functions_test.cpp b/quantities/elementary_functions_test.cpp index 5c6bf1d1fd..43b35fd6b8 100644 --- a/quantities/elementary_functions_test.cpp +++ b/quantities/elementary_functions_test.cpp @@ -37,7 +37,7 @@ using namespace principia::testing_utilities::_vanishes_before; class ElementaryFunctionsTest : public testing::Test {}; TEST_F(ElementaryFunctionsTest, FMA) { - if (!CanEmitFMAInstructions || !HasCPUFeatures(CPUFeatureFlags::FMA)) { + if (!CanEmitFMAInstructions || !cpuid_feature_flags::FPU.IsSet()) { GTEST_SKIP() << "Cannot test FMA on a machine without FMA"; } EXPECT_EQ(11 * Coulomb,