| // 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 "gmock/gmock.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/fsl/socket/strings.h" |
| #include "src/lib/fxl/strings/split_string.h" |
| #include "third_party/rapidjson/include/rapidjson/document.h" |
| #include "third_party/rapidjson/include/rapidjson/ostreamwrapper.h" |
| #include "third_party/rapidjson/include/rapidjson/prettywriter.h" |
| |
| namespace { |
| void ConfirmLines(std::ostringstream& oss, const std::vector<std::string>& expected_lines) { |
| auto lines = fxl::SplitStringCopy(oss.str(), "\n", fxl::kKeepWhitespace, fxl::kSplitWantNonEmpty); |
| EXPECT_THAT(lines, testing::UnorderedElementsAreArray(expected_lines)); |
| } |
| |
| std::string ExecuteWithSocket(fit::function<void(zx::socket)> generator) { |
| zx::socket endpoint0, endpoint1; |
| zx::socket::create(ZX_SOCKET_STREAM, &endpoint0, &endpoint1); |
| |
| std::string output; |
| std::thread receiver([&]() { fsl::BlockingCopyToString(std::move(endpoint0), &output); }); |
| generator(std::move(endpoint1)); |
| receiver.join(); |
| |
| return output; |
| } |
| |
| } // namespace |
| |
| namespace rapidjson { |
| // Teach the testing framework to print json doc. |
| extern void PrintTo(const rapidjson::Document& value, ::std::ostream* os) { |
| rapidjson::OStreamWrapper osw(*os); |
| rapidjson::PrettyWriter writer(osw); |
| value.Accept(writer); |
| } |
| } // namespace rapidjson |
| |
| namespace memory::test { |
| |
| using PrinterUnitTest = testing::Test; |
| |
| TEST_F(PrinterUnitTest, PrintCapture) { |
| 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, |
| }, |
| .kmem_extended = |
| { |
| .total_bytes = 300, |
| .free_bytes = 100, |
| .wired_bytes = 10, |
| .total_heap_bytes = 20, |
| .free_heap_bytes = 30, |
| .vmo_bytes = 40, |
| .vmo_pager_total_bytes = 15, |
| .vmo_pager_newest_bytes = 4, |
| .vmo_pager_oldest_bytes = 8, |
| .vmo_discardable_locked_bytes = 3, |
| .vmo_discardable_unlocked_bytes = 7, |
| .mmu_overhead_bytes = 50, |
| .ipc_bytes = 60, |
| .other_bytes = 70, |
| }, |
| .vmos = |
| { |
| { |
| .koid = 1, |
| .name = "v1", |
| .size_bytes = 300, |
| .parent_koid = 100, |
| .committed_bytes = 200, |
| .committed_scaled_bytes = 200, |
| .committed_fractional_scaled_bytes = 0, |
| }, |
| }, |
| .processes = |
| { |
| {.koid = 100, .name = "p1", .vmos = {1}}, |
| }, |
| }); |
| std::string output = |
| ExecuteWithSocket([&](zx::socket socket) { JsonPrinter(socket).PrintCapture(c); }); |
| rapidjson::Document doc; |
| doc.Parse(output.c_str()); |
| |
| rapidjson::Document expected; |
| expected.Parse(R"json( |
| { |
| "Time": 1234, |
| "Kernel": { |
| "total": 300, |
| "free": 100, |
| "wired": 10, |
| "total_heap": 20, |
| "free_heap": 30, |
| "vmo": 40, |
| "mmu": 50, |
| "ipc": 60, |
| "other": 70, |
| "vmo_pager_total": 15, |
| "vmo_pager_newest": 4, |
| "vmo_pager_oldest": 8, |
| "vmo_discardable_locked": 3, |
| "vmo_discardable_unlocked": 7, |
| "vmo_reclaim_disabled": 0 |
| }, |
| "Processes": [ |
| [ |
| "koid", |
| "name", |
| "vmos" |
| ], |
| [ |
| 100, |
| "p1", |
| [ |
| 1 |
| ] |
| ] |
| ], |
| "VmoNames": [ |
| "v1" |
| ], |
| "Vmos": [ |
| [ |
| "koid", |
| "name", |
| "parent_koid", |
| "committed_bytes", |
| "allocated_bytes" |
| ], |
| [ |
| 1, |
| 0, |
| 100, |
| 200, |
| 300 |
| ] |
| ] |
| } |
| )json"); |
| EXPECT_EQ(doc, expected); |
| } |
| |
| TEST_F(PrinterUnitTest, PrintCaptureAndBucketConfig) { |
| 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, |
| }, |
| .kmem_extended = |
| { |
| .total_bytes = 300, |
| .free_bytes = 100, |
| .wired_bytes = 10, |
| .total_heap_bytes = 20, |
| .free_heap_bytes = 30, |
| .vmo_bytes = 40, |
| .vmo_pager_total_bytes = 15, |
| .vmo_pager_newest_bytes = 4, |
| .vmo_pager_oldest_bytes = 8, |
| .vmo_discardable_locked_bytes = 3, |
| .vmo_discardable_unlocked_bytes = 7, |
| .mmu_overhead_bytes = 50, |
| .ipc_bytes = 60, |
| .other_bytes = 70, |
| }, |
| .vmos = |
| { |
| { |
| .koid = 1, |
| .name = "v1", |
| .size_bytes = 300, |
| .parent_koid = 100, |
| .committed_bytes = 200, |
| .committed_scaled_bytes = 200, |
| .committed_fractional_scaled_bytes = 0, |
| }, |
| }, |
| .processes = |
| { |
| {.koid = 100, .name = "p1", .vmos = {1}}, |
| }, |
| }); |
| |
| const std::string bucket_config = R"( |
| [ |
| { |
| "event_code" : 29, |
| "name" : "BlobfsInactive", |
| "process" : "blobfs\\.cm", |
| "vmo": "inactive-blob-.*" |
| } |
| ] |
| )"; |
| std::string output = ExecuteWithSocket([&](zx::socket socket) { |
| JsonPrinter(socket).PrintCaptureAndBucketConfig(c, bucket_config); |
| }); |
| rapidjson::Document doc; |
| doc.Parse(output.c_str()); |
| ASSERT_TRUE(doc.IsObject()); |
| |
| rapidjson::Value const& capture = doc["Capture"]; |
| rapidjson::Value const& buckets = doc["Buckets"]; |
| |
| // Test the content of `capture`. |
| ASSERT_TRUE(capture.IsObject()); |
| |
| EXPECT_EQ(1234, capture["Time"].GetInt64()); |
| |
| auto kernel = capture["Kernel"].GetObject(); |
| EXPECT_EQ(300U, kernel["total"].GetUint64()); |
| EXPECT_EQ(100U, kernel["free"].GetUint64()); |
| EXPECT_EQ(10U, kernel["wired"].GetUint64()); |
| EXPECT_EQ(20U, kernel["total_heap"].GetUint64()); |
| EXPECT_EQ(30U, kernel["free_heap"].GetUint64()); |
| EXPECT_EQ(40U, kernel["vmo"].GetUint64()); |
| EXPECT_EQ(50U, kernel["mmu"].GetUint64()); |
| EXPECT_EQ(60U, kernel["ipc"].GetUint64()); |
| EXPECT_EQ(70U, kernel["other"].GetUint64()); |
| EXPECT_EQ(15U, kernel["vmo_pager_total"].GetUint64()); |
| EXPECT_EQ(4U, kernel["vmo_pager_newest"].GetUint64()); |
| EXPECT_EQ(8U, kernel["vmo_pager_oldest"].GetUint64()); |
| EXPECT_EQ(3U, kernel["vmo_discardable_locked"].GetUint64()); |
| EXPECT_EQ(7U, kernel["vmo_discardable_unlocked"].GetUint64()); |
| |
| auto processes = capture["Processes"].GetArray(); |
| ASSERT_EQ(2U, processes.Size()); |
| auto process_header = processes[0].GetArray(); |
| EXPECT_STREQ("koid", process_header[0].GetString()); |
| EXPECT_STREQ("name", process_header[1].GetString()); |
| EXPECT_STREQ("vmos", process_header[2].GetString()); |
| auto process = processes[1].GetArray(); |
| EXPECT_EQ(100U, process[0].GetUint64()); |
| EXPECT_STREQ("p1", process[1].GetString()); |
| auto process_vmos = process[2].GetArray(); |
| ASSERT_EQ(1U, process_vmos.Size()); |
| EXPECT_EQ(1, process_vmos[0]); |
| |
| auto vmo_names = capture["VmoNames"].GetArray(); |
| ASSERT_EQ(1U, vmo_names.Size()); |
| EXPECT_STREQ("v1", vmo_names[0].GetString()); |
| |
| auto vmos = capture["Vmos"].GetArray(); |
| ASSERT_EQ(2U, vmos.Size()); |
| auto vmo_header = vmos[0].GetArray(); |
| EXPECT_STREQ("koid", vmo_header[0].GetString()); |
| EXPECT_STREQ("name", vmo_header[1].GetString()); |
| EXPECT_STREQ("parent_koid", vmo_header[2].GetString()); |
| EXPECT_STREQ("committed_bytes", vmo_header[3].GetString()); |
| EXPECT_STREQ("allocated_bytes", vmo_header[4].GetString()); |
| auto vmo = vmos[1].GetArray(); |
| EXPECT_EQ(1U, vmo[0].GetUint64()); |
| EXPECT_EQ(0U, vmo[1].GetUint64()); |
| EXPECT_EQ(100U, vmo[2].GetUint64()); |
| EXPECT_EQ(200U, vmo[3].GetUint64()); |
| EXPECT_EQ(300U, vmo[4].GetUint64()); |
| |
| // Test the content of `buckets`. |
| ASSERT_TRUE(buckets.IsArray()); |
| EXPECT_EQ(1U, buckets.Size()); |
| rapidjson::Value const& bucket = buckets[0]; |
| EXPECT_EQ(29U, bucket["event_code"].GetUint64()); |
| EXPECT_STREQ("BlobfsInactive", bucket["name"].GetString()); |
| EXPECT_STREQ("blobfs\\.cm", bucket["process"].GetString()); |
| EXPECT_STREQ("inactive-blob-.*", bucket["vmo"].GetString()); |
| } |
| |
| TEST_F(PrinterUnitTest, PrintSummaryKMEM) { |
| Capture c; |
| TestUtils::CreateCapture(&c, { |
| .time = 1234, |
| .kmem = |
| { |
| .total_bytes = 1024ul * 1024, |
| .free_bytes = 1024, |
| .wired_bytes = 2ul * 1024, |
| .total_heap_bytes = 3ul * 1024, |
| .free_heap_bytes = 2ul * 1024, |
| .vmo_bytes = 5ul * 1024, |
| .mmu_overhead_bytes = 6ul * 1024, |
| .ipc_bytes = 7ul * 1024, |
| .other_bytes = 8ul * 1024, |
| }, |
| }); |
| |
| std::ostringstream oss; |
| TextPrinter p(oss); |
| Summary s(c); |
| p.PrintSummary(s, CaptureLevel::KMEM, SORTED); |
| |
| ConfirmLines(oss, { |
| "Time: 1234 VMO: 5K Free: 1K", |
| }); |
| } |
| |
| TEST_F(PrinterUnitTest, PrintSummaryPROCESS) { |
| Capture c; |
| TestUtils::CreateCapture(&c, { |
| .time = 1234, |
| .kmem = |
| { |
| .total_bytes = 1024ul * 1024, |
| .free_bytes = 1024, |
| .wired_bytes = 2ul * 1024, |
| .total_heap_bytes = 3ul * 1024, |
| .free_heap_bytes = 2ul * 1024, |
| .vmo_bytes = 5ul * 1024, |
| .mmu_overhead_bytes = 6ul * 1024, |
| .ipc_bytes = 7ul * 1024, |
| .other_bytes = 8ul * 1024, |
| }, |
| .vmos = {{.koid = 1, |
| .name = "v1", |
| .committed_bytes = 1024, |
| .committed_scaled_bytes = 1024}}, |
| .processes = {{.koid = 100, .name = "p1", .vmos = {1}}}, |
| }); |
| |
| std::ostringstream oss; |
| TextPrinter p(oss); |
| Summary s(c); |
| p.PrintSummary(s, CaptureLevel::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 = 1024ul * 1024, |
| .free_bytes = 1024, |
| .wired_bytes = 2ul * 1024, |
| .total_heap_bytes = 3ul * 1024, |
| .free_heap_bytes = 2ul * 1024, |
| .vmo_bytes = 5ul * 1024, |
| .mmu_overhead_bytes = 6ul * 1024, |
| .ipc_bytes = 7ul * 1024, |
| .other_bytes = 8ul * 1024, |
| }, |
| .vmos = {{.koid = 1, |
| .name = "v1", |
| .committed_bytes = 1024, |
| .committed_scaled_bytes = 1024}}, |
| .processes = {{.koid = 100, .name = "p1", .vmos = {1}}}, |
| }); |
| |
| std::ostringstream oss; |
| TextPrinter p(oss); |
| Summary s(c); |
| p.PrintSummary(s, CaptureLevel::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 = 6ul * 1024}, |
| .vmos = |
| { |
| {.koid = 1, |
| .name = "v1", |
| .committed_bytes = 1024, |
| .committed_scaled_bytes = 1024}, |
| {.koid = 2, |
| .name = "v2", |
| .committed_bytes = 2ul * 1024, |
| .committed_scaled_bytes = 2ul * 1024}, |
| {.koid = 3, |
| .name = "v3", |
| .committed_bytes = 3ul * 1024, |
| .committed_scaled_bytes = 3ul * 1024}, |
| }, |
| .processes = |
| { |
| {.koid = 100, .name = "p1", .vmos = {1, 2}}, |
| {.koid = 200, .name = "p2", .vmos = {2, 3}}, |
| }, |
| }); |
| |
| std::ostringstream oss; |
| TextPrinter p(oss); |
| Summary s(c); |
| p.PrintSummary(s, CaptureLevel::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, .committed_scaled_bytes = 100}, |
| }, |
| .processes = |
| { |
| {.koid = 100, .name = "p1", .vmos = {1}}, |
| }, |
| }); |
| Summary s(c); |
| |
| std::ostringstream oss; |
| TextPrinter 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, |
| .vmo_bytes = 60, |
| .mmu_overhead_bytes = 30, |
| .ipc_bytes = 40, |
| .other_bytes = 50, |
| }, |
| }); |
| Summary s(c); |
| |
| std::ostringstream oss; |
| TextPrinter 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, .committed_scaled_bytes = 100}, |
| {.koid = 2, .name = "v2", .committed_bytes = 200, .committed_scaled_bytes = 200}, |
| }, |
| .processes = |
| { |
| {.koid = 100, .name = "p1", .vmos = {1}}, |
| {.koid = 200, .name = "p2", .vmos = {2}}, |
| }, |
| }); |
| Summary s(c); |
| |
| std::ostringstream oss; |
| TextPrinter 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, .committed_scaled_bytes = 100}, |
| {.koid = 2, .name = "v1", .committed_bytes = 100, .committed_scaled_bytes = 100}, |
| {.koid = 3, .name = "v1", .committed_bytes = 100, .committed_scaled_bytes = 100}, |
| {.koid = 4, .name = "v2", .committed_bytes = 100, .committed_scaled_bytes = 100}, |
| {.koid = 5, .name = "v3", .committed_bytes = 200, .committed_scaled_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; |
| TextPrinter 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, |
| .free_bytes = 100, |
| .wired_bytes = 10, |
| .vmo_bytes = 700, |
| }, |
| .vmos = |
| { |
| {.koid = 1, .name = "a1", .committed_bytes = 100, .committed_scaled_bytes = 100}, |
| {.koid = 2, .name = "b1", .committed_bytes = 200, .committed_scaled_bytes = 200}, |
| {.koid = 3, .name = "c1", .committed_bytes = 300, .committed_scaled_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; |
| TextPrinter p(oss); |
| p.PrintDigest(d); |
| ConfirmLines(oss, {"B: 200B", "A: 100B", "Undigested: 300B", "Orphaned: 100B", "Kernel: 10B", |
| "Free: 100B", "[Addl]PagerTotal: 0B", "[Addl]PagerNewest: 0B", |
| "[Addl]PagerOldest: 0B", "[Addl]DiscardableLocked: 0B", |
| "[Addl]DiscardableUnlocked: 0B", "[Addl]ZramCompressedBytes: 0B"}); |
| } |
| |
| TEST_F(PrinterUnitTest, OutputDigest) { |
| // Test kernel stats. |
| Capture c; |
| TestUtils::CreateCapture( |
| &c, |
| { |
| .time = 1234L * 1000000000L, |
| .kmem = |
| { |
| .total_bytes = 1000, |
| .free_bytes = 100, |
| .wired_bytes = 10, |
| .vmo_bytes = 700, |
| }, |
| .kmem_extended = |
| { |
| .total_bytes = 1000, |
| .free_bytes = 100, |
| .wired_bytes = 10, |
| .vmo_bytes = 700, |
| .vmo_pager_total_bytes = 300, |
| .vmo_pager_newest_bytes = 50, |
| .vmo_pager_oldest_bytes = 150, |
| .vmo_discardable_locked_bytes = 60, |
| .vmo_discardable_unlocked_bytes = 40, |
| }, |
| .vmos = |
| { |
| {.koid = 1, .name = "a1", .committed_bytes = 100, .committed_scaled_bytes = 100}, |
| {.koid = 2, .name = "b1", .committed_bytes = 200, .committed_scaled_bytes = 200}, |
| {.koid = 3, .name = "c1", .committed_bytes = 300, .committed_scaled_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; |
| TextPrinter 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", "1234,[Addl]PagerTotal,300", |
| "1234,[Addl]PagerNewest,50", "1234,[Addl]PagerOldest,150", |
| "1234,[Addl]DiscardableLocked,60", "1234,[Addl]DiscardableUnlocked,40", |
| "1234,[Addl]ZramCompressedBytes,0"}); |
| } |
| |
| TEST_F(PrinterUnitTest, FormatSize) { |
| struct TestCase { |
| uint64_t bytes; |
| const char* val; |
| }; |
| std::vector<TestCase> tests = { |
| {.bytes = 0, .val = "0B"}, |
| {.bytes = 1, .val = "1B"}, |
| {.bytes = 1023, .val = "1023B"}, |
| {.bytes = 1024, .val = "1K"}, |
| {.bytes = 1025, .val = "1K"}, |
| {.bytes = 1029, .val = "1K"}, |
| {.bytes = 1124, .val = "1.1K"}, |
| {.bytes = 1536, .val = "1.5K"}, |
| {.bytes = 2047, .val = "2K"}, |
| {.bytes = 1024ul * 1024, .val = "1M"}, |
| {.bytes = 1024ul * 1024 * 1024, .val = "1G"}, |
| {.bytes = 1024UL * 1024 * 1024 * 1024, .val = "1T"}, |
| {.bytes = 1024UL * 1024 * 1024 * 1024 * 1024, .val = "1P"}, |
| {.bytes = 1024UL * 1024 * 1024 * 1024 * 1024 * 1024, .val = "1E"}, |
| {.bytes = 1024UL * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, .val = "0B"}, |
| }; |
| for (const auto& test : tests) { |
| char buf[kMaxFormattedStringSize]; |
| EXPECT_STREQ(test.val, FormatSize(test.bytes, buf)); |
| } |
| } |
| |
| } // namespace memory::test |