151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov Copyright (c) 2005-2022 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
2351c0b2f7Stbbdev const char *globalCallMsg = "A TBB allocator function call is resolved into wrong implementation.";
2451c0b2f7Stbbdev
2551c0b2f7Stbbdev #if _WIN32||_WIN64
2651c0b2f7Stbbdev // must be defined in DLL for linker to not drop the dependency on the DLL.
2751c0b2f7Stbbdev extern "C" {
2851c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_malloc(size_t);
2951c0b2f7Stbbdev extern __declspec(dllexport) void scalable_free (void *);
3051c0b2f7Stbbdev extern __declspec(dllexport) void safer_scalable_free (void *, void (*)(void*));
3151c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_realloc(void *, size_t);
3251c0b2f7Stbbdev extern __declspec(dllexport) void *safer_scalable_realloc(void *, size_t, void *);
3351c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_calloc(size_t, size_t);
3451c0b2f7Stbbdev extern __declspec(dllexport) int scalable_posix_memalign(void **, size_t, size_t);
3551c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_aligned_malloc(size_t, size_t);
3651c0b2f7Stbbdev extern __declspec(dllexport) void *scalable_aligned_realloc(void *, size_t, size_t);
3751c0b2f7Stbbdev extern __declspec(dllexport) void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *);
3851c0b2f7Stbbdev extern __declspec(dllexport) void scalable_aligned_free(void *);
3951c0b2f7Stbbdev extern __declspec(dllexport) size_t scalable_msize(void *);
4051c0b2f7Stbbdev extern __declspec(dllexport) size_t safer_scalable_msize (void *, size_t (*)(void*));
41a080baf9SAlex extern __declspec(dllexport) int anchor();
4251c0b2f7Stbbdev }
4351c0b2f7Stbbdev #endif
4451c0b2f7Stbbdev
anchor()45a080baf9SAlex extern "C" int anchor() {
46a080baf9SAlex return 42;
47a080baf9SAlex }
48a080baf9SAlex
4951c0b2f7Stbbdev // Those functions must not be called instead of presented in dynamic library.
scalable_malloc(size_t)5051c0b2f7Stbbdev extern "C" void *scalable_malloc(size_t)
5151c0b2f7Stbbdev {
5251c0b2f7Stbbdev ASSERT(0, globalCallMsg);
5357f524caSIlya Isaev return nullptr;
5451c0b2f7Stbbdev }
scalable_free(void *)5551c0b2f7Stbbdev extern "C" void scalable_free (void *)
5651c0b2f7Stbbdev {
5751c0b2f7Stbbdev ASSERT(0, globalCallMsg);
5851c0b2f7Stbbdev }
safer_scalable_free(void *,void (*)(void *))5951c0b2f7Stbbdev extern "C" void safer_scalable_free (void *, void (*)(void*))
6051c0b2f7Stbbdev {
6151c0b2f7Stbbdev ASSERT(0, globalCallMsg);
6251c0b2f7Stbbdev }
scalable_realloc(void *,size_t)6351c0b2f7Stbbdev extern "C" void *scalable_realloc(void *, size_t)
6451c0b2f7Stbbdev {
6551c0b2f7Stbbdev ASSERT(0, globalCallMsg);
6657f524caSIlya Isaev return nullptr;
6751c0b2f7Stbbdev }
safer_scalable_realloc(void *,size_t,void *)6851c0b2f7Stbbdev extern "C" void *safer_scalable_realloc(void *, size_t, void *)
6951c0b2f7Stbbdev {
7051c0b2f7Stbbdev ASSERT(0, globalCallMsg);
7157f524caSIlya Isaev return nullptr;
7251c0b2f7Stbbdev }
scalable_calloc(size_t,size_t)7351c0b2f7Stbbdev extern "C" void *scalable_calloc(size_t, size_t)
7451c0b2f7Stbbdev {
7551c0b2f7Stbbdev ASSERT(0, globalCallMsg);
7657f524caSIlya Isaev return nullptr;
7751c0b2f7Stbbdev }
scalable_posix_memalign(void **,size_t,size_t)7851c0b2f7Stbbdev extern "C" int scalable_posix_memalign(void **, size_t, size_t)
7951c0b2f7Stbbdev {
8051c0b2f7Stbbdev ASSERT(0, globalCallMsg);
8151c0b2f7Stbbdev return 0;
8251c0b2f7Stbbdev }
scalable_aligned_malloc(size_t,size_t)8351c0b2f7Stbbdev extern "C" void *scalable_aligned_malloc(size_t, size_t)
8451c0b2f7Stbbdev {
8551c0b2f7Stbbdev ASSERT(0, globalCallMsg);
8657f524caSIlya Isaev return nullptr;
8751c0b2f7Stbbdev }
scalable_aligned_realloc(void *,size_t,size_t)8851c0b2f7Stbbdev extern "C" void *scalable_aligned_realloc(void *, size_t, size_t)
8951c0b2f7Stbbdev {
9051c0b2f7Stbbdev ASSERT(0, globalCallMsg);
9157f524caSIlya Isaev return nullptr;
9251c0b2f7Stbbdev }
safer_scalable_aligned_realloc(void *,size_t,size_t,void *)9351c0b2f7Stbbdev extern "C" void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *)
9451c0b2f7Stbbdev {
9551c0b2f7Stbbdev ASSERT(0, globalCallMsg);
9657f524caSIlya Isaev return nullptr;
9751c0b2f7Stbbdev }
scalable_aligned_free(void *)9851c0b2f7Stbbdev extern "C" void scalable_aligned_free(void *)
9951c0b2f7Stbbdev {
10051c0b2f7Stbbdev ASSERT(0, globalCallMsg);
10151c0b2f7Stbbdev }
scalable_msize(void *)10251c0b2f7Stbbdev extern "C" size_t scalable_msize(void *)
10351c0b2f7Stbbdev {
10451c0b2f7Stbbdev ASSERT(0, globalCallMsg);
10551c0b2f7Stbbdev return 0;
10651c0b2f7Stbbdev }
safer_scalable_msize(void *,size_t (*)(void *))10751c0b2f7Stbbdev extern "C" size_t safer_scalable_msize (void *, size_t (*)(void*))
10851c0b2f7Stbbdev {
10951c0b2f7Stbbdev ASSERT(0, globalCallMsg);
11051c0b2f7Stbbdev return 0;
11151c0b2f7Stbbdev }
11251c0b2f7Stbbdev
main()11351c0b2f7Stbbdev int main() {}
11451c0b2f7Stbbdev
11551c0b2f7Stbbdev #else // _USRDLL
11651c0b2f7Stbbdev
117a080baf9SAlex #include "common/config.h"
11851c0b2f7Stbbdev // harness_defs.h must be included before tbb_stddef.h to overcome exception-dependent
11951c0b2f7Stbbdev // system headers that come from tbb_stddef.h
1207941f880SIlya Isaev #if __TBB_WIN8UI_SUPPORT || __TBB_MIC_OFFLOAD || (__GNUC__ && __GNUC__ < 10 && __TBB_USE_SANITIZERS) || __TBB_SOURCE_DIRECTLY_INCLUDED
12151c0b2f7Stbbdev // The test does not work if dynamic load is unavailable.
12251c0b2f7Stbbdev // For MIC offload, it fails because liboffload brings libiomp which observes and uses the fake scalable_* calls.
123a080baf9SAlex // For sanitizers, it fails because RUNPATH is lost: https://github.com/google/sanitizers/issues/1219
124a080baf9SAlex #else
12551c0b2f7Stbbdev #include "common/test.h"
12651c0b2f7Stbbdev #include "common/memory_usage.h"
12751c0b2f7Stbbdev #include "common/utils_dynamic_libs.h"
12851c0b2f7Stbbdev #include "common/utils_assert.h"
12951c0b2f7Stbbdev #include "common/utils_report.h"
13051c0b2f7Stbbdev #include <cstring> // memset
13151c0b2f7Stbbdev
13251c0b2f7Stbbdev extern "C" {
13351c0b2f7Stbbdev #if _WIN32||_WIN64
13451c0b2f7Stbbdev extern __declspec(dllimport)
13551c0b2f7Stbbdev #endif
13651c0b2f7Stbbdev void *scalable_malloc(size_t);
137a080baf9SAlex
138a080baf9SAlex #if _WIN32||_WIN64
139a080baf9SAlex extern __declspec(dllimport)
140a080baf9SAlex #endif
141a080baf9SAlex int anchor();
14251c0b2f7Stbbdev }
14351c0b2f7Stbbdev
14451c0b2f7Stbbdev struct Run {
operator ()Run14551c0b2f7Stbbdev void operator()( std::size_t /*id*/ ) const {
14651c0b2f7Stbbdev
14751c0b2f7Stbbdev void* (*malloc_ptr)(std::size_t);
14851c0b2f7Stbbdev void (*free_ptr)(void*);
14951c0b2f7Stbbdev
15051c0b2f7Stbbdev void* (*aligned_malloc_ptr)(size_t size, size_t alignment);
15151c0b2f7Stbbdev void (*aligned_free_ptr)(void*);
15251c0b2f7Stbbdev
15351c0b2f7Stbbdev const char* actual_name;
15451c0b2f7Stbbdev utils::LIBRARY_HANDLE lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME1);
15551c0b2f7Stbbdev if (!lib) lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME2);
15651c0b2f7Stbbdev if (!lib) {
15751c0b2f7Stbbdev REPORT("Can't load " MALLOCLIB_NAME1 " or " MALLOCLIB_NAME2 "\n");
15851c0b2f7Stbbdev exit(1);
15951c0b2f7Stbbdev }
16051c0b2f7Stbbdev utils::GetAddress(lib, "scalable_malloc", malloc_ptr);
16151c0b2f7Stbbdev utils::GetAddress(lib, "scalable_free", free_ptr);
16251c0b2f7Stbbdev utils::GetAddress(lib, "scalable_aligned_malloc", aligned_malloc_ptr);
16351c0b2f7Stbbdev utils::GetAddress(lib, "scalable_aligned_free", aligned_free_ptr);
16451c0b2f7Stbbdev
16551c0b2f7Stbbdev for (size_t sz = 1024; sz <= 10*1024 ; sz*=10) {
16651c0b2f7Stbbdev void *p1 = aligned_malloc_ptr(sz, 16);
16751c0b2f7Stbbdev std::memset(p1, 0, sz);
16851c0b2f7Stbbdev aligned_free_ptr(p1);
16951c0b2f7Stbbdev }
17051c0b2f7Stbbdev
17151c0b2f7Stbbdev void *p = malloc_ptr(100);
17251c0b2f7Stbbdev std::memset(p, 1, 100);
17351c0b2f7Stbbdev free_ptr(p);
17451c0b2f7Stbbdev
17551c0b2f7Stbbdev utils::CloseLibrary(lib);
17651c0b2f7Stbbdev #if _WIN32 || _WIN64
17751c0b2f7Stbbdev ASSERT(GetModuleHandle(actual_name),
17851c0b2f7Stbbdev "allocator library must not be unloaded");
17951c0b2f7Stbbdev #else
18051c0b2f7Stbbdev ASSERT(dlsym(RTLD_DEFAULT, "scalable_malloc"),
18151c0b2f7Stbbdev "allocator library must not be unloaded");
18251c0b2f7Stbbdev #endif
18351c0b2f7Stbbdev }
18451c0b2f7Stbbdev };
18551c0b2f7Stbbdev
18651c0b2f7Stbbdev //! \brief \ref error_guessing
18751c0b2f7Stbbdev TEST_CASE("test unload lib") {
188a080baf9SAlex CHECK(anchor() == 42);
18951c0b2f7Stbbdev
19051c0b2f7Stbbdev // warm-up run
19151c0b2f7Stbbdev utils::NativeParallelFor( 1, Run() );
19251c0b2f7Stbbdev
193a080baf9SAlex // It seems Thread Sanitizer remembers some history information about destroyed threads,
194a080baf9SAlex // so memory consumption cannot be stabilized
195a080baf9SAlex std::ptrdiff_t memory_leak = 0;
19651c0b2f7Stbbdev {
19751c0b2f7Stbbdev /* 1st call to GetMemoryUsage() allocate some memory,
19851c0b2f7Stbbdev but it seems memory consumption stabilized after this.
19951c0b2f7Stbbdev */
20051c0b2f7Stbbdev utils::GetMemoryUsage();
20151c0b2f7Stbbdev std::size_t memory_in_use = utils::GetMemoryUsage();
20251c0b2f7Stbbdev std::size_t memory_check = utils::GetMemoryUsage();
20351c0b2f7Stbbdev REQUIRE_MESSAGE(memory_in_use == memory_check,
20451c0b2f7Stbbdev "Memory consumption should not increase after 1st GetMemoryUsage() call");
20551c0b2f7Stbbdev }
206a080baf9SAlex
20751c0b2f7Stbbdev {
20851c0b2f7Stbbdev // expect that memory consumption stabilized after several runs
20949e08aacStbbdev for (;;) {
21051c0b2f7Stbbdev std::size_t memory_in_use = utils::GetMemoryUsage();
21151c0b2f7Stbbdev for (int j=0; j<10; j++)
21251c0b2f7Stbbdev utils::NativeParallelFor( 1, Run() );
21351c0b2f7Stbbdev memory_leak = utils::GetMemoryUsage() - memory_in_use;
21449e08aacStbbdev if (memory_leak == 0)
21549e08aacStbbdev return;
21651c0b2f7Stbbdev }
21751c0b2f7Stbbdev }
21851c0b2f7Stbbdev }
21951c0b2f7Stbbdev
220a080baf9SAlex #endif /* Unsupported configurations */
22151c0b2f7Stbbdev
22251c0b2f7Stbbdev #endif // _USRDLL
223