149e08aacStbbdev /*
2*dc883a59SMarian Klymov     Copyright (c) 2005-2023 Intel Corporation
349e08aacStbbdev 
449e08aacStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
549e08aacStbbdev     you may not use this file except in compliance with the License.
649e08aacStbbdev     You may obtain a copy of the License at
749e08aacStbbdev 
849e08aacStbbdev         http://www.apache.org/licenses/LICENSE-2.0
949e08aacStbbdev 
1049e08aacStbbdev     Unless required by applicable law or agreed to in writing, software
1149e08aacStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1249e08aacStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349e08aacStbbdev     See the License for the specific language governing permissions and
1449e08aacStbbdev     limitations under the License.
1549e08aacStbbdev */
1649e08aacStbbdev 
1749e08aacStbbdev #ifndef __TBB_scalable_allocator_H
1849e08aacStbbdev #define __TBB_scalable_allocator_H
1949e08aacStbbdev 
2049e08aacStbbdev #ifdef __cplusplus
2149e08aacStbbdev #include "oneapi/tbb/detail/_config.h"
2249e08aacStbbdev #include "oneapi/tbb/detail/_utils.h"
23*dc883a59SMarian Klymov #include "oneapi/tbb/detail/_namespace_injection.h"
2449e08aacStbbdev #include <cstdlib>
2549e08aacStbbdev #include <utility>
268827ea7dSLong Nguyen #include <new> /* std::bad_alloc() */
2749e08aacStbbdev #else
288827ea7dSLong Nguyen #include "oneapi/tbb/detail/_export.h"
2949e08aacStbbdev #include <stddef.h> /* Need ptrdiff_t and size_t from here. */
30dbccbee9SIlya Mishin #if !defined(_MSC_VER) || defined(__clang__)
3149e08aacStbbdev #include <stdint.h> /* Need intptr_t from here. */
3249e08aacStbbdev #endif
3349e08aacStbbdev #endif
3449e08aacStbbdev 
3549e08aacStbbdev #if __TBB_CPP17_MEMORY_RESOURCE_PRESENT
3649e08aacStbbdev #include <memory_resource>
3749e08aacStbbdev #endif
3849e08aacStbbdev 
3949e08aacStbbdev #ifdef __cplusplus
4049e08aacStbbdev extern "C" {
4149e08aacStbbdev #endif /* __cplusplus */
4249e08aacStbbdev 
4349e08aacStbbdev #if _MSC_VER
4449e08aacStbbdev     #define __TBB_EXPORTED_FUNC __cdecl
4549e08aacStbbdev #else
4649e08aacStbbdev     #define __TBB_EXPORTED_FUNC
4749e08aacStbbdev #endif
4849e08aacStbbdev 
4949e08aacStbbdev /** The "malloc" analogue to allocate block of memory of size bytes.
5049e08aacStbbdev   * @ingroup memory_allocation */
518827ea7dSLong Nguyen TBBMALLOC_EXPORT void* __TBB_EXPORTED_FUNC scalable_malloc(size_t size);
5249e08aacStbbdev 
5349e08aacStbbdev /** The "free" analogue to discard a previously allocated piece of memory.
5449e08aacStbbdev     @ingroup memory_allocation */
558827ea7dSLong Nguyen TBBMALLOC_EXPORT void   __TBB_EXPORTED_FUNC scalable_free(void* ptr);
5649e08aacStbbdev 
5749e08aacStbbdev /** The "realloc" analogue complementing scalable_malloc.
5849e08aacStbbdev     @ingroup memory_allocation */
598827ea7dSLong Nguyen TBBMALLOC_EXPORT void* __TBB_EXPORTED_FUNC scalable_realloc(void* ptr, size_t size);
6049e08aacStbbdev 
6149e08aacStbbdev /** The "calloc" analogue complementing scalable_malloc.
6249e08aacStbbdev     @ingroup memory_allocation */
638827ea7dSLong Nguyen TBBMALLOC_EXPORT void* __TBB_EXPORTED_FUNC scalable_calloc(size_t nobj, size_t size);
6449e08aacStbbdev 
6549e08aacStbbdev /** The "posix_memalign" analogue.
6649e08aacStbbdev     @ingroup memory_allocation */
678827ea7dSLong Nguyen TBBMALLOC_EXPORT int __TBB_EXPORTED_FUNC scalable_posix_memalign(void** memptr, size_t alignment, size_t size);
6849e08aacStbbdev 
6949e08aacStbbdev /** The "_aligned_malloc" analogue.
7049e08aacStbbdev     @ingroup memory_allocation */
718827ea7dSLong Nguyen TBBMALLOC_EXPORT void* __TBB_EXPORTED_FUNC scalable_aligned_malloc(size_t size, size_t alignment);
7249e08aacStbbdev 
7349e08aacStbbdev /** The "_aligned_realloc" analogue.
7449e08aacStbbdev     @ingroup memory_allocation */
758827ea7dSLong Nguyen TBBMALLOC_EXPORT void* __TBB_EXPORTED_FUNC scalable_aligned_realloc(void* ptr, size_t size, size_t alignment);
7649e08aacStbbdev 
7749e08aacStbbdev /** The "_aligned_free" analogue.
7849e08aacStbbdev     @ingroup memory_allocation */
798827ea7dSLong Nguyen TBBMALLOC_EXPORT void __TBB_EXPORTED_FUNC scalable_aligned_free(void* ptr);
8049e08aacStbbdev 
8149e08aacStbbdev /** The analogue of _msize/malloc_size/malloc_usable_size.
8249e08aacStbbdev     Returns the usable size of a memory block previously allocated by scalable_*,
8349e08aacStbbdev     or 0 (zero) if ptr does not point to such a block.
8449e08aacStbbdev     @ingroup memory_allocation */
858827ea7dSLong Nguyen TBBMALLOC_EXPORT size_t __TBB_EXPORTED_FUNC scalable_msize(void* ptr);
8649e08aacStbbdev 
8749e08aacStbbdev /* Results for scalable_allocation_* functions */
8849e08aacStbbdev typedef enum {
8949e08aacStbbdev     TBBMALLOC_OK,
9049e08aacStbbdev     TBBMALLOC_INVALID_PARAM,
9149e08aacStbbdev     TBBMALLOC_UNSUPPORTED,
9249e08aacStbbdev     TBBMALLOC_NO_MEMORY,
9349e08aacStbbdev     TBBMALLOC_NO_EFFECT
9449e08aacStbbdev } ScalableAllocationResult;
9549e08aacStbbdev 
9649e08aacStbbdev /* Setting TBB_MALLOC_USE_HUGE_PAGES environment variable to 1 enables huge pages.
9749e08aacStbbdev    scalable_allocation_mode call has priority over environment variable. */
9849e08aacStbbdev typedef enum {
9949e08aacStbbdev     TBBMALLOC_USE_HUGE_PAGES,  /* value turns using huge pages on and off */
10049e08aacStbbdev     /* deprecated, kept for backward compatibility only */
10149e08aacStbbdev     USE_HUGE_PAGES = TBBMALLOC_USE_HUGE_PAGES,
10249e08aacStbbdev     /* try to limit memory consumption value (Bytes), clean internal buffers
10349e08aacStbbdev        if limit is exceeded, but not prevents from requesting memory from OS */
10449e08aacStbbdev     TBBMALLOC_SET_SOFT_HEAP_LIMIT,
10549e08aacStbbdev     /* Lower bound for the size (Bytes), that is interpreted as huge
10649e08aacStbbdev      * and not released during regular cleanup operations. */
10749e08aacStbbdev     TBBMALLOC_SET_HUGE_SIZE_THRESHOLD
10849e08aacStbbdev } AllocationModeParam;
10949e08aacStbbdev 
11049e08aacStbbdev /** Set TBB allocator-specific allocation modes.
11149e08aacStbbdev     @ingroup memory_allocation */
1128827ea7dSLong Nguyen TBBMALLOC_EXPORT int __TBB_EXPORTED_FUNC scalable_allocation_mode(int param, intptr_t value);
11349e08aacStbbdev 
11449e08aacStbbdev typedef enum {
11549e08aacStbbdev     /* Clean internal allocator buffers for all threads.
11649e08aacStbbdev        Returns TBBMALLOC_NO_EFFECT if no buffers cleaned,
11749e08aacStbbdev        TBBMALLOC_OK if some memory released from buffers. */
11849e08aacStbbdev     TBBMALLOC_CLEAN_ALL_BUFFERS,
11949e08aacStbbdev     /* Clean internal allocator buffer for current thread only.
12049e08aacStbbdev        Return values same as for TBBMALLOC_CLEAN_ALL_BUFFERS. */
12149e08aacStbbdev     TBBMALLOC_CLEAN_THREAD_BUFFERS
12249e08aacStbbdev } ScalableAllocationCmd;
12349e08aacStbbdev 
12449e08aacStbbdev /** Call TBB allocator-specific commands.
12549e08aacStbbdev     @ingroup memory_allocation */
1268827ea7dSLong Nguyen TBBMALLOC_EXPORT int __TBB_EXPORTED_FUNC scalable_allocation_command(int cmd, void *param);
12749e08aacStbbdev 
12849e08aacStbbdev #ifdef __cplusplus
12949e08aacStbbdev } /* extern "C" */
13049e08aacStbbdev #endif /* __cplusplus */
13149e08aacStbbdev 
13249e08aacStbbdev #ifdef __cplusplus
13349e08aacStbbdev 
13449e08aacStbbdev //! The namespace rml contains components of low-level memory pool interface.
13549e08aacStbbdev namespace rml {
13649e08aacStbbdev class MemoryPool;
13749e08aacStbbdev 
13849e08aacStbbdev typedef void *(*rawAllocType)(std::intptr_t pool_id, std::size_t &bytes);
13949e08aacStbbdev // returns non-zero in case of error
14049e08aacStbbdev typedef int   (*rawFreeType)(std::intptr_t pool_id, void* raw_ptr, std::size_t raw_bytes);
14149e08aacStbbdev 
14249e08aacStbbdev struct MemPoolPolicy {
14349e08aacStbbdev     enum {
14449e08aacStbbdev         TBBMALLOC_POOL_VERSION = 1
14549e08aacStbbdev     };
14649e08aacStbbdev 
14749e08aacStbbdev     rawAllocType pAlloc;
14849e08aacStbbdev     rawFreeType  pFree;
14949e08aacStbbdev                  // granularity of pAlloc allocations. 0 means default used.
15049e08aacStbbdev     std::size_t  granularity;
15149e08aacStbbdev     int          version;
15249e08aacStbbdev                  // all memory consumed at 1st pAlloc call and never returned,
15349e08aacStbbdev                  // no more pAlloc calls after 1st
15449e08aacStbbdev     unsigned     fixedPool : 1,
15549e08aacStbbdev                  // memory consumed but returned only at pool termination
15649e08aacStbbdev                  keepAllMemory : 1,
15749e08aacStbbdev                  reserved : 30;
15849e08aacStbbdev 
15949e08aacStbbdev     MemPoolPolicy(rawAllocType pAlloc_, rawFreeType pFree_,
16049e08aacStbbdev                   std::size_t granularity_ = 0, bool fixedPool_ = false,
16149e08aacStbbdev                   bool keepAllMemory_ = false) :
pAllocMemPoolPolicy16249e08aacStbbdev         pAlloc(pAlloc_), pFree(pFree_), granularity(granularity_), version(TBBMALLOC_POOL_VERSION),
16349e08aacStbbdev         fixedPool(fixedPool_), keepAllMemory(keepAllMemory_),
16449e08aacStbbdev         reserved(0) {}
16549e08aacStbbdev };
16649e08aacStbbdev 
16749e08aacStbbdev // enums have same values as appropriate enums from ScalableAllocationResult
16849e08aacStbbdev // TODO: use ScalableAllocationResult in pool_create directly
16949e08aacStbbdev enum MemPoolError {
17049e08aacStbbdev     // pool created successfully
17149e08aacStbbdev     POOL_OK = TBBMALLOC_OK,
17249e08aacStbbdev     // invalid policy parameters found
17349e08aacStbbdev     INVALID_POLICY = TBBMALLOC_INVALID_PARAM,
17449e08aacStbbdev      // requested pool policy is not supported by allocator library
17549e08aacStbbdev     UNSUPPORTED_POLICY = TBBMALLOC_UNSUPPORTED,
17649e08aacStbbdev     // lack of memory during pool creation
17749e08aacStbbdev     NO_MEMORY = TBBMALLOC_NO_MEMORY,
17849e08aacStbbdev     // action takes no effect
17949e08aacStbbdev     NO_EFFECT = TBBMALLOC_NO_EFFECT
18049e08aacStbbdev };
18149e08aacStbbdev 
1828827ea7dSLong Nguyen TBBMALLOC_EXPORT MemPoolError pool_create_v1(std::intptr_t pool_id, const MemPoolPolicy *policy,
18349e08aacStbbdev                             rml::MemoryPool **pool);
18449e08aacStbbdev 
1858827ea7dSLong Nguyen TBBMALLOC_EXPORT bool  pool_destroy(MemoryPool* memPool);
1868827ea7dSLong Nguyen TBBMALLOC_EXPORT void *pool_malloc(MemoryPool* memPool, std::size_t size);
1878827ea7dSLong Nguyen TBBMALLOC_EXPORT void *pool_realloc(MemoryPool* memPool, void *object, std::size_t size);
1888827ea7dSLong Nguyen TBBMALLOC_EXPORT void *pool_aligned_malloc(MemoryPool* mPool, std::size_t size, std::size_t alignment);
1898827ea7dSLong Nguyen TBBMALLOC_EXPORT void *pool_aligned_realloc(MemoryPool* mPool, void *ptr, std::size_t size, std::size_t alignment);
1908827ea7dSLong Nguyen TBBMALLOC_EXPORT bool  pool_reset(MemoryPool* memPool);
1918827ea7dSLong Nguyen TBBMALLOC_EXPORT bool  pool_free(MemoryPool *memPool, void *object);
1928827ea7dSLong Nguyen TBBMALLOC_EXPORT MemoryPool *pool_identify(void *object);
1938827ea7dSLong Nguyen TBBMALLOC_EXPORT std::size_t pool_msize(MemoryPool *memPool, void *object);
19449e08aacStbbdev 
19549e08aacStbbdev } // namespace rml
19649e08aacStbbdev 
19749e08aacStbbdev namespace tbb {
19849e08aacStbbdev namespace detail {
19949e08aacStbbdev namespace d1 {
20049e08aacStbbdev 
20149e08aacStbbdev // keep throw in a separate function to prevent code bloat
20249e08aacStbbdev template<typename E>
throw_exception(const E & e)20349e08aacStbbdev void throw_exception(const E &e) {
20449e08aacStbbdev #if TBB_USE_EXCEPTIONS
20549e08aacStbbdev     throw e;
20649e08aacStbbdev #else
20749e08aacStbbdev     suppress_unused_warning(e);
20849e08aacStbbdev #endif
20949e08aacStbbdev }
21049e08aacStbbdev 
21149e08aacStbbdev template<typename T>
21249e08aacStbbdev class scalable_allocator {
21349e08aacStbbdev public:
21449e08aacStbbdev     using value_type = T;
21549e08aacStbbdev     using propagate_on_container_move_assignment = std::true_type;
21649e08aacStbbdev 
21749e08aacStbbdev     //! Always defined for TBB containers
21849e08aacStbbdev     using is_always_equal = std::true_type;
21949e08aacStbbdev 
22049e08aacStbbdev     scalable_allocator() = default;
scalable_allocator(const scalable_allocator<U> &)22149e08aacStbbdev     template<typename U> scalable_allocator(const scalable_allocator<U>&) noexcept {}
22249e08aacStbbdev 
22349e08aacStbbdev     //! Allocate space for n objects.
allocate(std::size_t n)224b15aabb3Stbbdev     __TBB_nodiscard T* allocate(std::size_t n) {
22549e08aacStbbdev         T* p = static_cast<T*>(scalable_malloc(n * sizeof(value_type)));
22649e08aacStbbdev         if (!p) {
22749e08aacStbbdev             throw_exception(std::bad_alloc());
22849e08aacStbbdev         }
22949e08aacStbbdev         return p;
23049e08aacStbbdev     }
23149e08aacStbbdev 
23249e08aacStbbdev     //! Free previously allocated block of memory
deallocate(T * p,std::size_t)23349e08aacStbbdev     void deallocate(T* p, std::size_t) {
23449e08aacStbbdev         scalable_free(p);
23549e08aacStbbdev     }
23649e08aacStbbdev 
23749e08aacStbbdev #if TBB_ALLOCATOR_TRAITS_BROKEN
23849e08aacStbbdev     using pointer = value_type*;
23949e08aacStbbdev     using const_pointer = const value_type*;
24049e08aacStbbdev     using reference = value_type&;
24149e08aacStbbdev     using const_reference = const value_type&;
24249e08aacStbbdev     using difference_type = std::ptrdiff_t;
24349e08aacStbbdev     using size_type = std::size_t;
24449e08aacStbbdev     template<typename U> struct rebind {
24549e08aacStbbdev         using other = scalable_allocator<U>;
24649e08aacStbbdev     };
24749e08aacStbbdev     //! Largest value for which method allocate might succeed.
max_size()24849e08aacStbbdev     size_type max_size() const noexcept {
24949e08aacStbbdev         size_type absolutemax = static_cast<size_type>(-1) / sizeof (value_type);
25049e08aacStbbdev         return (absolutemax > 0 ? absolutemax : 1);
25149e08aacStbbdev     }
25249e08aacStbbdev     template<typename U, typename... Args>
construct(U * p,Args &&...args)25349e08aacStbbdev     void construct(U *p, Args&&... args)
25449e08aacStbbdev         { ::new((void *)p) U(std::forward<Args>(args)...); }
destroy(pointer p)25549e08aacStbbdev     void destroy(pointer p) { p->~value_type(); }
address(reference x)25649e08aacStbbdev     pointer address(reference x) const { return &x; }
address(const_reference x)25749e08aacStbbdev     const_pointer address(const_reference x) const { return &x; }
25849e08aacStbbdev #endif // TBB_ALLOCATOR_TRAITS_BROKEN
25949e08aacStbbdev 
26049e08aacStbbdev };
26149e08aacStbbdev 
26249e08aacStbbdev #if TBB_ALLOCATOR_TRAITS_BROKEN
26349e08aacStbbdev     template<>
26449e08aacStbbdev     class scalable_allocator<void> {
26549e08aacStbbdev     public:
26649e08aacStbbdev         using pointer = void*;
26749e08aacStbbdev         using const_pointer = const void*;
26849e08aacStbbdev         using value_type = void;
26949e08aacStbbdev         template<typename U> struct rebind {
27049e08aacStbbdev             using other = scalable_allocator<U>;
27149e08aacStbbdev         };
27249e08aacStbbdev     };
27349e08aacStbbdev #endif
27449e08aacStbbdev 
27549e08aacStbbdev template<typename T, typename U>
27649e08aacStbbdev inline bool operator==(const scalable_allocator<T>&, const scalable_allocator<U>&) noexcept { return true; }
27749e08aacStbbdev 
278b15aabb3Stbbdev #if !__TBB_CPP20_COMPARISONS_PRESENT
27949e08aacStbbdev template<typename T, typename U>
28049e08aacStbbdev inline bool operator!=(const scalable_allocator<T>&, const scalable_allocator<U>&) noexcept { return false; }
281b15aabb3Stbbdev #endif
28249e08aacStbbdev 
28349e08aacStbbdev #if __TBB_CPP17_MEMORY_RESOURCE_PRESENT
28449e08aacStbbdev 
28549e08aacStbbdev //! C++17 memory resource implementation for scalable allocator
28649e08aacStbbdev //! ISO C++ Section 23.12.2
28749e08aacStbbdev class scalable_resource_impl : public std::pmr::memory_resource {
28849e08aacStbbdev private:
do_allocate(std::size_t bytes,std::size_t alignment)28949e08aacStbbdev     void* do_allocate(std::size_t bytes, std::size_t alignment) override {
29049e08aacStbbdev         void* p = scalable_aligned_malloc(bytes, alignment);
29149e08aacStbbdev         if (!p) {
29249e08aacStbbdev             throw_exception(std::bad_alloc());
29349e08aacStbbdev         }
29449e08aacStbbdev         return p;
29549e08aacStbbdev     }
29649e08aacStbbdev 
do_deallocate(void * ptr,std::size_t,std::size_t)29749e08aacStbbdev     void do_deallocate(void* ptr, std::size_t /*bytes*/, std::size_t /*alignment*/) override {
29849e08aacStbbdev         scalable_free(ptr);
29949e08aacStbbdev     }
30049e08aacStbbdev 
30149e08aacStbbdev     //! Memory allocated by one instance of scalable_resource_impl could be deallocated by any
30249e08aacStbbdev     //! other instance of this class
do_is_equal(const std::pmr::memory_resource & other)30349e08aacStbbdev     bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
30449e08aacStbbdev         return this == &other ||
30549e08aacStbbdev #if __TBB_USE_OPTIONAL_RTTI
30649e08aacStbbdev             dynamic_cast<const scalable_resource_impl*>(&other) != nullptr;
30749e08aacStbbdev #else
30849e08aacStbbdev             false;
30949e08aacStbbdev #endif
31049e08aacStbbdev     }
31149e08aacStbbdev };
31249e08aacStbbdev 
31349e08aacStbbdev //! Global scalable allocator memory resource provider
scalable_memory_resource()31449e08aacStbbdev inline std::pmr::memory_resource* scalable_memory_resource() noexcept {
31549e08aacStbbdev     static tbb::detail::d1::scalable_resource_impl scalable_res;
31649e08aacStbbdev     return &scalable_res;
31749e08aacStbbdev }
31849e08aacStbbdev 
31949e08aacStbbdev #endif // __TBB_CPP17_MEMORY_RESOURCE_PRESENT
32049e08aacStbbdev 
32149e08aacStbbdev } // namespace d1
32249e08aacStbbdev } // namespace detail
32349e08aacStbbdev 
32449e08aacStbbdev inline namespace v1 {
32549e08aacStbbdev using detail::d1::scalable_allocator;
32649e08aacStbbdev #if __TBB_CPP17_MEMORY_RESOURCE_PRESENT
32749e08aacStbbdev using detail::d1::scalable_memory_resource;
32849e08aacStbbdev #endif
32949e08aacStbbdev } // namespace v1
33049e08aacStbbdev 
33149e08aacStbbdev } // namespace tbb
33249e08aacStbbdev 
33349e08aacStbbdev #endif /* __cplusplus */
33449e08aacStbbdev 
33549e08aacStbbdev #endif /* __TBB_scalable_allocator_H */
336