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 +----------------------------------------------------------------------+
17 #include "hphp/util/extent-hooks.h"
19 #include "hphp/util/assertions.h"
20 #include "hphp/util/managed-arena.h"
21 #include <folly/portability/SysMman.h>
23 #if USE_JEMALLOC_EXTENT_HOOKS
25 namespace HPHP
{ namespace alloc
{
27 // Trivial jemalloc extent hooks. If a hook always returns true (indicating
28 // failure), setting it to NULL can be more efficient.
31 extent_commit(extent_hooks_t
* /*extent_hooks*/, void* /*addr*/, size_t /*size*/,
32 size_t /*offset*/, size_t /*length*/, unsigned /*arena_ind*/) {
37 extent_purge(extent_hooks_t
* /*extent_hooks*/, void* addr
, size_t size
,
38 size_t offset
, size_t length
, unsigned /*arena_ind*/) {
39 // This function should return false upon success, which is the case when
41 return madvise((char*)addr
+ offset
, length
, MADV_DONTNEED
);
45 extent_purge_lazy(extent_hooks_t
* /*extent_hooks*/, void* addr
, size_t size
,
46 size_t offset
, size_t length
, unsigned /*arena_ind*/) {
48 return madvise((char*)addr
+ offset
, length
, MADV_FREE
);
50 return madvise((char*)addr
+ offset
, length
, MADV_DONTNEED
);
54 static bool extent_split(extent_hooks_t
* /*extent_hooks*/, void* /*addr*/,
55 size_t /*size*/, size_t /*sizea*/, size_t /*sizeb*/,
56 bool /*comitted*/, unsigned /*arena_ind*/) {
60 static bool extent_merge(extent_hooks_t
* /*extent_hooks*/, void* /*addra*/,
61 size_t /*sizea*/, void* /*addrb*/, size_t /*sizeb*/,
62 bool /*committed*/, unsigned /*arena_ind*/) {
66 extent_hooks_t
MultiRangeExtentAllocator::s_hooks
{
67 MultiRangeExtentAllocator::extent_alloc
,
72 extent_purge_lazy
, // purge_lazy
73 extent_purge
, // purge_forced
78 void MultiRangeExtentAllocator::appendMapper(RangeMapper
* m
) {
79 for (auto& p
: m_mappers
) {
85 throw std::runtime_error
{"too many mappers (check kMaxMapperCount)"};
88 size_t MultiRangeExtentAllocator::maxCapacity() const {
90 for (auto& p
: m_mappers
) {
94 result
+= p
->getRangeState().capacity();
100 void* MultiRangeExtentAllocator::
101 extent_alloc(extent_hooks_t
* extent_hooks
, void* addr
,
102 size_t size
, size_t alignment
, bool* zero
,
103 bool* commit
, unsigned arena_ind
) {
104 assertx(extent_hooks
== &MultiRangeExtentAllocator::s_hooks
);
105 if (addr
!= nullptr) {
109 assert(folly::isPowTwo(alignment
));
110 assertx(alignment
<= (2u << 20));
112 auto extAlloc
= GetByArenaId
<MultiRangeExtentAllocator
>(arena_ind
);
113 for (auto rangeMapper
: extAlloc
->m_mappers
) {
114 if (!rangeMapper
) return nullptr;
115 // RangeMapper::addMappingImpl() holds the lock on RangeState when adding
116 // new mappings, so no additional locking is needed here.
117 if (auto addr
= rangeMapper
->alloc(size
, alignment
)) {
118 extAlloc
->m_allocatedSize
.fetch_add(size
, std::memory_order_relaxed
);
126 extent_hooks_t
RangeFallbackExtentAllocator::s_hooks
{
127 RangeFallbackExtentAllocator::extent_alloc
,
128 nullptr, // dalloc, always fail with opt_retain
129 RangeFallbackExtentAllocator::extent_destroy
,
130 RangeFallbackExtentAllocator::extent_commit
,
131 nullptr, // decommit, no need with vm_overcommit
132 RangeFallbackExtentAllocator::extent_purge_lazy
,
133 RangeFallbackExtentAllocator::extent_purge
,
134 extent_split
, // always split
135 extent_merge
// always merge
139 void* RangeFallbackExtentAllocator::
140 extent_alloc(extent_hooks_t
* extent_hooks
, void* addr
,
141 size_t size
, size_t alignment
, bool* zero
,
142 bool* commit
, unsigned arena_ind
) {
143 assertx(extent_hooks
== &RangeFallbackExtentAllocator::s_hooks
);
144 auto extAlloc
= GetByArenaId
<RangeFallbackExtentAllocator
>(arena_ind
);
145 auto fallback_hooks
= extAlloc
->m_fallback_hooks
;
146 constexpr size_t kAlign
= 2u << 20;
147 if (addr
!= nullptr || alignment
> kAlign
) {
148 // Let the default hook handle weird cases.
149 return fallback_hooks
->alloc(extent_hooks
, addr
, size
, alignment
,
150 zero
, commit
, arena_ind
);
152 if (auto addr
= extAlloc
->getLowMapper()->alloc(size
, alignment
)) return addr
;
153 return fallback_hooks
->alloc(extent_hooks
, addr
, size
, alignment
,
154 zero
, commit
, arena_ind
);
157 void RangeFallbackExtentAllocator::
158 extent_destroy(extent_hooks_t
* extent_hooks
, void* addr
, size_t size
,
159 bool committed
, unsigned arena_ind
) {
160 auto extAlloc
= GetByArenaId
<RangeFallbackExtentAllocator
>(arena_ind
);
161 if (extAlloc
->inRange(addr
)) return;
162 auto fallback_hooks
= extAlloc
->m_fallback_hooks
;
163 return fallback_hooks
->destroy(extent_hooks
, addr
, size
,
164 committed
, arena_ind
);
167 bool RangeFallbackExtentAllocator::
168 extent_commit(extent_hooks_t
* extent_hooks
, void* addr
, size_t size
,
169 size_t offset
, size_t length
, unsigned arena_ind
) {
170 auto extAlloc
= GetByArenaId
<RangeFallbackExtentAllocator
>(arena_ind
);
171 if (extAlloc
->inRange(addr
)) return false;
172 auto fallback_hooks
= extAlloc
->m_fallback_hooks
;
173 return fallback_hooks
->commit(extent_hooks
, addr
, size
,
174 offset
, length
, arena_ind
);
177 bool RangeFallbackExtentAllocator::
178 extent_purge_lazy(extent_hooks_t
* extent_hooks
, void* addr
, size_t size
,
179 size_t offset
, size_t length
, unsigned arena_ind
) {
180 auto extAlloc
= GetByArenaId
<RangeFallbackExtentAllocator
>(arena_ind
);
181 if (extAlloc
->inRange(addr
)) return true; // never purge
182 auto fallback_hooks
= extAlloc
->m_fallback_hooks
;
183 auto fallback_purge
= fallback_hooks
->purge_lazy
;
184 if (!fallback_purge
) return true;
185 return fallback_purge(extent_hooks
, addr
, size
, offset
, length
, arena_ind
);
188 bool RangeFallbackExtentAllocator::
189 extent_purge(extent_hooks_t
* extent_hooks
, void* addr
, size_t size
,
190 size_t offset
, size_t length
, unsigned arena_ind
) {
191 auto extAlloc
= GetByArenaId
<RangeFallbackExtentAllocator
>(arena_ind
);
192 if (extAlloc
->inRange(addr
)) return true; // never purge
193 auto fallback_hooks
= extAlloc
->m_fallback_hooks
;
194 auto fallback_purge
= fallback_hooks
->purge_forced
;
195 if (!fallback_purge
) return true;
196 return fallback_purge(extent_hooks
, addr
, size
, offset
, length
, arena_ind
);