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/runtime/vm/type-profile.h"
19 #include "hphp/runtime/base/execution-context.h"
20 #include "hphp/runtime/base/init-fini-node.h"
21 #include "hphp/runtime/base/request-info.h"
22 #include "hphp/runtime/base/runtime-option.h"
23 #include "hphp/runtime/base/stats.h"
24 #include "hphp/runtime/ext/server/ext_server.h"
25 #include "hphp/runtime/vm/func.h"
26 #include "hphp/runtime/vm/jit/mcgen-translate.h"
27 #include "hphp/runtime/vm/jit/relocation.h"
28 #include "hphp/runtime/vm/jit/tc.h"
29 #include "hphp/runtime/vm/jit/write-lease.h"
30 #include "hphp/runtime/vm/treadmill.h"
31 #include "hphp/util/atomic-vector.h"
32 #include "hphp/util/boot-stats.h"
33 #include "hphp/util/lock.h"
34 #include "hphp/util/logger.h"
35 #include "hphp/util/struct-log.h"
36 #include "hphp/util/trace.h"
46 TRACE_SET_MOD(typeProfile
);
48 //////////////////////////////////////////////////////////////////////
53 * In cli mode, we only record samples if we're in recording to replay later.
55 * In server mode, we exclude warmup document requests from profiling.
58 RDS_LOCAL_NO_CHECK(TypeProfileLocals
, rl_typeProfileLocals
)
59 {TypeProfileLocals
{}};
64 std::atomic
<int64_t> numRequests
;
65 std::atomic
<int> relocateRequests
;
68 * RFH, or "requests served in first hour" is used as a performance metric that
69 * is affected by warmup speed as well as steady-state performance. For every
70 * element n in this list, we log a point along the RFH curve, which is the
71 * total number of requests served when server uptime hits n seconds.
73 constexpr std::array
<uint32_t, 32> rfhBuckets
= {{
74 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, // every 30s, to 5m
75 360, 420, 480, 540, 600, // every 1m, to 10m
76 900, 1200, 1500, 1800, 2100, 2400, 2700, 3000, 3300, 3600, // every 5m, to 1h
77 4500, 5400, 6300, 7200, // every 15m, to 2h
78 3 * 3600, 4 * 3600, 6 * 3600
80 std::atomic
<size_t> nextRFH
{0};
84 ProfileNonVMThread::ProfileNonVMThread() {
85 always_assert(!rl_typeProfileLocals
->nonVMThread
);
86 rl_typeProfileLocals
->nonVMThread
= true;
89 ProfileNonVMThread::~ProfileNonVMThread() {
90 rl_typeProfileLocals
->nonVMThread
= false;
93 void setRelocateRequests(int32_t n
) {
94 relocateRequests
.store(n
);
97 void profileWarmupStart() {
101 void profileWarmupEnd() {
105 typedef std::pair
<const Func
*, uint32_t> FuncHotness
;
106 static bool comp(const FuncHotness
& a
, const FuncHotness
& b
) {
107 return a
.second
> b
.second
;
110 int64_t requestCount() {
111 return numRequests
.load(std::memory_order_relaxed
);
114 static inline RequestKind
getRequestKind() {
115 if (rl_typeProfileLocals
->nonVMThread
) return RequestKind::NonVM
;
116 if (warmingUp
) return RequestKind::Warmup
;
117 return RequestKind::Standard
;
120 void profileRequestStart() {
121 rl_typeProfileLocals
->requestKind
= getRequestKind();
123 // Force the request to use interpreter (not even running jitted code) during
124 // retranslateAll when we need to dump out precise profile data.
125 auto const forceInterp
= jit::mcgen::pendingRetranslateAllScheduled() &&
126 RuntimeOption::DumpPreciseProfData
;
127 bool okToJit
= !forceInterp
&&
128 (rl_typeProfileLocals
->requestKind
== RequestKind::Standard
);
129 if (!RequestInfo::s_requestInfo
.isNull()) {
130 if (RID().isJittingDisabled()) {
132 } else if (!okToJit
) {
133 RID().setJittingDisabled(true);
136 jit::setMayAcquireLease(okToJit
);
138 // Force interpretation if needed.
139 if (rl_typeProfileLocals
->forceInterpret
!= forceInterp
) {
140 rl_typeProfileLocals
->forceInterpret
= forceInterp
;
141 if (!RequestInfo::s_requestInfo
.isNull()) {
146 if (okToJit
&& relocateRequests
> 0 && !--relocateRequests
) {
147 jit::tc::liveRelocate(true);
151 static void checkRFH(int64_t finished
) {
152 auto i
= nextRFH
.load(std::memory_order_relaxed
);
153 if (i
== rfhBuckets
.size() || !StructuredLog::enabled()) {
157 auto const uptime
= f_server_uptime();
158 if (uptime
== -1) return;
159 assertx(uptime
>= 0);
161 while (i
< rfhBuckets
.size() && uptime
>= rfhBuckets
[i
]) {
162 assertx(i
== 0 || rfhBuckets
[i
- 1] < rfhBuckets
[i
]);
163 if (!nextRFH
.compare_exchange_strong(i
, i
+ 1, std::memory_order_relaxed
)) {
164 // Someone else reported the sample at i. Try again with the current
169 // "bucket" and "uptime" will always be the same as long as the server
170 // retires at least one request in each second of wall time.
171 StructuredLogEntry cols
;
172 cols
.setInt("requests", finished
);
173 cols
.setInt("bucket", rfhBuckets
[i
]);
174 cols
.setInt("uptime", uptime
);
175 StructuredLog::log("hhvm_rfh", cols
);
181 void profileRequestEnd() {
183 rl_typeProfileLocals
->requestKind
== RequestKind::NonVM
) {
186 auto const finished
= numRequests
.fetch_add(1, std::memory_order_relaxed
) + 1;
187 static auto const requestSeries
= ServiceData::createTimeSeries(
189 {ServiceData::StatsType::RATE
, ServiceData::StatsType::SUM
},
190 {std::chrono::seconds(60), std::chrono::seconds(0)}
192 requestSeries
->addValue(1);