Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
cache_aligned_allocator.cpp
Go to the documentation of this file.
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 
18 
19 */
20 
21 #include "tbb/tbb_config.h"
23 #include "tbb/tbb_allocator.h"
24 #include "tbb/tbb_exception.h"
25 #include "tbb_misc.h"
26 #include "dynamic_link.h"
27 #include <cstdlib>
28 
29 #if _WIN32||_WIN64
31 #else
32 #include <dlfcn.h>
33 #endif /* _WIN32||_WIN64 */
34 
35 #if __TBB_WEAK_SYMBOLS_PRESENT
36 
37 #pragma weak scalable_malloc
38 #pragma weak scalable_free
39 #pragma weak scalable_aligned_malloc
40 #pragma weak scalable_aligned_free
41 
42 extern "C" {
43  void* scalable_malloc( size_t );
44  void scalable_free( void* );
45  void* scalable_aligned_malloc( size_t, size_t );
46  void scalable_aligned_free( void* );
47 }
48 
49 #endif /* __TBB_WEAK_SYMBOLS_PRESENT */
50 
51 namespace tbb {
52 
53 namespace internal {
54 
56 static void* DummyMalloc( size_t size );
57 
59 static void DummyFree( void * ptr );
60 
62 static void* (*MallocHandler)( size_t size ) = &DummyMalloc;
63 
65 static void (*FreeHandler)( void* pointer ) = &DummyFree;
66 
68 static void* dummy_padded_allocate( size_t bytes, size_t alignment );
69 
71 static void dummy_padded_free( void * ptr );
72 
73 // ! Allocates memory using standard malloc. It is used when scalable_allocator is not available
74 static void* padded_allocate( size_t bytes, size_t alignment );
75 
76 // ! Allocates memory using standard free. It is used when scalable_allocator is not available
77 static void padded_free( void* p );
78 
80 static void* (*padded_allocate_handler)( size_t bytes, size_t alignment ) = &dummy_padded_allocate;
81 
84 
91 };
92 
93 
94 #if TBB_USE_DEBUG
95 #define DEBUG_SUFFIX "_debug"
96 #else
97 #define DEBUG_SUFFIX
98 #endif /* TBB_USE_DEBUG */
99 
100 // MALLOCLIB_NAME is the name of the TBB memory allocator library.
101 #if _WIN32||_WIN64
102 #define MALLOCLIB_NAME "tbbmalloc" DEBUG_SUFFIX ".dll"
103 #elif __APPLE__
104 #define MALLOCLIB_NAME "libtbbmalloc" DEBUG_SUFFIX ".dylib"
105 #elif __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __sun || _AIX || __ANDROID__
106 #define MALLOCLIB_NAME "libtbbmalloc" DEBUG_SUFFIX ".so"
107 #elif __linux__ // Note that order of these #elif's is important!
108 #define MALLOCLIB_NAME "libtbbmalloc" DEBUG_SUFFIX __TBB_STRING(.so.TBB_COMPATIBLE_INTERFACE_VERSION)
109 #else
110 #error Unknown OS
111 #endif
112 
114 
119  bool success = dynamic_link( MALLOCLIB_NAME, MallocLinkTable, 4 );
120  if( !success ) {
121  // If unsuccessful, set the handlers to the default routines.
122  // This must be done now, and not before FillDynamicLinks runs, because if other
123  // threads call the handlers, we want them to go through the DoOneTimeInitializations logic,
124  // which forces them to wait.
125  FreeHandler = &std::free;
126  MallocHandler = &std::malloc;
129  }
130 #if !__TBB_RML_STATIC
131  PrintExtraVersionInfo( "ALLOCATOR", success?"scalable_malloc":"malloc" );
132 #endif
133 }
134 
138 }
139 
141 static void* DummyMalloc( size_t size ) {
144  return (*MallocHandler)( size );
145 }
146 
148 static void DummyFree( void * ptr ) {
151  (*FreeHandler)( ptr );
152 }
153 
155 static void* dummy_padded_allocate( size_t bytes, size_t alignment ) {
158  return (*padded_allocate_handler)(bytes, alignment);
159 }
160 
162 static void dummy_padded_free( void * ptr ) {
165  (*padded_free_handler)( ptr );
166 }
167 
168 // TODO: use CPUID to find actual line size, though consider backward compatibility
169 static size_t NFS_LineSize = 128;
170 
171 size_t NFS_GetLineSize() {
172  return NFS_LineSize;
173 }
174 
175 #if _MSC_VER && !defined(__INTEL_COMPILER)
176  // unary minus operator applied to unsigned type, result still unsigned
177  #pragma warning( disable: 4146 4706 )
178 #endif
179 
180 void* NFS_Allocate( size_t n, size_t element_size, void* /*hint*/ ) {
181  //TODO: make this functionality available via an adaptor over generic STL like allocator
182  const size_t nfs_cache_line_size = NFS_LineSize;
183  __TBB_ASSERT( nfs_cache_line_size <= NFS_MaxLineSize, "illegal value for NFS_LineSize" );
184  __TBB_ASSERT( is_power_of_two(nfs_cache_line_size), "must be power of two" );
185  size_t bytes = n*element_size;
186 
187  if (bytes<n || bytes+nfs_cache_line_size<bytes) {
188  // Overflow
190  }
191  // scalable_aligned_malloc considers zero size request an error, and returns NULL
192  if (bytes==0) bytes = 1;
193 
194  void* result = (*padded_allocate_handler)( bytes, nfs_cache_line_size );
195  if (!result)
197 
198  __TBB_ASSERT( is_aligned(result, nfs_cache_line_size), "The address returned isn't aligned to cache line size" );
199  return result;
200 }
201 
202 void NFS_Free( void* p ) {
203  (*padded_free_handler)( p );
204 }
205 
206 static void* padded_allocate( size_t bytes, size_t alignment ) {
207  unsigned char* result = NULL;
208  unsigned char* base = (unsigned char*)std::malloc(alignment+bytes);
209  if( base ) {
210  // Round up to the next line
211  result = (unsigned char*)((uintptr_t)(base+alignment)&-alignment);
212  // Record where block actually starts.
213  ((uintptr_t*)result)[-1] = uintptr_t(base);
214  }
215  return result;
216 }
217 
218 static void padded_free( void* p ) {
219  if( p ) {
220  __TBB_ASSERT( (uintptr_t)p>=0x4096, "attempt to free block not obtained from cache_aligned_allocator" );
221  // Recover where block actually starts
222  unsigned char* base = ((unsigned char**)p)[-1];
223  __TBB_ASSERT( (void*)((uintptr_t)(base+NFS_LineSize)&-NFS_LineSize)==p, "not allocated by NFS_Allocate?" );
224  std::free(base);
225  }
226 }
227 
229  void* result = (*MallocHandler) (n);
230  if (!result) {
232  }
233  return result;
234 }
235 
237  if( p ) {
238  (*FreeHandler)( p );
239  }
240 }
241 
243  if (MallocHandler == &DummyMalloc) {
244  void* void_ptr = (*MallocHandler)(1);
245  (*FreeHandler)(void_ptr);
246  }
248  // Cast to void avoids type mismatch errors on some compilers (e.g. __IBMCPP__)
249  __TBB_ASSERT( !(((void*)MallocHandler==(void*)&std::malloc) ^ ((void*)FreeHandler==(void*)&std::free)),
250  "Both shim pointers must refer to routines from the same package (either TBB or CRT)" );
251  return (void*)MallocHandler == (void*)&std::malloc;
252 }
253 
254 } // namespace internal
255 
256 } // namespace tbb
void *__TBB_EXPORTED_FUNC NFS_Allocate(size_t n_element, size_t element_size, void *hint)
Allocate memory on cache/sector line boundary.
static const dynamic_link_descriptor MallocLinkTable[]
Table describing how to link the handlers.
static void padded_free(void *p)
size_t __TBB_EXPORTED_FUNC NFS_GetLineSize()
Cache/sector line size.
#define DLD(s, h)
The helper to construct dynamic_link_descriptor structure.
Definition: dynamic_link.h:60
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void *__TBB_EXPORTED_FUNC scalable_malloc(size_t size)
bool is_power_of_two(integer_type arg)
A function to check if passed integer is a power of 2.
Definition: tbb_stddef.h:359
void PrintExtraVersionInfo(const char *category, const char *format,...)
Prints arbitrary extra TBB version information on stderr.
Definition: tbb_misc.cpp:202
Association between a handler name and location of pointer to it.
Definition: dynamic_link.h:64
OPEN_INTERNAL_NAMESPACE bool dynamic_link(const char *, const dynamic_link_descriptor *, size_t, dynamic_link_handle *handle, int)
static void * padded_allocate(size_t bytes, size_t alignment)
void const char const char int ITT_FORMAT __itt_group_sync p
void __TBB_EXPORTED_FUNC scalable_aligned_free(void *ptr)
void throw_exception(exception_id eid)
Versionless convenience wrapper for throw_exception_v4()
static void(* padded_free_handler)(void *p)
Handler for padded memory deallocation.
void *__TBB_EXPORTED_FUNC scalable_aligned_malloc(size_t size, size_t alignment)
static void *(* padded_allocate_handler)(size_t bytes, size_t alignment)
Handler for padded memory allocation.
static tbb::atomic< do_once_state > initialization_state
static void * dummy_padded_allocate(size_t bytes, size_t alignment)
Dummy routine used for first indirect call via padded_allocate_handler.
void *__TBB_EXPORTED_FUNC allocate_via_handler_v3(size_t n)
Allocates memory using MallocHandler.
bool is_aligned(T *pointer, uintptr_t alignment)
A function to check if passed in pointer is aligned on a specific border.
Definition: tbb_stddef.h:353
void initialize_cache_aligned_allocator()
Defined in cache_aligned_allocator.cpp.
The graph class.
void initialize_handler_pointers()
Initialize the allocation/free handler pointers.
static void(* FreeHandler)(void *pointer)
Handler for memory deallocation.
static void DummyFree(void *ptr)
Dummy routine used for first indirect call via FreeHandler.
void atomic_do_once(const F &initializer, atomic< do_once_state > &state)
One-time initialization function.
Definition: tbb_misc.h:210
void __TBB_EXPORTED_FUNC deallocate_via_handler_v3(void *p)
Deallocates memory using FreeHandler.
void __TBB_EXPORTED_FUNC scalable_free(void *ptr)
#define __TBB_EXPORTED_FUNC
const size_t NFS_MaxLineSize
Compile-time constant that is upper bound on cache line/sector size.
Definition: tbb_stddef.h:220
bool __TBB_EXPORTED_FUNC is_malloc_used_v3()
Returns true if standard malloc/free are used to work with memory.
Primary template for atomic.
Definition: atomic.h:407
static void * DummyMalloc(size_t size)
Dummy routine used for first indirect call via MallocHandler.
void __TBB_EXPORTED_FUNC NFS_Free(void *)
Free memory allocated by NFS_Allocate.
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t size
static void dummy_padded_free(void *ptr)
Dummy routine used for first indirect call via padded_free_handler.
static void *(* MallocHandler)(size_t size)
Handler for memory allocation.

Copyright © 2005-2019 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.