| 1 | /* |
| 2 | Copyright (c) 2005-2019 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 | // Basic testing of an allocator |
| 18 | // Tests against requirements in 20.1.5 of ISO C++ Standard (1998). |
| 19 | // Does not check for thread safety or false sharing issues. |
| 20 | // |
| 21 | // Tests for compatibility with the host's STL are in |
| 22 | // test_Allocator_STL.h. Those tests are in a separate file |
| 23 | // because they bring in lots of STL headers, and the tests here |
| 24 | // are supposed to work in the abscense of STL. |
| 25 | |
| 26 | #include "harness.h" |
| 27 | #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC |
| 28 | #include <utility> //for std::pair |
| 29 | #endif |
| 30 | |
| 31 | template<typename A> |
| 32 | struct is_zero_filling { |
| 33 | static const bool value = false; |
| 34 | }; |
| 35 | |
| 36 | int NumberOfFoo; |
| 37 | |
| 38 | template<typename T, size_t N> |
| 39 | struct Foo { |
| 40 | T foo_array[N]; |
| 41 | Foo() { |
| 42 | zero_fill<T>(foo_array, N); |
| 43 | ++NumberOfFoo; |
| 44 | } |
| 45 | Foo( const Foo& x ) { |
| 46 | *this = x; |
| 47 | ++NumberOfFoo; |
| 48 | } |
| 49 | ~Foo() { |
| 50 | --NumberOfFoo; |
| 51 | } |
| 52 | }; |
| 53 | |
| 54 | inline char PseudoRandomValue( size_t j, size_t k ) { |
| 55 | return char(j*3 ^ j>>4 ^ k); |
| 56 | } |
| 57 | |
| 58 | #if __APPLE__ |
| 59 | #include <fcntl.h> |
| 60 | #include <unistd.h> |
| 61 | |
| 62 | // A RAII class to disable stderr in a certain scope. It's not thread-safe. |
| 63 | class DisableStderr { |
| 64 | int stderrCopy; |
| 65 | static void dupToStderrAndClose(int fd) { |
| 66 | int ret = dup2(fd, STDERR_FILENO); // close current stderr |
| 67 | ASSERT(ret != -1, NULL); |
| 68 | ret = close(fd); |
| 69 | ASSERT(ret != -1, NULL); |
| 70 | } |
| 71 | public: |
| 72 | DisableStderr() { |
| 73 | int devNull = open("/dev/null" , O_WRONLY); |
| 74 | ASSERT(devNull != -1, NULL); |
| 75 | stderrCopy = dup(STDERR_FILENO); |
| 76 | ASSERT(stderrCopy != -1, NULL); |
| 77 | dupToStderrAndClose(devNull); |
| 78 | } |
| 79 | ~DisableStderr() { |
| 80 | dupToStderrAndClose(stderrCopy); |
| 81 | } |
| 82 | }; |
| 83 | #endif |
| 84 | |
| 85 | //! T is type and A is allocator for that type |
| 86 | template<typename T, typename A> |
| 87 | void TestBasic( A& a ) { |
| 88 | T x; |
| 89 | const T cx = T(); |
| 90 | |
| 91 | // See Table 32 in ISO ++ Standard |
| 92 | typename A::pointer px = &x; |
| 93 | typename A::const_pointer pcx = &cx; |
| 94 | |
| 95 | typename A::reference rx = x; |
| 96 | ASSERT( &rx==&x, NULL ); |
| 97 | |
| 98 | typename A::const_reference rcx = cx; |
| 99 | ASSERT( &rcx==&cx, NULL ); |
| 100 | |
| 101 | typename A::value_type v = x; |
| 102 | |
| 103 | typename A::size_type size; |
| 104 | size = 0; |
| 105 | --size; |
| 106 | ASSERT( size>0, "not an unsigned integral type?" ); |
| 107 | |
| 108 | typename A::difference_type difference; |
| 109 | difference = 0; |
| 110 | --difference; |
| 111 | ASSERT( difference<0, "not an signed integral type?" ); |
| 112 | |
| 113 | // "rebind" tested by our caller |
| 114 | |
| 115 | ASSERT( a.address(rx)==px, NULL ); |
| 116 | |
| 117 | ASSERT( a.address(rcx)==pcx, NULL ); |
| 118 | |
| 119 | typename A::pointer array[100]; |
| 120 | size_t sizeof_T = sizeof(T); |
| 121 | for( size_t k=0; k<100; ++k ) { |
| 122 | array[k] = k&1 ? a.allocate(k,array[0]) : a.allocate(k); |
| 123 | char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[k])); |
| 124 | for( size_t j=0; j<k*sizeof_T; ++j ) |
| 125 | s[j] = PseudoRandomValue(j,k); |
| 126 | } |
| 127 | |
| 128 | // Test hint argument. This can't be compiled when hint is void*, It should be const void* |
| 129 | typename A::pointer a_ptr; |
| 130 | const void * const_hint = NULL; |
| 131 | a_ptr = a.allocate (1, const_hint); |
| 132 | a.deallocate(a_ptr, 1); |
| 133 | |
| 134 | // Test "a.deallocate(p,n) |
| 135 | for( size_t k=0; k<100; ++k ) { |
| 136 | char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[k])); |
| 137 | for( size_t j=0; j<k*sizeof_T; ++j ) |
| 138 | ASSERT( s[j] == PseudoRandomValue(j,k), NULL ); |
| 139 | a.deallocate(array[k],k); |
| 140 | } |
| 141 | |
| 142 | // Test "a.max_size()" |
| 143 | AssertSameType( a.max_size(), typename A::size_type(0) ); |
| 144 | // Following assertion catches case where max_size() is so large that computation of |
| 145 | // number of bytes for such an allocation would overflow size_type. |
| 146 | ASSERT( a.max_size()*typename A::size_type(sizeof(T))>=a.max_size(), "max_size larger than reasonable" ); |
| 147 | |
| 148 | // Test "a.construct(p,t)" |
| 149 | int n = NumberOfFoo; |
| 150 | typename A::pointer p = a.allocate(1); |
| 151 | a.construct( p, cx ); |
| 152 | ASSERT( NumberOfFoo==n+1, "constructor for Foo not called?" ); |
| 153 | |
| 154 | // Test "a.destroy(p)" |
| 155 | a.destroy( p ); |
| 156 | ASSERT( NumberOfFoo==n, "destructor for Foo not called?" ); |
| 157 | a.deallocate(p,1); |
| 158 | |
| 159 | #if TBB_USE_EXCEPTIONS |
| 160 | volatile size_t too_big = (~size_t(0) - 1024*1024)/sizeof(T); |
| 161 | bool exception_caught = false; |
| 162 | typename A::pointer p1 = NULL; |
| 163 | try { |
| 164 | #if __APPLE__ |
| 165 | // On macOS*, failure to map memory results in messages to stderr; |
| 166 | // suppress them. |
| 167 | DisableStderr disableStderr; |
| 168 | #endif |
| 169 | p1 = a.allocate(too_big); |
| 170 | } catch ( std::bad_alloc& ) { |
| 171 | exception_caught = true; |
| 172 | } |
| 173 | ASSERT( exception_caught, "allocate expected to throw bad_alloc" ); |
| 174 | a.deallocate(p1, too_big); |
| 175 | #endif // TBB_USE_EXCEPTIONS |
| 176 | |
| 177 | #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC |
| 178 | { |
| 179 | typedef typename A:: template rebind<std::pair<typename A::value_type, typename A::value_type> >::other pair_allocator_type; |
| 180 | pair_allocator_type pair_allocator(a); |
| 181 | int NumberOfFooBeforeConstruct= NumberOfFoo; |
| 182 | typename pair_allocator_type::pointer pair_pointer = pair_allocator.allocate(1); |
| 183 | pair_allocator.construct( pair_pointer, cx, cx); |
| 184 | ASSERT( NumberOfFoo==NumberOfFooBeforeConstruct+2, "constructor for Foo not called appropriate number of times?" ); |
| 185 | |
| 186 | pair_allocator.destroy( pair_pointer ); |
| 187 | ASSERT( NumberOfFoo==NumberOfFooBeforeConstruct, "destructor for Foo not called appropriate number of times?" ); |
| 188 | pair_allocator.deallocate(pair_pointer,1); |
| 189 | } |
| 190 | #endif |
| 191 | |
| 192 | } |
| 193 | |
| 194 | #include "tbb/blocked_range.h" |
| 195 | |
| 196 | #if _MSC_VER && !defined(__INTEL_COMPILER) |
| 197 | // Workaround for erroneous "conditional expression is constant" warning in method check_allocate. |
| 198 | #pragma warning (disable: 4127) |
| 199 | #endif |
| 200 | |
| 201 | // A is an allocator for some type |
| 202 | template<typename A> |
| 203 | struct Body: NoAssign { |
| 204 | static const size_t max_k = 100000; |
| 205 | A &a; |
| 206 | Body(A &a_) : a(a_) {} |
| 207 | void check_allocate( typename A::pointer array[], size_t i, size_t t ) const |
| 208 | { |
| 209 | ASSERT(array[i] == 0, NULL); |
| 210 | size_t size = i * (i&3); |
| 211 | array[i] = i&1 ? a.allocate(size, array[i>>3]) : a.allocate(size); |
| 212 | ASSERT(array[i] != 0, "allocator returned null" ); |
| 213 | char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[i])); |
| 214 | for( size_t j=0; j<size*sizeof(typename A::value_type); ++j ) { |
| 215 | if(is_zero_filling<typename A::template rebind<void>::other>::value) |
| 216 | ASSERT( !s[j], NULL); |
| 217 | s[j] = PseudoRandomValue(i, t); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | void check_deallocate( typename A::pointer array[], size_t i, size_t t ) const |
| 222 | { |
| 223 | ASSERT(array[i] != 0, NULL); |
| 224 | size_t size = i * (i&3); |
| 225 | char* s = reinterpret_cast<char*>(reinterpret_cast<void*>(array[i])); |
| 226 | for( size_t j=0; j<size*sizeof(typename A::value_type); ++j ) |
| 227 | ASSERT( s[j] == PseudoRandomValue(i, t), "Thread safety test failed" ); |
| 228 | a.deallocate(array[i], size); |
| 229 | array[i] = 0; |
| 230 | } |
| 231 | |
| 232 | void operator()( size_t thread_id ) const { |
| 233 | typename A::pointer array[256]; |
| 234 | |
| 235 | for( size_t k=0; k<256; ++k ) |
| 236 | array[k] = 0; |
| 237 | for( size_t k=0; k<max_k; ++k ) { |
| 238 | size_t i = static_cast<unsigned char>(PseudoRandomValue(k,thread_id)); |
| 239 | if(!array[i]) check_allocate(array, i, thread_id); |
| 240 | else check_deallocate(array, i, thread_id); |
| 241 | } |
| 242 | for( size_t k=0; k<256; ++k ) |
| 243 | if(array[k]) |
| 244 | check_deallocate(array, k, thread_id); |
| 245 | } |
| 246 | }; |
| 247 | |
| 248 | // A is an allocator for some type, and U is another type |
| 249 | template<typename U, typename A> |
| 250 | void Test(A &a) { |
| 251 | typename A::template rebind<U>::other b(a); |
| 252 | TestBasic<U>(b); |
| 253 | TestBasic<typename A::value_type>(a); |
| 254 | |
| 255 | // thread safety |
| 256 | NativeParallelFor( 4, Body<A>(a) ); |
| 257 | ASSERT( NumberOfFoo==0, "Allocate/deallocate count mismatched" ); |
| 258 | |
| 259 | ASSERT( a==b, NULL ); |
| 260 | ASSERT( !(a!=b), NULL ); |
| 261 | } |
| 262 | |
| 263 | template<typename Allocator> |
| 264 | int TestMain(const Allocator &a = Allocator()) { |
| 265 | NumberOfFoo = 0; |
| 266 | typename Allocator::template rebind<Foo<char,1> >::other a1(a); |
| 267 | typename Allocator::template rebind<Foo<double,1> >::other a2(a); |
| 268 | Test<Foo<int,17> >( a1 ); |
| 269 | Test<Foo<float,23> >( a2 ); |
| 270 | return 0; |
| 271 | } |
| 272 | |