diff options
author | Eric Liu <ioeric@google.com> | 2018-10-02 10:43:55 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2018-10-02 10:43:55 +0000 |
commit | b1d7542dded29ecedf6c00c3b45fe4b0dc26777b (patch) | |
tree | c4e57ec35e0b5134ff2ecc9ffe8af59eaf554741 /clang-tools-extra/clangd/FS.cpp | |
parent | b91e08197cf74c1c2d92f0fc112e941f8ef883a1 (diff) | |
download | bcm5719-llvm-b1d7542dded29ecedf6c00c3b45fe4b0dc26777b.tar.gz bcm5719-llvm-b1d7542dded29ecedf6c00c3b45fe4b0dc26777b.zip |
[clangd] Cache FS stat() calls when building preamble.
Summary:
The file stats can be reused when preamble is reused (e.g. code
completion). It's safe to assume that cached status is not outdated as we
assume preamble files to remain unchanged.
On real file system, this made code completion ~20% faster on a measured file
(with big preamble). The preamble build time doesn't change much.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: mgorny, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D52419
llvm-svn: 343576
Diffstat (limited to 'clang-tools-extra/clangd/FS.cpp')
-rw-r--r-- | clang-tools-extra/clangd/FS.cpp | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/FS.cpp b/clang-tools-extra/clangd/FS.cpp new file mode 100644 index 00000000000..ce62a59271f --- /dev/null +++ b/clang-tools-extra/clangd/FS.cpp @@ -0,0 +1,92 @@ +//===--- FS.cpp - File system related utils ----------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FS.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/None.h" + +namespace clang { +namespace clangd { + +void PreambleFileStatusCache::update(const vfs::FileSystem &FS, vfs::Status S) { + SmallString<32> PathStore(S.getName()); + if (auto Err = FS.makeAbsolute(PathStore)) + return; + // Stores the latest status in cache as it can change in a preamble build. + StatCache.insert({PathStore, std::move(S)}); +} + +llvm::Optional<vfs::Status> +PreambleFileStatusCache::lookup(llvm::StringRef File) const { + auto I = StatCache.find(File); + if (I != StatCache.end()) + return I->getValue(); + return llvm::None; +} + +IntrusiveRefCntPtr<vfs::FileSystem> PreambleFileStatusCache::getProducingFS( + IntrusiveRefCntPtr<vfs::FileSystem> FS) { + // This invalidates old status in cache if files are re-`open()`ed or + // re-`stat()`ed in case file status has changed during preamble build. + class CollectFS : public vfs::ProxyFileSystem { + public: + CollectFS(IntrusiveRefCntPtr<vfs::FileSystem> FS, + PreambleFileStatusCache &StatCache) + : ProxyFileSystem(std::move(FS)), StatCache(StatCache) {} + + llvm::ErrorOr<std::unique_ptr<vfs::File>> + openFileForRead(const Twine &Path) override { + auto File = getUnderlyingFS().openFileForRead(Path); + if (!File || !*File) + return File; + // Eagerly stat opened file, as the followup `status` call on the file + // doesn't necessarily go through this FS. This puts some extra work on + // preamble build, but it should be worth it as preamble can be reused + // many times (e.g. code completion) and the repeated status call is + // likely to be cached in the underlying file system anyway. + if (auto S = File->get()->status()) + StatCache.update(getUnderlyingFS(), std::move(*S)); + return File; + } + + llvm::ErrorOr<vfs::Status> status(const Twine &Path) override { + auto S = getUnderlyingFS().status(Path); + if (S) + StatCache.update(getUnderlyingFS(), *S); + return S; + } + + private: + PreambleFileStatusCache &StatCache; + }; + return IntrusiveRefCntPtr<CollectFS>(new CollectFS(std::move(FS), *this)); +} + +IntrusiveRefCntPtr<vfs::FileSystem> PreambleFileStatusCache::getConsumingFS( + IntrusiveRefCntPtr<vfs::FileSystem> FS) const { + class CacheVFS : public vfs::ProxyFileSystem { + public: + CacheVFS(IntrusiveRefCntPtr<vfs::FileSystem> FS, + const PreambleFileStatusCache &StatCache) + : ProxyFileSystem(std::move(FS)), StatCache(StatCache) {} + + llvm::ErrorOr<vfs::Status> status(const Twine &Path) override { + if (auto S = StatCache.lookup(Path.str())) + return *S; + return getUnderlyingFS().status(Path); + } + + private: + const PreambleFileStatusCache &StatCache; + }; + return IntrusiveRefCntPtr<CacheVFS>(new CacheVFS(std::move(FS), *this)); +} + +} // namespace clangd +} // namespace clang |