[clangd] Add $/memoryUsage LSP extension
authorKadir Cetinkaya <kadircet@google.com>
Mon, 12 Oct 2020 22:10:04 +0000 (00:10 +0200)
committerKadir Cetinkaya <kadircet@google.com>
Mon, 19 Oct 2020 10:30:25 +0000 (12:30 +0200)
Performs a detailed profiling of clangd lsp server and conveys the
result to the client as a json object. It is of the form:
   {
     "_self": 0,
     "_total": 8,
     "child1": {
       "_self": 4,
       "_total": 4,
     }
     "child2": {
       "_self": 2,
       "_total": 4,
       "child_deep": {
         "_self": 2,
         "_total": 2,
       }
     }
   }

Differential Revision: https://reviews.llvm.org/D89277

clang-tools-extra/clangd/ClangdLSPServer.cpp
clang-tools-extra/clangd/ClangdLSPServer.h
clang-tools-extra/clangd/Protocol.cpp
clang-tools-extra/clangd/Protocol.h
clang-tools-extra/clangd/test/initialize-params.test
clang-tools-extra/clangd/test/memory_tree.test [new file with mode: 0644]

index d46147a..99c2465 100644 (file)
 #include "llvm/Support/Path.h"
 #include "llvm/Support/SHA1.h"
 #include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
 #include <chrono>
 #include <cstddef>
+#include <cstdint>
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -617,6 +620,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
                    ExecuteCommandParams::CLANGD_APPLY_TWEAK}},
              }},
             {"typeHierarchyProvider", true},
+            {"memoryUsageProvider", true}, // clangd extension.
         }}}};
   if (Opts.Encoding)
     Result["offsetEncoding"] = *Opts.Encoding;
@@ -1383,6 +1387,14 @@ void ClangdLSPServer::onSemanticTokensDelta(
       });
 }
 
+void ClangdLSPServer::onMemoryUsage(const NoParams &,
+                                    Callback<MemoryTree> Reply) {
+  llvm::BumpPtrAllocator DetailAlloc;
+  MemoryTree MT(&DetailAlloc);
+  profile(MT);
+  Reply(std::move(MT));
+}
+
 ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
                                  const ThreadsafeFS &TFS,
                                  const ClangdLSPServer::Options &Opts)
@@ -1425,6 +1437,7 @@ ClangdLSPServer::ClangdLSPServer(class Transport &Transp,
   MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink);
   MsgHandler->bind("textDocument/semanticTokens/full", &ClangdLSPServer::onSemanticTokens);
   MsgHandler->bind("textDocument/semanticTokens/full/delta", &ClangdLSPServer::onSemanticTokensDelta);
+  MsgHandler->bind("$/memoryUsage", &ClangdLSPServer::onMemoryUsage);
   if (Opts.FoldingRanges)
     MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange);
   // clang-format on
index 7054c48..9fb23a0 100644 (file)
@@ -24,6 +24,7 @@
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/JSON.h"
 #include <chrono>
+#include <cstddef>
 #include <memory>
 
 namespace clang {
@@ -141,6 +142,9 @@ private:
   void onSemanticTokens(const SemanticTokensParams &, Callback<SemanticTokens>);
   void onSemanticTokensDelta(const SemanticTokensDeltaParams &,
                              Callback<SemanticTokensOrDelta>);
+  /// This is a clangd extension. Provides a json tree representing memory usage
+  /// hierarchy.
+  void onMemoryUsage(const NoParams &, Callback<MemoryTree>);
 
   std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
 
index f41cea2..0b89c62 100644 (file)
@@ -1300,5 +1300,17 @@ llvm::json::Value toJSON(const FoldingRange &Range) {
   return Result;
 }
 
+llvm::json::Value toJSON(const MemoryTree &MT) {
+  llvm::json::Object Out;
+  int64_t Total = MT.self();
+  Out["_self"] = Total;
+  for (const auto &Entry : MT.children()) {
+    auto Child = toJSON(Entry.getSecond());
+    Total += *Child.getAsObject()->getInteger("_total");
+    Out[Entry.first] = std::move(Child);
+  }
+  Out["_total"] = Total;
+  return Out;
+}
 } // namespace clangd
 } // namespace clang
index 6f395ff..165a4a8 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "URI.h"
 #include "index/SymbolID.h"
+#include "support/MemoryTree.h"
 #include "clang/Index/IndexSymbol.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/Support/JSON.h"
@@ -1576,6 +1577,27 @@ struct FoldingRange {
 };
 llvm::json::Value toJSON(const FoldingRange &Range);
 
