1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fcntl.h>
6 #include <stdint.h>
7 
8 #include <memory>
9 
10 #include "base/files/scoped_file.h"
11 #include "base/memory/madv_free_discardable_memory_allocator_posix.h"
12 #include "base/memory/madv_free_discardable_memory_posix.h"
13 #include "base/process/process_metrics.h"
14 #include "base/tracing_buildflags.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 #if BUILDFLAG(ENABLE_BASE_TRACING)
19 #include "base/trace_event/memory_allocator_dump.h"  // no-presubmit-check
20 #include "base/trace_event/process_memory_dump.h"    // no-presubmit-check
21 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
22 
23 #define SUCCEED_IF_MADV_FREE_UNSUPPORTED()                                  \
24   do {                                                                      \
25     if (GetMadvFreeSupport() != base::MadvFreeSupport::kSupported) {        \
26       SUCCEED()                                                             \
27           << "MADV_FREE is not supported (Linux 4.5+ required), vacuously " \
28              "passing test";                                                \
29       return;                                                               \
30     }                                                                       \
31   } while (0)
32 
33 namespace base {
34 
35 class MadvFreeDiscardableMemoryAllocatorPosixTest : public ::testing::Test {
36  protected:
MadvFreeDiscardableMemoryAllocatorPosixTest()37   MadvFreeDiscardableMemoryAllocatorPosixTest() {
38 #if BUILDFLAG(ENABLE_BASE_TRACING)
39     base::trace_event::MemoryDumpArgs dump_args = {
40         base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
41     pmd_ = std::make_unique<base::trace_event::ProcessMemoryDump>(dump_args);
42 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
43   }
44 
45   std::unique_ptr<MadvFreeDiscardableMemoryPosix>
AllocateLockedMadvFreeDiscardableMemory(size_t size)46   AllocateLockedMadvFreeDiscardableMemory(size_t size) {
47     return std::unique_ptr<MadvFreeDiscardableMemoryPosix>(
48         static_cast<MadvFreeDiscardableMemoryPosix*>(
49             allocator_.AllocateLockedDiscardableMemory(size).release()));
50   }
51 
52 #if BUILDFLAG(ENABLE_BASE_TRACING)
GetDiscardableMemorySizeFromDump(const DiscardableMemory & mem,const std::string & dump_id)53   size_t GetDiscardableMemorySizeFromDump(const DiscardableMemory& mem,
54                                           const std::string& dump_id) {
55     return mem.CreateMemoryAllocatorDump(dump_id.c_str(), pmd_.get())
56         ->GetSizeInternal();
57   }
58 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
59 
60   MadvFreeDiscardableMemoryAllocatorPosix allocator_;
61   const size_t kPageSize = base::GetPageSize();
62 #if BUILDFLAG(ENABLE_BASE_TRACING)
63   std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd_;
64 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
65 };
66 
TEST_F(MadvFreeDiscardableMemoryAllocatorPosixTest,AllocateAndUseMemory)67 TEST_F(MadvFreeDiscardableMemoryAllocatorPosixTest, AllocateAndUseMemory) {
68   SUCCEED_IF_MADV_FREE_UNSUPPORTED();
69 
70   // Allocate 4 pages of discardable memory.
71   auto mem1 = AllocateLockedMadvFreeDiscardableMemory(kPageSize * 3 + 1);
72 
73   EXPECT_TRUE(mem1->IsLockedForTesting());
74 #if BUILDFLAG(ENABLE_BASE_TRACING)
75   EXPECT_EQ(GetDiscardableMemorySizeFromDump(*mem1, "dummy_dump_1"),
76             kPageSize * 3 + 1);
77 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
78   EXPECT_EQ(allocator_.GetBytesAllocated(), kPageSize * 3 + 1);
79 
80   // Allocate 3 pages of discardable memory, and free the previously allocated
81   // pages.
82   auto mem2 = AllocateLockedMadvFreeDiscardableMemory(kPageSize * 3);
83 
84   EXPECT_TRUE(mem2->IsLockedForTesting());
85 #if BUILDFLAG(ENABLE_BASE_TRACING)
86   EXPECT_EQ(GetDiscardableMemorySizeFromDump(*mem2, "dummy_dump_2"),
87             kPageSize * 3);
88 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
89   EXPECT_EQ(allocator_.GetBytesAllocated(), kPageSize * 6 + 1);
90 
91   mem1.reset();
92 
93   EXPECT_EQ(allocator_.GetBytesAllocated(), kPageSize * 3);
94 
95   // Write to and read from an allocated discardable memory buffer.
96   const char test_pattern[] = "ABCDEFGHIJKLMNOP";
97   char buffer[sizeof(test_pattern)];
98 
99   void* data = mem2->data();
100   memcpy(data, test_pattern, sizeof(test_pattern));
101 
102   data = mem2->data_as<uint8_t>();
103   memcpy(buffer, data, sizeof(test_pattern));
104 
105   EXPECT_EQ(memcmp(test_pattern, buffer, sizeof(test_pattern)), 0);
106 }
107 }  // namespace base
108