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/runtime/base/rds.h"
20 #include "hphp/runtime/base/runtime-option.h"
21 #include "hphp/runtime/base/types.h"
23 #include "hphp/runtime/vm/jit/bc-marker.h"
24 #include "hphp/runtime/vm/jit/print.h"
25 #include "hphp/runtime/vm/jit/translator.h"
26 #include "hphp/runtime/vm/jit/types.h"
28 #include "hphp/util/assertions.h"
29 #include "hphp/util/tiny-vector.h"
31 #include <folly/SharedMutex.h>
32 #include <tbb/concurrent_hash_map.h>
37 namespace HPHP
{ namespace jit
{
39 struct ProfDataDeserializer
;
40 struct ProfDataSerializer
;
42 //////////////////////////////////////////////////////////////////////////////
44 char* fetchSharedProfile(
45 TransID tid
, Offset bcOff
, const StringData
* name
,
46 bool create
, std::type_index type
);
48 void deserializeSharedProfiles(ProfDataDeserializer
& des
);
49 void serializeSharedProfiles(ProfDataSerializer
& ser
);
52 struct alignas(64) SharedProfileEntry
{
53 // An exclusive mutex would be sufficient here, but use SharedMutex for the
54 // small footprint (so more of value can fit in the same cache line) and
56 folly::SharedMutex mutex
;
61 std::unique_lock
<folly::SharedMutex
> lock(mutex
, std::try_to_lock
);
62 if (!lock
.owns_lock()) return;
68 SharedProfileEntry
<T
>* fetchSharedProfile(
69 TransID tid
, Offset bcOff
, const StringData
* name
, bool create
) {
70 auto const type
= std::type_index(typeid(T
));
71 auto const result
= fetchSharedProfile(tid
, bcOff
, name
, create
, type
);
72 return reinterpret_cast<SharedProfileEntry
<T
>*>(result
);
75 //////////////////////////////////////////////////////////////////////////////
78 struct SharedProfile
{
79 using Entry
= SharedProfileEntry
<T
>;
80 using Links
= TinyVector
<Entry
*, 1>;
82 SharedProfile(const TransContext
& context
,
83 const BCMarker
& marker
,
84 const StringData
* name
)
85 : m_kind(context
.kind
)
86 , m_links(createLinks(context
, marker
, name
))
90 * Access the data we collected during profiling.
95 assertx(optimizing());
97 for (auto const link
: m_links
) {
99 std::lock_guard
<folly::SharedMutex
> _(link
->mutex
);
100 T::reduce(result
, link
->value
);
106 * Access this profile's entry in order to update it.
110 Entry
* entry() const {
111 assertx(profiling());
112 assertx(m_links
.size() == 1);
113 assertx(m_links
[0] != nullptr);
118 * Query whether we are profiling or optimizing via this handle to a given
119 * shared profile. It's possible that neither is true, e.g. if we're JIT-ing
120 * a live translation, or an optimized one without a link from profiling.
122 bool optimizing() const {
123 if (m_kind
!= TransKind::Optimize
) {
126 for (auto const link
: m_links
) {
127 if (link
) return true;
131 bool profiling() const {
132 return m_kind
== TransKind::Profile
;
136 static constexpr Offset kPrologueOffset
= -1;
137 static constexpr Offset kFuncEntryOffset
= -2;
139 static Offset
bcOffForProfileKey(SrcKey sk
) {
140 // Use a placeholder value for prologues and function entries, as they
141 // are not part of a bytecode at any offset. Profiling of prologues for
142 // different number of arguments is still differentiated by profTransID.
143 if (sk
.prologue()) return kPrologueOffset
;
144 if (sk
.funcEntry()) return kFuncEntryOffset
;
148 static Entry
* createEntry(TransID profTransID
,
151 const StringData
* name
) {
153 case TransKind::Profile
:
154 return fetchSharedProfile
<T
>(profTransID
, bcOff
, name
, true);
156 case TransKind::Optimize
:
157 if (!isValidTransID(profTransID
)) return nullptr;
158 return fetchSharedProfile
<T
>(profTransID
, bcOff
, name
, false);
160 case TransKind::Anchor
:
161 case TransKind::Interp
:
162 case TransKind::Live
:
163 case TransKind::LivePrologue
:
164 case TransKind::ProfPrologue
:
165 case TransKind::OptPrologue
:
166 case TransKind::Invalid
:
169 always_assert(false);
172 static Links
createLinks(const TransContext
& context
,
173 const BCMarker
& marker
,
174 const StringData
* name
) {
175 auto const kind
= context
.kind
;
176 auto const profiling
= context
.kind
== TransKind::Profile
;
177 auto const& tids
= profiling
? context
.transIDs
: marker
.profTransIDs();
178 auto const bcOff
= bcOffForProfileKey(marker
.sk());
180 auto result
= Links
{};
181 result
.reserve(std::max(tids
.size(), static_cast<size_t>(1)));
183 // NB: tids can be empty during tracelet formation. In this case, create
184 // a dummy link corresponding to kInvalidTransID.
186 result
.push_back(createEntry(kInvalidTransID
, kind
, bcOff
, name
));
188 for (auto const tid
: tids
) {
189 result
.push_back(createEntry(tid
, kind
, bcOff
, name
));
195 const TransKind m_kind
;
199 ///////////////////////////////////////////////////////////////////////////////