Switch to SharedMutex in SharedProfileEntry
[hiphop-php.git] / hphp / runtime / vm / jit / shared-profile.h
blob623965db597843b76cd00e89e8f98e08635b84f8
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/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>
34 #include <typeindex>
35 #include <utility>
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);
51 template <typename T>
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
55 // inlineability.
56 folly::SharedMutex mutex;
57 T value;
59 template <typename F>
60 void update(F&& f) {
61 std::unique_lock<folly::SharedMutex> lock(mutex, std::try_to_lock);
62 if (!lock.owns_lock()) return;
63 f(value);
67 template <typename T>
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 //////////////////////////////////////////////////////////////////////////////
77 template<class T>
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.
92 * Pre: optimizing()
94 T data() const {
95 assertx(optimizing());
96 auto result = T{};
97 for (auto const link : m_links) {
98 if (!link) continue;
99 std::lock_guard<folly::SharedMutex> _(link->mutex);
100 T::reduce(result, link->value);
102 return result;
106 * Access this profile's entry in order to update it.
108 * Pre: profiling()
110 Entry* entry() const {
111 assertx(profiling());
112 assertx(m_links.size() == 1);
113 assertx(m_links[0] != nullptr);
114 return m_links[0];
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) {
124 return false;
126 for (auto const link : m_links) {
127 if (link) return true;
129 return false;
131 bool profiling() const {
132 return m_kind == TransKind::Profile;
135 private:
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;
145 return sk.offset();
148 static Entry* createEntry(TransID profTransID,
149 TransKind kind,
150 Offset bcOff,
151 const StringData* name) {
152 switch (kind) {
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:
167 return nullptr;
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.
185 if (tids.empty()) {
186 result.push_back(createEntry(kInvalidTransID, kind, bcOff, name));
188 for (auto const tid : tids) {
189 result.push_back(createEntry(tid, kind, bcOff, name));
191 return result;
194 private:
195 const TransKind m_kind;
196 const Links m_links;
199 ///////////////////////////////////////////////////////////////////////////////