declare_folded_class NO LONGER _in_file
[hiphop-php.git] / hphp / util / managed-arena.h
blob9647aca8902e6745267699506a8dac13abd17ed4
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 #pragma once
19 #include "hphp/util/alloc-defs.h"
20 #include "hphp/util/bump-mapper.h"
21 #include "hphp/util/extent-hooks.h"
22 #include <limits>
23 #include <string>
25 #if USE_JEMALLOC_EXTENT_HOOKS
27 namespace HPHP { namespace alloc {
29 ////////////////////////////////////////////////////////////////////////////////
31 /**
32 * ManagedArena is a wrapper around jemalloc arena with customized extent hooks.
33 * The extent hook is a set of callbacks jemalloc uses to interact with the OS
34 * when managing memory mappings.
36 * For various purposes, we want to control the properties of the underlying
37 * memory in a particular arena, such as address range, physical placement on
38 * NUMA nodes, or huge pages. The extent alloc hook comes in handy for the
39 * purpose, and is wrapped in the ExtentAllocator policy class.
41 template <typename ExtentAllocator>
42 struct ManagedArena : public ExtentAllocator {
43 private:
44 // Constructor forwards all arguments. Use `CreateAt()` or `AttachTo()` to
45 // create instances.
46 template<typename... Args>
47 explicit ManagedArena(Args&&... args)
48 : ExtentAllocator(std::forward<Args>(args)...) {}
50 void create();
51 void updateHook();
53 ManagedArena(const ManagedArena&) = delete;
54 ManagedArena& operator=(const ManagedArena&) = delete;
55 // Don't run the destructor, as we are not good at managing arena lifetime.
56 ~ManagedArena() = delete;
58 public:
59 unsigned id() const {
60 return m_arenaId;
63 void bindCurrentThread() {
64 mallctlWrite("thread.arena", id());
67 // For stats reporting
68 size_t unusedSize();
69 std::string reportStats();
71 template<typename... Args>
72 static ManagedArena* CreateAt(void* addr, Args&&... args) {
73 auto arena = new (addr) ManagedArena(std::forward<Args>(args)...);
74 arena->create();
75 arena->updateHook();
76 return arena;
79 template<typename... Args>
80 static ManagedArena* AttachTo(void* addr, unsigned id, Args&&... args) {
81 auto arena = new (addr) ManagedArena(std::forward<Args>(args)...);
82 arena->m_arenaId = id;
83 arena->updateHook();
84 return arena;
87 protected:
88 static constexpr auto kInvalidArena = std::numeric_limits<unsigned>::max();
89 unsigned m_arenaId{kInvalidArena};
92 using RangeArena = alloc::ManagedArena<alloc::MultiRangeExtentAllocator>;
93 using LowArena = RangeArena;
94 using HighArena = RangeArena;
95 static_assert(alignof(RangeArena) <= 64, "");
96 using RangeArenaStorage = std::aligned_storage<sizeof(RangeArena), 64>::type;
97 extern RangeArenaStorage g_lowerArena;
98 extern RangeArenaStorage g_lowArena;
99 extern RangeArenaStorage g_lowColdArena;
100 extern RangeArenaStorage g_highArena;
101 extern RangeArenaStorage g_coldArena;
103 #ifndef MAX_MANAGED_ARENA_COUNT
104 #define MAX_MANAGED_ARENA_COUNT 16
105 #endif
106 static_assert(MAX_MANAGED_ARENA_COUNT >= 1, "");
107 // All ManagedArena's represented as an array of pair<id, pointer>. Each
108 // pointer can be casted to the underlying ExtentAllocator/Arena. We use this
109 // to access the state of ExtentAllocators in extent hooks. An id of zero
110 // indicates an empty entry. If the arena doesn't have a custom extent hook,
111 // the arena won't be registered here.
112 using ArenaArray = std::array<std::pair<unsigned, void*>,
113 MAX_MANAGED_ARENA_COUNT>;
114 extern ArenaArray g_arenas;
115 template<typename T> inline T* GetByArenaId(unsigned id) {
116 for (auto i : g_arenas) {
117 if (i.first == id) {
118 return static_cast<T*>(i.second);
121 return nullptr;
124 inline LowArena* lowArena() {
125 auto p = reinterpret_cast<LowArena*>(&g_lowArena);
126 if (p->id()) return p;
127 return nullptr;
130 inline HighArena* highArena() {
131 auto p = reinterpret_cast<HighArena*>(&g_highArena);
132 if (p->id()) return p;
133 return nullptr;
136 using PreMappedArena = alloc::ManagedArena<alloc::RangeFallbackExtentAllocator>;
138 extern PreMappedArena* g_arena0;
139 extern std::vector<PreMappedArena*> g_local_arenas; // keyed by numa node id
143 using DefaultArena = alloc::ManagedArena<alloc::DefaultExtentAllocator>;
146 * Make sure we have at least `count` extra arenas, with the same number of
147 * extra arenas for each NUMA node. Returns whether we have enough arenas to
148 * meet the required count. This function tries to create the extra arenas at
149 * the first time it is called with nonzero count. Subsequent calls won't
150 * change the number of extra arenas.
152 bool setup_extra_arenas(unsigned count);
154 * Get the next extra arena on the specified NUMA node.
156 DefaultArena* next_extra_arena(int node);
160 #endif // USE_JEMALLOC_EXTENT_HOOKS