JemallocNodumpAllocator.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright 2016-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. #include <folly/experimental/JemallocNodumpAllocator.h>
  17. #include <folly/Conv.h>
  18. #include <folly/String.h>
  19. #include <folly/memory/Malloc.h>
  20. #include <glog/logging.h>
  21. namespace folly {
  22. JemallocNodumpAllocator::JemallocNodumpAllocator(State state) {
  23. if (state == State::ENABLED && extend_and_setup_arena()) {
  24. LOG(INFO) << "Set up arena: " << arena_index_;
  25. }
  26. }
  27. bool JemallocNodumpAllocator::extend_and_setup_arena() {
  28. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
  29. if (mallctl == nullptr) {
  30. // Not linked with jemalloc.
  31. return false;
  32. }
  33. size_t len = sizeof(arena_index_);
  34. if (auto ret = mallctl(
  35. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
  36. "arenas.extend"
  37. #else
  38. "arenas.create"
  39. #endif
  40. ,
  41. &arena_index_,
  42. &len,
  43. nullptr,
  44. 0)) {
  45. LOG(FATAL) << "Unable to extend arena: " << errnoStr(ret);
  46. }
  47. flags_ = MALLOCX_ARENA(arena_index_) | MALLOCX_TCACHE_NONE;
  48. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
  49. const auto key =
  50. folly::to<std::string>("arena.", arena_index_, ".chunk_hooks");
  51. chunk_hooks_t hooks;
  52. len = sizeof(hooks);
  53. // Read the existing hooks
  54. if (auto ret = mallctl(key.c_str(), &hooks, &len, nullptr, 0)) {
  55. LOG(FATAL) << "Unable to get the hooks: " << errnoStr(ret);
  56. }
  57. if (original_alloc_ == nullptr) {
  58. original_alloc_ = hooks.alloc;
  59. } else {
  60. DCHECK_EQ(original_alloc_, hooks.alloc);
  61. }
  62. // Set the custom hook
  63. hooks.alloc = &JemallocNodumpAllocator::alloc;
  64. if (auto ret =
  65. mallctl(key.c_str(), nullptr, nullptr, &hooks, sizeof(hooks))) {
  66. LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret);
  67. }
  68. #else
  69. const auto key =
  70. folly::to<std::string>("arena.", arena_index_, ".extent_hooks");
  71. extent_hooks_t* hooks;
  72. len = sizeof(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);
  76. }
  77. if (original_alloc_ == nullptr) {
  78. original_alloc_ = hooks->alloc;
  79. } else {
  80. DCHECK_EQ(original_alloc_, hooks->alloc);
  81. }
  82. // Set the custom hook
  83. extent_hooks_ = *hooks;
  84. extent_hooks_.alloc = &JemallocNodumpAllocator::alloc;
  85. extent_hooks_t* new_hooks = &extent_hooks_;
  86. if (auto ret = mallctl(
  87. key.c_str(), nullptr, nullptr, &new_hooks, sizeof(new_hooks))) {
  88. LOG(FATAL) << "Unable to set the hooks: " << errnoStr(ret);
  89. }
  90. #endif
  91. return true;
  92. #else // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
  93. return false;
  94. #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
  95. }
  96. void* JemallocNodumpAllocator::allocate(size_t size) {
  97. return mallocx != nullptr ? mallocx(size, flags_) : malloc(size);
  98. }
  99. void* JemallocNodumpAllocator::reallocate(void* p, size_t size) {
  100. return rallocx != nullptr ? rallocx(p, size, flags_) : realloc(p, size);
  101. }
  102. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
  103. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_CHUNK
  104. chunk_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
  105. void* JemallocNodumpAllocator::alloc(
  106. void* chunk,
  107. #else
  108. extent_hooks_t JemallocNodumpAllocator::extent_hooks_;
  109. extent_alloc_t* JemallocNodumpAllocator::original_alloc_ = nullptr;
  110. void* JemallocNodumpAllocator::alloc(
  111. extent_hooks_t* extent,
  112. void* new_addr,
  113. #endif
  114. size_t size,
  115. size_t alignment,
  116. bool* zero,
  117. bool* commit,
  118. unsigned arena_ind) {
  119. void* result = original_alloc_(
  120. JEMALLOC_CHUNK_OR_EXTENT,
  121. #ifdef FOLLY_JEMALLOC_NODUMP_ALLOCATOR_EXTENT
  122. new_addr,
  123. #endif
  124. size,
  125. alignment,
  126. zero,
  127. commit,
  128. arena_ind);
  129. if (result != nullptr) {
  130. if (auto ret = madvise(result, size, MADV_DONTDUMP)) {
  131. VLOG(1) << "Unable to madvise(MADV_DONTDUMP): " << errnoStr(ret);
  132. }
  133. }
  134. return result;
  135. }
  136. #endif // FOLLY_JEMALLOC_NODUMP_ALLOCATOR_SUPPORTED
  137. void JemallocNodumpAllocator::deallocate(void* p, size_t) {
  138. dallocx != nullptr ? dallocx(p, flags_) : free(p);
  139. }
  140. void JemallocNodumpAllocator::deallocate(void* p, void* userData) {
  141. const uint64_t flags = reinterpret_cast<uint64_t>(userData);
  142. dallocx != nullptr ? dallocx(p, static_cast<int>(flags)) : free(p);
  143. }
  144. JemallocNodumpAllocator& globalJemallocNodumpAllocator() {
  145. static auto instance = new JemallocNodumpAllocator();
  146. return *instance;
  147. }
  148. } // namespace folly