diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -24,6 +24,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/JSON.h" #include +#include #include namespace clang { @@ -141,6 +142,9 @@ void onSemanticTokens(const SemanticTokensParams &, Callback); void onSemanticTokensDelta(const SemanticTokensDeltaParams &, Callback); + /// This is a clangd extension. It invokes a showMessage with current + /// profiling info. + void onDumpMemoryTree(const NoParams &, Callback); std::vector getFixes(StringRef File, const clangd::Diagnostic &D); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -36,8 +36,11 @@ #include "llvm/Support/Path.h" #include "llvm/Support/SHA1.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/raw_ostream.h" #include #include +#include +#include #include #include #include @@ -1383,6 +1386,38 @@ }); } +void ClangdLSPServer::onDumpMemoryTree(const NoParams &, + Callback Reply) { + llvm::BumpPtrAllocator Alloc; + MemoryTree MT(&Alloc); + profile(MT); + + std::function + DumpTree = [&](llvm::StringRef Key, const MemoryTree &MT, + llvm::raw_ostream &OS, size_t Indent) { + size_t Total = MT.self(); + std::string ChildText; + llvm::raw_string_ostream ChildStream(ChildText); + for (const auto &Entry : MT.children()) { + ChildStream << '\n'; + Total += + DumpTree(Entry.first, Entry.getSecond(), ChildStream, Indent + 2); + } + OS << std::string(Indent, ' ') << Key << ": " << Total << " bytes" + << ChildStream.str(); + return Total; + }; + + ShowMessageParams Msg; + llvm::raw_string_ostream Str(Msg.message); + DumpTree("clangd_lsp_server", MT, Str, 0); + Str.flush(); + + notify("window/showMessage", std::move(Msg)); + Reply(nullptr); +} + ClangdLSPServer::ClangdLSPServer(class Transport &Transp, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts) @@ -1425,6 +1460,7 @@ MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink); MsgHandler->bind("textDocument/semanticTokens/full", &ClangdLSPServer::onSemanticTokens); MsgHandler->bind("textDocument/semanticTokens/full/delta", &ClangdLSPServer::onSemanticTokensDelta); + MsgHandler->bind("$/dumpMemoryTree", &ClangdLSPServer::onDumpMemoryTree); if (Opts.FoldingRanges) MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange); // clang-format on diff --git a/clang-tools-extra/clangd/test/memory_tree.test b/clang-tools-extra/clangd/test/memory_tree.test new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/test/memory_tree.test @@ -0,0 +1,33 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void func() {}"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"$/dumpMemoryTree","params":{}} +# CHECK: "method": "window/showMessage", +# CHECK-NEXT: "params": { +# CHECK-NEXT: "message": " +# CHECK-SAME: clangd_lsp_server: {{[0-9]+}} bytes\n +# CHECK-SAME: clangd_server: {{[0-9]+}} bytes\n +# CHECK-SAME: tuscheduler: {{[0-9]+}} bytes\n +# CHECK-SAME: /clangd-test/main.cpp: {{[0-9]+}} bytes\n +# CHECK-SAME: ast: {{[0-9]+}} bytes\n +# CHECK-SAME: preamble: {{[0-9]+}} bytes\n +# CHECK-SAME: dynamic_index: {{[0-9]+}} bytes\n +# CHECK-SAME: preamble: {{[0-9]+}} bytes\n +# CHECK-SAME: symbols: {{[0-9]+}} bytes\n +# CHECK-SAME: index: {{[0-9]+}} bytes\n +# CHECK-SAME: main_file: {{[0-9]+}} bytes\n +# CHECK-SAME: symbols: {{[0-9]+}} bytes\n +# CHECK-SAME: /clangd-test/main.cpp: {{[0-9]+}} bytes\n +# CHECK-SAME: relations: {{[0-9]+}} bytes\n +# CHECK-SAME: references: {{[0-9]+}} bytes\n +# CHECK-SAME: symbols: {{[0-9]+}} bytes\n +# CHECK-SAME: index: {{[0-9]+}} bytes" +# CHECK-NEXT: "type": 3 +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} +