diff --git a/src/benchmark.cc b/src/benchmark.cc index c7baa103d..1f7d94750 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -222,42 +223,17 @@ State::State(std::string name, IterationCount max_iters, } } - // Note: The use of offsetof below is technically undefined until C++17 - // because State is not a standard layout type. However, all compilers - // currently provide well-defined behavior as an extension (which is - // demonstrated since constexpr evaluation must diagnose all undefined - // behavior). However, GCC and Clang also warn about this use of offsetof, - // which must be suppressed. -#if defined(__INTEL_COMPILER) -#pragma warning push -#pragma warning(disable : 1875) -#elif defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif -#if defined(__NVCC__) -#pragma nv_diagnostic push -#pragma nv_diag_suppress 1427 -#endif -#if defined(__NVCOMPILER) -#pragma diagnostic push -#pragma diag_suppress offset_in_non_POD_nonstandard -#endif - // Offset tests to ensure commonly accessed data is on the first cache line. - const int cache_line_size = 64; - static_assert( - offsetof(State, skipped_) <= (cache_line_size - sizeof(skipped_)), ""); -#if defined(__INTEL_COMPILER) -#pragma warning pop -#elif defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif -#if defined(__NVCC__) -#pragma nv_diagnostic pop -#endif -#if defined(__NVCOMPILER) -#pragma diagnostic pop -#endif + // Ensure commonly accessed data is on the first cache line. State is not a + // standard-layout type, so the offset is measured on the live object. + // + // The check is enabled under NDEBUG as well: a State is constructed once per + // benchmark instance and thread, never inside the iteration loop. + BM_CHECK_ALWAYS(reinterpret_cast(&skipped_) - + reinterpret_cast(this) <= + /*cache_line_size=*/64 - + static_cast(sizeof(skipped_))) + << "the commonly accessed members of State must fit in the first cache " + "line"; } void State::PauseTiming() { diff --git a/src/check.h b/src/check.h index aa8c78c92..b6fc22ff0 100644 --- a/src/check.h +++ b/src/check.h @@ -79,15 +79,20 @@ class CheckHandler { } // end namespace internal } // end namespace benchmark -// The BM_CHECK macro returns a std::ostream object that can have extra -// information written to it. -#ifndef NDEBUG -#define BM_CHECK(b) \ +// Like BM_CHECK, but enabled in every build configuration. Reserved for +// invariants that are cheap enough to verify unconditionally and that must not +// be violated silently in a release build. +#define BM_CHECK_ALWAYS(b) \ (b ? ::benchmark::internal::GetNullLogInstance() \ : ::benchmark::internal::CheckHandler( \ std::string_view(#b), std::string_view(__FILE__), \ std::string_view(__func__), __LINE__) \ .GetLog()) + +// The BM_CHECK macro returns a std::ostream object that can have extra +// information written to it. +#ifndef NDEBUG +#define BM_CHECK(b) BM_CHECK_ALWAYS(b) #else #define BM_CHECK(b) ::benchmark::internal::GetNullLogInstance() #endif