[clang-tools-extra] r326546 - [clangd] Debounce streams of updates.
Ilya Biryukov via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 2 10:31:03 PST 2018
The TUSchedulerTest::Debounce breaks on Windows buildbots. Probably because
the timeouts of 50ms/10ms/40ms are too low to be scheduled properly.
Increased the timeouts in r326598 to 1s/200ms/2s, hopefully that would
unbreak the buildbots.
We could tweak them back to lower values that work on Monday :-)
On Fri, Mar 2, 2018 at 9:58 AM Sam McCall via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: sammccall
> Date: Fri Mar 2 00:56:37 2018
> New Revision: 326546
>
> URL: http://llvm.org/viewvc/llvm-project?rev=326546&view=rev
> Log:
> [clangd] Debounce streams of updates.
>
> Summary:
> Don't actually start building ASTs for new revisions until either:
> - 500ms have passed since the last revision, or
> - we actually need the revision for something (or to unblock the queue)
>
> In practice, this avoids the "first keystroke results in diagnostics"
> problem.
> This is kind of awkward to test, and the test is pretty bad.
> It can be observed nicely by capturing a trace, though.
>
> Reviewers: hokein, ilya-biryukov
>
> Subscribers: klimek, jkorous-apple, ioeric, cfe-commits
>
> Differential Revision: https://reviews.llvm.org/D43648
>
> Modified:
> clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
> clang-tools-extra/trunk/clangd/ClangdServer.cpp
> clang-tools-extra/trunk/clangd/ClangdServer.h
> clang-tools-extra/trunk/clangd/TUScheduler.cpp
> clang-tools-extra/trunk/clangd/TUScheduler.h
> clang-tools-extra/trunk/clangd/Threading.cpp
> clang-tools-extra/trunk/clangd/Threading.h
> clang-tools-extra/trunk/unittests/clangd/TUSchedulerTests.cpp
>
> Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Fri Mar 2 00:56:37
> 2018
> @@ -405,7 +405,7 @@ ClangdLSPServer::ClangdLSPServer(JSONOut
> : Out(Out), CDB(std::move(CompileCommandsDir)), CCOpts(CCOpts),
> Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
> StorePreamblesInMemory, BuildDynamicSymbolIndex, StaticIdx,
> - ResourceDir) {}
> + ResourceDir,
> /*UpdateDebounce=*/std::chrono::milliseconds(500)) {}
>
> bool ClangdLSPServer::run(std::istream &In, JSONStreamStyle InputStyle) {
> assert(!IsDone && "Run was called before");
>
> Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Fri Mar 2 00:56:37
> 2018
> @@ -76,7 +76,8 @@ ClangdServer::ClangdServer(GlobalCompila
> unsigned AsyncThreadsCount,
> bool StorePreamblesInMemory,
> bool BuildDynamicSymbolIndex, SymbolIndex
> *StaticIdx,
> - llvm::Optional<StringRef> ResourceDir)
> + llvm::Optional<StringRef> ResourceDir,
> + std::chrono::steady_clock::duration
> UpdateDebounce)
> : CompileArgs(CDB,
> ResourceDir ? ResourceDir->str() :
> getStandardResourceDir()),
> DiagConsumer(DiagConsumer), FSProvider(FSProvider),
> @@ -91,7 +92,8 @@ ClangdServer::ClangdServer(GlobalCompila
> FileIdx
> ? [this](PathRef Path,
> ParsedAST *AST) { FileIdx->update(Path,
> AST); }
> - : ASTParsedCallback()) {
> + : ASTParsedCallback(),
> + UpdateDebounce) {
> if (FileIdx && StaticIdx) {
> MergedIndex = mergeIndex(FileIdx.get(), StaticIdx);
> Index = MergedIndex.get();
>
> Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
> +++ clang-tools-extra/trunk/clangd/ClangdServer.h Fri Mar 2 00:56:37 2018
> @@ -125,6 +125,8 @@ public:
> /// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on
> a
> /// worker thread. Therefore, instances of \p DiagConsumer must properly
> /// synchronize access to shared state.
> + /// UpdateDebounce determines how long to wait after a new version of
> the file
> + /// before starting to compute diagnostics.
> ///
> /// \p StorePreamblesInMemory defines whether the Preambles generated by
> /// clangd are stored in-memory or on disk.
> @@ -135,13 +137,17 @@ public:
> ///
> /// If \p StaticIdx is set, ClangdServer uses the index for global code
> /// completion.
> + /// FIXME(sammccall): pull out an options struct.
> ClangdServer(GlobalCompilationDatabase &CDB,
> DiagnosticsConsumer &DiagConsumer,
> FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
> bool StorePreamblesInMemory,
> bool BuildDynamicSymbolIndex = false,
> SymbolIndex *StaticIdx = nullptr,
> - llvm::Optional<StringRef> ResourceDir = llvm::None);
> + llvm::Optional<StringRef> ResourceDir = llvm::None,
> + /* Tiny default debounce, so tests hit the debounce logic
> */
> + std::chrono::steady_clock::duration UpdateDebounce =
> + std::chrono::milliseconds(20));
>
> /// Set the root path of the workspace.
> void setRootPath(PathRef RootPath);
>
> Modified: clang-tools-extra/trunk/clangd/TUScheduler.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/TUScheduler.cpp?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/TUScheduler.cpp (original)
> +++ clang-tools-extra/trunk/clangd/TUScheduler.cpp Fri Mar 2 00:56:37 2018
> @@ -54,6 +54,7 @@
>
> namespace clang {
> namespace clangd {
> +using std::chrono::steady_clock;
> namespace {
> class ASTWorkerHandle;
>
> @@ -69,8 +70,8 @@ class ASTWorkerHandle;
> /// worker.
> class ASTWorker {
> friend class ASTWorkerHandle;
> - ASTWorker(llvm::StringRef File, Semaphore &Barrier, CppFile AST,
> - bool RunSync);
> + ASTWorker(llvm::StringRef File, Semaphore &Barrier, CppFile AST, bool
> RunSync,
> + steady_clock::duration UpdateDebounce);
>
> public:
> /// Create a new ASTWorker and return a handle to it.
> @@ -79,7 +80,8 @@ public:
> /// synchronously instead. \p Barrier is acquired when processing each
> /// request, it is be used to limit the number of actively running
> threads.
> static ASTWorkerHandle Create(llvm::StringRef File, AsyncTaskRunner
> *Tasks,
> - Semaphore &Barrier, CppFile AST);
> + Semaphore &Barrier, CppFile AST,
> + steady_clock::duration UpdateDebounce);
> ~ASTWorker();
>
> void update(ParseInputs Inputs, WantDiagnostics,
> @@ -101,18 +103,27 @@ private:
> /// Adds a new task to the end of the request queue.
> void startTask(llvm::StringRef Name, UniqueFunction<void()> Task,
> llvm::Optional<WantDiagnostics> UpdateType);
> + /// Determines the next action to perform.
> + /// All actions that should never run are disarded.
> + /// Returns a deadline for the next action. If it's expired, run now.
> + /// scheduleLocked() is called again at the deadline, or if requests
> arrive.
> + Deadline scheduleLocked();
> /// Should the first task in the queue be skipped instead of run?
> bool shouldSkipHeadLocked() const;
>
> struct Request {
> UniqueFunction<void()> Action;
> std::string Name;
> + steady_clock::time_point AddTime;
> Context Ctx;
> llvm::Optional<WantDiagnostics> UpdateType;
> };
>
> - std::string File;
> + const std::string File;
> const bool RunSync;
> + // Time to wait after an update to see whether another update obsoletes
> it.
> + const steady_clock::duration UpdateDebounce;
> +
> Semaphore &Barrier;
> // AST and FileInputs are only accessed on the processing thread from
> run().
> CppFile AST;
> @@ -172,9 +183,10 @@ private:
> };
>
> ASTWorkerHandle ASTWorker::Create(llvm::StringRef File, AsyncTaskRunner
> *Tasks,
> - Semaphore &Barrier, CppFile AST) {
> - std::shared_ptr<ASTWorker> Worker(
> - new ASTWorker(File, Barrier, std::move(AST), /*RunSync=*/!Tasks));
> + Semaphore &Barrier, CppFile AST,
> + steady_clock::duration UpdateDebounce) {
> + std::shared_ptr<ASTWorker> Worker(new ASTWorker(
> + File, Barrier, std::move(AST), /*RunSync=*/!Tasks, UpdateDebounce));
> if (Tasks)
> Tasks->runAsync("worker:" + llvm::sys::path::filename(File),
> [Worker]() { Worker->run(); });
> @@ -183,9 +195,9 @@ ASTWorkerHandle ASTWorker::Create(llvm::
> }
>
> ASTWorker::ASTWorker(llvm::StringRef File, Semaphore &Barrier, CppFile
> AST,
> - bool RunSync)
> - : File(File), RunSync(RunSync), Barrier(Barrier), AST(std::move(AST)),
> - Done(false) {
> + bool RunSync, steady_clock::duration UpdateDebounce)
> + : File(File), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
> + Barrier(Barrier), AST(std::move(AST)), Done(false) {
> if (RunSync)
> return;
> }
> @@ -275,8 +287,8 @@ void ASTWorker::startTask(llvm::StringRe
> {
> std::lock_guard<std::mutex> Lock(Mutex);
> assert(!Done && "running a task after stop()");
> - Requests.push_back(
> - {std::move(Task), Name, Context::current().clone(), UpdateType});
> + Requests.push_back({std::move(Task), Name, steady_clock::now(),
> + Context::current().clone(), UpdateType});
> }
> RequestsCV.notify_all();
> }
> @@ -286,17 +298,31 @@ void ASTWorker::run() {
> Request Req;
> {
> std::unique_lock<std::mutex> Lock(Mutex);
> - RequestsCV.wait(Lock, [&]() { return Done || !Requests.empty(); });
> - if (Requests.empty()) {
> - assert(Done);
> - return;
> - }
> - // Even when Done is true, we finish processing all pending requests
> - // before exiting the processing loop.
> + for (auto Wait = scheduleLocked(); !Wait.expired();
> + Wait = scheduleLocked()) {
> + if (Done) {
> + if (Requests.empty())
> + return;
> + else // Even though Done is set, finish pending requests.
> + break; // However, skip delays to shutdown fast.
> + }
> +
> + // Tracing: we have a next request, attribute this sleep to it.
> + Optional<WithContext> Ctx;
> + Optional<trace::Span> Tracer;
> + if (!Requests.empty()) {
> + Ctx.emplace(Requests.front().Ctx.clone());
> + Tracer.emplace("Debounce");
> + SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
> + if (!(Wait == Deadline::infinity()))
> + SPAN_ATTACH(*Tracer, "sleep_ms",
> +
> std::chrono::duration_cast<std::chrono::milliseconds>(
> + Wait.time() - steady_clock::now())
> + .count());
> + }
>
> - while (shouldSkipHeadLocked())
> - Requests.pop_front();
> - assert(!Requests.empty() && "skipped the whole queue");
> + wait(Lock, RequestsCV, Wait);
> + }
> Req = std::move(Requests.front());
> // Leave it on the queue for now, so waiters don't see an empty
> queue.
> } // unlock Mutex
> @@ -316,6 +342,24 @@ void ASTWorker::run() {
> }
> }
>
> +Deadline ASTWorker::scheduleLocked() {
> + if (Requests.empty())
> + return Deadline::infinity(); // Wait for new requests.
> + while (shouldSkipHeadLocked())
> + Requests.pop_front();
> + assert(!Requests.empty() && "skipped the whole queue");
> + // Some updates aren't dead yet, but never end up being used.
> + // e.g. the first keystroke is live until obsoleted by the second.
> + // We debounce "maybe-unused" writes, sleeping 500ms in case they
> become dead.
> + // But don't delay reads (including updates where diagnostics are
> needed).
> + for (const auto &R : Requests)
> + if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
> + return Deadline::zero();
> + // Front request needs to be debounced, so determine when we're ready.
> + Deadline D(Requests.front().AddTime + UpdateDebounce);
> + return D;
> +}
> +
> // Returns true if Requests.front() is a dead update that can be skipped.
> bool ASTWorker::shouldSkipHeadLocked() const {
> assert(!Requests.empty());
> @@ -370,10 +414,12 @@ struct TUScheduler::FileData {
>
> TUScheduler::TUScheduler(unsigned AsyncThreadsCount,
> bool StorePreamblesInMemory,
> - ASTParsedCallback ASTCallback)
> + ASTParsedCallback ASTCallback,
> + steady_clock::duration UpdateDebounce)
> : StorePreamblesInMemory(StorePreamblesInMemory),
> PCHOps(std::make_shared<PCHContainerOperations>()),
> - ASTCallback(std::move(ASTCallback)), Barrier(AsyncThreadsCount) {
> + ASTCallback(std::move(ASTCallback)), Barrier(AsyncThreadsCount),
> + UpdateDebounce(UpdateDebounce) {
> if (0 < AsyncThreadsCount) {
> PreambleTasks.emplace();
> WorkerThreads.emplace();
> @@ -409,7 +455,8 @@ void TUScheduler::update(
> // Create a new worker to process the AST-related tasks.
> ASTWorkerHandle Worker = ASTWorker::Create(
> File, WorkerThreads ? WorkerThreads.getPointer() : nullptr,
> Barrier,
> - CppFile(File, StorePreamblesInMemory, PCHOps, ASTCallback));
> + CppFile(File, StorePreamblesInMemory, PCHOps, ASTCallback),
> + UpdateDebounce);
> FD = std::unique_ptr<FileData>(new FileData{Inputs,
> std::move(Worker)});
> } else {
> FD->Inputs = Inputs;
>
> Modified: clang-tools-extra/trunk/clangd/TUScheduler.h
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/TUScheduler.h?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/TUScheduler.h (original)
> +++ clang-tools-extra/trunk/clangd/TUScheduler.h Fri Mar 2 00:56:37 2018
> @@ -17,6 +17,7 @@
>
> namespace clang {
> namespace clangd {
> +
> /// 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).
> @@ -46,10 +47,12 @@ enum class WantDiagnostics {
> /// and scheduling tasks.
> /// Callbacks are run on a threadpool and it's appropriate to do slow
> work in
> /// them. Each task has a name, used for tracing (should be
> UpperCamelCase).
> +/// FIXME(sammccall): pull out a scheduler options struct.
> class TUScheduler {
> public:
> TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory,
> - ASTParsedCallback ASTCallback);
> + ASTParsedCallback ASTCallback,
> + std::chrono::steady_clock::duration UpdateDebounce);
> ~TUScheduler();
>
> /// Returns estimated memory usage for each of the currently open files.
> @@ -101,6 +104,7 @@ private:
> // asynchronously.
> llvm::Optional<AsyncTaskRunner> PreambleTasks;
> llvm::Optional<AsyncTaskRunner> WorkerThreads;
> + std::chrono::steady_clock::duration UpdateDebounce;
> };
> } // namespace clangd
> } // namespace clang
>
> Modified: clang-tools-extra/trunk/clangd/Threading.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Threading.cpp?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/Threading.cpp (original)
> +++ clang-tools-extra/trunk/clangd/Threading.cpp Fri Mar 2 00:56:37 2018
> @@ -76,10 +76,19 @@ void AsyncTaskRunner::runAsync(llvm::Twi
> Deadline timeoutSeconds(llvm::Optional<double> Seconds) {
> using namespace std::chrono;
> if (!Seconds)
> - return llvm::None;
> + return Deadline::infinity();
> return steady_clock::now() +
>
> duration_cast<steady_clock::duration>(duration<double>(*Seconds));
> }
>
> +void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
> + Deadline D) {
> + if (D == Deadline::zero())
> + return;
> + if (D == Deadline::infinity())
> + return CV.wait(Lock);
> + CV.wait_until(Lock, D.time());
> +}
> +
> } // namespace clangd
> } // namespace clang
>
> Modified: clang-tools-extra/trunk/clangd/Threading.h
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Threading.h?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/clangd/Threading.h (original)
> +++ clang-tools-extra/trunk/clangd/Threading.h Fri Mar 2 00:56:37 2018
> @@ -50,18 +50,50 @@ private:
> std::size_t FreeSlots;
> };
>
> -/// A point in time we may wait for, or None to wait forever.
> +/// A point in time we can wait for.
> +/// Can be zero (don't wait) or infinity (wait forever).
> /// (Not time_point::max(), because many std::chrono implementations
> overflow).
> -using Deadline = llvm::Optional<std::chrono::steady_clock::time_point>;
> -/// Makes a deadline from a timeout in seconds.
> +class Deadline {
> +public:
> + Deadline(std::chrono::steady_clock::time_point Time)
> + : Type(Finite), Time(Time) {}
> + static Deadline zero() { return Deadline(Zero); }
> + static Deadline infinity() { return Deadline(Infinite); }
> +
> + std::chrono::steady_clock::time_point time() const {
> + assert(Type == Finite);
> + return Time;
> + }
> + bool expired() const {
> + return (Type == Zero) ||
> + (Type == Finite && Time < std::chrono::steady_clock::now());
> + }
> + bool operator==(const Deadline &Other) const {
> + return (Type == Other.Type) && (Type != Finite || Time == Other.Time);
> + }
> +
> +private:
> + enum Type { Zero, Infinite, Finite };
> +
> + Deadline(enum Type Type) : Type(Type) {}
> + enum Type Type;
> + std::chrono::steady_clock::time_point Time;
> +};
> +
> +/// Makes a deadline from a timeout in seconds. None means wait forever.
> Deadline timeoutSeconds(llvm::Optional<double> Seconds);
> +/// Wait once on CV for the specified duration.
> +void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
> + Deadline D);
> /// Waits on a condition variable until F() is true or D expires.
> template <typename Func>
> LLVM_NODISCARD bool wait(std::unique_lock<std::mutex> &Lock,
> std::condition_variable &CV, Deadline D, Func F)
> {
> - if (D)
> - return CV.wait_until(Lock, *D, F);
> - CV.wait(Lock, F);
> + while (!F()) {
> + if (D.expired())
> + return false;
> + wait(Lock, CV, D);
> + }
> return true;
> }
>
> @@ -73,7 +105,7 @@ public:
> /// Destructor waits for all pending tasks to finish.
> ~AsyncTaskRunner();
>
> - void wait() const { (void) wait(llvm::None); }
> + void wait() const { (void)wait(Deadline::infinity()); }
> LLVM_NODISCARD bool wait(Deadline D) const;
> // The name is used for tracing and debugging (e.g. to name a spawned
> thread).
> void runAsync(llvm::Twine Name, UniqueFunction<void()> Action);
>
> Modified: clang-tools-extra/trunk/unittests/clangd/TUSchedulerTests.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/TUSchedulerTests.cpp?rev=326546&r1=326545&r2=326546&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/unittests/clangd/TUSchedulerTests.cpp
> (original)
> +++ clang-tools-extra/trunk/unittests/clangd/TUSchedulerTests.cpp Fri Mar
> 2 00:56:37 2018
> @@ -42,7 +42,8 @@ private:
> TEST_F(TUSchedulerTests, MissingFiles) {
> TUScheduler S(getDefaultAsyncThreadsCount(),
> /*StorePreamblesInMemory=*/true,
> - /*ASTParsedCallback=*/nullptr);
> + /*ASTParsedCallback=*/nullptr,
> +
> /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero());
>
> auto Added = testPath("added.cpp");
> Files[Added] = "";
> @@ -94,9 +95,11 @@ TEST_F(TUSchedulerTests, WantDiagnostics
> // To avoid a racy test, don't allow tasks to actualy run on the
> worker
> // thread until we've scheduled them all.
> Notification Ready;
> - TUScheduler S(getDefaultAsyncThreadsCount(),
> - /*StorePreamblesInMemory=*/true,
> - /*ASTParsedCallback=*/nullptr);
> + TUScheduler S(
> + getDefaultAsyncThreadsCount(),
> + /*StorePreamblesInMemory=*/true,
> + /*ASTParsedCallback=*/nullptr,
> + /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero());
> auto Path = testPath("foo.cpp");
> S.update(Path, getInputs(Path, ""), WantDiagnostics::Yes,
> [&](std::vector<DiagWithFixIts>) { Ready.wait(); });
> @@ -118,6 +121,28 @@ TEST_F(TUSchedulerTests, WantDiagnostics
> EXPECT_EQ(2, CallbackCount);
> }
>
> +TEST_F(TUSchedulerTests, Debounce) {
> + std::atomic<int> CallbackCount(0);
> + {
> + TUScheduler S(getDefaultAsyncThreadsCount(),
> + /*StorePreamblesInMemory=*/true,
> + /*ASTParsedCallback=*/nullptr,
> + /*UpdateDebounce=*/std::chrono::milliseconds(50));
> + auto Path = testPath("foo.cpp");
> + S.update(Path, getInputs(Path, "auto (debounced)"),
> WantDiagnostics::Auto,
> + [&](std::vector<DiagWithFixIts> Diags) {
> + ADD_FAILURE() << "auto should have been debounced and
> canceled";
> + });
> + std::this_thread::sleep_for(std::chrono::milliseconds(10));
> + S.update(Path, getInputs(Path, "auto (timed out)"),
> WantDiagnostics::Auto,
> + [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
> + std::this_thread::sleep_for(std::chrono::milliseconds(60));
> + S.update(Path, getInputs(Path, "auto (shut down)"),
> WantDiagnostics::Auto,
> + [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
> + }
> + EXPECT_EQ(2, CallbackCount);
> +}
> +
> TEST_F(TUSchedulerTests, ManyUpdates) {
> const int FilesCount = 3;
> const int UpdatesPerFile = 10;
> @@ -131,7 +156,8 @@ TEST_F(TUSchedulerTests, ManyUpdates) {
> {
> TUScheduler S(getDefaultAsyncThreadsCount(),
> /*StorePreamblesInMemory=*/true,
> - /*ASTParsedCallback=*/nullptr);
> + /*ASTParsedCallback=*/nullptr,
> + /*UpdateDebounce=*/std::chrono::milliseconds(50));
>
> std::vector<std::string> Files;
> for (int I = 0; I < FilesCount; ++I) {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
--
Regards,
Ilya Biryukov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180302/28942b8f/attachment-0001.html>
More information about the cfe-commits
mailing list