Skip to content

Commit 20118c8

Browse files
WizKidfacebook-github-bot
authored andcommitted
Make it possible to pre emit system lib and embed that in HHVM
Summary: - Instead of parsing all of system lib everytime HHVM starts we do it when we build HHVM and then include the unitemitters inside the binary - I also include the preparsed decls in the binary - After we build the HHVM binary we use it to preemit and get decls and then we embed them into the binary - This step runs in parallel with build info and build info is slower so this doesn't slow down the building of HHVM at all. - Result - Takes `hphp/test/run quick` from 100 seconds to 25. - Take `hphp/test/run -r quick` from 280 seconds to 220 seconds. - Takes `hphp/test/run quick slow` from 15 minutes to 3.5 minutes. Reviewed By: ricklavoie Differential Revision: D46606416 fbshipit-source-id: 7427831ec971f878004aad014c621a2f6471d9fe
1 parent 7683147 commit 20118c8

34 files changed

+485
-182
lines changed

hphp/compiler/compiler-systemlib.cpp

+287
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#include "hphp/compiler/compiler-systemlib.h"
18+
19+
#include "hphp/hack/src/hackc/ffi_bridge/decl_provider.h"
20+
#include "hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs.h"
21+
22+
#include "hphp/hhvm/process-init.h"
23+
24+
#include "hphp/runtime/base/file-util.h"
25+
#include "hphp/runtime/base/preg.h"
26+
27+
#include "hphp/runtime/ext/extension-registry.h"
28+
29+
#include "hphp/runtime/vm/native.h"
30+
#include "hphp/runtime/vm/runtime-compiler.h"
31+
#include "hphp/runtime/vm/unit-emitter.h"
32+
33+
#include "hphp/runtime/version.h"
34+
35+
#include "hphp/util/build-info.h"
36+
#include "hphp/util/logger.h"
37+
#include "hphp/util/rds-local.h"
38+
#include "hphp/util/timer.h"
39+
40+
#include <boost/filesystem.hpp>
41+
#include <boost/program_options/options_description.hpp>
42+
#include <boost/program_options/positional_options.hpp>
43+
#include <boost/program_options/variables_map.hpp>
44+
#include <boost/program_options/parsers.hpp>
45+
46+
47+
#include <filesystem>
48+
#include <iostream>
49+
50+
using namespace boost::program_options;
51+
52+
namespace HPHP {
53+
54+
///////////////////////////////////////////////////////////////////////////////
55+
56+
namespace {
57+
58+
///////////////////////////////////////////////////////////////////////////////
59+
60+
struct CompilerOptions {
61+
std::string outputDir;
62+
std::string inputDir;
63+
std::vector<std::string> inputs;
64+
};
65+
66+
///////////////////////////////////////////////////////////////////////////////
67+
68+
int prepareOptions(CompilerOptions &po, int argc, char **argv) {
69+
options_description desc("HipHop Systemlib Compiler for PHP Usage:\n\n"
70+
"\thhvm --compile-systemlib <options> <inputs>\n\n"
71+
"Options");
72+
73+
std::vector<std::string> formats;
74+
75+
desc.add_options()
76+
("help", "display this message")
77+
("version", "display version number")
78+
("output-dir", value<std::string>(&po.outputDir), "output directory")
79+
("input-dir", value<std::string>(&po.inputDir), "input directory")
80+
("inputs,i", value<std::vector<std::string>>(&po.inputs)->composing(),
81+
"input file names")
82+
;
83+
84+
positional_options_description p;
85+
p.add("inputs", -1);
86+
variables_map vm;
87+
try {
88+
auto opts = command_line_parser(argc, argv).options(desc)
89+
.positional(p).run();
90+
try {
91+
store(opts, vm);
92+
notify(vm);
93+
#if defined(BOOST_VERSION) && BOOST_VERSION >= 105000 && BOOST_VERSION <= 105400
94+
} catch (const error_with_option_name &e) {
95+
std::string wrong_name = e.get_option_name();
96+
std::string right_name = get_right_option_name(opts, wrong_name);
97+
std::string message = e.what();
98+
if (right_name != "") {
99+
boost::replace_all(message, wrong_name, right_name);
100+
}
101+
Logger::Error("Error in command line: %s", message.c_str());
102+
std::cout << desc << "\n";
103+
return -1;
104+
#endif
105+
} catch (const error& e) {
106+
Logger::Error("Error in command line: %s", e.what());
107+
std::cout << desc << "\n";
108+
return -1;
109+
}
110+
} catch (const unknown_option& e) {
111+
Logger::Error("Error in command line: %s", e.what());
112+
std::cout << desc << "\n";
113+
return -1;
114+
} catch (const error& e) {
115+
Logger::Error("Error in command line: %s", e.what());
116+
std::cout << desc << "\n";
117+
return -1;
118+
} catch (...) {
119+
Logger::Error("Error in command line parsing.");
120+
std::cout << desc << "\n";
121+
return -1;
122+
}
123+
if (argc <= 1 || vm.count("help")) {
124+
std::cout << desc << "\n";
125+
return 1;
126+
}
127+
if (vm.count("version")) {
128+
std::cout << "HipHop Repo Compiler";
129+
std::cout << " " << HHVM_VERSION;
130+
std::cout << " (" << (debug ? "dbg" : "rel") << ")\n";
131+
std::cout << "Compiler: " << compilerId() << "\n";
132+
std::cout << "Repo schema: " << repoSchemaId() << "\n";
133+
return 1;
134+
}
135+
136+
if (po.outputDir.empty()) {
137+
Logger::Error("Error in command line: output-dir must be provided.");
138+
std::cout << desc << "\n";
139+
return -1;
140+
}
141+
142+
if (po.inputDir.empty()) po.inputDir = '.';
143+
po.inputDir = FileUtil::normalizeDir(po.inputDir);
144+
145+
IniSetting::Map ini = IniSetting::Map::object;
146+
Hdf config;
147+
Hdf runtime = config["Runtime"];
148+
RuntimeOption::Load(ini, runtime);
149+
// Option::Load(ini, config);
150+
151+
pcre_init();
152+
153+
return 0;
154+
}
155+
156+
bool compile_systemlib(const std::filesystem::path& path, std::string output_dir, const Extension* extension) {
157+
std::string content;
158+
boost::filesystem::load_string_file(path.string(), content);
159+
160+
// Create Unit Emitter
161+
std::string fname = "/:"+path.filename().string();
162+
auto ue = compile_systemlib_string_to_ue(content.c_str(), content.length(), fname.c_str(), extension);
163+
assertx(ue);
164+
165+
if (!ue->check(getenv("HHVM_VERIFY_VERBOSE_SYSTEM"))) {
166+
Logger::Error("Verification failed for unit %s. Re-run with "
167+
"HHVM_VERIFY_VERBOSE_SYSTEM=1 to see more details.",
168+
fname.c_str());
169+
return false;
170+
}
171+
172+
if (ue->m_fatalUnit) {
173+
Logger::Error("Something went wrong when compiling %s because a fatal unit was created",
174+
fname.c_str());
175+
return false;
176+
}
177+
178+
UnitEmitterSerdeWrapper uew = std::move(ue);
179+
180+
BlobEncoder uew_encoder;
181+
uew.serde(uew_encoder);
182+
183+
boost::filesystem::save_string_file(output_dir + "/" + path.filename().string() + ".ue", std::string(static_cast<const char*>(uew_encoder.data()), uew_encoder.size()));
184+
185+
// Create Decls
186+
auto const& defaults = RepoOptions::defaultsForSystemlib();
187+
188+
hackc::DeclParserConfig options;
189+
defaults.flags().initDeclConfig(options);
190+
191+
auto decls = hackc::direct_decl_parse_and_serialize(
192+
options,
193+
fname,
194+
{(const uint8_t*)content.data(), content.size()}
195+
);
196+
197+
if (decls.has_errors) {
198+
Logger::Error("Something went wrong when getting decls for %s because it has errors",
199+
fname.c_str());
200+
return false;
201+
}
202+
203+
auto serialized = hackc::decls_holder_to_binary(*decls.decls);
204+
boost::filesystem::save_string_file(output_dir + "/" + path.filename().string() + ".decls", std::string(serialized.begin(), serialized.end()));
205+
206+
return true;
207+
}
208+
209+
bool process(CompilerOptions &po) {
210+
register_process_init();
211+
212+
hphp_process_init(true);
213+
ExtensionRegistry::moduleRegisterNative();
214+
SCOPE_EXIT { hphp_process_exit(); };
215+
216+
auto files = std::map<std::string, std::filesystem::path>();
217+
218+
for (const auto& input : po.inputs) {
219+
auto input_path = std::filesystem::path(po.inputDir + input);
220+
if (std::filesystem::is_directory(input_path)) {
221+
for (const auto& entry : std::filesystem::directory_iterator(input_path)) {
222+
auto path = entry.path();
223+
files[path.filename().string()] = path;
224+
}
225+
} else {
226+
files[input_path.filename().string()] = input_path;
227+
}
228+
}
229+
230+
for (auto extension : ExtensionRegistry::getExtensions()) {
231+
for (auto file : extension->hackFiles()) {
232+
auto path = files.at("ext_" + file);
233+
if (!compile_systemlib(path.string(), po.outputDir, extension)) {
234+
return false;
235+
}
236+
}
237+
}
238+
239+
return true;
240+
}
241+
242+
///////////////////////////////////////////////////////////////////////////////
243+
244+
}
245+
246+
///////////////////////////////////////////////////////////////////////////////
247+
248+
int compiler_systemlib_main(int argc, char **argv) {
249+
try {
250+
rds::local::init();
251+
SCOPE_EXIT { rds::local::fini(); };
252+
253+
CompilerOptions po;
254+
auto const ret = prepareOptions(po, argc, argv);
255+
if (ret == 1) return 0; // --help
256+
if (ret != 0) return ret; // command line error
257+
258+
Timer totalTimer(Timer::WallTime, "running compile systemlib");
259+
always_assert_flog(
260+
mkdir(po.outputDir.c_str(), 0777) == 0 || errno == EEXIST,
261+
"Unable to mkdir({}): {}",
262+
po.outputDir.c_str(),
263+
folly::errnoStr(errno)
264+
);
265+
266+
if (!process(po)) {
267+
Logger::Error("compile systemlib failed");
268+
return -1;
269+
} else {
270+
Logger::Info("all files saved in %s ...", po.outputDir.c_str());
271+
return 0;
272+
}
273+
return 0;
274+
} catch (const Exception& e) {
275+
Logger::Error("Exception: %s", e.getMessage().c_str());
276+
} catch (const std::exception& e) {
277+
Logger::Error("std::exception: %s", e.what());
278+
} catch (...) {
279+
Logger::Error("(non-standard exception \"%s\" was thrown)",
280+
current_exception_name().c_str());
281+
}
282+
return -1;
283+
}
284+
285+
///////////////////////////////////////////////////////////////////////////////
286+
287+
}

