Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 12 additions & 36 deletions src/benchmark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
Expand Down Expand Up @@ -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<const char*>(&skipped_) -
reinterpret_cast<const char*>(this) <=
/*cache_line_size=*/64 -
static_cast<std::ptrdiff_t>(sizeof(skipped_)))
<< "the commonly accessed members of State must fit in the first cache "
"line";
}

void State::PauseTiming() {
Expand Down
13 changes: 9 additions & 4 deletions src/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down