2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
19 #include "hphp/util/alloc-defs.h"
20 #include "hphp/util/bump-mapper.h"
21 #include "hphp/util/extent-hooks.h"
25 #if USE_JEMALLOC_EXTENT_HOOKS
27 namespace HPHP
{ namespace alloc
{
29 ////////////////////////////////////////////////////////////////////////////////
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
{
44 // Constructor forwards all arguments. Use `CreateAt()` or `AttachTo()` to
46 template<typename
... Args
>
47 explicit ManagedArena(Args
&&... args
)
48 : ExtentAllocator(std::forward
<Args
>(args
)...) {}
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;
63 void bindCurrentThread() {
64 mallctlWrite("thread.arena", id());
67 // For stats reporting
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
)...);
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
;
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
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
) {
118 return static_cast<T
*>(i
.second
);
124 inline LowArena
* lowArena() {
125 auto p
= reinterpret_cast<LowArena
*>(&g_lowArena
);
126 if (p
->id()) return p
;
130 inline HighArena
* highArena() {
131 auto p
= reinterpret_cast<HighArena
*>(&g_highArena
);
132 if (p
->id()) return p
;
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