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/jit/tc.h"
18 #include "hphp/runtime/vm/jit/tc-internal.h"
20 #include "hphp/runtime/base/rds.h"
21 #include "hphp/runtime/base/runtime-option.h"
23 #include "hphp/runtime/vm/runtime-compiler.h"
24 #include "hphp/runtime/vm/jit/code-cache.h"
25 #include "hphp/runtime/vm/jit/mcgen.h"
26 #include "hphp/runtime/vm/jit/prof-data.h"
27 #include "hphp/runtime/vm/jit/trans-db.h"
29 #include "hphp/util/data-block.h"
30 #include "hphp/util/build-info.h"
32 #include <folly/Format.h>
38 namespace HPHP::jit::tc
{
42 bool dumpTCCode(folly::StringPiece filename
) {
43 #define OPEN_FILE(F, SUFFIX) \
44 auto const F ## name = folly::to<std::string>(filename, SUFFIX); \
45 FILE* F = fopen(F ## name .c_str(),"wb"); \
46 if (F == nullptr) return false; \
47 SCOPE_EXIT{ fclose(F); };
49 OPEN_FILE(aFile
, "_a");
50 OPEN_FILE(acoldFile
, "_acold");
51 OPEN_FILE(afrozenFile
, "_afrozen");
55 // dump starting from the main region
57 auto writeBlock
= [&](const CodeBlock
& cb
, FILE* file
) {
59 auto const count
= cb
.used();
60 result
= fwrite(cb
.base(), 1, count
, file
) == count
;
64 writeBlock(code().main(), aFile
);
65 writeBlock(code().cold(), acoldFile
);
66 writeBlock(code().frozen(), afrozenFile
);
71 auto const dataPath
= RuntimeOption::EvalDumpTCPath
+ "/tc_data.txt.gz";
72 gzFile tcDataFile
= gzopen(dataPath
.c_str(), "w");
73 if (!tcDataFile
) return false;
74 SCOPE_EXIT
{ gzclose(tcDataFile
); };
76 if (!gzprintf(tcDataFile
,
81 "acold.frontier = %p\n"
83 "afrozen.frontier = %p\n\n",
84 repoSchemaId().begin(),
85 code().main().base(), code().main().frontier(),
86 code().cold().base(), code().cold().frontier(),
87 code().frozen().base(), code().frozen().frontier())) {
91 if (!gzprintf(tcDataFile
, "total_translations = %zu\n\n",
92 transdb::getNumTranslations())) {
96 // Print all translations, including their execution counters. If global
97 // counters are disabled (default), fall back to using ProfData, covering
98 // only profiling translations.
99 if (transdb::enabled()) {
100 // Admin requests do not automatically init ProfData, so do it explicitly.
101 // No need for matching exit call; data is immortal with trans DB enabled.
102 requestInitProfData();
104 const TransRec invalid
;
105 assertx(!invalid
.isValid());
106 for (TransID t
= 0; t
< transdb::getNumTranslations(); t
++) {
107 auto transRec
= transdb::getTransRec(t
);
108 if (!transRec
) transRec
= &invalid
;
109 auto const ret
= gzputs(tcDataFile
, transRec
->print().c_str());
118 ////////////////////////////////////////////////////////////////////////////////
122 return RuntimeOption::EvalDumpTC
||
123 RuntimeOption::EvalDumpIR
||
124 RuntimeOption::EvalDumpRegion
||
125 RuntimeOption::EvalDumpInlDecision
||
126 RuntimeOption::EvalDumpCallTargets
||
127 RuntimeOption::EvalDumpLayoutCFG
||
128 RuntimeOption::EvalDumpVBC
;
131 bool dump(bool ignoreLease
/* = false */) {
132 if (!mcgen::initialized()) return false;
135 std::unique_lock
<SimpleMutex
> codeLock
;
136 std::unique_lock
<SimpleMutex
> metaLock
;
138 codeLock
= lockCode();
139 metaLock
= lockMetadata();
141 if (!dumpTCData()) return false;
142 if (!dumpTCCode(RO::EvalDumpTCPath
+ "/tc_dump")) return false;
145 if (!RO::RepoAuthoritative
) {
146 dump_compiled_units(RO::EvalDumpTCPath
+ "/hhvm.hhbc");
152 std::vector
<UsageInfo
> getUsageInfo() {
153 std::vector
<UsageInfo
> tcUsageInfo
;
155 code().forEachBlock([&] (const char* name
, const CodeBlock
& a
) {
156 tcUsageInfo
.emplace_back(UsageInfo
{
157 std::string("code.") + name
,
163 tcUsageInfo
.emplace_back(UsageInfo
{
165 code().data().used(),
166 code().data().capacity(),
169 tcUsageInfo
.emplace_back(UsageInfo
{
172 RuntimeOption::EvalRDSSize
* 3 / 4,
175 tcUsageInfo
.emplace_back(UsageInfo
{
177 rds::usedLocalBytes(),
178 RuntimeOption::EvalRDSSize
* 3 / 4,
181 tcUsageInfo
.emplace_back(UsageInfo
{
183 rds::usedPersistentBytes(),
184 RuntimeOption::EvalRDSSize
/ 4,
190 std::string
getTCSpace() {
192 size_t total_size
= 0;
193 size_t total_capacity
= 0;
195 auto const add_row
= [&] (const UsageInfo
& ui
) {
196 auto const percent
= ui
.capacity
? 100 * ui
.used
/ ui
.capacity
: 0;
198 usage
+= folly::format(
199 "mcg: {:9} bytes ({}%) in {}\n",
200 ui
.used
, percent
, ui
.name
204 total_size
+= ui
.used
;
205 total_capacity
+= ui
.capacity
;
209 auto const uis
= getUsageInfo();
210 std::for_each(uis
.begin(), uis
.end(), add_row
);
211 add_row(UsageInfo
{ "total", total_size
, total_capacity
, false });
216 std::string
getTCAddrs() {
219 code().forEachBlock([&] (const char* name
, const CodeBlock
& a
) {
220 addrs
+= folly::format("{}: {}\n", name
, a
.base()).str();
225 std::vector
<TCMemInfo
> getTCMemoryUsage() {
226 std::vector
<TCMemInfo
> ret
;
228 [&](const char* name
, const CodeBlock
& a
) {
229 ret
.emplace_back(TCMemInfo
{