2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/experimental/JemallocNodumpAllocator.h>
19 #include <folly/Conv.h>
20 #include <folly/Malloc.h>
21 #include <folly/String.h>
22 #include <glog/logging.h>
26 JemallocNodumpAllocator::JemallocNodumpAllocator(State state) {
27 if (state == State::ENABLED && extend_and_setup_arena()) {
28 LOG(INFO) << "Set up arena: " << arena_index_;
32 JemallocNodumpAllocator::~JemallocNodumpAllocator() {
33 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT
34 if (arena_index_ != 0) {
35 // Destroy the arena because the hooks are linked to us.
36 const auto key = folly::to<std::string>("arena.", arena_index_, ".destroy");
37 if (auto ret = mallctl(key.c_str(), nullptr, 0, nullptr, 0)) {
38 LOG(FATAL) << "Unable to destroy arena: " << errnoStr(ret);
40 LOG(INFO) << "Destroy arena: " << arena_index_;
45 bool JemallocNodumpAllocator::extend_and_setup_arena() {
46 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
47 if (mallctl == nullptr) {
48 // Not linked with jemalloc.
52 size_t len = sizeof(arena_index_);
53 if (auto ret = mallctl(
54 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
64 LOG(FATAL) << "Unable to extend arena: " << errnoStr(ret);
66 flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE;
68 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
70 folly::to<std::string>("arena.", arena_index_, ".chunk_hooks");
73 // Read the existing hooks
74 if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) {
75 LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret);
77 if (original_alloc_ == nullptr) {
78 original_alloc_ = hooks.alloc;
80 DCHECK_EQ(original_alloc_, hooks.alloc);
83 // Set the custom hook
84 hooks.alloc = &JemallocNodumpAllocator::alloc;
86 mallctl(key.c_str(), nullptr, nullptr, &hooks, sizeof(hooks))) {
87 LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret);
91 folly::to<std::string>("arena.", arena_index_, ".extent_hooks");
92 extent_hooks_t* hooks;
94 // Read the existing hooks
95 if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) {
96 LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret);
98 if (original_alloc_ == nullptr) {
99 original_alloc_ = hooks->alloc;
101 DCHECK_EQ(original_alloc_, hooks->alloc);
104 // Set the custom hook
105 extent_hooks_ = *hooks;
106 extent_hooks_.alloc = &JemallocNodumpAllocator::alloc;
107 extent_hooks_t* new_hooks = &extent_hooks_;
108 if (auto ret = mallctl(
109 key.c_str(), nullptr, nullptr, &new_hooks, sizeof(new_hooks))) {
110 LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret);
115 #else // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
117 #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
120 void* JemallocNodumpAllocator::allocate(size_t size) {
121 return mallocx != nullptr ? mallocx(size, flags_) : malloc(size);
124 void* JemallocNodumpAllocator::reallocate(void* p, size_t size) {
125 return rallocx != nullptr ? rallocx(p, size, flags_) : realloc(p, size);
128 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
130 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
131 chunk_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
132 void* JemallocNodumpAllocator::alloc(
135 extent_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
136 void* JemallocNodumpAllocator::alloc(
137 extent_hooks_t* extent,
144 unsigned arena_ind) {
145 void* result = original_alloc_(
146 JEMALLOC_CHUNK_OR_EXTENT,
147 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT
155 if (result != nullptr) {
156 if (auto ret = madvise(result, size, MADV_DONTDUMP)) {
157 VLOG(1) << "Unable to madvise(MADV_DONTDUMP): " << errnoStr(ret);
164 #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
166 void JemallocNodumpAllocator::deallocate(void* p) {
167 dallocx != nullptr ? dallocx(p, flags_) : free(p);
170 void JemallocNodumpAllocator::deallocate(void* p, void* userData) {
171 const uint64_t flags = reinterpret_cast<uint64_t>(userData);
172 dallocx != nullptr ? dallocx(p, static_cast<int>(flags)) : free(p);
175 JemallocNodumpAllocator& globalJemallocNodumpAllocator() {
176 static auto instance = new JemallocNodumpAllocator();