1 | /* |
2 | * Copyright 2018-present Facebook, Inc. |
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 | // http://www.canonware.com/download/jemalloc/jemalloc-latest/doc/jemalloc.html |
18 | |
19 | #pragma once |
20 | |
21 | #include <folly/CPortability.h> |
22 | #include <folly/memory/Malloc.h> |
23 | #include <folly/portability/Config.h> |
24 | #include <folly/portability/Memory.h> |
25 | #include <folly/portability/SysMman.h> |
26 | |
27 | #include <cstddef> |
28 | #include <cstdint> |
29 | |
30 | namespace folly { |
31 | |
32 | /** |
33 | * An allocator which uses Jemalloc to create a dedicated huge page arena, |
34 | * backed by 2MB huge pages (on linux x86-64). |
35 | * |
36 | * This allocator is specifically intended for linux with the transparent |
37 | * huge page support set to 'madvise' and defrag policy set to 'madvise' |
38 | * or 'defer+madvise'. |
39 | * These can be controller via /sys/kernel/mm/transparent_hugepage/enabled |
40 | * and /sys/kernel/mm/transparent_hugepage/defrag. |
41 | * |
42 | * The allocator reserves a fixed-size area using mmap, and sets the |
43 | * MADV_HUGEPAGE page attribute using the madvise system call. |
44 | * A custom jemalloc hook is installed which is called when creating a new |
45 | * extent of memory. This will allocate from the reserved area if possible, |
46 | * and otherwise fall back to the default method. |
47 | * Jemalloc does not use allocated extents across different arenas without |
48 | * first unmapping them, and the advice flags are cleared on munmap. |
49 | * A regular malloc will never end up allocating memory from this arena. |
50 | * |
51 | * If binary isn't linked with jemalloc, the logic falls back to malloc / free. |
52 | * |
53 | * Note that the madvise call does not guarantee huge pages, it is best effort. |
54 | * |
55 | * 1GB Huge Pages are not supported at this point. |
56 | */ |
57 | class JemallocHugePageAllocator { |
58 | public: |
59 | static bool init(int nr_pages); |
60 | |
61 | static void* allocate(size_t size) { |
62 | // If uninitialized, flags_ will be 0 and the mallocx behavior |
63 | // will match that of a regular malloc |
64 | return hugePagesSupported ? mallocx(size, flags_) : malloc(size); |
65 | } |
66 | |
67 | static void* reallocate(void* p, size_t size) { |
68 | return hugePagesSupported ? rallocx(p, size, flags_) : realloc(p, size); |
69 | } |
70 | |
71 | static void deallocate(void* p, size_t = 0) { |
72 | hugePagesSupported ? dallocx(p, flags_) : free(p); |
73 | } |
74 | |
75 | static bool initialized() { |
76 | return flags_ != 0; |
77 | } |
78 | |
79 | static size_t freeSpace(); |
80 | static bool addressInArena(void* address); |
81 | |
82 | private: |
83 | static int flags_; |
84 | static bool hugePagesSupported; |
85 | }; |
86 | |
87 | // STL compatible huge page allocator, for use with STL-style containers |
88 | template <typename T> |
89 | class CxxHugePageAllocator { |
90 | private: |
91 | using Self = CxxHugePageAllocator<T>; |
92 | |
93 | public: |
94 | using value_type = T; |
95 | |
96 | CxxHugePageAllocator() {} |
97 | |
98 | template <typename U> |
99 | explicit CxxHugePageAllocator(CxxHugePageAllocator<U> const&) {} |
100 | |
101 | T* allocate(std::size_t n) { |
102 | return static_cast<T*>(JemallocHugePageAllocator::allocate(sizeof(T) * n)); |
103 | } |
104 | void deallocate(T* p, std::size_t n) { |
105 | JemallocHugePageAllocator::deallocate(p, sizeof(T) * n); |
106 | } |
107 | |
108 | friend bool operator==(Self const&, Self const&) noexcept { |
109 | return true; |
110 | } |
111 | friend bool operator!=(Self const&, Self const&) noexcept { |
112 | return false; |
113 | } |
114 | }; |
115 | |
116 | } // namespace folly |
117 | |