| // Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "src/developer/memory/metrics/printer.h" | |
| #include <gtest/gtest.h> | |
| #include "src/developer/memory/metrics/capture.h" | |
| #include "src/developer/memory/metrics/summary.h" | |
| #include "src/developer/memory/metrics/tests/test_utils.h" | |
| #include "src/lib/fxl/strings/split_string.h" | |
| namespace memory { | |
| namespace test { | |
| using PrinterUnitTest = testing::Test; | |
| void ConfirmLines(std::ostringstream& oss, std::vector<std::string> expected_lines) { | |
| SCOPED_TRACE(""); | |
| auto lines = fxl::SplitStringCopy(oss.str(), "\n", fxl::kKeepWhitespace, fxl::kSplitWantNonEmpty); | |
| ASSERT_EQ(expected_lines.size(), lines.size()); | |
| for (size_t li = 0; li < expected_lines.size(); li++) { | |
| SCOPED_TRACE(li); | |
| std::string expected_line = expected_lines.at(li); | |
| std::string_view line = lines.at(li); | |
| EXPECT_STREQ(expected_line.c_str(), line.data()); | |
| } | |
| } | |
| TEST_F(PrinterUnitTest, PrintCaptureKMEM) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = {.total_bytes = 300, | |
| .free_bytes = 100, | |
| .wired_bytes = 10, | |
| .total_heap_bytes = 20, | |
| .free_heap_bytes = 30, | |
| .vmo_bytes = 40, | |
| .mmu_overhead_bytes = 50, | |
| .ipc_bytes = 60, | |
| .other_bytes = 70}, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "v1", .committed_bytes = 100}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1}}, | |
| }, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.PrintCapture(c, KMEM, SORTED); | |
| ConfirmLines(oss, {"K,1234,300,100,10,20,30,40,50,60,70"}); | |
| } | |
| TEST_F(PrinterUnitTest, PrintCaptureVMO) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = | |
| { | |
| .total_bytes = 300, | |
| .free_bytes = 100, | |
| .wired_bytes = 10, | |
| .total_heap_bytes = 20, | |
| .free_heap_bytes = 30, | |
| .vmo_bytes = 40, | |
| .mmu_overhead_bytes = 50, | |
| .ipc_bytes = 60, | |
| .other_bytes = 70, | |
| }, | |
| .vmos = | |
| { | |
| { | |
| .koid = 1, | |
| .name = "v1", | |
| .size_bytes = 100, | |
| .parent_koid = 200, | |
| .committed_bytes = 300, | |
| }, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1}}, | |
| }, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.PrintCapture(c, VMO, SORTED); | |
| ConfirmLines(oss, { | |
| "K,1234,300,100,10,20,30,40,50,60,70", | |
| "P,100,p1,1", | |
| "V,1,v1,200,300", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, PrintSummaryKMEM) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = | |
| { | |
| .total_bytes = 1024 * 1024, | |
| .free_bytes = 1024, | |
| .wired_bytes = 2 * 1024, | |
| .total_heap_bytes = 3 * 1024, | |
| .free_heap_bytes = 2 * 1024, | |
| .vmo_bytes = 5 * 1024, | |
| .mmu_overhead_bytes = 6 * 1024, | |
| .ipc_bytes = 7 * 1024, | |
| .other_bytes = 8 * 1024, | |
| }, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| Summary s(c); | |
| p.PrintSummary(s, KMEM, SORTED); | |
| ConfirmLines(oss, { | |
| "Time: 1234 VMO: 5K Free: 1K", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, PrintSummaryPROCESS) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = | |
| { | |
| .total_bytes = 1024 * 1024, | |
| .free_bytes = 1024, | |
| .wired_bytes = 2 * 1024, | |
| .total_heap_bytes = 3 * 1024, | |
| .free_heap_bytes = 2 * 1024, | |
| .vmo_bytes = 5 * 1024, | |
| .mmu_overhead_bytes = 6 * 1024, | |
| .ipc_bytes = 7 * 1024, | |
| .other_bytes = 8 * 1024, | |
| }, | |
| .vmos = {{.koid = 1, .name = "v1", .committed_bytes = 1024}}, | |
| .processes = {{.koid = 100, .name = "p1", .vmos = {1}}}, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| Summary s(c); | |
| p.PrintSummary(s, PROCESS, SORTED); | |
| ConfirmLines(oss, { | |
| "Time: 1234 VMO: 5K Free: 1K", | |
| "kernel<1> 30K", | |
| "p1<100> 1K", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, PrintSummaryVMO) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = | |
| { | |
| .total_bytes = 1024 * 1024, | |
| .free_bytes = 1024, | |
| .wired_bytes = 2 * 1024, | |
| .total_heap_bytes = 3 * 1024, | |
| .free_heap_bytes = 2 * 1024, | |
| .vmo_bytes = 5 * 1024, | |
| .mmu_overhead_bytes = 6 * 1024, | |
| .ipc_bytes = 7 * 1024, | |
| .other_bytes = 8 * 1024, | |
| }, | |
| .vmos = {{.koid = 1, .name = "v1", .committed_bytes = 1024}}, | |
| .processes = {{.koid = 100, .name = "p1", .vmos = {1}}}, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| Summary s(c); | |
| p.PrintSummary(s, VMO, SORTED); | |
| ConfirmLines(oss, { | |
| "Time: 1234 VMO: 5K Free: 1K", | |
| "kernel<1> 30K", | |
| " other 8K", | |
| " ipc 7K", | |
| " mmu 6K", | |
| " vmo 4K", | |
| " heap 3K", | |
| " wired 2K", | |
| "p1<100> 1K", | |
| " v1 1K", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, PrintSummaryVMOShared) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234, | |
| .kmem = {.vmo_bytes = 6 * 1024}, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "v1", .committed_bytes = 1024}, | |
| {.koid = 2, .name = "v2", .committed_bytes = 2 * 1024}, | |
| {.koid = 3, .name = "v3", .committed_bytes = 3 * 1024}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1, 2}}, | |
| {.koid = 200, .name = "p2", .vmos = {2, 3}}, | |
| }, | |
| }); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| Summary s(c); | |
| p.PrintSummary(s, VMO, SORTED); | |
| ConfirmLines(oss, { | |
| "Time: 1234 VMO: 6K Free: 0B", | |
| "p2<200> 3K 4K 5K", | |
| " v3 3K", | |
| " v2 0B 1K 2K", | |
| "p1<100> 1K 2K 3K", | |
| " v1 1K", | |
| " v2 0B 1K 2K", | |
| "kernel<1> 0B", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, OutputSummarySingle) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234L * 1000000000L, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "v1", .committed_bytes = 100}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1}}, | |
| }, | |
| }); | |
| Summary s(c); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.OutputSummary(s, SORTED, ZX_KOID_INVALID); | |
| ConfirmLines(oss, { | |
| "1234,100,p1,100,100,100", | |
| "1234,1,kernel,0,0,0", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, 100); | |
| ConfirmLines(oss, { | |
| "1234,100,v1,100,100,100", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, OutputSummaryKernel) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234L * 1000000000L, | |
| .kmem = | |
| { | |
| .wired_bytes = 10, | |
| .total_heap_bytes = 20, | |
| .mmu_overhead_bytes = 30, | |
| .ipc_bytes = 40, | |
| .other_bytes = 50, | |
| .vmo_bytes = 60, | |
| }, | |
| }); | |
| Summary s(c); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.OutputSummary(s, SORTED, ZX_KOID_INVALID); | |
| ConfirmLines(oss, { | |
| "1234,1,kernel,210,210,210", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, ProcessSummary::kKernelKoid); | |
| ConfirmLines(oss, { | |
| "1234,1,vmo,60,60,60", | |
| "1234,1,other,50,50,50", | |
| "1234,1,ipc,40,40,40", | |
| "1234,1,mmu,30,30,30", | |
| "1234,1,heap,20,20,20", | |
| "1234,1,wired,10,10,10", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, OutputSummaryDouble) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234L * 1000000000L, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "v1", .committed_bytes = 100}, | |
| {.koid = 2, .name = "v2", .committed_bytes = 200}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1}}, | |
| {.koid = 200, .name = "p2", .vmos = {2}}, | |
| }, | |
| }); | |
| Summary s(c); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.OutputSummary(s, SORTED, ZX_KOID_INVALID); | |
| ConfirmLines(oss, { | |
| "1234,200,p2,200,200,200", | |
| "1234,100,p1,100,100,100", | |
| "1234,1,kernel,0,0,0", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, 100); | |
| ConfirmLines(oss, { | |
| "1234,100,v1,100,100,100", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, 200); | |
| ConfirmLines(oss, { | |
| "1234,200,v2,200,200,200", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, OutputSummaryShared) { | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234L * 1000000000L, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "v1", .committed_bytes = 100}, | |
| {.koid = 2, .name = "v1", .committed_bytes = 100}, | |
| {.koid = 3, .name = "v1", .committed_bytes = 100}, | |
| {.koid = 4, .name = "v2", .committed_bytes = 100}, | |
| {.koid = 5, .name = "v3", .committed_bytes = 200}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 100, .name = "p1", .vmos = {1, 2, 4}}, | |
| {.koid = 200, .name = "p2", .vmos = {2, 3, 5}}, | |
| }, | |
| }); | |
| Summary s(c); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.OutputSummary(s, SORTED, ZX_KOID_INVALID); | |
| ConfirmLines(oss, { | |
| "1234,200,p2,300,350,400", | |
| "1234,100,p1,200,250,300", | |
| "1234,1,kernel,0,0,0", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, 100); | |
| ConfirmLines(oss, { | |
| "1234,100,v1,100,150,200", | |
| "1234,100,v2,100,100,100", | |
| }); | |
| oss.str(""); | |
| p.OutputSummary(s, SORTED, 200); | |
| ConfirmLines(oss, { | |
| "1234,200,v3,200,200,200", | |
| "1234,200,v1,100,150,200", | |
| }); | |
| } | |
| TEST_F(PrinterUnitTest, PrintDigest) { | |
| // Test kernel stats. | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .kmem = | |
| { | |
| .total_bytes = 1000, | |
| .wired_bytes = 10, | |
| .free_bytes = 100, | |
| .vmo_bytes = 700, | |
| }, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "a1", .committed_bytes = 100}, | |
| {.koid = 2, .name = "b1", .committed_bytes = 200}, | |
| {.koid = 3, .name = "c1", .committed_bytes = 300}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 1, .name = "p1", .vmos = {1}}, | |
| {.koid = 2, .name = "q1", .vmos = {2}}, | |
| }, | |
| }); | |
| Digester digester({{"A", ".*", "a.*"}, {"B", ".*", "b.*"}}); | |
| Digest d(c, &digester); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.PrintDigest(d); | |
| ConfirmLines(oss, {"B: 200B", "A: 100B", "Undigested: 300B", "Orphaned: 100B", "Kernel: 10B", | |
| "Free: 100B"}); | |
| } | |
| TEST_F(PrinterUnitTest, OutputDigest) { | |
| // Test kernel stats. | |
| Capture c; | |
| TestUtils::CreateCapture(&c, { | |
| .time = 1234L * 1000000000L, | |
| .kmem = | |
| { | |
| .total_bytes = 1000, | |
| .wired_bytes = 10, | |
| .free_bytes = 100, | |
| .vmo_bytes = 700, | |
| }, | |
| .vmos = | |
| { | |
| {.koid = 1, .name = "a1", .committed_bytes = 100}, | |
| {.koid = 2, .name = "b1", .committed_bytes = 200}, | |
| {.koid = 3, .name = "c1", .committed_bytes = 300}, | |
| }, | |
| .processes = | |
| { | |
| {.koid = 1, .name = "p1", .vmos = {1}}, | |
| {.koid = 2, .name = "q1", .vmos = {2}}, | |
| }, | |
| }); | |
| Digester digester({{"A", ".*", "a.*"}, {"B", ".*", "b.*"}}); | |
| Digest d(c, &digester); | |
| std::ostringstream oss; | |
| Printer p(oss); | |
| p.OutputDigest(d); | |
| ConfirmLines(oss, {"1234,B,200", "1234,A,100", "1234,Undigested,300", "1234,Orphaned,100", | |
| "1234,Kernel,10", "1234,Free,100"}); | |
| } | |
| TEST_F(PrinterUnitTest, FormatSize) { | |
| struct TestCase { | |
| uint64_t bytes; | |
| const char* val; | |
| }; | |
| std::vector<TestCase> tests = { | |
| {0, "0B"}, | |
| {1, "1B"}, | |
| {1023, "1023B"}, | |
| {1024, "1K"}, | |
| {1025, "1K"}, | |
| {1029, "1K"}, | |
| {1124, "1.1K"}, | |
| {1536, "1.5K"}, | |
| {2047, "2K"}, | |
| {1024 * 1024, "1M"}, | |
| {1024 * 1024 * 1024, "1G"}, | |
| {1024UL * 1024 * 1024 * 1024, "1T"}, | |
| {1024UL * 1024 * 1024 * 1024 * 1024, "1P"}, | |
| {1024UL * 1024 * 1024 * 1024 * 1024 * 1024, "1E"}, | |
| {1024UL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, "0B"}, | |
| }; | |
| for (const auto& test : tests) { | |
| char buf[kMaxFormattedStringSize]; | |
| EXPECT_STREQ(test.val, FormatSize(test.bytes, buf)); | |
| } | |
| } | |
| } // namespace test | |
| } // namespace memory |