Add logging for comparison behaviors
[hiphop-php.git] / hphp / util / managed-arena.cpp
blob1e1b59ad5583836c0e38b95415cfb4292ce3a447
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/managed-arena.h"
19 #include "hphp/util/address-range.h"
20 #include "hphp/util/assertions.h"
22 #if USE_JEMALLOC_EXTENT_HOOKS
24 namespace HPHP { namespace alloc {
26 static_assert(sizeof(RangeState) <= 64, "");
27 static_assert(alignof(RangeState) <= 64, "");
28 using RangeStateStorage = std::aligned_storage<sizeof(RangeState), 64>::type;
30 RangeArenaStorage g_lowerArena{};
31 RangeArenaStorage g_lowArena{};
32 RangeArenaStorage g_highArena{};
33 RangeArenaStorage g_coldArena{};
34 RangeArenaStorage g_lowColdArena{};
35 RangeStateStorage g_ranges[3];
36 ArenaArray g_arenas;
37 PreMappedArena* g_arena0; // arena 0, if we end up injecting pages
38 std::vector<PreMappedArena*> g_local_arenas; // keyed by numa node id
40 NEVER_INLINE RangeState& getRange(AddrRangeClass index) {
41 auto result = reinterpret_cast<RangeState*>(g_ranges + index);
42 if (!result->low()) {
43 static std::atomic_flag lock = ATOMIC_FLAG_INIT;
44 while (lock.test_and_set(std::memory_order_acquire)) {
45 // Spin while another thread initializes the ranges. We don't really reach
46 // here, because the function is called very early during process
47 // initialization when there is only one thread. Do it just for extra
48 // safety in case someone starts to abuse the code.
50 if (!result->high()) {
51 new (&(g_ranges[AddrRangeClass::VeryLow]))
52 RangeState(kLowArenaMinAddr, 2ull << 30);
53 new (&(g_ranges[AddrRangeClass::Low]))
54 RangeState(2ull << 30, kLowArenaMaxAddr);
55 new (&(g_ranges[AddrRangeClass::Uncounted]))
56 RangeState(kLowArenaMaxAddr, kHighArenaMaxAddr);
58 lock.clear(std::memory_order_release);
59 assertx(result->high());
61 return *result;
64 //////////////////////////////////////////////////////////////////////
66 template<typename ExtentAllocator>
67 std::string ManagedArena<ExtentAllocator>::reportStats() {
68 char buffer[128];
69 using Traits = extent_allocator_traits<ExtentAllocator>;
70 std::snprintf(buffer, sizeof(buffer),
71 "Arena %d: capacity %zd, max_capacity %zd, used %zd\n",
72 id(),
73 ExtentAllocator::allocatedSize(),
74 ExtentAllocator::maxCapacity(),
75 s_pageSize * mallctl_pactive(id()));
76 return std::string{buffer};
79 template<typename ExtentAllocator>
80 size_t ManagedArena<ExtentAllocator>::unusedSize() {
81 auto const active = s_pageSize * mallctl_pactive(id());
82 return ExtentAllocator::allocatedSize() - active;
85 template<typename ExtentAllocator>
86 void ManagedArena<ExtentAllocator>::create() {
87 using Traits = extent_allocator_traits<ExtentAllocator>;
88 assertx(m_arenaId == kInvalidArena);
89 size_t idSize = sizeof(m_arenaId);
90 if (mallctl("arenas.create", &m_arenaId, &idSize, nullptr, 0)) {
91 throw std::runtime_error{"arenas.create"};
93 char command[32];
94 ssize_t decay_ms = Traits::get_decay_ms();
95 std::snprintf(command, sizeof(command),
96 "arena.%d.dirty_decay_ms", m_arenaId);
97 if (mallctl(command, nullptr, nullptr, &decay_ms, sizeof(decay_ms))) {
98 throw std::runtime_error{command};
103 template<typename ExtentAllocator>
104 void ManagedArena<ExtentAllocator>::updateHook() {
105 using Traits = extent_allocator_traits<ExtentAllocator>;
106 if (auto hooks_ptr = Traits::get_hooks()) {
107 // We need to do `GetByArenaId()` in custom extent hooks, so register the
108 // arena in the global list. It is important that we do this before actually
109 // updating the hooks.
110 assertx(GetByArenaId<ManagedArena>(m_arenaId) == nullptr);
111 bool registered = false;
112 for (auto& i : g_arenas) {
113 if (!i.second) {
114 i.first = m_arenaId;
115 i.second = this;
116 registered = true;
117 break;
120 if (!registered) {
121 throw std::out_of_range{
122 "too many ManagedArena's, check MAX_MANAGED_ARENA_COUNT"};
125 char command[32];
126 std::snprintf(command, sizeof(command), "arena.%d.extent_hooks", m_arenaId);
127 auto fallback = Traits::get_fallback(this);
128 size_t oldSize = sizeof(extent_hooks_t*);
129 if (mallctl(command, fallback, (fallback ? &oldSize : nullptr),
130 &hooks_ptr, sizeof(hooks_ptr))) {
131 throw std::runtime_error{command};
133 #if (JEMALLOC_VERSION_MAJOR > 5) || \
134 ((JEMALLOC_VERSION_MAJOR == 5) && (JEMALLOC_VERSION_MINOR >= 1))
135 // Avoid asking excessive memory through the hook, in order to make better
136 // use of preallocated pages.
137 std::snprintf(command, sizeof(command),
138 "arena.%d.retain_grow_limit", m_arenaId);
139 size_t limit = 16ull << 20;
140 if (mallctl(command, nullptr, nullptr, &limit, sizeof(limit))) {
141 throw std::runtime_error{command};
144 #endif
147 template void ManagedArena<MultiRangeExtentAllocator>::create();
148 template void ManagedArena<MultiRangeExtentAllocator>::updateHook();
149 template size_t ManagedArena<MultiRangeExtentAllocator>::unusedSize();
150 template std::string ManagedArena<MultiRangeExtentAllocator>::reportStats();
152 template void ManagedArena<DefaultExtentAllocator>::create();
153 template void ManagedArena<DefaultExtentAllocator>::updateHook();
154 template void ManagedArena<RangeFallbackExtentAllocator>::create();
155 template void ManagedArena<RangeFallbackExtentAllocator>::updateHook();
159 #endif