151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev 1851c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1 1951c0b2f7Stbbdev 2051c0b2f7Stbbdev #if _USRDLL 2151c0b2f7Stbbdev #include "common/utils_assert.h" 2251c0b2f7Stbbdev #include <stdlib.h> // for NULL 2351c0b2f7Stbbdev 2451c0b2f7Stbbdev const char *globalCallMsg = "A TBB allocator function call is resolved into wrong implementation."; 2551c0b2f7Stbbdev 2651c0b2f7Stbbdev #if _WIN32||_WIN64 2751c0b2f7Stbbdev // must be defined in DLL for linker to not drop the dependency on the DLL. 2851c0b2f7Stbbdev extern "C" { 2951c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_malloc(size_t); 3051c0b2f7Stbbdev extern __declspec(dllexport) void scalable_free (void *); 3151c0b2f7Stbbdev extern __declspec(dllexport) void safer_scalable_free (void *, void (*)(void*)); 3251c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_realloc(void *, size_t); 3351c0b2f7Stbbdev extern __declspec(dllexport) void *safer_scalable_realloc(void *, size_t, void *); 3451c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_calloc(size_t, size_t); 3551c0b2f7Stbbdev extern __declspec(dllexport) int scalable_posix_memalign(void **, size_t, size_t); 3651c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_aligned_malloc(size_t, size_t); 3751c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_aligned_realloc(void *, size_t, size_t); 3851c0b2f7Stbbdev extern __declspec(dllexport) void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *); 3951c0b2f7Stbbdev extern __declspec(dllexport) void scalable_aligned_free(void *); 4051c0b2f7Stbbdev extern __declspec(dllexport) size_t scalable_msize(void *); 4151c0b2f7Stbbdev extern __declspec(dllexport) size_t safer_scalable_msize (void *, size_t (*)(void*)); 42*a080baf9SAlex extern __declspec(dllexport) int anchor(); 4351c0b2f7Stbbdev } 4451c0b2f7Stbbdev #endif 4551c0b2f7Stbbdev 46*a080baf9SAlex extern "C" int anchor() { 47*a080baf9SAlex return 42; 48*a080baf9SAlex } 49*a080baf9SAlex 5051c0b2f7Stbbdev // Those functions must not be called instead of presented in dynamic library. 5151c0b2f7Stbbdev extern "C" void *scalable_malloc(size_t) 5251c0b2f7Stbbdev { 5351c0b2f7Stbbdev ASSERT(0, globalCallMsg); 5451c0b2f7Stbbdev return NULL; 5551c0b2f7Stbbdev } 5651c0b2f7Stbbdev extern "C" void scalable_free (void *) 5751c0b2f7Stbbdev { 5851c0b2f7Stbbdev ASSERT(0, globalCallMsg); 5951c0b2f7Stbbdev } 6051c0b2f7Stbbdev extern "C" void safer_scalable_free (void *, void (*)(void*)) 6151c0b2f7Stbbdev { 6251c0b2f7Stbbdev ASSERT(0, globalCallMsg); 6351c0b2f7Stbbdev } 6451c0b2f7Stbbdev extern "C" void *scalable_realloc(void *, size_t) 6551c0b2f7Stbbdev { 6651c0b2f7Stbbdev ASSERT(0, globalCallMsg); 6751c0b2f7Stbbdev return NULL; 6851c0b2f7Stbbdev } 6951c0b2f7Stbbdev extern "C" void *safer_scalable_realloc(void *, size_t, void *) 7051c0b2f7Stbbdev { 7151c0b2f7Stbbdev ASSERT(0, globalCallMsg); 7251c0b2f7Stbbdev return NULL; 7351c0b2f7Stbbdev } 7451c0b2f7Stbbdev extern "C" void *scalable_calloc(size_t, size_t) 7551c0b2f7Stbbdev { 7651c0b2f7Stbbdev ASSERT(0, globalCallMsg); 7751c0b2f7Stbbdev return NULL; 7851c0b2f7Stbbdev } 7951c0b2f7Stbbdev extern "C" int scalable_posix_memalign(void **, size_t, size_t) 8051c0b2f7Stbbdev { 8151c0b2f7Stbbdev ASSERT(0, globalCallMsg); 8251c0b2f7Stbbdev return 0; 8351c0b2f7Stbbdev } 8451c0b2f7Stbbdev extern "C" void *scalable_aligned_malloc(size_t, size_t) 8551c0b2f7Stbbdev { 8651c0b2f7Stbbdev ASSERT(0, globalCallMsg); 8751c0b2f7Stbbdev return NULL; 8851c0b2f7Stbbdev } 8951c0b2f7Stbbdev extern "C" void *scalable_aligned_realloc(void *, size_t, size_t) 9051c0b2f7Stbbdev { 9151c0b2f7Stbbdev ASSERT(0, globalCallMsg); 9251c0b2f7Stbbdev return NULL; 9351c0b2f7Stbbdev } 9451c0b2f7Stbbdev extern "C" void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *) 9551c0b2f7Stbbdev { 9651c0b2f7Stbbdev ASSERT(0, globalCallMsg); 9751c0b2f7Stbbdev return NULL; 9851c0b2f7Stbbdev } 9951c0b2f7Stbbdev extern "C" void scalable_aligned_free(void *) 10051c0b2f7Stbbdev { 10151c0b2f7Stbbdev ASSERT(0, globalCallMsg); 10251c0b2f7Stbbdev } 10351c0b2f7Stbbdev extern "C" size_t scalable_msize(void *) 10451c0b2f7Stbbdev { 10551c0b2f7Stbbdev ASSERT(0, globalCallMsg); 10651c0b2f7Stbbdev return 0; 10751c0b2f7Stbbdev } 10851c0b2f7Stbbdev extern "C" size_t safer_scalable_msize (void *, size_t (*)(void*)) 10951c0b2f7Stbbdev { 11051c0b2f7Stbbdev ASSERT(0, globalCallMsg); 11151c0b2f7Stbbdev return 0; 11251c0b2f7Stbbdev } 11351c0b2f7Stbbdev 11451c0b2f7Stbbdev int main() {} 11551c0b2f7Stbbdev 11651c0b2f7Stbbdev #else // _USRDLL 11751c0b2f7Stbbdev 118*a080baf9SAlex #include "common/config.h" 11951c0b2f7Stbbdev // harness_defs.h must be included before tbb_stddef.h to overcome exception-dependent 12051c0b2f7Stbbdev // system headers that come from tbb_stddef.h 121*a080baf9SAlex #if __TBB_WIN8UI_SUPPORT || __TBB_MIC_OFFLOAD || (__GNUC__ && __GNUC__ < 10 && __TBB_USE_SANITIZERS) 12251c0b2f7Stbbdev // The test does not work if dynamic load is unavailable. 12351c0b2f7Stbbdev // For MIC offload, it fails because liboffload brings libiomp which observes and uses the fake scalable_* calls. 124*a080baf9SAlex // For sanitizers, it fails because RUNPATH is lost: https://github.com/google/sanitizers/issues/1219 125*a080baf9SAlex #else 12651c0b2f7Stbbdev #include "common/test.h" 12751c0b2f7Stbbdev #include "common/memory_usage.h" 12851c0b2f7Stbbdev #include "common/utils_dynamic_libs.h" 12951c0b2f7Stbbdev #include "common/utils_assert.h" 13051c0b2f7Stbbdev #include "common/utils_report.h" 13151c0b2f7Stbbdev #include <cstring> // memset 13251c0b2f7Stbbdev 13351c0b2f7Stbbdev extern "C" { 13451c0b2f7Stbbdev #if _WIN32||_WIN64 13551c0b2f7Stbbdev extern __declspec(dllimport) 13651c0b2f7Stbbdev #endif 13751c0b2f7Stbbdev void *scalable_malloc(size_t); 138*a080baf9SAlex 139*a080baf9SAlex #if _WIN32||_WIN64 140*a080baf9SAlex extern __declspec(dllimport) 141*a080baf9SAlex #endif 142*a080baf9SAlex int anchor(); 14351c0b2f7Stbbdev } 14451c0b2f7Stbbdev 14551c0b2f7Stbbdev struct Run { 14651c0b2f7Stbbdev void operator()( std::size_t /*id*/ ) const { 14751c0b2f7Stbbdev 14851c0b2f7Stbbdev void* (*malloc_ptr)(std::size_t); 14951c0b2f7Stbbdev void (*free_ptr)(void*); 15051c0b2f7Stbbdev 15151c0b2f7Stbbdev void* (*aligned_malloc_ptr)(size_t size, size_t alignment); 15251c0b2f7Stbbdev void (*aligned_free_ptr)(void*); 15351c0b2f7Stbbdev 15451c0b2f7Stbbdev const char* actual_name; 15551c0b2f7Stbbdev utils::LIBRARY_HANDLE lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME1); 15651c0b2f7Stbbdev if (!lib) lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME2); 15751c0b2f7Stbbdev if (!lib) { 15851c0b2f7Stbbdev REPORT("Can't load " MALLOCLIB_NAME1 " or " MALLOCLIB_NAME2 "\n"); 15951c0b2f7Stbbdev exit(1); 16051c0b2f7Stbbdev } 16151c0b2f7Stbbdev utils::GetAddress(lib, "scalable_malloc", malloc_ptr); 16251c0b2f7Stbbdev utils::GetAddress(lib, "scalable_free", free_ptr); 16351c0b2f7Stbbdev utils::GetAddress(lib, "scalable_aligned_malloc", aligned_malloc_ptr); 16451c0b2f7Stbbdev utils::GetAddress(lib, "scalable_aligned_free", aligned_free_ptr); 16551c0b2f7Stbbdev 16651c0b2f7Stbbdev for (size_t sz = 1024; sz <= 10*1024 ; sz*=10) { 16751c0b2f7Stbbdev void *p1 = aligned_malloc_ptr(sz, 16); 16851c0b2f7Stbbdev std::memset(p1, 0, sz); 16951c0b2f7Stbbdev aligned_free_ptr(p1); 17051c0b2f7Stbbdev } 17151c0b2f7Stbbdev 17251c0b2f7Stbbdev void *p = malloc_ptr(100); 17351c0b2f7Stbbdev std::memset(p, 1, 100); 17451c0b2f7Stbbdev free_ptr(p); 17551c0b2f7Stbbdev 17651c0b2f7Stbbdev utils::CloseLibrary(lib); 17751c0b2f7Stbbdev #if _WIN32 || _WIN64 17851c0b2f7Stbbdev ASSERT(GetModuleHandle(actual_name), 17951c0b2f7Stbbdev "allocator library must not be unloaded"); 18051c0b2f7Stbbdev #else 18151c0b2f7Stbbdev ASSERT(dlsym(RTLD_DEFAULT, "scalable_malloc"), 18251c0b2f7Stbbdev "allocator library must not be unloaded"); 18351c0b2f7Stbbdev #endif 18451c0b2f7Stbbdev } 18551c0b2f7Stbbdev }; 18651c0b2f7Stbbdev 18751c0b2f7Stbbdev //! \brief \ref error_guessing 18851c0b2f7Stbbdev TEST_CASE("test unload lib") { 189*a080baf9SAlex CHECK(anchor() == 42); 19051c0b2f7Stbbdev 19151c0b2f7Stbbdev // warm-up run 19251c0b2f7Stbbdev utils::NativeParallelFor( 1, Run() ); 19351c0b2f7Stbbdev 194*a080baf9SAlex // It seems Thread Sanitizer remembers some history information about destroyed threads, 195*a080baf9SAlex // so memory consumption cannot be stabilized 196*a080baf9SAlex std::ptrdiff_t memory_leak = 0; 19751c0b2f7Stbbdev { 19851c0b2f7Stbbdev /* 1st call to GetMemoryUsage() allocate some memory, 19951c0b2f7Stbbdev but it seems memory consumption stabilized after this. 20051c0b2f7Stbbdev */ 20151c0b2f7Stbbdev utils::GetMemoryUsage(); 20251c0b2f7Stbbdev std::size_t memory_in_use = utils::GetMemoryUsage(); 20351c0b2f7Stbbdev std::size_t memory_check = utils::GetMemoryUsage(); 20451c0b2f7Stbbdev REQUIRE_MESSAGE(memory_in_use == memory_check, 20551c0b2f7Stbbdev "Memory consumption should not increase after 1st GetMemoryUsage() call"); 20651c0b2f7Stbbdev } 207*a080baf9SAlex 20851c0b2f7Stbbdev { 20951c0b2f7Stbbdev // expect that memory consumption stabilized after several runs 21049e08aacStbbdev for (;;) { 21151c0b2f7Stbbdev std::size_t memory_in_use = utils::GetMemoryUsage(); 21251c0b2f7Stbbdev for (int j=0; j<10; j++) 21351c0b2f7Stbbdev utils::NativeParallelFor( 1, Run() ); 21451c0b2f7Stbbdev memory_leak = utils::GetMemoryUsage() - memory_in_use; 21549e08aacStbbdev if (memory_leak == 0) 21649e08aacStbbdev return; 21751c0b2f7Stbbdev } 21851c0b2f7Stbbdev } 21951c0b2f7Stbbdev } 22051c0b2f7Stbbdev 221*a080baf9SAlex #endif /* Unsupported configurations */ 22251c0b2f7Stbbdev 22351c0b2f7Stbbdev #endif // _USRDLL 224