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

Copyright © 2005-2020 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.