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