hphp/compiler/compiler-systemlib.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#pragma once
18+
19+
namespace HPHP {
20+
21+
int compiler_systemlib_main(int argc, char** argv);
22+
23+
}

hphp/hack/src/hackc/ffi_bridge/compiler_ffi.rs

+12
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ mod ffi {
472472
/// Decode a binary DeclsHolder blob back to DeclsHolder
473473
fn binary_to_decls_holder(json: &CxxString) -> Result<Box<DeclsHolder>>;
474474

475+
/// Decode a binary DeclsHolder blob back to DeclsAndBlob
476+
fn binary_to_decls_and_blob(json: &CxxString) -> Result<DeclsAndBlob>;
477+
475478
/// Format facts into a human readable string for debugging.
476479
fn facts_debug(facts: &FileFacts) -> String;
477480

@@ -815,6 +818,15 @@ fn binary_to_decls_holder(blob: &CxxString) -> bincode::Result<Box<DeclsHolder>>
815818
}))
816819
}
817820

821+
fn binary_to_decls_and_blob(blob: &CxxString) -> bincode::Result<ffi::DeclsAndBlob> {
822+
let decls = binary_to_decls_holder(blob)?;
823+
Ok(ffi::DeclsAndBlob {
824+
serialized: decl_provider::serialize_decls(&decls.parsed_file.decls).unwrap(),
825+
has_errors: decls.parsed_file.has_first_pass_parse_errors,
826+
decls,
827+
})
828+
}
829+
818830
fn facts_debug(facts: &ffi::FileFacts) -> String {
819831
format!("{facts:#?}")
820832
}

hphp/hhvm/main.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "hphp/runtime/base/execution-context.h"
2424
#include "hphp/hhvm/process-init.h"
2525
#include "hphp/compiler/compiler.h"
26+
#include "hphp/compiler/compiler-systemlib.h"
2627
#include "hphp/hhbbc/hhbbc.h"
2728

2829
#include "hphp/util/embedded-data.h"
@@ -62,6 +63,11 @@ int main(int argc, char** argv) {
6263
return HPHP::HHBBC::main(argc - 1, argv + 1);
6364
}
6465

66+
if (argc > 1 &&!strcmp(argv[1], "--compile-systemlib")) {
67+
argv[1] = "compile-systemlib";
68+
return HPHP::compiler_systemlib_main(argc - 1, argv + 1);
69+
}
70+
6571
if (argc > 1 && !strcmp(argv[1], HPHP::extern_worker::s_option)) {
6672
return HPHP::extern_worker::main(argc, argv);
6773
}

0 commit comments

Comments
 (0)