Use RATs from HHBBC in init_use_vars
[hiphop-php.git] / hphp / runtime / vm / type-profile.cpp
blobaacb15796c7d87a50e74918b3acb3f839df5dc9e
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2015 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/runtime/vm/type-profile.h"
19 #include <atomic>
20 #include <cstdint>
21 #include <queue>
22 #include <utility>
24 #include <tbb/concurrent_hash_map.h>
26 #include "hphp/util/lock.h"
27 #include "hphp/util/logger.h"
28 #include "hphp/util/trace.h"
30 #include "hphp/runtime/base/runtime-option.h"
31 #include "hphp/runtime/base/stats.h"
32 #include "hphp/runtime/base/thread-info.h"
33 #include "hphp/runtime/vm/func.h"
34 #include "hphp/runtime/vm/jit/mc-generator.h"
35 #include "hphp/runtime/vm/jit/write-lease.h"
36 #include "hphp/runtime/vm/treadmill.h"
37 #include "hphp/runtime/vm/jit/relocation.h"
38 #include "hphp/util/atomic-vector.h"
40 namespace HPHP {
42 TRACE_SET_MOD(typeProfile);
44 //////////////////////////////////////////////////////////////////////
46 void profileInit() {
50 * Warmup/profiling.
52 * In cli mode, we only record samples if we're in recording to replay later.
54 * In server mode, we exclude warmup document requests from profiling, then
55 * record samples for EvalJitProfileInterpRequests standard requests.
57 bool __thread profileOn = false;
58 static bool warmingUp;
59 static int64_t numRequests;
60 bool __thread standardRequest = true;
61 static std::atomic<bool> singleJitLock;
62 static std::atomic<int> singleJitRequests;
63 static std::atomic<int> relocateRequests;
65 void setRelocateRequests(int32_t n) {
66 relocateRequests.store(n);
69 namespace {
71 using FuncProfileCounters = tbb::concurrent_hash_map<FuncId,uint32_t>;
72 FuncProfileCounters s_func_counters;
76 void profileWarmupStart() {
77 warmingUp = true;
80 void profileWarmupEnd() {
81 warmingUp = false;
84 typedef std::pair<const Func*, uint32_t> FuncHotness;
85 static bool comp(const FuncHotness& a, const FuncHotness& b) {
86 return a.second > b.second;
90 * Set AttrHot on hot functions. Sort all functions by their profile count, and
91 * set AttrHot to the top Eval.HotFuncCount functions.
93 static Mutex syncLock;
94 static void setHotFuncAttr() {
95 static bool synced = false;
96 if (synced) return;
98 Lock lock(syncLock);
99 if (synced) return;
102 * s_treadmill forces any Funcs that are being destroyed to go through a
103 * treadmill pass, to make sure we won't try to dereference something that's
104 * being pulled out from under us.
106 Func::s_treadmill = true;
107 SCOPE_EXIT {
108 Func::s_treadmill = false;
111 if (RuntimeOption::EvalHotFuncCount) {
112 std::priority_queue<FuncHotness,
113 std::vector<FuncHotness>,
114 bool(*)(const FuncHotness& a, const FuncHotness& b)>
115 queue(comp);
117 Func::getFuncVec().foreach([&](const Func* f) {
118 if (!f) return;
119 auto const profCounter = [&]() -> uint32_t {
120 FuncProfileCounters::const_accessor acc;
121 if (s_func_counters.find(acc, f->getFuncId())) {
122 return acc->second;
124 return 0;
125 }();
126 auto fh = FuncHotness(f, profCounter);
127 if (queue.size() >= RuntimeOption::EvalHotFuncCount) {
128 if (!comp(fh, queue.top())) return;
129 queue.pop();
131 queue.push(fh);
134 while (queue.size()) {
135 auto f = queue.top().first;
136 queue.pop();
137 const_cast<Func*>(f)->setAttrs(f->attrs() | AttrHot);
141 // We won't need the counters anymore. But there might be requests in flight
142 // that still thought they were profiling, so we need to clear it on the
143 // treadmill.
144 Treadmill::enqueue([&] {
145 FuncProfileCounters newMap(0);
146 swap(s_func_counters, newMap);
149 synced = true;
152 void profileIncrementFuncCounter(const Func* f) {
153 FuncProfileCounters::accessor acc;
154 auto const value = FuncProfileCounters::value_type(f->getFuncId(), 0);
155 s_func_counters.insert(acc, value);
156 ++acc->second;
159 int64_t requestCount() {
160 return numRequests;
163 static inline bool doneProfiling() {
164 return (numRequests >= RuntimeOption::EvalJitProfileInterpRequests) ||
165 (RuntimeOption::ClientExecutionMode() &&
166 !RuntimeOption::EvalJitProfileRecord);
169 static inline bool profileThisRequest() {
170 if (warmingUp) return false;
171 if (doneProfiling()) return false;
172 if (RuntimeOption::ServerExecutionMode()) return true;
173 return RuntimeOption::EvalJitProfileRecord;
176 void profileRequestStart() {
177 bool p = profileThisRequest();
178 if (profileOn && !p) {
179 // If we are turning off profiling, set AttrHot on
180 // functions that are "hot".
181 setHotFuncAttr();
183 profileOn = p;
185 bool okToJit = !warmingUp && !p;
186 if (okToJit) {
187 jit::Lease::mayLock(true);
188 if (singleJitRequests < RuntimeOption::EvalNumSingleJitRequests) {
189 bool flag = false;
190 if (!singleJitLock.compare_exchange_strong(flag, true)) {
191 jit::Lease::mayLock(false);
195 if (standardRequest != okToJit) {
196 standardRequest = okToJit;
197 if (!ThreadInfo::s_threadInfo.isNull()) {
198 ThreadInfo::s_threadInfo->m_reqInjectionData.updateJit();
202 if (standardRequest && relocateRequests > 0 && !--relocateRequests) {
203 jit::liveRelocate(true);
207 void profileRequestEnd() {
208 if (warmingUp) return;
209 numRequests++; // racy RMW; ok to miss a rare few.
210 if (standardRequest &&
211 singleJitRequests < RuntimeOption::EvalNumSingleJitRequests &&
212 jit::Lease::mayLock(true)) {
213 assert(singleJitLock);
214 ++singleJitRequests;
215 singleJitLock = false;
216 if (RuntimeOption::ServerExecutionMode()) {
217 Logger::Warning("Finished singleJitRequest %d", singleJitRequests.load());