40ebe99eb7817178aed9caf4c7bb68c737e97c61
[folly.git] / folly / experimental / JemallocNodumpAllocator.h
1 /*
2  * Copyright 2017 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/portability/Config.h>
22
23 #ifdef FOLLY_HAVE_LIBJEMALLOC
24
25 #include <folly/portability/SysMman.h>
26 #include <jemalloc/jemalloc.h>
27
28 #if (JEMALLOC_VERSION_MAJOR > 3) && defined(MADV_DONTDUMP)
29 #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED 1
30 #if (JEMALLOC_VERSION_MAJOR == 4)
31 #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
32 #define JEMALLOC_CHUNK_OR_EXTENT chunk
33 #else
34 #define FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT
35 #define JEMALLOC_CHUNK_OR_EXTENT extent
36 #endif
37 #endif
38
39 #endif // FOLLY_HAVE_LIBJEMALLOC
40
41 #include <cstddef>
42
43 namespace folly {
44
45 /**
46  * An allocator which uses Jemalloc to create an dedicated arena to allocate
47  * memory from. The only special property set on the allocated memory is that
48  * the memory is not dump-able.
49  *
50  * This is done by setting MADV_DONTDUMP using the `madvise` system call. A
51  * custom hook installed which is called when allocating a new chunk / extent of
52  * memory.  All it does is call the original jemalloc hook to allocate the
53  * memory and then set the advise on it before returning the pointer to the
54  * allocated memory. Jemalloc does not use allocated chunks / extents across
55  * different arenas, without `munmap`-ing them first, and the advises are not
56  * sticky i.e. they are unset if `munmap` is done. Also this arena can't be used
57  * by any other part of the code by just calling `malloc`.
58  *
59  * If target system doesn't support MADV_DONTDUMP or jemalloc doesn't support
60  * custom arena hook, JemallocNodumpAllocator would fall back to using malloc /
61  * free. Such behavior can be identified by using
62  * !defined(FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED).
63  *
64  * Similarly, if binary isn't linked with jemalloc, the logic would fall back to
65  * malloc / free.
66  */
67 class JemallocNodumpAllocator {
68  public:
69   enum class State {
70     ENABLED,
71     DISABLED,
72   };
73
74   // To be used as IOBuf::FreeFunction, userData should be set to
75   // reinterpret_cast<void*>(getFlags()).
76   static void deallocate(void* p, void* userData);
77
78   explicit JemallocNodumpAllocator(State state = State::ENABLED);
79   ~JemallocNodumpAllocator();
80
81   void* allocate(size_t size);
82   void* reallocate(void* p, size_t size);
83   void deallocate(void* p);
84
85   unsigned getArenaIndex() const { return arena_index_; }
86   int getFlags() const { return flags_; }
87
88  private:
89 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
90 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
91   static chunk_alloc_t* original_alloc_;
92   static void* alloc(
93       void* chunk,
94 #else
95   extent_hooks_t extent_hooks_;
96   static extent_alloc_t* original_alloc_;
97   static void* alloc(
98       extent_hooks_t* extent,
99       void* new_addr,
100 #endif
101       size_t size,
102       size_t alignment,
103       bool* zero,
104       bool* commit,
105       unsigned arena_ind);
106 #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
107
108   bool extend_and_setup_arena();
109
110   unsigned arena_index_{0};
111   int flags_{0};
112 };
113
114 /**
115  * JemallocNodumpAllocator singleton.
116  */
117 JemallocNodumpAllocator& globalJemallocNodumpAllocator();
118
119 } // folly