Created
April 9, 2016 18:39
-
-
Save kennethchiu/0a173bb2c7876d1d56f6b216125187fd to your computer and use it in GitHub Desktop.
Bounds checking macros and benchmark of bounds checking cost
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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