dispenso
A library for task parallelism
 
Loading...
Searching...
No Matches
small_buffer_allocator.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
14#pragma once
15
16#include <dispenso/detail/math.h>
17#include <dispenso/platform.h>
18
19namespace dispenso {
20
26constexpr size_t kMaxSmallBufferSize = 256;
27
28namespace detail {
29
30DISPENSO_DLL_ACCESS char* allocSmallBufferImpl(size_t ordinal);
31DISPENSO_DLL_ACCESS void deallocSmallBufferImpl(size_t ordinal, void* buf);
32
33DISPENSO_DLL_ACCESS size_t approxBytesAllocatedSmallBufferImpl(size_t ordinal);
34
35// This has the effect of selecting actual block sizes starting with 4 bytes. Smaller requests
36// (e.g. 1 byte, 2 bytes) will still utilize 4-byte blocks. Choice of 4 bytes as the smallest
37// mainly aligns to sizeof(ptr) on 32-bit platforms, where we'd expect most common use cases to be
38// no smaller than one pointer. Retaining 4-byte buckets on 64-bit platforms doesn't cost much
39// (tiny startup/teardown cost, and trivial amount of memory) when not using 4-byte or smaller
40// allocations, and makes the code simpler.
41constexpr size_t getOrdinal(size_t blockSize) {
42 return std::max<ssize_t>(0, log2const(blockSize) - 2);
43}
44
45template <size_t kBlockSize>
46inline std::enable_if_t<(kBlockSize <= kMaxSmallBufferSize), char*> allocSmallOrLarge() {
47#if defined(DISPENSO_NO_SMALL_BUFFER_ALLOCATOR)
48 return reinterpret_cast<char*>(alignedMalloc(kBlockSize, kBlockSize));
49#else
50 return allocSmallBufferImpl(getOrdinal(kBlockSize));
51#endif // DISPENSO_NO_SMALL_BUFFER_ALLOCATOR
52}
53
54template <size_t kBlockSize>
55inline std::enable_if_t<(kBlockSize > kMaxSmallBufferSize), char*> allocSmallOrLarge() {
56 return reinterpret_cast<char*>(alignedMalloc(kBlockSize, kBlockSize));
57}
58
59template <size_t kBlockSize>
60inline std::enable_if_t<(kBlockSize <= kMaxSmallBufferSize), void> deallocSmallOrLarge(void* buf) {
61#if defined(DISPENSO_NO_SMALL_BUFFER_ALLOCATOR)
62 alignedFree(buf);
63#else
64 deallocSmallBufferImpl(getOrdinal(kBlockSize), buf);
65#endif // DISPENSO_NO_SMALL_BUFFER_ALLOCATOR
66}
67
68template <size_t kBlockSize>
69inline std::enable_if_t<(kBlockSize > kMaxSmallBufferSize), void> deallocSmallOrLarge(void* buf) {
70 alignedFree(buf);
71}
72
73} // namespace detail
74
86template <size_t kBlockSize>
87inline char* allocSmallBuffer() {
88 return detail::allocSmallOrLarge<kBlockSize>();
89}
99template <size_t kBlockSize>
100inline void deallocSmallBuffer(void* buf) {
101 detail::deallocSmallOrLarge<kBlockSize>(buf);
102}
103
111template <size_t kBlockSize>
113 return detail::approxBytesAllocatedSmallBufferImpl(detail::getOrdinal(kBlockSize));
114}
115
116} // namespace dispenso
detail::OpResult< T > OpResult
Definition pipeline.h:29
void deallocSmallBuffer(void *buf)
constexpr size_t kMaxSmallBufferSize
char * allocSmallBuffer()
size_t approxBytesAllocatedSmallBuffer()