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