+/// Keys starting with an underscore(_) represent leaves, e.g. _total or _self
+/// for memory usage of whole subtree or only that specific node in bytes. All
+/// other keys represents children. An example:
+///   {
+///     "_self": 0,
+///     "_total": 8,
+///     "child1": {
+///       "_self": 4,
+///       "_total": 4,
+///     }
+///     "child2": {
+///       "_self": 2,
+///       "_total": 4,
+///       "child_deep": {
+///         "_self": 2,
+///         "_total": 2,
+///       }
+///     }
+///   }
+llvm::json::Value toJSON(const MemoryTree &MT);
+
 } // namespace clangd
 } // namespace clang
 
index 4125c27..8f4d065 100644 (file)
@@ -66,6 +66,7 @@
 # CHECK-NEXT:        ]
 # CHECK-NEXT:      },
 # CHECK-NEXT:      "hoverProvider": true,
+# CHECK-NEXT:      "memoryUsageProvider": true
 # CHECK-NEXT:      "referencesProvider": true,
 # CHECK-NEXT:      "renameProvider": true,
 # CHECK-NEXT:      "selectionRangeProvider": true,
diff --git a/clang-tools-extra/clangd/test/memory_tree.test b/clang-tools-extra/clangd/test/memory_tree.test
new file mode 100644 (file)
index 0000000..41efdfb
--- /dev/null
@@ -0,0 +1,81 @@
+# 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":"$/memoryUsage","params":{}}
+# CHECK:        "id": 1,
+# CHECK-NEXT:   "jsonrpc": "2.0",
+# CHECK-NEXT:   "result": {
+# CHECK-NEXT:     "_self": {{[0-9]+}},
+# CHECK-NEXT:     "_total": {{[0-9]+}},
+# CHECK-NEXT:     "clangd_server": {
+# CHECK-NEXT:       "_self": {{[0-9]+}},
+# CHECK-NEXT:       "_total": {{[0-9]+}},
+# CHECK-NEXT:       "dynamic_index": {
+# CHECK-NEXT:         "_self": {{[0-9]+}},
+# CHECK-NEXT:         "_total": {{[0-9]+}},
+# CHECK-NEXT:         "main_file": {
+# CHECK-NEXT:           "_self": {{[0-9]+}},
+# CHECK-NEXT:           "_total": {{[0-9]+}},
+# CHECK-NEXT:           "index": {
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           },
+# CHECK-NEXT:           "symbols": {
+# CHECK-NEXT:             "{{.*}}main.cpp": {
+# CHECK-NEXT:               "_self": {{[0-9]+}},
+# CHECK-NEXT:               "_total": {{[0-9]+}},
+# CHECK-NEXT:               "references": {
+# CHECK-NEXT:                 "_self": {{[0-9]+}},
+# CHECK-NEXT:                 "_total": {{[0-9]+}}
+# CHECK-NEXT:               },
+# CHECK-NEXT:               "relations": {
+# CHECK-NEXT:                 "_self": {{[0-9]+}},
+# CHECK-NEXT:                 "_total": {{[0-9]+}}
+# CHECK-NEXT:               },
+# CHECK-NEXT:               "symbols": {
+# CHECK-NEXT:                 "_self": {{[0-9]+}},
+# CHECK-NEXT:                 "_total": {{[0-9]+}}
+# CHECK-NEXT:               }
+# CHECK-NEXT:             },
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           }
+# CHECK-NEXT:         },
+# CHECK-NEXT:         "preamble": {
+# CHECK-NEXT:           "_self": {{[0-9]+}},
+# CHECK-NEXT:           "_total": {{[0-9]+}},
+# CHECK-NEXT:           "index": {
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           },
+# CHECK-NEXT:           "symbols": {
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           }
+# CHECK-NEXT:         }
+# CHECK-NEXT:       },
+# CHECK-NEXT:       "tuscheduler": {
+# CHECK-NEXT:         "{{.*}}main.cpp": {
+# CHECK-NEXT:           "_self": {{[0-9]+}},
+# CHECK-NEXT:           "_total": {{[0-9]+}},
+# CHECK-NEXT:           "ast": {
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           },
+# CHECK-NEXT:           "preamble": {
+# CHECK-NEXT:             "_self": {{[0-9]+}},
+# CHECK-NEXT:             "_total": {{[0-9]+}}
+# CHECK-NEXT:           }
+# CHECK-NEXT:         },
+# CHECK-NEXT:         "_self": {{[0-9]+}},
+# CHECK-NEXT:         "_total": {{[0-9]+}}
+# CHECK-NEXT:       }
+# CHECK-NEXT:     }
+# CHECK-NEXT:   }
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
+