kadircet updated this revision to Diff 297173. kadircet marked 2 inline comments as done. kadircet added a comment.
- Implement periodic profiling Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88417/new/ https://reviews.llvm.org/D88417 Files: clang-tools-extra/clangd/ClangdLSPServer.cpp clang-tools-extra/clangd/ClangdLSPServer.h clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/ClangdServer.h clang-tools-extra/clangd/unittests/ClangdTests.cpp
Index: clang-tools-extra/clangd/unittests/ClangdTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -17,6 +17,7 @@ #include "TestFS.h" #include "TestTU.h" #include "URI.h" +#include "support/MemoryTree.h" #include "support/Path.h" #include "support/Threading.h" #include "clang/Config/config.h" @@ -27,6 +28,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" @@ -48,6 +50,7 @@ namespace { using ::testing::AllOf; +using ::testing::Contains; using ::testing::ElementsAre; using ::testing::Field; using ::testing::Gt; @@ -1236,6 +1239,21 @@ EXPECT_FALSE(DiagConsumer.HadDiagsInLastCallback); } +TEST(ClangdServer, MemoryUsageTest) { + MockFS FS; + MockCompilationDatabase CDB; + ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); + + auto FooCpp = testPath("foo.cpp"); + Server.addDocument(FooCpp, ""); + ASSERT_TRUE(Server.blockUntilIdleForTest()); + + llvm::BumpPtrAllocator Alloc; + MemoryTree MT(&Alloc); + Server.profile(MT); + ASSERT_TRUE(MT.children().count("tuscheduler")); + EXPECT_TRUE(MT.child("tuscheduler").children().count(FooCpp)); +} } // namespace } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/clangd/ClangdServer.h +++ clang-tools-extra/clangd/ClangdServer.h @@ -25,6 +25,7 @@ #include "refactor/Tweak.h" #include "support/Cancellation.h" #include "support/Function.h" +#include "support/MemoryTree.h" #include "support/ThreadsafeFS.h" #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/Core/Replacement.h" @@ -340,6 +341,9 @@ LLVM_NODISCARD bool blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10); + /// Builds a nested representation of memory used by components. + void profile(MemoryTree &MT) const; + private: void formatCode(PathRef File, llvm::StringRef Code, ArrayRef<tooling::Range> Ranges, Index: clang-tools-extra/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdServer.cpp +++ clang-tools-extra/clangd/ClangdServer.cpp @@ -28,6 +28,7 @@ #include "refactor/Tweak.h" #include "support/Logger.h" #include "support/Markup.h" +#include "support/MemoryTree.h" #include "support/ThreadsafeFS.h" #include "support/Trace.h" #include "clang/Format/Format.h" @@ -824,5 +825,12 @@ BackgroundIdx->blockUntilIdleForTest(TimeoutSeconds)); } +void ClangdServer::profile(MemoryTree &MT) const { + if (DynamicIdx) + DynamicIdx->profile(MT.child("dynamic_index")); + if (BackgroundIdx) + BackgroundIdx->profile(MT.child("background_index")); + WorkScheduler.profile(MT.child("tuscheduler")); +} } // namespace clangd } // namespace clang Index: clang-tools-extra/clangd/ClangdLSPServer.h =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.h +++ clang-tools-extra/clangd/ClangdLSPServer.h @@ -22,6 +22,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/JSON.h" +#include <chrono> #include <memory> namespace clang { @@ -156,6 +157,13 @@ /// Sends a "publishDiagnostics" notification to the LSP client. void publishDiagnostics(const PublishDiagnosticsParams &); + /// Profiles resource-usage. No-op if there's no active tracer. + void profile(bool Detailed); + + /// Timepoint until which profiling is off. It is used to throttle profiling + /// requests. + std::chrono::steady_clock::time_point NoProfileBefore; + /// Since initialization of CDBs and ClangdServer is done lazily, the /// following context captures the one used while creating ClangdLSPServer and /// passes it to above mentioned object instances to make sure they share the Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ClangdLSPServer.h" +#include "ClangdServer.h" #include "CodeComplete.h" #include "Diagnostics.h" #include "DraftStore.h" @@ -26,6 +27,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" @@ -33,6 +35,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/ScopedPrinter.h" +#include <chrono> #include <cstddef> #include <memory> #include <mutex> @@ -144,7 +147,6 @@ return error("Files must be saved first: {0} (and {1} others)", LastInvalidFile, InvalidFileCount - 1); } - } // namespace // MessageHandler dispatches incoming LSP messages. @@ -163,14 +165,16 @@ log("<-- {0}", Method); if (Method == "exit") return false; - if (!Server.Server) + if (!Server.Server) { elog("Notification {0} before initialization", Method); - else if (Method == "$/cancelRequest") + } else if (Method == "$/cancelRequest") { onCancel(std::move(Params)); - else if (auto Handler = Notifications.lookup(Method)) + } else if (auto Handler = Notifications.lookup(Method)) { Handler(std::move(Params)); - else + Server.profile(/*Detailed=*/false); + } else { log("unhandled notification {0}", Method); + } return true; } @@ -1227,6 +1231,25 @@ notify("textDocument/publishDiagnostics", Params); } +void ClangdLSPServer::profile(bool Detailed) { + if (!trace::enabled()) + return; + // Profiling might be expensive, so we throttle it to happen once every 5 + // minutes. + static constexpr auto ProfileInterval = std::chrono::minutes(5); + auto Now = std::chrono::steady_clock::now(); + if (Now < NoProfileBefore) + return; + + trace::Span Tracer(Detailed ? "ProfileDetailed" : "ProfileBrief"); + llvm::BumpPtrAllocator DetailAlloc; + MemoryTree MT(Detailed ? &DetailAlloc : nullptr); + if (Server) + Server->profile(MT); + MT.record("clangd_server"); + NoProfileBefore = Now + ProfileInterval; +} + // FIXME: This function needs to be properly tested. void ClangdLSPServer::onChangeConfiguration( const DidChangeConfigurationParams &Params) { @@ -1397,6 +1420,10 @@ if (Opts.FoldingRanges) MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange); // clang-format on + + // Delay profiling for a minute, as serious allocations don't happen at + // startup. + NoProfileBefore = std::chrono::steady_clock::now() + std::chrono::minutes(1); } ClangdLSPServer::~ClangdLSPServer() {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits