1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev 
18*51c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev #if _USRDLL
21*51c0b2f7Stbbdev #include "common/utils_assert.h"
22*51c0b2f7Stbbdev #include <stdlib.h> // for NULL
23*51c0b2f7Stbbdev 
24*51c0b2f7Stbbdev const char *globalCallMsg = "A TBB allocator function call is resolved into wrong implementation.";
25*51c0b2f7Stbbdev 
26*51c0b2f7Stbbdev #if _WIN32||_WIN64
27*51c0b2f7Stbbdev // must be defined in DLL for linker to not drop the dependency on the DLL.
28*51c0b2f7Stbbdev extern "C" {
29*51c0b2f7Stbbdev     extern __declspec(dllexport) void *scalable_malloc(size_t);
30*51c0b2f7Stbbdev     extern __declspec(dllexport) void scalable_free (void *);
31*51c0b2f7Stbbdev     extern __declspec(dllexport) void safer_scalable_free (void *, void (*)(void*));
32*51c0b2f7Stbbdev     extern __declspec(dllexport) void *scalable_realloc(void *, size_t);
33*51c0b2f7Stbbdev     extern __declspec(dllexport) void *safer_scalable_realloc(void *, size_t, void *);
34*51c0b2f7Stbbdev     extern __declspec(dllexport) void *scalable_calloc(size_t, size_t);
35*51c0b2f7Stbbdev     extern __declspec(dllexport) int scalable_posix_memalign(void **, size_t, size_t);
36*51c0b2f7Stbbdev     extern __declspec(dllexport) void *scalable_aligned_malloc(size_t, size_t);
37*51c0b2f7Stbbdev     extern __declspec(dllexport) void *scalable_aligned_realloc(void *, size_t, size_t);
38*51c0b2f7Stbbdev     extern __declspec(dllexport) void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *);
39*51c0b2f7Stbbdev     extern __declspec(dllexport) void scalable_aligned_free(void *);
40*51c0b2f7Stbbdev     extern __declspec(dllexport) size_t scalable_msize(void *);
41*51c0b2f7Stbbdev     extern __declspec(dllexport) size_t safer_scalable_msize (void *, size_t (*)(void*));
42*51c0b2f7Stbbdev }
43*51c0b2f7Stbbdev #endif
44*51c0b2f7Stbbdev 
45*51c0b2f7Stbbdev // Those functions must not be called instead of presented in dynamic library.
46*51c0b2f7Stbbdev extern "C" void *scalable_malloc(size_t)
47*51c0b2f7Stbbdev {
48*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
49*51c0b2f7Stbbdev     return NULL;
50*51c0b2f7Stbbdev }
51*51c0b2f7Stbbdev extern "C" void scalable_free (void *)
52*51c0b2f7Stbbdev {
53*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
54*51c0b2f7Stbbdev }
55*51c0b2f7Stbbdev extern "C" void safer_scalable_free (void *, void (*)(void*))
56*51c0b2f7Stbbdev {
57*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
58*51c0b2f7Stbbdev }
59*51c0b2f7Stbbdev extern "C" void *scalable_realloc(void *, size_t)
60*51c0b2f7Stbbdev {
61*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
62*51c0b2f7Stbbdev     return NULL;
63*51c0b2f7Stbbdev }
64*51c0b2f7Stbbdev extern "C" void *safer_scalable_realloc(void *, size_t, void *)
65*51c0b2f7Stbbdev {
66*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
67*51c0b2f7Stbbdev     return NULL;
68*51c0b2f7Stbbdev }
69*51c0b2f7Stbbdev extern "C" void *scalable_calloc(size_t, size_t)
70*51c0b2f7Stbbdev {
71*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
72*51c0b2f7Stbbdev     return NULL;
73*51c0b2f7Stbbdev }
74*51c0b2f7Stbbdev extern "C" int scalable_posix_memalign(void **, size_t, size_t)
75*51c0b2f7Stbbdev {
76*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
77*51c0b2f7Stbbdev     return 0;
78*51c0b2f7Stbbdev }
79*51c0b2f7Stbbdev extern "C" void *scalable_aligned_malloc(size_t, size_t)
80*51c0b2f7Stbbdev {
81*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
82*51c0b2f7Stbbdev     return NULL;
83*51c0b2f7Stbbdev }
84*51c0b2f7Stbbdev extern "C" void *scalable_aligned_realloc(void *, size_t, size_t)
85*51c0b2f7Stbbdev {
86*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
87*51c0b2f7Stbbdev     return NULL;
88*51c0b2f7Stbbdev }
89*51c0b2f7Stbbdev extern "C" void *safer_scalable_aligned_realloc(void *, size_t, size_t, void *)
90*51c0b2f7Stbbdev {
91*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
92*51c0b2f7Stbbdev     return NULL;
93*51c0b2f7Stbbdev }
94*51c0b2f7Stbbdev extern "C" void scalable_aligned_free(void *)
95*51c0b2f7Stbbdev {
96*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
97*51c0b2f7Stbbdev }
98*51c0b2f7Stbbdev extern "C" size_t scalable_msize(void *)
99*51c0b2f7Stbbdev {
100*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
101*51c0b2f7Stbbdev     return 0;
102*51c0b2f7Stbbdev }
103*51c0b2f7Stbbdev extern "C" size_t safer_scalable_msize (void *, size_t (*)(void*))
104*51c0b2f7Stbbdev {
105*51c0b2f7Stbbdev     ASSERT(0, globalCallMsg);
106*51c0b2f7Stbbdev     return 0;
107*51c0b2f7Stbbdev }
108*51c0b2f7Stbbdev 
109*51c0b2f7Stbbdev int main() {}
110*51c0b2f7Stbbdev 
111*51c0b2f7Stbbdev #else  // _USRDLL
112*51c0b2f7Stbbdev 
113*51c0b2f7Stbbdev // harness_defs.h must be included before tbb_stddef.h to overcome exception-dependent
114*51c0b2f7Stbbdev // system headers that come from tbb_stddef.h
115*51c0b2f7Stbbdev #if __TBB_WIN8UI_SUPPORT || __TBB_MIC_OFFLOAD
116*51c0b2f7Stbbdev // The test does not work if dynamic load is unavailable.
117*51c0b2f7Stbbdev // For MIC offload, it fails because liboffload brings libiomp which observes and uses the fake scalable_* calls.
118*51c0b2f7Stbbdev #else
119*51c0b2f7Stbbdev #include "common/test.h"
120*51c0b2f7Stbbdev #include "common/memory_usage.h"
121*51c0b2f7Stbbdev #include "common/utils_dynamic_libs.h"
122*51c0b2f7Stbbdev #include "common/utils_assert.h"
123*51c0b2f7Stbbdev #include "common/utils_report.h"
124*51c0b2f7Stbbdev #include <cstring> // memset
125*51c0b2f7Stbbdev 
126*51c0b2f7Stbbdev extern "C" {
127*51c0b2f7Stbbdev #if _WIN32||_WIN64
128*51c0b2f7Stbbdev     extern __declspec(dllimport)
129*51c0b2f7Stbbdev #endif
130*51c0b2f7Stbbdev     void *scalable_malloc(size_t);
131*51c0b2f7Stbbdev }
132*51c0b2f7Stbbdev 
133*51c0b2f7Stbbdev struct Run {
134*51c0b2f7Stbbdev     void operator()( std::size_t /*id*/ ) const {
135*51c0b2f7Stbbdev 
136*51c0b2f7Stbbdev         void* (*malloc_ptr)(std::size_t);
137*51c0b2f7Stbbdev         void (*free_ptr)(void*);
138*51c0b2f7Stbbdev 
139*51c0b2f7Stbbdev         void* (*aligned_malloc_ptr)(size_t size, size_t alignment);
140*51c0b2f7Stbbdev         void  (*aligned_free_ptr)(void*);
141*51c0b2f7Stbbdev 
142*51c0b2f7Stbbdev         const char* actual_name;
143*51c0b2f7Stbbdev         utils::LIBRARY_HANDLE lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME1);
144*51c0b2f7Stbbdev         if (!lib)      lib = utils::OpenLibrary(actual_name = MALLOCLIB_NAME2);
145*51c0b2f7Stbbdev         if (!lib) {
146*51c0b2f7Stbbdev             REPORT("Can't load " MALLOCLIB_NAME1 " or " MALLOCLIB_NAME2 "\n");
147*51c0b2f7Stbbdev             exit(1);
148*51c0b2f7Stbbdev         }
149*51c0b2f7Stbbdev         utils::GetAddress(lib, "scalable_malloc", malloc_ptr);
150*51c0b2f7Stbbdev         utils::GetAddress(lib, "scalable_free", free_ptr);
151*51c0b2f7Stbbdev         utils::GetAddress(lib, "scalable_aligned_malloc", aligned_malloc_ptr);
152*51c0b2f7Stbbdev         utils::GetAddress(lib, "scalable_aligned_free", aligned_free_ptr);
153*51c0b2f7Stbbdev 
154*51c0b2f7Stbbdev         for (size_t sz = 1024; sz <= 10*1024 ; sz*=10) {
155*51c0b2f7Stbbdev             void *p1 = aligned_malloc_ptr(sz, 16);
156*51c0b2f7Stbbdev             std::memset(p1, 0, sz);
157*51c0b2f7Stbbdev             aligned_free_ptr(p1);
158*51c0b2f7Stbbdev         }
159*51c0b2f7Stbbdev 
160*51c0b2f7Stbbdev         void *p = malloc_ptr(100);
161*51c0b2f7Stbbdev         std::memset(p, 1, 100);
162*51c0b2f7Stbbdev         free_ptr(p);
163*51c0b2f7Stbbdev 
164*51c0b2f7Stbbdev         utils::CloseLibrary(lib);
165*51c0b2f7Stbbdev #if _WIN32 || _WIN64
166*51c0b2f7Stbbdev         ASSERT(GetModuleHandle(actual_name),
167*51c0b2f7Stbbdev                "allocator library must not be unloaded");
168*51c0b2f7Stbbdev #else
169*51c0b2f7Stbbdev         ASSERT(dlsym(RTLD_DEFAULT, "scalable_malloc"),
170*51c0b2f7Stbbdev                "allocator library must not be unloaded");
171*51c0b2f7Stbbdev #endif
172*51c0b2f7Stbbdev     }
173*51c0b2f7Stbbdev };
174*51c0b2f7Stbbdev 
175*51c0b2f7Stbbdev //! \brief \ref error_guessing
176*51c0b2f7Stbbdev TEST_CASE("test unload lib") {
177*51c0b2f7Stbbdev     int i;
178*51c0b2f7Stbbdev     std::ptrdiff_t memory_leak = 0;
179*51c0b2f7Stbbdev 
180*51c0b2f7Stbbdev     // warm-up run
181*51c0b2f7Stbbdev     utils::NativeParallelFor( 1, Run() );
182*51c0b2f7Stbbdev 
183*51c0b2f7Stbbdev     {
184*51c0b2f7Stbbdev         /* 1st call to GetMemoryUsage() allocate some memory,
185*51c0b2f7Stbbdev            but it seems memory consumption stabilized after this.
186*51c0b2f7Stbbdev         */
187*51c0b2f7Stbbdev         utils::GetMemoryUsage();
188*51c0b2f7Stbbdev         std::size_t memory_in_use = utils::GetMemoryUsage();
189*51c0b2f7Stbbdev         std::size_t memory_check = utils::GetMemoryUsage();
190*51c0b2f7Stbbdev         REQUIRE_MESSAGE(memory_in_use == memory_check,
191*51c0b2f7Stbbdev             "Memory consumption should not increase after 1st GetMemoryUsage() call");
192*51c0b2f7Stbbdev     }
193*51c0b2f7Stbbdev     {
194*51c0b2f7Stbbdev         // expect that memory consumption stabilized after several runs
195*51c0b2f7Stbbdev         for (i=0; i<3; i++) {
196*51c0b2f7Stbbdev             std::size_t memory_in_use = utils::GetMemoryUsage();
197*51c0b2f7Stbbdev             for (int j=0; j<10; j++)
198*51c0b2f7Stbbdev                 utils::NativeParallelFor( 1, Run() );
199*51c0b2f7Stbbdev             memory_leak = utils::GetMemoryUsage() - memory_in_use;
200*51c0b2f7Stbbdev             if (memory_leak == 0)  // possibly too strong?
201*51c0b2f7Stbbdev                 break;
202*51c0b2f7Stbbdev         }
203*51c0b2f7Stbbdev     }
204*51c0b2f7Stbbdev     if(3==i) {
205*51c0b2f7Stbbdev         // not stabilized, could be leak
206*51c0b2f7Stbbdev         REPORT( "Error: memory leak of up to %ld bytes\n", static_cast<long>(memory_leak));
207*51c0b2f7Stbbdev         exit(1);
208*51c0b2f7Stbbdev     }
209*51c0b2f7Stbbdev 
210*51c0b2f7Stbbdev }
211*51c0b2f7Stbbdev 
212*51c0b2f7Stbbdev #endif /* __TBB_WIN8UI_SUPPORT */
213*51c0b2f7Stbbdev 
214*51c0b2f7Stbbdev #endif // _USRDLL
215