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