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 #define __TBB_NO_IMPLICIT_LINKAGE 1 18*51c0b2f7Stbbdev 19*51c0b2f7Stbbdev #include "common/test.h" 20*51c0b2f7Stbbdev #include "common/utils.h" 21*51c0b2f7Stbbdev #include "common/utils_report.h" 22*51c0b2f7Stbbdev #include "common/memory_usage.h" 23*51c0b2f7Stbbdev #include "tbb/detail/_utils.h" 24*51c0b2f7Stbbdev #include "tbb/scalable_allocator.h" 25*51c0b2f7Stbbdev #include "thread" 26*51c0b2f7Stbbdev #include <stdio.h> 27*51c0b2f7Stbbdev 28*51c0b2f7Stbbdev class minimalAllocFree { 29*51c0b2f7Stbbdev public: 30*51c0b2f7Stbbdev void operator()(int size) const { 31*51c0b2f7Stbbdev tbb::scalable_allocator<char> a; 32*51c0b2f7Stbbdev char* str = a.allocate( size ); 33*51c0b2f7Stbbdev a.deallocate( str, size ); 34*51c0b2f7Stbbdev } 35*51c0b2f7Stbbdev }; 36*51c0b2f7Stbbdev 37*51c0b2f7Stbbdev 38*51c0b2f7Stbbdev template<typename Body, typename Arg> 39*51c0b2f7Stbbdev void RunThread(const Body& body, const Arg& arg) { 40*51c0b2f7Stbbdev std::thread job(body, arg); 41*51c0b2f7Stbbdev job.join(); 42*51c0b2f7Stbbdev } 43*51c0b2f7Stbbdev 44*51c0b2f7Stbbdev /*--------------------------------------------------------------------*/ 45*51c0b2f7Stbbdev // The regression test against bug #1518 where thread bootstrap allocations "leaked" 46*51c0b2f7Stbbdev 47*51c0b2f7Stbbdev bool TestBootstrapLeak() { 48*51c0b2f7Stbbdev /* In the bug 1518, each thread leaked ~384 bytes. 49*51c0b2f7Stbbdev Initially, scalable allocator maps 1MB. Thus it is necessary to take out most of this space. 50*51c0b2f7Stbbdev 1MB is chunked into 16K blocks; of those, one block is for thread bootstrap, and one more 51*51c0b2f7Stbbdev should be reserved for the test body. 62 blocks left, each can serve 15 objects of 1024 bytes. 52*51c0b2f7Stbbdev */ 53*51c0b2f7Stbbdev const int alloc_size = 1024; 54*51c0b2f7Stbbdev const int take_out_count = 15*62; 55*51c0b2f7Stbbdev 56*51c0b2f7Stbbdev tbb::scalable_allocator<char> a; 57*51c0b2f7Stbbdev char* array[take_out_count]; 58*51c0b2f7Stbbdev for( int i=0; i<take_out_count; ++i ) 59*51c0b2f7Stbbdev array[i] = a.allocate( alloc_size ); 60*51c0b2f7Stbbdev 61*51c0b2f7Stbbdev RunThread( minimalAllocFree(), alloc_size ); // for threading library to take some memory 62*51c0b2f7Stbbdev size_t memory_in_use = utils::GetMemoryUsage(); 63*51c0b2f7Stbbdev // Wait for memory usage data to "stabilize". The test number (1000) has nothing underneath. 64*51c0b2f7Stbbdev for( int i=0; i<1000; i++) { 65*51c0b2f7Stbbdev if( utils::GetMemoryUsage()!=memory_in_use ) { 66*51c0b2f7Stbbdev memory_in_use = utils::GetMemoryUsage(); 67*51c0b2f7Stbbdev i = -1; 68*51c0b2f7Stbbdev } 69*51c0b2f7Stbbdev } 70*51c0b2f7Stbbdev 71*51c0b2f7Stbbdev ptrdiff_t memory_leak = 0; 72*51c0b2f7Stbbdev // Note that 16K bootstrap memory block is enough to serve 42 threads. 73*51c0b2f7Stbbdev const int num_thread_runs = 200; 74*51c0b2f7Stbbdev for (int run=0; run<3; run++) { 75*51c0b2f7Stbbdev memory_in_use = utils::GetMemoryUsage(); 76*51c0b2f7Stbbdev for( int i=0; i<num_thread_runs; ++i ) 77*51c0b2f7Stbbdev RunThread( minimalAllocFree(), alloc_size ); 78*51c0b2f7Stbbdev 79*51c0b2f7Stbbdev memory_leak = utils::GetMemoryUsage() - memory_in_use; 80*51c0b2f7Stbbdev if (!memory_leak) 81*51c0b2f7Stbbdev break; 82*51c0b2f7Stbbdev } 83*51c0b2f7Stbbdev if( memory_leak>0 ) { // possibly too strong? 84*51c0b2f7Stbbdev REPORT( "Error: memory leak of up to %ld bytes\n", static_cast<long>(memory_leak)); 85*51c0b2f7Stbbdev } 86*51c0b2f7Stbbdev 87*51c0b2f7Stbbdev for( int i=0; i<take_out_count; ++i ) 88*51c0b2f7Stbbdev a.deallocate( array[i], alloc_size ); 89*51c0b2f7Stbbdev 90*51c0b2f7Stbbdev return memory_leak<=0; 91*51c0b2f7Stbbdev } 92*51c0b2f7Stbbdev 93*51c0b2f7Stbbdev /*--------------------------------------------------------------------*/ 94*51c0b2f7Stbbdev // The regression test against a bug with incompatible semantics of msize and realloc 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev bool TestReallocMsize(size_t startSz) { 97*51c0b2f7Stbbdev bool passed = true; 98*51c0b2f7Stbbdev 99*51c0b2f7Stbbdev char *buf = (char*)scalable_malloc(startSz); 100*51c0b2f7Stbbdev REQUIRE_MESSAGE(buf, ""); 101*51c0b2f7Stbbdev size_t realSz = scalable_msize(buf); 102*51c0b2f7Stbbdev REQUIRE_MESSAGE(realSz>=startSz, "scalable_msize must be not less then allocated size"); 103*51c0b2f7Stbbdev memset(buf, 'a', realSz-1); 104*51c0b2f7Stbbdev buf[realSz-1] = 0; 105*51c0b2f7Stbbdev char *buf1 = (char*)scalable_realloc(buf, 2*realSz); 106*51c0b2f7Stbbdev REQUIRE_MESSAGE(buf1, ""); 107*51c0b2f7Stbbdev REQUIRE_MESSAGE((scalable_msize(buf1)>=2*realSz), "scalable_msize must be not less then allocated size"); 108*51c0b2f7Stbbdev buf1[2*realSz-1] = 0; 109*51c0b2f7Stbbdev if ( strspn(buf1, "a") < realSz-1 ) { 110*51c0b2f7Stbbdev REPORT( "Error: data broken for %d Bytes object.\n", startSz); 111*51c0b2f7Stbbdev passed = false; 112*51c0b2f7Stbbdev } 113*51c0b2f7Stbbdev scalable_free(buf1); 114*51c0b2f7Stbbdev 115*51c0b2f7Stbbdev return passed; 116*51c0b2f7Stbbdev } 117*51c0b2f7Stbbdev 118*51c0b2f7Stbbdev // regression test against incorrect work of msize/realloc 119*51c0b2f7Stbbdev // for aligned objects 120*51c0b2f7Stbbdev void TestAlignedMsize() 121*51c0b2f7Stbbdev { 122*51c0b2f7Stbbdev const int NUM = 4; 123*51c0b2f7Stbbdev char *p[NUM]; 124*51c0b2f7Stbbdev size_t objSizes[NUM]; 125*51c0b2f7Stbbdev size_t allocSz[] = {4, 8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0}; 126*51c0b2f7Stbbdev size_t align[] = {8, 512, 2*1024, 4*1024, 8*1024, 16*1024, 0}; 127*51c0b2f7Stbbdev 128*51c0b2f7Stbbdev for (int a=0; align[a]; a++) 129*51c0b2f7Stbbdev for (int s=0; allocSz[s]; s++) { 130*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) { 131*51c0b2f7Stbbdev p[i] = (char*)scalable_aligned_malloc(allocSz[s], align[a]); 132*51c0b2f7Stbbdev CHECK(tbb::detail::is_aligned(p[i], align[a])); 133*51c0b2f7Stbbdev } 134*51c0b2f7Stbbdev 135*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) { 136*51c0b2f7Stbbdev objSizes[i] = scalable_msize(p[i]); 137*51c0b2f7Stbbdev REQUIRE_MESSAGE(objSizes[i] >= allocSz[s], "allocated size must be not less than requested"); 138*51c0b2f7Stbbdev memset(p[i], i, objSizes[i]); 139*51c0b2f7Stbbdev } 140*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) { 141*51c0b2f7Stbbdev for (unsigned j=0; j<objSizes[i]; j++) 142*51c0b2f7Stbbdev REQUIRE_MESSAGE((((char*)p[i])[j] == i), "Error: data broken"); 143*51c0b2f7Stbbdev } 144*51c0b2f7Stbbdev 145*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) { 146*51c0b2f7Stbbdev p[i] = (char*)scalable_aligned_realloc(p[i], 2*allocSz[s], align[a]); 147*51c0b2f7Stbbdev CHECK(tbb::detail::is_aligned(p[i], align[a])); 148*51c0b2f7Stbbdev memset((char*)p[i]+allocSz[s], i+1, allocSz[s]); 149*51c0b2f7Stbbdev } 150*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) { 151*51c0b2f7Stbbdev for (unsigned j=0; j<allocSz[s]; j++) 152*51c0b2f7Stbbdev REQUIRE_MESSAGE((((char*)p[i])[j] == i), "Error: data broken"); 153*51c0b2f7Stbbdev for (size_t j=allocSz[s]; j<2*allocSz[s]; j++) 154*51c0b2f7Stbbdev REQUIRE_MESSAGE((((char*)p[i])[j] == i+1), "Error: data broken"); 155*51c0b2f7Stbbdev } 156*51c0b2f7Stbbdev for (int i=0; i<NUM; i++) 157*51c0b2f7Stbbdev scalable_free(p[i]); 158*51c0b2f7Stbbdev } 159*51c0b2f7Stbbdev } 160*51c0b2f7Stbbdev 161*51c0b2f7Stbbdev //! \brief \ref error_guessing 162*51c0b2f7Stbbdev TEST_CASE("testing leaks") { 163*51c0b2f7Stbbdev // Check whether memory usage data can be obtained; if not, skip test_bootstrap_leak. 164*51c0b2f7Stbbdev if (utils::GetMemoryUsage()) { 165*51c0b2f7Stbbdev REQUIRE_MESSAGE(TestBootstrapLeak(), "Test failed" ); 166*51c0b2f7Stbbdev } 167*51c0b2f7Stbbdev } 168*51c0b2f7Stbbdev 169*51c0b2f7Stbbdev //! \brief \ref error_guessing 170*51c0b2f7Stbbdev TEST_CASE("testing realloc mem size") { 171*51c0b2f7Stbbdev bool passed = true; 172*51c0b2f7Stbbdev // TestReallocMsize runs for each power of 2 and each Fibonacci number below 64K 173*51c0b2f7Stbbdev for (size_t a=1, b=1, sum=1; sum<=64*1024; ) { 174*51c0b2f7Stbbdev passed &= TestReallocMsize(sum); 175*51c0b2f7Stbbdev a = b; 176*51c0b2f7Stbbdev b = sum; 177*51c0b2f7Stbbdev sum = a+b; 178*51c0b2f7Stbbdev } 179*51c0b2f7Stbbdev for (size_t a=2; a<=64*1024; a*=2) { 180*51c0b2f7Stbbdev passed &= TestReallocMsize(a); 181*51c0b2f7Stbbdev } 182*51c0b2f7Stbbdev REQUIRE_MESSAGE( passed, "Test failed" ); 183*51c0b2f7Stbbdev } 184*51c0b2f7Stbbdev 185*51c0b2f7Stbbdev //! \brief \ref error_guessing 186*51c0b2f7Stbbdev TEST_CASE("testing memory align") { 187*51c0b2f7Stbbdev TestAlignedMsize(); 188*51c0b2f7Stbbdev } 189