diff --git a/clang-tools-extra/clangd/support/Trace.h b/clang-tools-extra/clangd/support/Trace.h --- a/clang-tools-extra/clangd/support/Trace.h +++ b/clang-tools-extra/clangd/support/Trace.h @@ -17,6 +17,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_ #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_TRACE_H_ +#include "MemoryTree.h" #include "support/Context.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -68,6 +69,15 @@ const llvm::StringLiteral LabelName; }; +/// Convenient helper for collecting memory usage metrics from across multiple +/// components. Results are recorded under a metric named "memory_usage". +void recordMemoryUsage(double Value, llvm::StringRef ComponentName); + +/// Traverses \p MT while concatenating edges on the path with "." as component +/// names and records total memory usage of each node under "memory_usage" +/// metric. +void recordMemoryUsage(const MemoryTree &MT, std::string RootName); + /// A consumer of trace events and measurements. The events are produced by /// Spans and trace::log, the measurements are produced by Metrics::record. /// Implementations of this interface must be thread-safe. diff --git a/clang-tools-extra/clangd/support/Trace.cpp b/clang-tools-extra/clangd/support/Trace.cpp --- a/clang-tools-extra/clangd/support/Trace.cpp +++ b/clang-tools-extra/clangd/support/Trace.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "support/Trace.h" +#include "MemoryTree.h" #include "support/Context.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" @@ -20,6 +21,7 @@ #include #include #include +#include namespace clang { namespace clangd { @@ -253,6 +255,21 @@ Key> JSONTracer::SpanKey; EventTracer *T = nullptr; + +size_t traverseTree(const MemoryTree &MT, std::string &ComponentName) { + size_t OriginalLen = ComponentName.size(); + if (!ComponentName.empty()) + ComponentName += '.'; + size_t Total = MT.self(); + for (const auto &Entry : MT.children()) { + ComponentName += Entry.first; + Total += traverseTree(Entry.getSecond(), ComponentName); + ComponentName.resize(OriginalLen + 1); + } + ComponentName.resize(OriginalLen); + recordMemoryUsage(Total, ComponentName); + return Total; +} } // namespace Session::Session(EventTracer &Tracer) { @@ -326,6 +343,17 @@ Context EventTracer::beginSpan(llvm::StringRef Name, llvm::json::Object *Args) { return Context::current().clone(); } + +void recordMemoryUsage(double Value, llvm::StringRef ComponentName) { + static constexpr Metric MemoryUsage("memory_usage", Metric::Value, + "component_name"); + + MemoryUsage.record(Value, ComponentName); +} + +void recordMemoryUsage(const MemoryTree &MT, std::string RootName) { + traverseTree(MT, RootName); +} } // namespace trace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/support/TraceTests.cpp b/clang-tools-extra/clangd/unittests/support/TraceTests.cpp --- a/clang-tools-extra/clangd/unittests/support/TraceTests.cpp +++ b/clang-tools-extra/clangd/unittests/support/TraceTests.cpp @@ -8,6 +8,7 @@ #include "TestTracer.h" #include "support/Context.h" +#include "support/MemoryTree.h" #include "support/Trace.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" @@ -186,6 +187,43 @@ StartsWith("d,dist,\"a\nb\",1"), "")); } +TEST(recordMemoryUsage, Traversal) { + trace::TestTracer Tracer; + constexpr llvm::StringLiteral MetricName = "memory_usage"; + auto AddNodes = [](MemoryTree Root) { + Root.child("leaf").addUsage(1); + + { + auto &Detail = Root.detail("detail"); + Detail.addUsage(1); + Detail.child("leaf").addUsage(1); + auto &Child = Detail.child("child"); + Child.addUsage(1); + Child.child("leaf").addUsage(1); + } + + { + auto &Child = Root.child("child"); + Child.addUsage(1); + Child.child("leaf").addUsage(1); + } + return Root; + }; + + llvm::BumpPtrAllocator Alloc; + trace::recordMemoryUsage(AddNodes(MemoryTree(&Alloc)), "root"); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root"), ElementsAre(7)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.leaf"), ElementsAre(1)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.detail"), ElementsAre(4)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.detail.leaf"), + ElementsAre(1)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.detail.child"), + ElementsAre(2)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.detail.child.leaf"), + ElementsAre(1)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.child"), ElementsAre(2)); + EXPECT_THAT(Tracer.takeMetric(MetricName, "root.child.leaf"), ElementsAre(1)); +} } // namespace } // namespace clangd } // namespace clang