1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/paged_memory.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <algorithm>
20*6dbdd20aSAndroid Build Coastguard Worker #include <cmath>
21*6dbdd20aSAndroid Build Coastguard Worker #include <cstddef>
22*6dbdd20aSAndroid Build Coastguard Worker
23*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
24*6dbdd20aSAndroid Build Coastguard Worker #include <Windows.h>
25*6dbdd20aSAndroid Build Coastguard Worker #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
26*6dbdd20aSAndroid Build Coastguard Worker #include <sys/mman.h>
27*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
28*6dbdd20aSAndroid Build Coastguard Worker
29*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/container_annotations.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
32*6dbdd20aSAndroid Build Coastguard Worker
33*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
34*6dbdd20aSAndroid Build Coastguard Worker namespace base {
35*6dbdd20aSAndroid Build Coastguard Worker
36*6dbdd20aSAndroid Build Coastguard Worker namespace {
37*6dbdd20aSAndroid Build Coastguard Worker
38*6dbdd20aSAndroid Build Coastguard Worker #if TRACK_COMMITTED_SIZE()
39*6dbdd20aSAndroid Build Coastguard Worker constexpr size_t kCommitChunkSize = 4 * 1024 * 1024; // 4MB
40*6dbdd20aSAndroid Build Coastguard Worker #endif
41*6dbdd20aSAndroid Build Coastguard Worker
RoundUpToSysPageSize(size_t req_size)42*6dbdd20aSAndroid Build Coastguard Worker size_t RoundUpToSysPageSize(size_t req_size) {
43*6dbdd20aSAndroid Build Coastguard Worker const size_t page_size = GetSysPageSize();
44*6dbdd20aSAndroid Build Coastguard Worker return (req_size + page_size - 1) & ~(page_size - 1);
45*6dbdd20aSAndroid Build Coastguard Worker }
46*6dbdd20aSAndroid Build Coastguard Worker
GuardSize()47*6dbdd20aSAndroid Build Coastguard Worker size_t GuardSize() {
48*6dbdd20aSAndroid Build Coastguard Worker return GetSysPageSize();
49*6dbdd20aSAndroid Build Coastguard Worker }
50*6dbdd20aSAndroid Build Coastguard Worker
51*6dbdd20aSAndroid Build Coastguard Worker } // namespace
52*6dbdd20aSAndroid Build Coastguard Worker
53*6dbdd20aSAndroid Build Coastguard Worker // static
Allocate(size_t req_size,int flags)54*6dbdd20aSAndroid Build Coastguard Worker PagedMemory PagedMemory::Allocate(size_t req_size, int flags) {
55*6dbdd20aSAndroid Build Coastguard Worker size_t rounded_up_size = RoundUpToSysPageSize(req_size);
56*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(rounded_up_size >= req_size);
57*6dbdd20aSAndroid Build Coastguard Worker size_t outer_size = rounded_up_size + GuardSize() * 2;
58*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
59*6dbdd20aSAndroid Build Coastguard Worker void* ptr = VirtualAlloc(nullptr, outer_size, MEM_RESERVE, PAGE_NOACCESS);
60*6dbdd20aSAndroid Build Coastguard Worker if (!ptr && (flags & kMayFail))
61*6dbdd20aSAndroid Build Coastguard Worker return PagedMemory();
62*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(ptr);
63*6dbdd20aSAndroid Build Coastguard Worker char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
64*6dbdd20aSAndroid Build Coastguard Worker #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
65*6dbdd20aSAndroid Build Coastguard Worker void* ptr = mmap(nullptr, outer_size, PROT_READ | PROT_WRITE,
66*6dbdd20aSAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
67*6dbdd20aSAndroid Build Coastguard Worker if (ptr == MAP_FAILED && (flags & kMayFail))
68*6dbdd20aSAndroid Build Coastguard Worker return PagedMemory();
69*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(ptr && ptr != MAP_FAILED);
70*6dbdd20aSAndroid Build Coastguard Worker char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
71*6dbdd20aSAndroid Build Coastguard Worker int res = mprotect(ptr, GuardSize(), PROT_NONE);
72*6dbdd20aSAndroid Build Coastguard Worker res |= mprotect(usable_region + rounded_up_size, GuardSize(), PROT_NONE);
73*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(res == 0);
74*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
75*6dbdd20aSAndroid Build Coastguard Worker
76*6dbdd20aSAndroid Build Coastguard Worker auto memory = PagedMemory(usable_region, req_size);
77*6dbdd20aSAndroid Build Coastguard Worker #if TRACK_COMMITTED_SIZE()
78*6dbdd20aSAndroid Build Coastguard Worker size_t initial_commit = req_size;
79*6dbdd20aSAndroid Build Coastguard Worker if (flags & kDontCommit)
80*6dbdd20aSAndroid Build Coastguard Worker initial_commit = std::min(initial_commit, kCommitChunkSize);
81*6dbdd20aSAndroid Build Coastguard Worker memory.EnsureCommitted(initial_commit);
82*6dbdd20aSAndroid Build Coastguard Worker #endif // TRACK_COMMITTED_SIZE()
83*6dbdd20aSAndroid Build Coastguard Worker return memory;
84*6dbdd20aSAndroid Build Coastguard Worker }
85*6dbdd20aSAndroid Build Coastguard Worker
PagedMemory()86*6dbdd20aSAndroid Build Coastguard Worker PagedMemory::PagedMemory() {}
87*6dbdd20aSAndroid Build Coastguard Worker
88*6dbdd20aSAndroid Build Coastguard Worker // clang-format off
PagedMemory(char * p,size_t size)89*6dbdd20aSAndroid Build Coastguard Worker PagedMemory::PagedMemory(char* p, size_t size) : p_(p), size_(size) {
90*6dbdd20aSAndroid Build Coastguard Worker ANNOTATE_NEW_BUFFER(p_, size_, committed_size_)
91*6dbdd20aSAndroid Build Coastguard Worker }
92*6dbdd20aSAndroid Build Coastguard Worker
PagedMemory(PagedMemory && other)93*6dbdd20aSAndroid Build Coastguard Worker PagedMemory::PagedMemory(PagedMemory&& other) noexcept {
94*6dbdd20aSAndroid Build Coastguard Worker *this = other;
95*6dbdd20aSAndroid Build Coastguard Worker other.p_ = nullptr;
96*6dbdd20aSAndroid Build Coastguard Worker }
97*6dbdd20aSAndroid Build Coastguard Worker // clang-format on
98*6dbdd20aSAndroid Build Coastguard Worker
operator =(PagedMemory && other)99*6dbdd20aSAndroid Build Coastguard Worker PagedMemory& PagedMemory::operator=(PagedMemory&& other) {
100*6dbdd20aSAndroid Build Coastguard Worker this->~PagedMemory();
101*6dbdd20aSAndroid Build Coastguard Worker new (this) PagedMemory(std::move(other));
102*6dbdd20aSAndroid Build Coastguard Worker return *this;
103*6dbdd20aSAndroid Build Coastguard Worker }
104*6dbdd20aSAndroid Build Coastguard Worker
~PagedMemory()105*6dbdd20aSAndroid Build Coastguard Worker PagedMemory::~PagedMemory() {
106*6dbdd20aSAndroid Build Coastguard Worker if (!p_)
107*6dbdd20aSAndroid Build Coastguard Worker return;
108*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(size_);
109*6dbdd20aSAndroid Build Coastguard Worker char* start = p_ - GuardSize();
110*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
111*6dbdd20aSAndroid Build Coastguard Worker BOOL res = VirtualFree(start, 0, MEM_RELEASE);
112*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(res != 0);
113*6dbdd20aSAndroid Build Coastguard Worker #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
114*6dbdd20aSAndroid Build Coastguard Worker const size_t outer_size = RoundUpToSysPageSize(size_) + GuardSize() * 2;
115*6dbdd20aSAndroid Build Coastguard Worker int res = munmap(start, outer_size);
116*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(res == 0);
117*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
118*6dbdd20aSAndroid Build Coastguard Worker ANNOTATE_DELETE_BUFFER(p_, size_, committed_size_)
119*6dbdd20aSAndroid Build Coastguard Worker }
120*6dbdd20aSAndroid Build Coastguard Worker
AdviseDontNeed(void * p,size_t size)121*6dbdd20aSAndroid Build Coastguard Worker bool PagedMemory::AdviseDontNeed(void* p, size_t size) {
122*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(p_);
123*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(p >= p_);
124*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(static_cast<char*>(p) + size <= p_ + size_);
125*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
126*6dbdd20aSAndroid Build Coastguard Worker // Discarding pages on Windows has more CPU cost than is justified for the
127*6dbdd20aSAndroid Build Coastguard Worker // possible memory savings.
128*6dbdd20aSAndroid Build Coastguard Worker return false;
129*6dbdd20aSAndroid Build Coastguard Worker #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
130*6dbdd20aSAndroid Build Coastguard Worker // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
131*6dbdd20aSAndroid Build Coastguard Worker // http://man7.org/linux/man-pages/man2/madvise.2.html
132*6dbdd20aSAndroid Build Coastguard Worker int res = madvise(p, size, MADV_DONTNEED);
133*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(res == 0);
134*6dbdd20aSAndroid Build Coastguard Worker return true;
135*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
136*6dbdd20aSAndroid Build Coastguard Worker // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
137*6dbdd20aSAndroid Build Coastguard Worker }
138*6dbdd20aSAndroid Build Coastguard Worker
139*6dbdd20aSAndroid Build Coastguard Worker #if TRACK_COMMITTED_SIZE()
EnsureCommitted(size_t committed_size)140*6dbdd20aSAndroid Build Coastguard Worker void PagedMemory::EnsureCommitted(size_t committed_size) {
141*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(committed_size <= size_);
142*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
143*6dbdd20aSAndroid Build Coastguard Worker if (committed_size_ >= committed_size)
144*6dbdd20aSAndroid Build Coastguard Worker return;
145*6dbdd20aSAndroid Build Coastguard Worker // Rounding up.
146*6dbdd20aSAndroid Build Coastguard Worker size_t delta = committed_size - committed_size_;
147*6dbdd20aSAndroid Build Coastguard Worker size_t num_additional_chunks =
148*6dbdd20aSAndroid Build Coastguard Worker (delta + kCommitChunkSize - 1) / kCommitChunkSize;
149*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(num_additional_chunks * kCommitChunkSize >= delta);
150*6dbdd20aSAndroid Build Coastguard Worker // Don't commit more than the total size.
151*6dbdd20aSAndroid Build Coastguard Worker size_t commit_size = std::min(num_additional_chunks * kCommitChunkSize,
152*6dbdd20aSAndroid Build Coastguard Worker size_ - committed_size_);
153*6dbdd20aSAndroid Build Coastguard Worker void* res = VirtualAlloc(p_ + committed_size_, commit_size, MEM_COMMIT,
154*6dbdd20aSAndroid Build Coastguard Worker PAGE_READWRITE);
155*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_CHECK(res);
156*6dbdd20aSAndroid Build Coastguard Worker ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_,
157*6dbdd20aSAndroid Build Coastguard Worker committed_size_ + commit_size)
158*6dbdd20aSAndroid Build Coastguard Worker committed_size_ += commit_size;
159*6dbdd20aSAndroid Build Coastguard Worker #else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
160*6dbdd20aSAndroid Build Coastguard Worker // mmap commits automatically as needed, so we only track here for ASAN.
161*6dbdd20aSAndroid Build Coastguard Worker committed_size = std::max(committed_size_, committed_size);
162*6dbdd20aSAndroid Build Coastguard Worker ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_, committed_size)
163*6dbdd20aSAndroid Build Coastguard Worker committed_size_ = committed_size;
164*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
165*6dbdd20aSAndroid Build Coastguard Worker }
166*6dbdd20aSAndroid Build Coastguard Worker #endif // TRACK_COMMITTED_SIZE()
167*6dbdd20aSAndroid Build Coastguard Worker
168*6dbdd20aSAndroid Build Coastguard Worker } // namespace base
169*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
170