diff --git a/test/unit/instrument_malloc.hpp b/test/unit/instrument_malloc.hpp deleted file mode 100644 index 62efc835a4b18d15164ecb72fea134d3ca89a658..0000000000000000000000000000000000000000 --- a/test/unit/instrument_malloc.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -// Base class for scoped-instrumentation of glibc malloc. -// -// For the lifetime of a `with_instrumented_malloc` object, -// global memory allocation hooks will be set so that -// the virtual `on_malloc`, `on_realloc`, `on_memalign` -// and `on_free` calls will be invoked before the corresponding -// `malloc`, `realloc` etc. is executed. -// -// Scopes of `with_instrumented_malloc` may be nested, but: -// * Don't interleave lifetimes of these objects and expect things -// to work! -// * Don't try and create new `with_instrumented_malloc` instances -// from within an `on_malloc` callback (or others). -// * Definitely don't try and use this in a multithreaded context. -// -// Calling code should check CAN_INSTRUMENT_MALLOC preprocessor -// symbol to see if this functionality is available. - -#include <cstddef> - -#if (__GLIBC__==2) -#include <malloc.h> -#define CAN_INSTRUMENT_MALLOC -#endif - -// Disable if using address sanitizer though: - -// This is how clang tells us. -#if defined(__has_feature) -#if __has_feature(address_sanitizer) -#undef CAN_INSTRUMENT_MALLOC -#endif -# if __has_feature(thread_sanitizer) -#undef CAN_INSTRUMENT_MALLOC -# endif -#endif -// This is how gcc tells us. -#if defined(__SANITIZE_ADDRESS__) -#undef CAN_INSTRUMENT_MALLOC -#endif - -namespace testing { - -#ifdef CAN_INSTRUMENT_MALLOC - -// For run-time, temporary intervention in the malloc-family calls, -// there is still no better alternative than to use the -// deprecated __malloc_hook pointers and friends. - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#if defined(__INTEL_COMPILER) -#pragma warning push -#pragma warning disable 1478 -#endif - -// Totally not thread safe! -struct with_instrumented_malloc { - with_instrumented_malloc() { - push(); - } - - ~with_instrumented_malloc() { - pop(); - } - - virtual void on_malloc(std::size_t, const void*) {} - virtual void on_realloc(void*, std::size_t, const void*) {} - virtual void on_free(void*, const void*) {} - virtual void on_memalign(std::size_t, std::size_t, const void*) {} - -private: - static with_instrumented_malloc*& instance() { - static with_instrumented_malloc* ptr = nullptr; - return ptr; - } - - with_instrumented_malloc* prev_; - decltype(__malloc_hook) saved_malloc_hook_; - decltype(__realloc_hook) saved_realloc_hook_; - decltype(__free_hook) saved_free_hook_; - decltype(__memalign_hook) saved_memalign_hook_; - - void push() { - saved_malloc_hook_ = __malloc_hook; - saved_realloc_hook_ = __realloc_hook; - saved_free_hook_ = __free_hook; - saved_memalign_hook_ = __memalign_hook; - - prev_ = instance(); - instance() = this; - - __malloc_hook = malloc_hook; - __realloc_hook = realloc_hook; - __free_hook = free_hook; - __memalign_hook = memalign_hook; - } - - void pop() { - instance() = prev_; - __malloc_hook = saved_malloc_hook_; - __realloc_hook = saved_realloc_hook_; - __free_hook = saved_free_hook_; - __memalign_hook = saved_memalign_hook_; - } - - struct windback_guard { - with_instrumented_malloc* p; - - windback_guard(): p(instance()) { p->pop(); } - ~windback_guard() { p->push(); } - }; - - static void* malloc_hook(std::size_t size, const void* caller) { - windback_guard g; - g.p->on_malloc(size, caller); - return malloc(size); - } - - static void* realloc_hook(void* ptr, std::size_t size, const void* caller) { - windback_guard g; - g.p->on_realloc(ptr, size, caller); - return realloc(ptr, size); - } - - static void free_hook(void* ptr, const void* caller) { - windback_guard g; - g.p->on_free(ptr, caller); - free(ptr); - } - - static void* memalign_hook(std::size_t alignment, std::size_t size, const void* caller) { - windback_guard g; - g.p->on_memalign(alignment, size, caller); - return memalign(alignment, size); - } -}; - -#pragma GCC diagnostic pop -#if defined(__INTEL_COMPILER) -#pragma warning pop -#endif - -#else - -struct with_instrumented_malloc { - with_instrumented_malloc() { - throw std::runtime_error("malloc instrumentation not supported\n"); - } - - virtual void on_malloc(std::size_t, const void*) {} - virtual void on_realloc(void*, std::size_t, const void*) {} - virtual void on_free(void*, const void*) {} - virtual void on_memalign(std::size_t, std::size_t, const void*) {} -}; - -#endif // ifdef CAN_INSTRUMENT_MALLOC - -} // namespace testing diff --git a/test/unit/test_padded.cpp b/test/unit/test_padded.cpp index 7f2f52b38a4c171e3b99b545218b72f0b9587443..664ef744d5774201b2ad259b18887db983a6d6f2 100644 --- a/test/unit/test_padded.cpp +++ b/test/unit/test_padded.cpp @@ -4,7 +4,6 @@ #include "../gtest.h" #include "common.hpp" -#include "instrument_malloc.hpp" using arb::util::padded_allocator; @@ -56,105 +55,3 @@ TEST(padded_vector, allocator_propagation) { c = std::move(a); EXPECT_EQ(c.get_allocator().alignment(), pa.alignment()); } - - -#ifdef CAN_INSTRUMENT_MALLOC - -struct alloc_data { - unsigned n_malloc = 0; - unsigned n_realloc = 0; - unsigned n_memalign = 0; - unsigned n_free = 0; - - std::size_t last_malloc = -1; - std::size_t last_realloc = -1; - std::size_t last_memalign = -1; -}; - -struct count_allocs: testing::with_instrumented_malloc { - alloc_data data; - - void on_malloc(std::size_t size, const void*) override { - ++data.n_malloc; - data.last_malloc = size; - } - - void on_realloc(void*, std::size_t size, const void*) override { - ++data.n_realloc; - data.last_realloc = size; - } - - void on_memalign(std::size_t, std::size_t size, const void*) override { - ++data.n_memalign; - data.last_memalign = size; - } - - void on_free(void*, const void*) override { - ++data.n_free; - } - - void reset() { - data = alloc_data(); - } -}; - -TEST(padded_vector, instrumented) { - count_allocs A; - - padded_allocator<double> pad256(256), pad32(32); - pvector<double> v1p256(303, pad256); - alloc_data mdata = A.data; - - unsigned expected_v1_alloc = 303*sizeof(double); - expected_v1_alloc = expected_v1_alloc%256? 256*(1+expected_v1_alloc/256): expected_v1_alloc; - - EXPECT_EQ(1u, mdata.n_memalign); - EXPECT_EQ(0u, mdata.n_malloc); - EXPECT_EQ(0u, mdata.n_realloc); - EXPECT_EQ(expected_v1_alloc, mdata.last_memalign); - - // Move assignment: allocators propagate, so we do not expect v2 - // to perform a new allocation. - - pvector<double> v2p32(10, pad32); - A.reset(); - v2p32 = std::move(v1p256); - mdata = A.data; - - EXPECT_EQ(0u, mdata.n_memalign); - EXPECT_EQ(0u, mdata.n_malloc); - EXPECT_EQ(0u, mdata.n_realloc); - - pvector<double> v3p256(101, pad256), v4p256(700, pad256); - - A.reset(); - v4p256 = v3p256; // same alignment, larger size => shouldn't need to allocate - mdata = A.data; - - EXPECT_EQ(0u, mdata.n_memalign); - EXPECT_EQ(0u, mdata.n_malloc); - EXPECT_EQ(0u, mdata.n_realloc); - - A.reset(); - pvector<double> v5p32(701, pad32); - mdata = A.data; - - unsigned expected_v5_alloc = 701*sizeof(double); - expected_v5_alloc = expected_v5_alloc%32? 32*(1+expected_v5_alloc/32): expected_v5_alloc; - - EXPECT_EQ(1u, mdata.n_memalign); - EXPECT_EQ(0u, mdata.n_malloc); - EXPECT_EQ(0u, mdata.n_realloc); - EXPECT_EQ(expected_v5_alloc, mdata.last_memalign); - - A.reset(); - v5p32 = v3p256; // enough space, but different alignment, so should free and then allocate. - mdata = A.data; - - EXPECT_EQ(1u, mdata.n_free); - EXPECT_EQ(1u, mdata.n_memalign); - EXPECT_EQ(0u, mdata.n_malloc); - EXPECT_EQ(0u, mdata.n_realloc); -} - -#endif // ifdef CAN_INSTRUMENT_MALLOC