dispenso 1.4.1
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
15#pragma once
16
17#include <dispenso/detail/math.h>
18#include <dispenso/platform.h>
19
20namespace dispenso {
21
27constexpr size_t kMaxSmallBufferSize = 256;
28
29namespace detail {
30
31DISPENSO_DLL_ACCESS char* allocSmallBufferImpl(size_t ordinal);
32DISPENSO_DLL_ACCESS void deallocSmallBufferImpl(size_t ordinal, void* buf);
33
34DISPENSO_DLL_ACCESS size_t approxBytesAllocatedSmallBufferImpl(size_t ordinal);
35
36// This has the effect of selecting actual block sizes starting with 4 bytes. Smaller requests
37// (e.g. 1 byte, 2 bytes) will still utilize 4-byte blocks. Choice of 4 bytes as the smallest
38// mainly aligns to sizeof(ptr) on 32-bit platforms, where we'd expect most common use cases to be
39// no smaller than one pointer. Retaining 4-byte buckets on 64-bit platforms doesn't cost much
40// (tiny startup/teardown cost, and trivial amount of memory) when not using 4-byte or smaller
41// allocations, and makes the code simpler.
42constexpr size_t getOrdinal(size_t blockSize) {
43 return std::max<ssize_t>(0, log2const(blockSize) - 2);
44}
45
46template <size_t kBlockSize>
47inline std::enable_if_t<(kBlockSize <= kMaxSmallBufferSize), char*> allocSmallOrLarge() {
48#if defined(DISPENSO_NO_SMALL_BUFFER_ALLOCATOR)
49 return reinterpret_cast<char*>(alignedMalloc(kBlockSize, kBlockSize));
50#else
51 return allocSmallBufferImpl(getOrdinal(kBlockSize));
52#endif // DISPENSO_NO_SMALL_BUFFER_ALLOCATOR
53}
54
55template <size_t kBlockSize>
56inline std::enable_if_t<(kBlockSize > kMaxSmallBufferSize), char*> allocSmallOrLarge() {
57 return reinterpret_cast<char*>(alignedMalloc(kBlockSize, kBlockSize));
58}
59
60template <size_t kBlockSize>
61inline std::enable_if_t<(kBlockSize <= kMaxSmallBufferSize), void> deallocSmallOrLarge(void* buf) {
62#if defined(DISPENSO_NO_SMALL_BUFFER_ALLOCATOR)
63 alignedFree(buf);
64#else
65 deallocSmallBufferImpl(getOrdinal(kBlockSize), buf);
66#endif // DISPENSO_NO_SMALL_BUFFER_ALLOCATOR
67}
68
69template <size_t kBlockSize>
70inline std::enable_if_t<(kBlockSize > kMaxSmallBufferSize), void> deallocSmallOrLarge(void* buf) {
71 alignedFree(buf);
72}
73
74} // namespace detail
75
87template <size_t kBlockSize>
88inline char* allocSmallBuffer() {
89 return detail::allocSmallOrLarge<kBlockSize>();
90}
100template <size_t kBlockSize>
101inline void deallocSmallBuffer(void* buf) {
102 detail::deallocSmallOrLarge<kBlockSize>(buf);
103}
104
112template <size_t kBlockSize>
114 return detail::approxBytesAllocatedSmallBufferImpl(detail::getOrdinal(kBlockSize));
115}
116
117} // namespace dispenso
void deallocSmallBuffer(void *buf)
constexpr size_t kMaxSmallBufferSize
char * allocSmallBuffer()
size_t approxBytesAllocatedSmallBuffer()
constexpr uint32_t log2const(uint64_t v)
Compute log base 2 of a value (compile-time).
Definition util.h:172