//===-- MemoryTreeTests.cpp -------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "support/MemoryTree.h" #include "support/TestTracer.h" #include "support/Trace.h" #include "llvm/Support/Allocator.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include namespace clang { namespace clangd { namespace { using testing::Contains; using testing::ElementsAre; using testing::IsEmpty; using testing::UnorderedElementsAre; MATCHER_P2(WithNameAndSize, Name, Size, "") { return arg.first == Name && arg.getSecond().total() == static_cast(Size); } TEST(MemoryTree, Basics) { MemoryTree MT; EXPECT_EQ(MT.total(), 0U); EXPECT_THAT(MT.children(), IsEmpty()); MT.addUsage(42); EXPECT_EQ(MT.total(), 42U); EXPECT_THAT(MT.children(), IsEmpty()); MT.child("leaf").addUsage(1); EXPECT_EQ(MT.total(), 43U); EXPECT_THAT(MT.children(), UnorderedElementsAre(WithNameAndSize("leaf", 1))); // child should be idempotent. MT.child("leaf").addUsage(1); EXPECT_EQ(MT.total(), 44U); EXPECT_THAT(MT.children(), UnorderedElementsAre(WithNameAndSize("leaf", 2))); } TEST(MemoryTree, DetailedNodesWithoutDetails) { MemoryTree MT; MT.detail("should_be_ignored").addUsage(2); EXPECT_THAT(MT.children(), IsEmpty()); EXPECT_EQ(MT.total(), 2U); // Make sure children from details are merged. MT.detail("first_detail").child("leaf").addUsage(1); MT.detail("second_detail").child("leaf").addUsage(1); EXPECT_THAT(MT.children(), Contains(WithNameAndSize("leaf", 2))); } TEST(MemoryTree, DetailedNodesWithDetails) { llvm::BumpPtrAllocator Alloc; MemoryTree MT(&Alloc); { auto &Detail = MT.detail("first_detail"); Detail.child("leaf").addUsage(1); EXPECT_THAT(MT.children(), Contains(WithNameAndSize("first_detail", 1))); EXPECT_THAT(Detail.children(), Contains(WithNameAndSize("leaf", 1))); } { auto &Detail = MT.detail("second_detail"); Detail.child("leaf").addUsage(1); EXPECT_THAT(MT.children(), Contains(WithNameAndSize("second_detail", 1))); EXPECT_THAT(Detail.children(), Contains(WithNameAndSize("leaf", 1))); } } TEST(MemoryTree, Record) { trace::TestTracer Tracer; static constexpr llvm::StringLiteral MetricName = "memory_usage"; static constexpr trace::Metric OutMetric(MetricName, trace::Metric::Value, "component_name"); 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; record(AddNodes(MemoryTree(&Alloc)), "root", OutMetric); 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