Skip to content

Commit

Permalink
Optimize compile time by using asm.
Browse files Browse the repository at this point in the history
Switches to using asm incbin to embed the V8 snapshot instead of
outputing C code and then compiling it.

Compile time for from_snapshot.o goes from 44s to 1s.
  • Loading branch information
ry committed Aug 1, 2018
1 parent db8dc0e commit 6b6fac2
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 96 deletions.
9 changes: 9 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ static_library("libdeno") {
sources = [
"src/from_snapshot.cc",
]
data = [
"$target_gen_dir/snapshot_deno.bin",
]
data_deps = [
":bundle",
]
deps = [
":create_snapshot_deno",
":deno_bindings",
Expand Down Expand Up @@ -139,6 +145,9 @@ v8_source_set("deno_base_test") {
"src/from_snapshot.cc",
"src/mock_runtime_test.cc",
]
data = [
"$target_gen_dir/snapshot_mock_runtime.bin",
]
deps = [
":create_snapshot_mock_runtime",
":deno_base",
Expand Down
6 changes: 3 additions & 3 deletions build_extra/deno.gni
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ template("create_snapshot") {
])
tool = ":snapshot_creator"
visibility = [ ":*" ] # Only targets in this file can depend on this.
snapshot_out_cc = "$target_gen_dir/snapshot_$name.cc"
snapshot_out_bin = "$target_gen_dir/snapshot_$name.bin"
inputs = [
invoker.js,
]
outputs = [
snapshot_out_cc,
snapshot_out_bin,
]
args = [
rebase_path(snapshot_out_cc, root_build_dir),
rebase_path(snapshot_out_bin, root_build_dir),
rebase_path(invoker.js, root_build_dir),
]

Expand Down
22 changes: 0 additions & 22 deletions src/file_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,6 @@

namespace deno {

std::string BinaryContentAsC(const char* name, const std::string& data) {
char b[512];
std::string output;
// Write prefix.
snprintf(b, sizeof(b), "static const char %s_data[] = {\n", name);
output.append(b);
// Write actual data.
for (size_t i = 0; i < data.size(); ++i) {
if ((i & 0x1F) == 0x1F) output.append("\n");
if (i > 0) output.append(",");
snprintf(b, sizeof(b), "%hhu", static_cast<unsigned char>(data.at(i)));
output.append(b);
}
output.append("\n");
// Write suffix.
output.append("};\n");
snprintf(b, sizeof(b), "static const int %s_size = %" PRId64 ";\n", name,
static_cast<uint64_t>(data.size()));
output.append(b);
return output;
}

bool ReadFileToString(const char* fn, std::string* contents) {
std::ifstream file(fn, std::ios::binary);
if (file.fail()) {
Expand Down
1 change: 0 additions & 1 deletion src/file_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
namespace deno {
bool ReadFileToString(const char* fn, std::string* contents);
std::string Basename(std::string const& filename);
std::string BinaryContentAsC(const char* name, const std::string& data);
} // namespace deno

#endif // FILE_UTIL_H_
7 changes: 0 additions & 7 deletions src/file_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,5 @@ TEST(FileUtilTest, Basename) {
EXPECT_EQ("foo.txt", deno::Basename("C:\\home\\ryan\\foo.txt"));
}

TEST(FileUtilTest, BinaryContentAsC) {
auto c_code = deno::BinaryContentAsC("aaa", std::string("bbb"));
EXPECT_TRUE(c_code.find("static const char aaa_data[]") != std::string::npos);
EXPECT_TRUE(c_code.find("static const int aaa_size = 3;") !=
std::string::npos);
}

// TODO(ry) success unit test. Needs a tempfile or fixture.
// TEST(FileUtilTest, ReadFileToStringSuccess) { }
24 changes: 20 additions & 4 deletions src/from_snapshot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@
#include "deno.h"
#include "internal.h"

extern const char deno_snapshot_start asm("deno_snapshot_start");
extern const char deno_snapshot_end asm("deno_snapshot_end");
#ifdef DENO_MOCK_RUNTIME
#include "snapshot_mock_runtime.cc"
asm(".data\n"
"deno_snapshot_start: .incbin \"gen/snapshot_mock_runtime.bin\"\n"
"deno_snapshot_end:\n"
".globl deno_snapshot_start;\n"
".globl deno_snapshot_end;");
#else
#include "snapshot_deno.cc"
#endif
asm(".data\n"
"deno_snapshot_start: .incbin \"gen/snapshot_deno.bin\"\n"
"deno_snapshot_end:\n"
".globl deno_snapshot_start;\n"
".globl deno_snapshot_end;");
#endif // DENO_MOCK_RUNTIME

namespace deno {

Expand Down Expand Up @@ -42,7 +52,13 @@ Deno* NewFromSnapshot(void* data, deno_recv_cb cb) {
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
params.external_references = external_references;
params.snapshot_blob = StartupBlob_snapshot();

CHECK_NE(&deno_snapshot_start, nullptr);
int snapshot_len =
static_cast<int>(&deno_snapshot_end - &deno_snapshot_start);
static v8::StartupData snapshot = {&deno_snapshot_start, snapshot_len};
params.snapshot_blob = &snapshot;

v8::Isolate* isolate = v8::Isolate::New(params);
AddIsolate(d, isolate);

Expand Down
65 changes: 6 additions & 59 deletions src/snapshot_creator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,72 +40,17 @@ v8::StartupData MakeSnapshot(const char* js_filename, const char* js_source) {
return snapshot_blob;
}

class StartupDataCppWriter {
public:
StartupDataCppWriter(const char* name, const char* filename,
const std::string& data)
: name_(name),
filename_(filename),
data_(data),
file_(filename_, std::ios::binary) {}

bool Write() {
if (file_.bad()) {
return false;
}
WritePrefix();
WriteData();
WriteSuffix();

file_.close();
// printf("Wrote %s %d %s \n", name_, data_.size(), filename_);
return !file_.bad();
}

private:
void WritePrefix() {
file_ << "// Autogenerated snapshot file. Do not edit.\n\n";
file_ << "#include \"third_party/v8/include/v8.h\"\n\n";
file_ << "namespace deno { \n\n";
}

void WriteSuffix() {
char buffer[500];
snprintf(buffer, sizeof(buffer), "v8::StartupData* StartupBlob_%s() {\n",
name_);
file_ << buffer;
snprintf(buffer, sizeof(buffer), " return &%s_blob;\n", name_);
file_ << buffer;
file_ << "}\n\n";
file_ << "} // namespace deno\n\n";
}

void WriteData() {
char buffer[500];
file_ << BinaryContentAsC(name_, data_);
snprintf(buffer, sizeof(buffer),
"static v8::StartupData %s_blob = { %s_data, %s_size };\n", name_,
name_, name_);
file_ << buffer;
}

const char* name_;
const char* filename_;
std::string data_;
std::ofstream file_;
};

} // namespace deno

int main(int argc, char** argv) {
const char* snapshot_out_cc = argv[1];
const char* snapshot_out_bin = argv[1];
const char* js_fn = argv[2];

v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

CHECK_EQ(argc, 3);
CHECK_NE(js_fn, nullptr);
CHECK_NE(snapshot_out_cc, nullptr);
CHECK_NE(snapshot_out_bin, nullptr);

std::string js_source;
CHECK(deno::ReadFileToString(js_fn, &js_source));
Expand All @@ -114,6 +59,8 @@ int main(int argc, char** argv) {
auto snapshot_blob = deno::MakeSnapshot(js_fn, js_source.c_str());
std::string snapshot_str(snapshot_blob.data, snapshot_blob.raw_size);

deno::StartupDataCppWriter writer("snapshot", snapshot_out_cc, snapshot_str);
CHECK(writer.Write());
std::ofstream file_(snapshot_out_bin, std::ios::binary);
file_ << snapshot_str;
file_.close();
return file_.bad();
}

0 comments on commit 6b6fac2

Please sign in to comment.