2018-01-31 16:51:16 +08:00
|
|
|
//===--- TUScheduler.h -------------------------------------------*-C++-*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TUSCHEDULER_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TUSCHEDULER_H
|
|
|
|
|
|
|
|
#include "ClangdUnit.h"
|
|
|
|
#include "Function.h"
|
|
|
|
#include "Threading.h"
|
2018-02-08 15:37:35 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
[clangd] Speculative code completion index request before Sema is run.
Summary:
For index-based code completion, send an asynchronous speculative index
request, based on the index request for the last code completion on the same
file and the filter text typed before the cursor, before sema code completion
is invoked. This can reduce the code completion latency (by roughly latency of
sema code completion) if the speculative request is the same as the one
generated for the ongoing code completion from sema. As a sequence of code
completions often have the same scopes and proximity paths etc, this should be
effective for a number of code completions.
Trace with speculative index request:{F6997544}
Reviewers: hokein, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: javed.absar, jfb, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D50962
llvm-svn: 340604
2018-08-24 19:23:56 +08:00
|
|
|
#include <future>
|
2018-01-31 16:51:16 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
2018-03-02 16:56:37 +08:00
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
/// Returns a number of a default async threads to use for TUScheduler.
|
|
|
|
/// Returned value is always >= 1 (i.e. will not cause requests to be processed
|
|
|
|
/// synchronously).
|
|
|
|
unsigned getDefaultAsyncThreadsCount();
|
|
|
|
|
|
|
|
struct InputsAndAST {
|
|
|
|
const ParseInputs &Inputs;
|
|
|
|
ParsedAST &AST;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct InputsAndPreamble {
|
2018-03-15 01:46:52 +08:00
|
|
|
llvm::StringRef Contents;
|
|
|
|
const tooling::CompileCommand &Command;
|
2018-01-31 16:51:16 +08:00
|
|
|
const PreambleData *Preamble;
|
|
|
|
};
|
|
|
|
|
2018-02-22 21:11:12 +08:00
|
|
|
/// Determines whether diagnostics should be generated for a file snapshot.
|
|
|
|
enum class WantDiagnostics {
|
|
|
|
Yes, /// Diagnostics must be generated for this snapshot.
|
|
|
|
No, /// Diagnostics must not be generated for this snapshot.
|
|
|
|
Auto, /// Diagnostics must be generated for this snapshot or a subsequent one,
|
|
|
|
/// within a bounded amount of time.
|
|
|
|
};
|
|
|
|
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
/// Configuration of the AST retention policy. This only covers retention of
|
|
|
|
/// *idle* ASTs. If queue has operations requiring the AST, they might be
|
|
|
|
/// kept in memory.
|
|
|
|
struct ASTRetentionPolicy {
|
|
|
|
/// Maximum number of ASTs to be retained in memory when there are no pending
|
|
|
|
/// requests for them.
|
|
|
|
unsigned MaxRetainedASTs = 3;
|
|
|
|
};
|
|
|
|
|
[clangd] Add callbacks on parsed AST in addition to parsed preambles
Summary:
Will be used for updating the dynamic index on updates to the open files.
Currently we collect only information coming from the preamble
AST. This has a bunch of limitations:
- Dynamic index misses important information from the body of the
file, e.g. locations of definitions.
- XRefs cannot be collected at all, since we can only obtain full
information for the current file (preamble is parsed with skipped
function bodies, therefore not reliable).
This patch only adds the new callback, actually updates to the index
will be done in a follow-up patch.
Reviewers: hokein
Reviewed By: hokein
Subscribers: kadircet, javed.absar, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D50847
llvm-svn: 340401
2018-08-22 19:39:16 +08:00
|
|
|
class ParsingCallbacks {
|
|
|
|
public:
|
|
|
|
virtual ~ParsingCallbacks() = default;
|
|
|
|
|
|
|
|
/// Called on the AST that was built for emitting the preamble. The built AST
|
|
|
|
/// contains only AST nodes from the #include directives at the start of the
|
|
|
|
/// file. AST node in the current file should be observed on onMainAST call.
|
|
|
|
virtual void onPreambleAST(PathRef Path, ASTContext &Ctx,
|
|
|
|
std::shared_ptr<clang::Preprocessor> PP) {}
|
|
|
|
/// Called on the AST built for the file itself. Note that preamble AST nodes
|
|
|
|
/// are not deserialized and should be processed in the onPreambleAST call
|
|
|
|
/// instead.
|
|
|
|
/// The \p AST always contains all AST nodes for the main file itself, and
|
|
|
|
/// only a portion of the AST nodes deserialized from the preamble. Note that
|
|
|
|
/// some nodes from the preamble may have been deserialized and may also be
|
|
|
|
/// accessed from the main file AST, e.g. redecls of functions from preamble,
|
|
|
|
/// etc. Clients are expected to process only the AST nodes from the main file
|
|
|
|
/// in this callback (obtained via ParsedAST::getLocalTopLevelDecls) to obtain
|
|
|
|
/// optimal performance.
|
|
|
|
virtual void onMainAST(PathRef Path, ParsedAST &AST) {}
|
|
|
|
};
|
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
/// Handles running tasks for ClangdServer and managing the resources (e.g.,
|
|
|
|
/// preambles and ASTs) for opened files.
|
|
|
|
/// TUScheduler is not thread-safe, only one thread should be providing updates
|
|
|
|
/// and scheduling tasks.
|
|
|
|
/// Callbacks are run on a threadpool and it's appropriate to do slow work in
|
2018-02-19 17:56:28 +08:00
|
|
|
/// them. Each task has a name, used for tracing (should be UpperCamelCase).
|
2018-03-02 16:56:37 +08:00
|
|
|
/// FIXME(sammccall): pull out a scheduler options struct.
|
2018-01-31 16:51:16 +08:00
|
|
|
class TUScheduler {
|
|
|
|
public:
|
|
|
|
TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory,
|
2018-09-04 00:37:59 +08:00
|
|
|
std::unique_ptr<ParsingCallbacks> ASTCallbacks,
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
std::chrono::steady_clock::duration UpdateDebounce,
|
|
|
|
ASTRetentionPolicy RetentionPolicy);
|
2018-02-08 15:37:35 +08:00
|
|
|
~TUScheduler();
|
2018-01-31 16:51:16 +08:00
|
|
|
|
|
|
|
/// Returns estimated memory usage for each of the currently open files.
|
|
|
|
/// The order of results is unspecified.
|
|
|
|
std::vector<std::pair<Path, std::size_t>> getUsedBytesPerFile() const;
|
|
|
|
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
/// Returns a list of files with ASTs currently stored in memory. This method
|
|
|
|
/// is not very reliable and is only used for test. E.g., the results will not
|
|
|
|
/// contain files that currently run something over their AST.
|
|
|
|
std::vector<Path> getFilesWithCachedAST() const;
|
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
/// Schedule an update for \p File. Adds \p File to a list of tracked files if
|
|
|
|
/// \p File was not part of it before.
|
|
|
|
/// FIXME(ibiryukov): remove the callback from this function.
|
2018-02-22 21:11:12 +08:00
|
|
|
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD,
|
2018-07-04 04:59:33 +08:00
|
|
|
llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
|
2018-01-31 16:51:16 +08:00
|
|
|
|
|
|
|
/// Remove \p File from the list of tracked files and schedule removal of its
|
2018-02-08 15:37:35 +08:00
|
|
|
/// resources.
|
|
|
|
void remove(PathRef File);
|
2018-01-31 16:51:16 +08:00
|
|
|
|
|
|
|
/// Schedule an async read of the AST. \p Action will be called when AST is
|
|
|
|
/// ready. The AST passed to \p Action refers to the version of \p File
|
|
|
|
/// tracked at the time of the call, even if new updates are received before
|
|
|
|
/// \p Action is executed.
|
|
|
|
/// If an error occurs during processing, it is forwarded to the \p Action
|
|
|
|
/// callback.
|
2018-02-19 17:56:28 +08:00
|
|
|
void runWithAST(llvm::StringRef Name, PathRef File,
|
2018-03-13 07:22:35 +08:00
|
|
|
Callback<InputsAndAST> Action);
|
2018-01-31 16:51:16 +08:00
|
|
|
|
2018-08-30 23:07:34 +08:00
|
|
|
/// Controls whether preamble reads wait for the preamble to be up-to-date.
|
|
|
|
enum PreambleConsistency {
|
|
|
|
/// The preamble is generated from the current version of the file.
|
|
|
|
/// If the content was recently updated, we will wait until we have a
|
|
|
|
/// preamble that reflects that update.
|
|
|
|
/// This is the slowest option, and may be delayed by other tasks.
|
|
|
|
Consistent,
|
|
|
|
/// The preamble may be generated from an older version of the file.
|
|
|
|
/// Reading from locations in the preamble may cause files to be re-read.
|
|
|
|
/// This gives callers two options:
|
|
|
|
/// - validate that the preamble is still valid, and only use it if so
|
|
|
|
/// - accept that the preamble contents may be outdated, and try to avoid
|
|
|
|
/// reading source code from headers.
|
|
|
|
/// This is the fastest option, usually a preamble is available immediately.
|
|
|
|
Stale,
|
|
|
|
};
|
|
|
|
/// Schedule an async read of the preamble.
|
2018-07-09 18:45:33 +08:00
|
|
|
/// If there's no preamble yet (because the file was just opened), we'll wait
|
2018-08-30 23:07:34 +08:00
|
|
|
/// for it to build. The result may be null if it fails to build or is empty.
|
|
|
|
/// If an error occurs, it is forwarded to the \p Action callback.
|
2018-03-13 07:22:35 +08:00
|
|
|
void runWithPreamble(llvm::StringRef Name, PathRef File,
|
2018-08-30 23:07:34 +08:00
|
|
|
PreambleConsistency Consistency,
|
2018-03-13 07:22:35 +08:00
|
|
|
Callback<InputsAndPreamble> Action);
|
2018-01-31 16:51:16 +08:00
|
|
|
|
2018-02-13 16:59:23 +08:00
|
|
|
/// Wait until there are no scheduled or running tasks.
|
|
|
|
/// Mostly useful for synchronizing tests.
|
|
|
|
bool blockUntilIdle(Deadline D) const;
|
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
private:
|
2018-02-08 15:37:35 +08:00
|
|
|
/// This class stores per-file data in the Files map.
|
|
|
|
struct FileData;
|
2018-01-31 16:51:16 +08:00
|
|
|
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
public:
|
|
|
|
/// Responsible for retaining and rebuilding idle ASTs. An implementation is
|
|
|
|
/// an LRU cache.
|
|
|
|
class ASTCache;
|
|
|
|
|
2018-08-09 17:05:45 +08:00
|
|
|
// The file being built/processed in the current thread. This is a hack in
|
|
|
|
// order to get the file name into the index implementations. Do not depend on
|
|
|
|
// this inside clangd.
|
|
|
|
// FIXME: remove this when there is proper index support via build system
|
|
|
|
// integration.
|
|
|
|
static llvm::Optional<llvm::StringRef> getFileBeingProcessedInContext();
|
|
|
|
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
private:
|
2018-02-08 15:37:35 +08:00
|
|
|
const bool StorePreamblesInMemory;
|
|
|
|
const std::shared_ptr<PCHContainerOperations> PCHOps;
|
2018-09-04 00:37:59 +08:00
|
|
|
std::unique_ptr<ParsingCallbacks> Callbacks; // not nullptr
|
2018-02-08 15:37:35 +08:00
|
|
|
Semaphore Barrier;
|
|
|
|
llvm::StringMap<std::unique_ptr<FileData>> Files;
|
[clangd] Keep only a limited number of idle ASTs in memory
Summary:
After this commit, clangd will only keep the last 3 accessed ASTs in
memory. Preambles for each of the opened files are still kept in
memory to make completion and AST rebuilds fast.
AST rebuilds are usually fast enough, but having the last ASTs in
memory still considerably improves latency of operations like
findDefinition and documeneHighlight, which are often sent multiple
times a second when moving around the code. So keeping some of the last
accessed ASTs in memory seems like a reasonable tradeoff.
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: malaperle, arphaman, klimek, javed.absar, ioeric, MaskRay, jkorous, cfe-commits
Differential Revision: https://reviews.llvm.org/D47063
llvm-svn: 333737
2018-06-01 18:08:43 +08:00
|
|
|
std::unique_ptr<ASTCache> IdleASTs;
|
2018-02-08 15:37:35 +08:00
|
|
|
// None when running tasks synchronously and non-None when running tasks
|
|
|
|
// asynchronously.
|
2018-02-13 16:59:23 +08:00
|
|
|
llvm::Optional<AsyncTaskRunner> PreambleTasks;
|
|
|
|
llvm::Optional<AsyncTaskRunner> WorkerThreads;
|
2018-03-02 16:56:37 +08:00
|
|
|
std::chrono::steady_clock::duration UpdateDebounce;
|
2018-01-31 16:51:16 +08:00
|
|
|
};
|
2018-08-09 17:05:45 +08:00
|
|
|
|
[clangd] Speculative code completion index request before Sema is run.
Summary:
For index-based code completion, send an asynchronous speculative index
request, based on the index request for the last code completion on the same
file and the filter text typed before the cursor, before sema code completion
is invoked. This can reduce the code completion latency (by roughly latency of
sema code completion) if the speculative request is the same as the one
generated for the ongoing code completion from sema. As a sequence of code
completions often have the same scopes and proximity paths etc, this should be
effective for a number of code completions.
Trace with speculative index request:{F6997544}
Reviewers: hokein, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: javed.absar, jfb, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D50962
llvm-svn: 340604
2018-08-24 19:23:56 +08:00
|
|
|
/// Runs \p Action asynchronously with a new std::thread. The context will be
|
2018-09-14 08:56:11 +08:00
|
|
|
/// propagated.
|
[clangd] Speculative code completion index request before Sema is run.
Summary:
For index-based code completion, send an asynchronous speculative index
request, based on the index request for the last code completion on the same
file and the filter text typed before the cursor, before sema code completion
is invoked. This can reduce the code completion latency (by roughly latency of
sema code completion) if the speculative request is the same as the one
generated for the ongoing code completion from sema. As a sequence of code
completions often have the same scopes and proximity paths etc, this should be
effective for a number of code completions.
Trace with speculative index request:{F6997544}
Reviewers: hokein, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: javed.absar, jfb, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D50962
llvm-svn: 340604
2018-08-24 19:23:56 +08:00
|
|
|
template <typename T>
|
|
|
|
std::future<T> runAsync(llvm::unique_function<T()> Action) {
|
|
|
|
return std::async(std::launch::async,
|
|
|
|
[](llvm::unique_function<T()> &&Action, Context Ctx) {
|
|
|
|
WithContext WithCtx(std::move(Ctx));
|
|
|
|
return Action();
|
|
|
|
},
|
|
|
|
std::move(Action), Context::current().clone());
|
|
|
|
}
|
|
|
|
|
2018-01-31 16:51:16 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
|
|
|
|
#endif
|