versioner: use a virtual filesystem for input files.
Use an InMemoryFileSystem to store and share input files across
compilations.
This improves the result of `time versioner` further, from:
versioner 109.12s user 17.43s system 2433% cpu 5.201 total
to:
versioner 112.20s user 1.38s system 2416% cpu 4.700 total
Bug: http://b/32748936
Test: python run_tests.py
Change-Id: I72d37b7c30850b8399cc40338247700fe3e7b2f9
diff --git a/tools/versioner/src/VFS.cpp b/tools/versioner/src/VFS.cpp
new file mode 100644
index 0000000..cd6d367
--- /dev/null
+++ b/tools/versioner/src/VFS.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <err.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <clang/Basic/VirtualFileSystem.h>
+#include <llvm/ADT/IntrusiveRefCntPtr.h>
+#include <llvm/Support/MemoryBuffer.h>
+
+#include "Utils.h"
+
+using android::base::unique_fd;
+using namespace clang::vfs;
+
+static void addDirectoryToVFS(InMemoryFileSystem* vfs, const std::string& path) {
+ char* paths[] = { const_cast<char*>(path.c_str()), nullptr };
+ FTS* fts = fts_open(paths, FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR, nullptr);
+ if (!fts) {
+ err(1, "failed to open directory %s", path.c_str());
+ }
+
+ while (FTSENT* ent = fts_read(fts)) {
+ if ((ent->fts_info & FTS_F) == 0) {
+ continue;
+ }
+
+ const char* file_path = ent->fts_accpath;
+ unique_fd fd(open(file_path, O_RDONLY | O_CLOEXEC));
+ if (fd == -1) {
+ err(1, "failed to open header '%s'", file_path);
+ }
+
+ auto buffer_opt = llvm::MemoryBuffer::getOpenFileSlice(fd, file_path, -1, 0);
+ if (!buffer_opt) {
+ errx(1, "failed to map header '%s'", file_path);
+ }
+
+ if (!vfs->addFile(file_path, ent->fts_statp->st_mtim.tv_sec, std::move(buffer_opt.get()))) {
+ errx(1, "failed to add file '%s'", file_path);
+ }
+ }
+
+ fts_close(fts);
+}
+
+llvm::IntrusiveRefCntPtr<FileSystem> createCommonVFS(const std::string& header_dir,
+ const std::string& dependency_dir,
+ bool add_versioning_header) {
+ auto vfs = std::make_unique<InMemoryFileSystem>();
+ addDirectoryToVFS(vfs.get(), header_dir);
+ if (!dependency_dir.empty()) {
+ addDirectoryToVFS(vfs.get(), dependency_dir);
+ }
+
+ if (add_versioning_header) {
+ const char* top = getenv("ANDROID_BUILD_TOP");
+ if (!top) {
+ errx(1, "-i passed, but ANDROID_BUILD_TOP is unset");
+ }
+
+ std::string header_path = std::string(top) + "/bionic/libc/include/android/versioning.h";
+ auto buffer_opt = llvm::MemoryBuffer::getFile(header_path);
+ if (!buffer_opt) {
+ err(1, "failed to open %s", header_path.c_str());
+ }
+ vfs->addFile("android/versioning.h", 0, std::move(buffer_opt.get()));
+ }
+
+ return llvm::IntrusiveRefCntPtr<FileSystem>(vfs.release());
+}