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/server/warmup-request-handler.h"
19 #include "hphp/runtime/base/memory-manager.h"
20 #include "hphp/runtime/base/program-functions.h"
21 #include "hphp/runtime/ext/server/ext_server.h"
22 #include "hphp/runtime/vm/jit/mcgen-translate.h"
23 #include "hphp/runtime/server/http-server.h"
24 #include "hphp/runtime/server/replay-transport.h"
26 #include "hphp/util/boot-stats.h"
27 #include "hphp/util/hash-map.h"
28 #include "hphp/util/hash-set.h"
29 #include "hphp/util/struct-log.h"
30 #include "hphp/util/timer.h"
32 #include <boost/filesystem.hpp>
33 #include <folly/Range.h>
34 #include <folly/Format.h>
35 #include <folly/Memory.h>
38 ///////////////////////////////////////////////////////////////////////////////
40 void WarmupRequestHandler::setupRequest(Transport
* transport
) {
41 m_reqHandler
.setupRequest(transport
);
44 void WarmupRequestHandler::teardownRequest(Transport
* transport
) noexcept
{
45 m_reqHandler
.teardownRequest(transport
);
48 void WarmupRequestHandler::handleRequest(Transport
*transport
) {
49 // There is one WarmupRequestHandler per-thread, but we want to track request
50 // count across all threads. Therefore we let WarmupRequestHandlerFactory
51 // track the global request count.
52 m_factory
->bumpReqCount();
53 m_reqHandler
.handleRequest(transport
);
56 void WarmupRequestHandler::abortRequest(Transport
*transport
) {
57 m_reqHandler
.abortRequest(transport
);
60 void WarmupRequestHandler::logToAccessLog(Transport
*transport
) {
61 m_reqHandler
.logToAccessLog(transport
);
64 std::unique_ptr
<RequestHandler
> WarmupRequestHandlerFactory::createHandler() {
66 std::make_unique
<WarmupRequestHandler
>(m_timeout
, shared_from_this());
69 void WarmupRequestHandlerFactory::bumpReqCount() {
70 // Bump the request count. When we hit m_warmupReqThreshold,
71 // add additional threads to the server.
72 auto const oldReqNum
= m_reqNumber
.fetch_add(1, std::memory_order_relaxed
);
73 if (oldReqNum
!= m_warmupReqThreshold
) {
77 Logger::Info("Finished warmup; saturating worker threads");
78 m_server
->saturateWorkers();
81 void InternalWarmupWorker::doJob(WarmupJob job
) {
82 if (f_server_is_stopping()) return;
83 if (f_server_uptime() > 0 &&
84 jit::mcgen::retranslateAllScheduled()) return;
85 HttpServer::CheckMemAndWait();
86 folly::StringPiece
f(job
.hdfFile
);
87 auto const pos
= f
.rfind('/');
88 auto const str
= (pos
== f
.npos
) ? f
: f
.subpiece(pos
+ 1);
89 BootStats::Block
timer(folly::sformat("warmup:{}:{}", str
, job
.index
),
90 RuntimeOption::ServerExecutionMode());
92 HttpRequestHandler
handler(0);
94 Logger::FInfo("Replaying warmup request {}:{}", job
.hdfFile
, job
.index
);
96 Timer::GetMonotonicTime(start
);
97 rt
.onRequestStart(start
);
98 rt
.replayInput(Hdf(job
.hdfFile
));
100 } catch (std::exception
& e
) {
101 Logger::FWarning("Got exception during warmup request {}:{}, {}",
102 job
.hdfFile
, job
.index
, e
.what());
106 InternalWarmupRequestPlayer::InternalWarmupRequestPlayer(int threadCount
,
108 : JobQueueDispatcher
<InternalWarmupWorker
>(threadCount
, threadCount
,
110 , m_noDuplicate(dedup
) {
113 InternalWarmupRequestPlayer::~InternalWarmupRequestPlayer() {
117 void InternalWarmupRequestPlayer::
118 runAfterDelay(const std::vector
<std::string
>& files
,
119 unsigned nTimes
, unsigned delaySeconds
) {
120 if (nTimes
== 0) return;
126 hphp_fast_string_map
<unsigned> seen
;
127 hphp_fast_string_set deduped
;
130 for (auto const& file
: files
) {
131 if (m_noDuplicate
&& !deduped
.insert(file
).second
) continue;
133 boost::filesystem::path
p(file
);
134 if (boost::filesystem::is_regular_file(p
)) {
135 enqueue(WarmupJob
{file
, ++seen
[file
]});
136 } else if (boost::filesystem::is_directory(p
)) {
137 for (auto const& f
: boost::filesystem::directory_iterator(p
)) {
138 if (boost::filesystem::is_regular_file(f
.path())) {
139 std::string subFile
= f
.path().native();
140 // Only do it for .hdf files.
141 if (subFile
.size() < 5 ||
142 subFile
.substr(subFile
.size() - 4) != ".hdf") {
143 Logger::FWarning("Skipping {} for warmup because it doesn't "
144 "look like a .hdf file", subFile
);
147 enqueue(WarmupJob
{subFile
, ++seen
[subFile
]});
151 } catch (std::exception
& e
) {
152 Logger::FError("Exception preparing warmup requests: {}", e
.what());
156 // Log what was replayed.
157 if (StructuredLog::enabled()) {
158 for (const auto& row
: seen
) {
159 StructuredLogEntry cols
;
160 cols
.setStr("file", row
.first
);
161 cols
.setInt("times", row
.second
);
162 StructuredLog::log("hhvm_replay", cols
);
167 ///////////////////////////////////////////////////////////////////////////////