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 bool JemallocNodumpAllocator::extend_and_setup_arena() {
33 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
34 if (mallctl == nullptr) {
35 // Not linked with jemalloc.
39 size_t len = sizeof(arena_index_);
40 if (auto ret = mallctl(
41 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
51 LOG(FATAL) << "Unable to extend arena: " << errnoStr(ret);
53 flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE;
55 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
57 folly::to<std::string>("arena.", arena_index_, ".chunk_hooks");
60 // Read the existing hooks
61 if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) {
62 LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret);
64 if (original_alloc_ == nullptr) {
65 original_alloc_ = hooks.alloc;
67 DCHECK_EQ(original_alloc_, hooks.alloc);
70 // Set the custom hook
71 hooks.alloc = &JemallocNodumpAllocator::alloc;
73 mallctl(key.c_str(), nullptr, nullptr, &hooks, sizeof(hooks))) {
74 LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret);
78 folly::to<std::string>("arena.", arena_index_, ".extent_hooks");
79 extent_hooks_t* hooks;
81 // Read the existing hooks
82 if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) {
83 LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret);
85 if (original_alloc_ == nullptr) {
86 original_alloc_ = hooks->alloc;
88 DCHECK_EQ(original_alloc_, hooks->alloc);
91 // Set the custom hook
92 hooks->alloc = &JemallocNodumpAllocator::alloc;
96 #else // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
98 #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
101 void* JemallocNodumpAllocator::allocate(size_t size) {
102 return mallocx != nullptr ? mallocx(size, flags_) : malloc(size);
105 void* JemallocNodumpAllocator::reallocate(void* p, size_t size) {
106 return rallocx != nullptr ? rallocx(p, size, flags_) : realloc(p, size);
109 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
111 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
112 chunk_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
113 void* JemallocNodumpAllocator::alloc(
116 extent_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
117 void* JemallocNodumpAllocator::alloc(
118 extent_hooks_t* extent,
125 unsigned arena_ind) {
126 void* result = original_alloc_(
127 JEMALLOC_CHUNK_OR_EXTENT,
128 #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT
136 if (result != nullptr) {
137 if (auto ret = madvise(result, size, MADV_DONTDUMP)) {
138 VLOG(1) << "Unable to madvise(MADV_DONTDUMP): " << errnoStr(ret);
145 #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
147 void JemallocNodumpAllocator::deallocate(void* p) {
148 dallocx != nullptr ? dallocx(p, flags_) : free(p);
151 void JemallocNodumpAllocator::deallocate(void* p, void* userData) {
152 const uint64_t flags = reinterpret_cast<uint64_t>(userData);
153 dallocx != nullptr ? dallocx(p, static_cast<int>(flags)) : free(p);
156 JemallocNodumpAllocator& globalJemallocNodumpAllocator() {
157 static auto instance = new JemallocNodumpAllocator();