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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_RUNTIME_RDS_H_
17 #define incl_HPHP_RUNTIME_RDS_H_
23 #include <type_traits>
24 #include <boost/variant.hpp>
25 #include <folly/Range.h>
26 #include <folly/Optional.h>
28 #include "hphp/runtime/base/types.h"
30 #include "hphp/util/alloc.h"
31 #include "hphp/util/type-scan.h"
33 #ifndef RDS_FIXED_PERSISTENT_BASE
34 // If RDS_FIXED_PERSISTENT_BASE is defined from compiler command line, don't
35 // mess with it. This makes it possible not to use fixed persistent base when
36 // linking against jemalloc 5+.
37 #ifndef incl_HPHP_UTIL_ALLOC_H_
38 #error "please include alloc.h before determining RDS implementation!"
40 #if USE_JEMALLOC_EXTENT_HOOKS
41 #define RDS_FIXED_PERSISTENT_BASE 1
51 struct ArrayAccessProfile
;
52 struct ArrayIterProfile
;
53 struct ArrayKindProfile
;
54 struct CallTargetProfile
;
58 struct IsTypeStructProfile
;
65 //////////////////////////////////////////////////////////////////////
67 namespace HPHP
{ namespace rds
{
69 //////////////////////////////////////////////////////////////////////
72 * The RDS (Request Data Segment) is a region of memory quickly accessible to
73 * each hhvm thread that is running a PHP request.
75 * Essentially this is a per-thread memory region, along with an internal
76 * dynamic link table to give the segment the same layout for each thread as
77 * new data is allocated.
79 * The RDS starts with a small header that is statically layed out, followed by
80 * the main "normal" segment, which is (logically) reset at the beginning of
81 * every request. The next section, called "local", contains unshared but still
82 * persistent data---this is data that is local to a thread but retains its
83 * value across requests. The final section contains shared "persistent" data,
84 * which is data that retains the same values across requests.
86 * The shared persistent segment is allocated RDS Layout:
87 * within [1G, 4G) offset from the persistent
88 * base (0 if RDS_FIXED_PERSISTENT_BASE is +-------------+ <-- tl_base
89 * defined as 1, which is safe if address from | Header |
90 * lower_malloc() is below 4G). +-------------+
92 * The normal region is perhaps analogous to | Normal |
93 * .bss, while the persistent region is | region |
94 * analogous to .rodata, and the local region | | growing higher
95 * is similar to .data. +-------------+ vvv
97 * When we're running in C++, the base of RDS +-------------+ ^^^
98 * is available via a thread local exported | Local | growing lower
99 * from this module (tl_base). When running | region |
100 * in JIT-compiled code, a machine register +-------------+ higher address
101 * is reserved to always point at the base of +-------------+
102 * RDS. | Persistent |
106 * Every element in the "normal" segment has an associated generation number,
107 * and the segment as a whole has a "current" generation number. A particular
108 * element is considered initialized if its generation number matches the
109 * segment's current generation number. If it does not, the element should be
110 * considered to contain garbage and should be initialized as needed by the
111 * element type. Once done, it must be manually marked as initialized.
113 * Allocation/linking API:
115 * You can allocate data from RDS in two primary ways, either by
116 * binding a Link, or anonymously. The distinction is whether the
117 * allocated space is associated with some unique key that allows it
118 * to be re-found for any new attempts to allocate that symbol.
120 * Anonymous allocations are created with rds::alloc. Non-anonymous
121 * allocations can be created in two ways:
123 * rds::bind(Symbol) uses an RDS-internal link table to find if
124 * there is an existing handle for the given symbol.
126 * rds::Link<T>::bind allows the caller to make use of the
127 * uniqueness of other runtime structure (e.g. the Class
128 * structure) to avoid having a special key and needing to do
129 * lookups in the internal RDS link table. The "key" for the
130 * allocation is the rds::Link<> object itself.
132 * Finally, you can allocate anonymous single bits at a time with
137 //////////////////////////////////////////////////////////////////////
140 * Lifetime-related hooks, exported to be called at the appropriate
141 * times. If shouldRegister is false the resultant rds will be excluded from
142 * the global rds list.
146 void threadInit(bool shouldRegister
= true);
147 void threadExit(bool shouldUnregister
= true);
151 * Flushing RDS means to madvise the memory away. Should only be done
152 * while a request is not in flight on this thread.
154 * This is done to conserve memory if a particular thread is unlikely
155 * to need to serve another PHP request for a while.
160 * Return the number of bytes that have been allocated from either
161 * persistent, local, or non-persistent RDS.
164 size_t usedLocalBytes();
165 size_t usedPersistentBytes();
167 folly::Range
<const char*> normalSection();
168 folly::Range
<const char*> localSection();
170 // Invoke F on each initialized allocation in the normal section. F is invoked
171 // with a void* pointer to the data, the size of the data, and the stored
173 template <typename F
> void forEachNormalAlloc(F
);
174 template <typename F
> void forEachLocalAlloc(F
);
177 * The thread-local pointer to the base of RDS.
179 extern __thread
void* tl_base
;
181 //////////////////////////////////////////////////////////////////////
184 * RDS symbols are centrally registered here.
186 * All StringData*'s below must be static strings.
190 * Symbols for rds::Link's.
192 struct LinkID
{ const char* type
; };
193 struct LinkName
{ const char* type
; LowStringPtr name
; };
196 * Class constant values are TypedValue's stored in RDS.
198 struct ClsConstant
{ LowStringPtr clsName
;
199 LowStringPtr cnsName
; };
202 * StaticMethod{F,}Cache allocations. These are used to cache static
203 * method dispatch targets in a given class context. The `name' field
204 * here is a string that encodes the target class, property, and
207 struct StaticMethod
{ LowStringPtr name
; };
208 struct StaticMethodF
{ LowStringPtr name
; };
211 * Profiling translations may store various kinds of junk under
212 * symbols that are keyed on translation id. These generally should
213 * go in Mode::Local or Mode::Persistent, depending on the use case.
215 #define RDS_PROFILE_SYMBOLS \
216 PR(ArrayAccessProfile) \
217 PR(ArrayIterProfile) \
218 PR(ArrayKindProfile) \
219 PR(CallTargetProfile) \
222 PR(IsTypeStructProfile) \
228 enum class ProfileKind
{
238 Profile(TransID transId
, Offset bcOff
, const StringData
* name
)
239 : kind
{ProfileKind::None
}
246 Profile(const jit::T*, TransID transId, \
247 Offset bcOff, const StringData* name) \
248 : kind{ProfileKind::T} \
263 * Static class properties in Mode::Local
266 struct SPropCache
{ LowPtr
<const Class
> cls
;
269 struct StaticMemoValue
{ FuncId funcId
; };
270 struct StaticMemoCache
{ FuncId funcId
; };
272 struct LSBMemoValue
{
273 LowPtr
<const Class
> cls
;
277 struct LSBMemoCache
{
278 LowPtr
<const Class
> cls
;
287 using Symbol
= boost::variant
<
302 //////////////////////////////////////////////////////////////////////
304 enum class Mode
: unsigned {
307 Persistent
= 1u << 2,
309 NonPersistent
= Normal
| Local
,
310 NonLocal
= Normal
| Persistent
,
311 NonNormal
= Local
| Persistent
,
313 Any
= Normal
| Local
| Persistent
,
316 using ModeU
= std::underlying_type
<Mode
>::type
;
318 template<Mode Mask
> constexpr bool maybe(Mode mode
) {
319 return !!(static_cast<ModeU
>(mode
) & static_cast<ModeU
>(Mask
));
322 template<Mode RHS
> constexpr bool in(Mode LHS
) {
323 return !(static_cast<ModeU
>(LHS
) & ~static_cast<ModeU
>(RHS
));
326 constexpr bool pure(Mode mask
) {
327 return !(static_cast<ModeU
>(mask
) & (static_cast<ModeU
>(mask
) - 1));
331 * Handles into Request Data Segment.
333 * For `Normal` and `Local` mode, it is an offset from rds::tl_base. The offset
334 * must be smaller than 1 << 30.
336 * For `Persistent` mode, the handle is an offset from `s_persistent_base`.
337 * When `RDS_FIXED_PERSISTENT_BASE` is defined, `s_persistent_base` is always 0,
338 * and the handle is the same as the address, and must be at least 1 << 30.
340 using Handle
= uint32_t;
341 constexpr Handle kUninitHandle
= 0;
342 constexpr Handle kBeingBound
= 1;
343 constexpr Handle kBeingBoundWithWaiters
= 2;
344 constexpr Handle kMinPersistentHandle
= 1u << 30;
345 constexpr Handle kMaxHandle
= std::numeric_limits
<Handle
>::max();
348 * Normal segment element generation numbers.
350 * The segment's current generation number will never be kInvalidGenNumber;
351 * thus, it is safe to use to mark an element as being uninitialized
354 using GenNumber
= uint8_t;
355 constexpr GenNumber kInvalidGenNumber
= 0;
358 * Tag passed to RDS handle initialization routines to indicate that the handle
359 * is known to be normal.
361 enum class NormalTag
{};
364 * rds::Link<T,M> is a thin, typed wrapper around an rds::Handle.
366 * Note that nothing prevents using non-POD types with this. But nothing here
367 * is going to run the constructor. (In the non-persistent region, the space
368 * for T will contain garbage at the start of each request.)
370 * Links are atomic types. All apis may be called concurrently by
371 * multiple threads, and the alloc() api guarantees only a single
372 * caller will actually allocate new space in RDS.
374 template<class T
, Mode M
>
376 explicit Link(Handle handle
= kUninitHandle
);
379 * We allow copy construction or assignment from a Link of a narrower Mode,
380 * but it is a compile-time error if we try to do it the other way.
382 Link(const Link
<T
,M
>&);
383 Link
<T
,M
>& operator=(const Link
<T
,M
>&);
385 template<Mode OM
> /* implicit */ Link(
387 typename
std::enable_if
<in
<M
>(OM
), bool>::type
= false);
389 template<Mode OM
> typename
std::enable_if
<in
<M
>(OM
),Link
<T
,M
>>::type
&
390 operator=(const Link
<T
,OM
>&);
393 * Ensure this Link is bound to an RDS allocation.
395 * Allocation is atomic and idempotent. This ensures that only one thread
396 * allocates the handle, and (in the cast of persistent handles) that the
397 * value is initialized as part of the operation. The effect is that other
398 * threads only ever see an unbound handle or a bound handle with a valid
401 * rds::Link's are "keyed" by context---generally meaning that they're owned
402 * by an object with an independent means of enforcing uniqueness. The `sym`
403 * argument should also be unique, but is used only for optimizations.
405 * If the Link is already bound, both `mode` and `Align` are ignored. If the
406 * mode is not persistent, `init_val` is ignored.
410 template<size_t Align
= alignof(T
)>
411 void bind(Mode mode
, Symbol sym
, const T
* init_val
= nullptr);
414 * Dereference a Link and access its RDS memory for the current thread.
418 T
& operator*() const;
419 T
* operator->() const;
423 * Whether this Link is bound to RDS memory or not (i.e., whether its
424 * internal handle is valid).
429 * Access to the underlying rds::Handle.
431 Handle
handle() const;
434 * Access to the underlying rds::Handle; returns kUninitHandle if
437 Handle
maybeHandle() const;
440 * Return the generation number of this element.
442 * Pre: bound() && isNormal()
444 GenNumber
genNumber() const;
447 * Return the handle for this element's generation number.
449 * Pre: bound() && isNormal()
451 Handle
genNumberHandle() const;
454 * Check whether this element is initialized.
456 * This is only an interesting designation for normal handles, where we need
457 * to check the generation number. Persistent handles are expected not to be
458 * "published" until they are in some sort of initialized state (which might
459 * simply be some nullish sentinel value).
466 * Manually mark this element as initialized or uninitialized.
468 * Pre: bound() && isNormal()
470 void markInit() const;
471 void markUninit() const;
474 * Initialize this element to `val'.
476 * Anything previously stored in the element is considered to be garbage, so
477 * it is not destructed. initWith() can thus be used to unconditionally
478 * initialize something that might already be inited, but only if it's
479 * trivially destructible.
483 void initWith(const T
& val
) const;
484 void initWith(T
&& val
) const;
487 * Check which segment this element resides in.
491 bool isNormal() const;
492 bool isLocal() const;
493 bool isPersistent() const;
496 * For access from the JIT only.
498 static constexpr size_t handleOff() {
499 return offsetof(Link
, m_handle
);
503 template<class OT
, Mode OM
> friend struct Link
;
507 Handle
raw() const { return m_handle
.load(std::memory_order_relaxed
); }
508 std::atomic
<Handle
> m_handle
;
512 * Return a bound link to memory from RDS, using the given Symbol.
514 * Mode indicates whether the memory should be placed in the persistent region
515 * or not, Align indicates the alignment requirements, and extraSize allows for
516 * allocating additional space beyond sizeof(T), for variable-length structures
517 * (not allowed for normal mode). All three arguments are ignored if there is
518 * already an allocation for the Symbol---they only affect the first caller for
521 * N indicates that the binding for `key' will always be in the "normal" RDS
522 * region; it is allowed to be true only if `key' is only ever bound with
525 template<class T
, Mode M
, size_t Align
= alignof(T
)>
526 Link
<T
,M
> bind(Symbol key
, size_t extraSize
= 0);
529 * Remove a bound link from RDS metadata. The actual space in RDS is
532 void unbind(Symbol
, Handle
);
535 * Try to bind to a symbol in RDS, returning an unbound link if the
536 * Symbol isn't already allocated in RDS. Mode and alignment are not
537 * specified---if the symbol is already bound, these are already
538 * fixed. The `T' must be the same `T' that the symbol is mapped to,
539 * if it's already mapped.
541 template<class T
, Mode M
= Mode::Any
>
542 Link
<T
,M
> attach(Symbol key
);
545 * Allocate anonymous memory from RDS.
547 * The memory is not keyed on any Symbol, so the handle in the returned Link
550 template<class T
, Mode M
= Mode::Normal
, size_t Align
= alignof(T
)>
554 * Allocate a single anonymous bit from non-persistent RDS. The bit
555 * can be manipulated with testAndSetBit().
557 * Note: the returned integer is *not* an rds::Handle.
560 bool testAndSetBit(size_t bit
);
562 folly::Optional
<Symbol
> reverseLink(Handle handle
);
564 //////////////////////////////////////////////////////////////////////
567 * Retrieve the current generation number for the normal segment.
569 GenNumber
currentGenNumber();
572 * Retrieve the handle for the current generation number for the normal segment.
574 Handle
currentGenNumberHandle();
576 //////////////////////////////////////////////////////////////////////
579 * Dereference an un-typed rds::Handle which is guaranteed to be in one of the
580 * `modes`, optionally specifying a specific RDS base to use.
582 template<class T
, Mode M
> T
& handleToRef(Handle h
);
583 template<class T
, Mode M
> T
& handleToRef(void* base
, Handle h
);
586 * Conversion between a pointer and an rds::Handle which is guaranteed to be in
587 * one of the modes specified in `M`.
589 template<class T
= void, Mode M
> T
* handleToPtr(Handle h
);
590 template<Mode M
> Handle
ptrToHandle(const void* ptr
);
591 template<Mode M
> Handle
ptrToHandle(uintptr_t ptr
);
594 * Whether `handle' looks valid---i.e., whether it lies within the RDS bounds.
596 bool isValidHandle(Handle handle
);
599 * Whether `handle' is from the normal RDS region.
601 * Pre: isValidHandle(handle)
603 bool isNormalHandle(Handle handle
);
606 * Whether `handle' is from the local RDS region.
608 * Pre: isValidHandle(handle)
610 bool isLocalHandle(Handle handle
);
613 * Whether `handle' is from the persistent RDS region.
615 * Pre: isValidHandle(handle)
617 bool isPersistentHandle(Handle handle
);
620 * The generation number associated with `handle'.
622 * Pre: isNormalHandle(handle)
624 GenNumber
genNumberOf(Handle handle
);
627 * The handle for the generation number associated with `handle'.
629 * Pre: isNormalHandle(handle)
631 Handle
genNumberHandleFrom(Handle handle
);
634 * Whether the handle has been bound.
636 bool isHandleBound(Handle handle
);
639 * Whether the element associated with `handle' is initialized.
641 bool isHandleInit(Handle handle
);
642 bool isHandleInit(Handle handle
, NormalTag
);
645 * Mark the element associated with `handle' as being initialized.
647 * Pre: isNormalHandle(handle)
649 void initHandle(Handle handle
);
652 * Marks the element associated with the supplied handle as being
653 * uninitialized. This happens automatically after every request, but can be
654 * done manually with this.
656 * Pre: isNormalHandle(handle)
658 void uninitHandle(Handle handle
);
661 * Used to record information about the rds handle h in the
662 * perf-data-pid.map (if enabled).
663 * The type indicates the type of entry (eg ClsConstant), and the
664 * msg identifies this particular entry (eg function-name:local-name)
666 void recordRds(Handle h
, size_t size
,
667 folly::StringPiece type
, folly::StringPiece msg
);
668 void recordRds(Handle h
, size_t size
, const Symbol
& sym
);
670 void visitSymbols(std::function
<void(const Symbol
&,Handle
,uint32_t)> fun
);
673 * Return a list of all the tl_bases for any threads that are using RDS
675 std::vector
<void*> allTLBases();
677 //////////////////////////////////////////////////////////////////////
679 extern rds::Link
<bool, Mode::Persistent
> s_persistentTrue
;
683 #include "hphp/runtime/base/rds-inl.h"