Skip to content

Instantly share code, notes, and snippets.

@kennethchiu
Created April 9, 2016 18:39
Show Gist options
  • Save kennethchiu/0a173bb2c7876d1d56f6b216125187fd to your computer and use it in GitHub Desktop.
Save kennethchiu/0a173bb2c7876d1d56f6b216125187fd to your computer and use it in GitHub Desktop.
Bounds checking macros and benchmark of bounds checking cost
#include <iostream>
#include <chrono>
// This macro will always bounds check, even if debug build.
#define UNQ_ALWAYS_CHKBND(a, i) \
chk_bnd(a, i, __FILE__, __LINE__, __func__)
// This macro will be compiled out if NDEBUG is defined.
#ifndef NDEBUG
#define UNQ_DBG_CHKBND(a, i) \
chk_bnd(a, i, __FILE__, __LINE__, __func__)
#else
#define UNQ_DBG_CHKBND(a, i)
#endif
// Check bounds. Print file name, function name, and line number.
template <typename T, typename IT, std::size_t N>
inline void
chk_bnd(T (&)[N], const IT index, const char *const file_name, unsigned int line_no, const char *const func_name)
if (index < 0) {
std::cerr << "In " << func_name << "() at " << file_name << ":" << line_no << ": ";
std::cerr << "Array index " << index << " is negative." << std::endl;
abort();
} else if (index >= IT(N)) {
std::cerr << "In " << func_name << "() at " << file_name << ":" << line_no << ": ";
std::cerr << "Array index " << index << " is out-of-bounds for array of size " << N << "." << std::endl;
abort();
}
}
// Utility to get the number of elements in an array.
template <typename T, std::size_t N>
constexpr inline auto
n_elems(T (&)[N]) { return N; }
int main() {
// Measure cost of bounds-checking.
{
constexpr int N = 10'000'000;
static int a[N];
// Make one pass to warm cache and memory.
for (auto &e : a) { e = 1234; }
// First, without bounds checking.
auto start = std::chrono::steady_clock::now();
for (int i = 0; i < 50; i++) {
for (std::size_t i = 0; i < n_elems(a); i++) {
a[i] = i;
}
}
auto end = std::chrono::steady_clock::now();
auto diff = end - start;
std::cout << std::chrono::duration<double>(diff).count() << " seconds" << std::endl;
// Now test with bounds checking.
start = std::chrono::steady_clock::now();
for (int i = 0; i < 50; i++) {
for (std::size_t i = 0; i < n_elems(a); i++) {
UNQ_ALWAYS_CHKBND(a, i);
a[i] = i;
}
}
end = std::chrono::steady_clock::now();
diff = end - start;
std::cout << std::chrono::duration<double>(diff).count() << " seconds" << std::endl;
}
// Uncomment below to test bounds checking macros.
/*
{
int a[10];
UNQ_ALWAYS_CHKBND(a, 10);
UNQ_ALWAYS_CHKBND(a, -1);
UNQ_DBG_CHKBND(a, 10);
UNQ_DBG_CHKBND(a, -1);
}
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment