From 010efcd04dc10ecb61ade037a0ad19892f12b3a2 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Mon, 15 Mar 2021 08:24:06 -0700 Subject: [PATCH] Initial memory wrapper, bugs everywhere --- src/scripts/apex_exec | 9 + src/wrappers/CMakeLists.txt | 13 +- src/wrappers/memory_wrapper.c | 197 ++++++++++++++++++++ src/wrappers/memory_wrapper.h | 55 ++++++ src/wrappers/memory_wrapper_internal.cpp | 217 +++++++++++++++++++++++ 5 files changed, 487 insertions(+), 4 deletions(-) create mode 100644 src/wrappers/memory_wrapper.c create mode 100644 src/wrappers/memory_wrapper.h create mode 100644 src/wrappers/memory_wrapper_internal.cpp diff --git a/src/scripts/apex_exec b/src/scripts/apex_exec index 815a1ae1..c82994cf 100755 --- a/src/scripts/apex_exec +++ b/src/scripts/apex_exec @@ -42,6 +42,7 @@ where APEX options are zero or more of: --apex:kokkos enable Kokkos support --apex:raja enable RAJA support --apex:pthread enable pthread wrapper support + --apex:memory enable memory wrapper support --apex:untied enable tasks to migrate cores/OS threads during execution (not compatible with trace output) --apex:cuda_counters enable CUDA/CUPTI counter support @@ -82,6 +83,7 @@ stat=no period=1000000 io=no pthread=no +memory=no debugger="" prog="" @@ -112,6 +114,10 @@ while (( "$#" )); do pthread=yes shift ;; + --apex:memory) + memory=yes + shift + ;; --apex:otf2) otf2=yes export APEX_OTF2=1 @@ -260,6 +266,9 @@ fi if [ $pthread = 1 ]; then PTHREAD_LIB=${BASEDIR}/lib/libapex_pthread_wrapper${SHLIBX}: fi +if [ $memory = 1 ]; then + PTHREAD_LIB=${BASEDIR}/lib/libapex_memory_wrapper${SHLIBX}: +fi if [ ${apple} = 1 ]; then APEX_LD_PRELOAD=${PTHREAD_LIB}${BASEDIR}/lib/libapex${SHLIBX}:@OMPT_LIBRARY@ else diff --git a/src/wrappers/CMakeLists.txt b/src/wrappers/CMakeLists.txt index a1194d9f..45a993db 100644 --- a/src/wrappers/CMakeLists.txt +++ b/src/wrappers/CMakeLists.txt @@ -1,16 +1,21 @@ -# Make sure the compiler can find include files from our Apex library. +# Make sure the compiler can find include files from our Apex library. include_directories (${APEX_SOURCE_DIR}/src/apex ${APEX_SOURCE_DIR}/src/wrappers) -# Make sure the linker can find the Apex library once it is built. +# Make sure the linker can find the Apex library once it is built. link_directories (${APEX_BINARY_DIR}/src/apex) -# Add library called "testOverhead" that is built from the source file +# Add library called "apex_pthread_wrapper" that is built from the source file add_library (apex_pthread_wrapper pthread_wrapper.c pthread_wrapper_internal.cpp) add_dependencies (apex_pthread_wrapper apex) target_link_libraries (apex_pthread_wrapper apex) -INSTALL(TARGETS apex_pthread_wrapper +# Add library called "apex_memory_wrapper" that is built from the source file +add_library (apex_memory_wrapper memory_wrapper.c memory_wrapper_internal.cpp) +add_dependencies (apex_memory_wrapper apex) +target_link_libraries (apex_memory_wrapper apex) + +INSTALL(TARGETS apex_pthread_wrapper apex_memory_wrapper RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib diff --git a/src/wrappers/memory_wrapper.c b/src/wrappers/memory_wrapper.c new file mode 100644 index 00000000..5211d2cc --- /dev/null +++ b/src/wrappers/memory_wrapper.c @@ -0,0 +1,197 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef APEX_PRELOAD_LIB +/********************************/ +/* LD_PRELOAD wrapper functions */ +/********************************/ + +#define RESET_DLERROR() dlerror() +#define CHECK_DLERROR() { \ + char const * err = dlerror(); \ + if (err) { \ + printf("Error getting %s handle: %s\n", name, err); \ + fflush(stdout); \ + exit(1); \ + } \ +} + +static +void * get_system_function_handle(char const * name, void * caller) +{ + void * handle; + + // Reset error pointer + RESET_DLERROR(); + + // Attempt to get the function handle + handle = dlsym(RTLD_NEXT, name); + + // Detect errors + CHECK_DLERROR(); + + // Prevent recursion if more than one wrapping approach has been loaded. + // This happens because we support wrapping pthreads three ways at once: + // #defines in Profiler.h, -Wl,-wrap on the link line, and LD_PRELOAD. + if (handle == caller) { + RESET_DLERROR(); + void * syms = dlopen(NULL, RTLD_NOW); + CHECK_DLERROR(); + do { + RESET_DLERROR(); + handle = dlsym(syms, name); + CHECK_DLERROR(); + } while (handle == caller); + } + + return handle; +} + +void* malloc (size_t size) { + static malloc_p _malloc = NULL; + if (!_malloc) { + _malloc = (malloc_p)get_system_function_handle("malloc", (void*)malloc); + } + return apex_malloc_wrapper(_malloc, size); +} + +void* calloc (size_t nmemb, size_t size) { + static calloc_p _calloc = NULL; + if (!_calloc) { + _calloc = (calloc_p)get_system_function_handle("calloc", (void*)calloc); + } + return apex_calloc_wrapper(_calloc, nmemb, size); +} + +#if defined(memalign) +void* memalign (size_t alignment, size_t size) { + static memalign_p _memalign = NULL; + if (!_memalign) { + _memalign = (memalign_p)get_system_function_handle("memalign", (void*)memalign); + } + return apex_memalign_wrapper(_memalign, alignment, size); +} +#endif + +void* realloc (void* ptr, size_t size) { + static realloc_p _realloc = NULL; + if (!_realloc) { + _realloc = (realloc_p)get_system_function_handle("realloc", (void*)realloc); + } + return apex_realloc_wrapper(_realloc, ptr, size); +} + +#if defined(reallocarray) +void* reallocarray (void* ptr, size_t nmemb, size_t size) { + static reallocarray_p _reallocarray = NULL; + if (!_reallocarray) { + _reallocarray = (reallocarray_p)get_system_function_handle("reallocarray", (void*)reallocarray); + } + return apex_reallocarray_wrapper(_reallocarray, ptr, nmemb, size); +} +#endif + +#if defined(reallocf) +void* reallocf (void* ptr, size_t size) { + static reallocf_p _reallocf = NULL; + if (!_reallocf) { + _reallocf = (reallocf_p)get_system_function_handle("reallocf", (void*)reallocf); + } + return apex_reallocf_wrapper(_reallocf, ptr, size); +} +#endif + +#if defined(valloc) +void* valloc (size_t size) { + static valloc_p _valloc = NULL; + if (!_valloc) { + _valloc = (valloc_p)get_system_function_handle("valloc", (void*)valloc); + } + return apex_valloc_wrapper(_valloc, size); +} +#endif + +#if defined(malloc_usable_size) +size_t malloc_usable_size (void* ptr) { + static malloc_usable_size_p _malloc_usable_size = NULL; + if (!_malloc_usable_size) { + _malloc_usable_size = (malloc_usable_size_p)get_system_function_handle("malloc_usable_size", (void*)malloc_usable_size); + } + return apex_malloc_usable_size_wrapper(_malloc_usable_size, ptr); +} +#endif + +void free (void* ptr) { + static free_p _free = NULL; + if (!_free) { + _free = (free_p)get_system_function_handle("free", (void*)free); + } + return apex_free_wrapper(_free, ptr); +} + +#else // Wrap via the the link line. + +void* __real_malloc(size_t); +void* __wrap_malloc(size_t size) { + return apex_malloc_wrapper(__real_malloc, size); +} + +void* __real_calloc(size_t, size_t); +void* __wrap_calloc(size_t nmemb, size_t size) { + return apex_calloc_wrapper(__real_calloc, nmemb, size); +} + +#if defined(memalign) +void* __real_memalign(size_t, size_t); +void* __wrap_memalign(size_t alignment, size_t size) { + return apex_memalign_wrapper(__real_memalign, alignment, size); +} +#endif + +void* __real_realloc(void*, size_t); +void* __wrap_realloc(void* ptr, size_t size) { + return apex_realloc_wrapper(__real_realloc, ptr, size); +} + +#if defined(reallocarray) +void* __real_reallocarray(void*, size_t, size_t); +void* __wrap_reallocarray(void* ptr, size_t nmemb, size_t size) { + return apex_reallocarray_wrapper(__real_reallocarray, ptr, nmemb, size); +} +#endif + +#if defined(reallocf) +void* __real_reallocf(void*, size_t); +void* __wrap_reallocf(void* ptr, size_t size) { + return apex_reallocf_wrapper(__real_reallocf, ptr, size); +} +#endif + +#if defined(valloc) +void* __real_valloc(size_t); +void* __wrap_valloc(size_t size) { + return apex_valloc_wrapper(__vallocllocf, size); +} +#endif + +#if defined(malloc_usable_size) +size_t __real_malloc_usable_size(void*); +size_t __wrap_malloc_usable_size(void* ptr) { + return apex_malloc_usable_size_wrapper(__malloc_usable_size, ptr); +} +#endif + +void __real_free(void*); +void __wrap_free(void* ptr) { + return apex_free_wrapper(__real_free, ptr); +} + +#endif //APEX_PRELOAD_LIB diff --git a/src/wrappers/memory_wrapper.h b/src/wrappers/memory_wrapper.h new file mode 100644 index 00000000..294ce8dd --- /dev/null +++ b/src/wrappers/memory_wrapper.h @@ -0,0 +1,55 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +typedef void* (*malloc_p)(size_t); +typedef void* (*calloc_p)(size_t, size_t); +#if defined(memalign) +typedef void* (*memalign_p)(void*, size_t, size_t); +#endif +typedef void* (*realloc_p)(void*, size_t); +#if defined(reallocarray) +typedef void* (*reallocarray_p)(void*, size_t, size_t); +#endif +#if defined(reallocf) +typedef void* (*reallocf_p)(void*, size_t); +#endif +#if defined(valloc) +typedef void* (*valloc_p)(size_t); +#endif +#if defined(malloc_usable_size) +typedef size_t (*valloc_p)(void*); +#endif +typedef void (*free_p)(void*); + +#ifdef __cplusplus +extern "C" { +#endif + +void* apex_malloc_wrapper(malloc_p malloc_call, size_t size); +void* apex_calloc_wrapper(calloc_p calloc_call, size_t nmemb, size_t size); +#if defined(memalign) +void* apex_memalign_wrapper(memalign_p calloc_call, size_t align, size_t size); +#endif +void* apex_realloc_wrapper(realloc_p realloc_call, void* ptr, size_t size); +#if defined(reallocarray) +void* apex_reallocarray_wrapper(reallocarray_p reallocarray_call, void* ptr, size_t nmemb, size_t size); +#endif +#if defined(reallocf) +void* apex_reallocf_wrapper(reallocf_p reallocf_call, void* ptr, size_t size); +#endif +#if defined(valloc) +void* apex_valloc_wrapper(valloc_p valloc_call, size_t size); +#endif +#if defined(malloc_usable_size) +void* apex_malloc_usable_size_wrapper(malloc_usable_size_p malloc_usable_size_call, void* ptr); +#endif +void apex_free_wrapper(free_p free_call, void* ptr); + +#ifdef __cplusplus +} +#endif + +#define APEX_PRELOAD_LIB diff --git a/src/wrappers/memory_wrapper_internal.cpp b/src/wrappers/memory_wrapper_internal.cpp new file mode 100644 index 00000000..70badbd9 --- /dev/null +++ b/src/wrappers/memory_wrapper_internal.cpp @@ -0,0 +1,217 @@ +#include "apex_api.hpp" +#include "memory_wrapper.h" +#include + +/////////////////////////////////////////////////////////////////////////////// +// Below is the malloc wrapper +/////////////////////////////////////////////////////////////////////////////// + +bool& inWrapper() { + thread_local static bool _inWrapper = false; + return _inWrapper; +} + +extern "C" +void* apex_malloc_wrapper(malloc_p malloc_call, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return malloc_call(size); + printf("Here!\n"); + } else { + inWrapper() = true; + printf("Here!\n"); + + // do the allocation + auto retval = malloc_call(size); + apex::sample_value("malloc bytes", size, true); + + inWrapper() = false; + return retval; + } +} + +extern "C" +void* apex_calloc_wrapper(calloc_p calloc_call, size_t nmemb, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return calloc_call(nmemb, size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = calloc_call(nmemb, size); + + inWrapper() = false; + return retval; + } +} + +#if defined(memalign) +extern "C" +void* apex_memalign_wrapper(memalign_p memalign_call, size_t nmemb, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return memalign_call(nmemb, size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = memalign_call(nmemb, size); + + inWrapper() = false; + return retval; + } +} +#endif + +extern "C" +void* apex_realloc_wrapper(realloc_p realloc_call, void* ptr, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return realloc_call(ptr, size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = realloc_call(ptr, size); + + inWrapper() = false; + return retval; + } +} + +#if defined(reallocarray) +extern "C" +void* apex_reallocarray_wrapper(reallocarray_p reallocarray_call, void* ptr, size_t nmemb, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return reallocarray_call(ptr, nmemb, size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = reallocarray_call(ptr, nmemb, size); + + inWrapper() = false; + return retval; + } +} +#endif + +#if defined(reallocf) +extern "C" +void* apex_reallocf_wrapper(reallocf_p reallocf_call, void* ptr, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return reallocf_call(ptr, size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = reallocf_call(ptr, size); + + inWrapper() = false; + return retval; + } +} +#endif + +#if defined(valloc) +extern "C" +void* apex_valloc_wrapper(valloc_p valloc_call, size_t size) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return valloc_call(size); + } else { + inWrapper() = true; + + // do the allocation + auto retval = valloc_call(size); + + inWrapper() = false; + return retval; + } +} +#endif + +#if defined(malloc_usable_size) +extern "C" +size_t apex_malloc_usable_size_wrapper(malloc_usable_size_p malloc_usable_size_call, void* ptr) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return malloc_usable_size_call(ptr); + } else { + inWrapper() = true; + + // do the allocation + auto retval = malloc_usable_size_call(ptr); + + inWrapper() = false; + return retval; + } +} +#endif + +extern "C" +void apex_free_wrapper(free_p free_call, void* ptr) { + if(inWrapper()) { + // Another wrapper has already intercepted the call so just pass through + return free_call(ptr); + } else { + inWrapper() = true; + + // do the allocation + free_call(ptr); + + inWrapper() = false; + return; + } +} + +extern "C" void* apex_malloc(size_t size) { + return apex_malloc_wrapper(malloc, size); +} + +extern "C" void* apex_calloc(size_t nmemb, size_t size) { + return apex_calloc_wrapper(calloc, nmemb, size); +} + +#if defined(memalign) +extern "C" void* apex_memalign(size_t nmemb, size_t size) { + return apex_memalign_wrapper(memalign, nmemb, size); +} +#endif + +extern "C" void* apex_realloc(void* ptr, size_t size) { + return apex_realloc_wrapper(realloc, ptr, size); +} + +#if defined(reallocarray) +extern "C" void* apex_reallocarray(void* ptr, size_t nmemb, size_t size) { + return apex_reallocarray_wrapper(reallocarray, ptr, nmemb, size); +} +#endif + +#if defined(reallocf) +extern "C" void* apex_reallocf(void* ptr, size_t size) { + return apex_reallocf_wrapper(reallocf, ptr, size); +} +#endif + +#if defined(valloc) +extern "C" void* apex_valloc(size_t size) { + return apex_valloc_wrapper(valloc, size); +} +#endif + +#if defined(malloc_usable_size) +extern "C" void* apex_malloc_usable_size(void* ptr) { + return apex_malloc_usable_size_wrapper(malloc_usable_size, ptr); +} +#endif + +extern "C" void apex_free(void* ptr) { + return apex_free_wrapper(free, ptr); +} + +