blob: 551c5ca975ad8bdccb5ad9fa6c0526d7dae48ce4 [file] [log] [blame]
Eric Seckleredf3f7c2018-10-23 16:44:53 +01001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Primiano Tucci2c5488f2019-06-01 03:27:28 +010017#include "perfetto/ext/base/paged_memory.h"
Eric Seckleredf3f7c2018-10-23 16:44:53 +010018
19#include <algorithm>
20#include <cmath>
21
22#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
23#include <Windows.h>
24#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
25#include <sys/mman.h>
26#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
27
28#include "perfetto/base/logging.h"
Primiano Tucci2c5488f2019-06-01 03:27:28 +010029#include "perfetto/ext/base/container_annotations.h"
30#include "perfetto/ext/base/utils.h"
Eric Seckleredf3f7c2018-10-23 16:44:53 +010031
32namespace perfetto {
33namespace base {
34
35namespace {
36
Eric Seckler2ad5a7d2018-10-24 09:43:19 +010037#if TRACK_COMMITTED_SIZE()
Primiano Tucci90d69302020-08-20 17:22:12 +020038constexpr size_t kCommitChunkSize = 4 * 1024 * 1024; // 4MB
39#endif
40
41size_t RoundUpToSysPageSize(size_t req_size) {
42 const size_t page_size = GetSysPageSize();
43 return (req_size + page_size - 1) & ~(page_size - 1);
44}
45
46size_t GuardSize() {
47 return GetSysPageSize();
48}
Eric Seckleredf3f7c2018-10-23 16:44:53 +010049
50} // namespace
51
52// static
Primiano Tucci90d69302020-08-20 17:22:12 +020053PagedMemory PagedMemory::Allocate(size_t req_size, int flags) {
54 size_t rounded_up_size = RoundUpToSysPageSize(req_size);
55 PERFETTO_CHECK(rounded_up_size >= req_size);
56 size_t outer_size = rounded_up_size + GuardSize() * 2;
Eric Seckleredf3f7c2018-10-23 16:44:53 +010057#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
58 void* ptr = VirtualAlloc(nullptr, outer_size, MEM_RESERVE, PAGE_NOACCESS);
59 if (!ptr && (flags & kMayFail))
60 return PagedMemory();
61 PERFETTO_CHECK(ptr);
Primiano Tucci90d69302020-08-20 17:22:12 +020062 char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
Eric Seckleredf3f7c2018-10-23 16:44:53 +010063#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
64 void* ptr = mmap(nullptr, outer_size, PROT_READ | PROT_WRITE,
Primiano Tuccia23e8f72019-02-25 11:45:44 +010065 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Eric Seckleredf3f7c2018-10-23 16:44:53 +010066 if (ptr == MAP_FAILED && (flags & kMayFail))
67 return PagedMemory();
68 PERFETTO_CHECK(ptr && ptr != MAP_FAILED);
Primiano Tucci90d69302020-08-20 17:22:12 +020069 char* usable_region = reinterpret_cast<char*>(ptr) + GuardSize();
70 int res = mprotect(ptr, GuardSize(), PROT_NONE);
71 res |= mprotect(usable_region + rounded_up_size, GuardSize(), PROT_NONE);
Eric Seckleredf3f7c2018-10-23 16:44:53 +010072 PERFETTO_CHECK(res == 0);
73#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
74
Primiano Tucci90d69302020-08-20 17:22:12 +020075 auto memory = PagedMemory(usable_region, req_size);
Eric Seckler2ad5a7d2018-10-24 09:43:19 +010076#if TRACK_COMMITTED_SIZE()
Primiano Tucci90d69302020-08-20 17:22:12 +020077 size_t initial_commit = req_size;
Eric Seckleredf3f7c2018-10-23 16:44:53 +010078 if (flags & kDontCommit)
79 initial_commit = std::min(initial_commit, kCommitChunkSize);
80 memory.EnsureCommitted(initial_commit);
Eric Seckler2ad5a7d2018-10-24 09:43:19 +010081#endif // TRACK_COMMITTED_SIZE()
Eric Seckleredf3f7c2018-10-23 16:44:53 +010082 return memory;
83}
84
85PagedMemory::PagedMemory() {}
86
Ryana7fc7a32019-07-16 18:53:21 +010087// clang-format off
88PagedMemory::PagedMemory(char* p, size_t size) : p_(p), size_(size) {
89 ANNOTATE_NEW_BUFFER(p_, size_, committed_size_)
90}
Eric Seckleredf3f7c2018-10-23 16:44:53 +010091
Ryana7fc7a32019-07-16 18:53:21 +010092PagedMemory::PagedMemory(PagedMemory&& other) noexcept {
Eric Seckleredf3f7c2018-10-23 16:44:53 +010093 *this = other;
94 other.p_ = nullptr;
95}
Ryana7fc7a32019-07-16 18:53:21 +010096// clang-format on
Eric Seckleredf3f7c2018-10-23 16:44:53 +010097
98PagedMemory& PagedMemory::operator=(PagedMemory&& other) {
Ryana7fc7a32019-07-16 18:53:21 +010099 this->~PagedMemory();
100 new (this) PagedMemory(std::move(other));
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100101 return *this;
102}
103
104PagedMemory::~PagedMemory() {
105 if (!p_)
106 return;
107 PERFETTO_CHECK(size_);
Primiano Tucci90d69302020-08-20 17:22:12 +0200108 char* start = p_ - GuardSize();
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100109#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
110 BOOL res = VirtualFree(start, 0, MEM_RELEASE);
111 PERFETTO_CHECK(res != 0);
112#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tucci90d69302020-08-20 17:22:12 +0200113 const size_t outer_size = RoundUpToSysPageSize(size_) + GuardSize() * 2;
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100114 int res = munmap(start, outer_size);
115 PERFETTO_CHECK(res == 0);
116#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tucci335412d2019-05-30 16:29:16 +0100117 ANNOTATE_DELETE_BUFFER(p_, size_, committed_size_)
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100118}
119
120bool PagedMemory::AdviseDontNeed(void* p, size_t size) {
121 PERFETTO_DCHECK(p_);
122 PERFETTO_DCHECK(p >= p_);
123 PERFETTO_DCHECK(static_cast<char*>(p) + size <= p_ + size_);
Stephen Nuskoaca77482020-01-10 15:47:06 +0000124#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) || PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100125 // Discarding pages on Windows has more CPU cost than is justified for the
126 // possible memory savings.
127 return false;
Stephen Nuskoaca77482020-01-10 15:47:06 +0000128#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
129 // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100130 // http://man7.org/linux/man-pages/man2/madvise.2.html
131 int res = madvise(p, size, MADV_DONTNEED);
132 PERFETTO_DCHECK(res == 0);
133 return true;
Stephen Nuskoaca77482020-01-10 15:47:06 +0000134#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) ||
135 // PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100136}
137
Eric Seckler2ad5a7d2018-10-24 09:43:19 +0100138#if TRACK_COMMITTED_SIZE()
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100139void PagedMemory::EnsureCommitted(size_t committed_size) {
140 PERFETTO_DCHECK(committed_size > 0u);
141 PERFETTO_DCHECK(committed_size <= size_);
142#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
143 if (committed_size_ >= committed_size)
144 return;
145 // Rounding up.
146 size_t delta = committed_size - committed_size_;
147 size_t num_additional_chunks =
148 (delta + kCommitChunkSize - 1) / kCommitChunkSize;
149 PERFETTO_DCHECK(num_additional_chunks * kCommitChunkSize >= delta);
150 // Don't commit more than the total size.
151 size_t commit_size = std::min(num_additional_chunks * kCommitChunkSize,
152 size_ - committed_size_);
153 void* res = VirtualAlloc(p_ + committed_size_, commit_size, MEM_COMMIT,
154 PAGE_READWRITE);
155 PERFETTO_CHECK(res);
Eric Seckler050fb212018-10-24 16:03:27 +0100156 ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_,
Primiano Tucci7d47d3f2019-06-01 02:17:01 +0100157 committed_size_ + commit_size)
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100158 committed_size_ += commit_size;
159#else // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Eric Seckler2ad5a7d2018-10-24 09:43:19 +0100160 // mmap commits automatically as needed, so we only track here for ASAN.
161 committed_size = std::max(committed_size_, committed_size);
Primiano Tucci335412d2019-05-30 16:29:16 +0100162 ANNOTATE_CHANGE_SIZE(p_, size_, committed_size_, committed_size)
Eric Seckler2ad5a7d2018-10-24 09:43:19 +0100163 committed_size_ = committed_size;
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100164#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
165}
Eric Seckler2ad5a7d2018-10-24 09:43:19 +0100166#endif // TRACK_COMMITTED_SIZE()
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100167
Eric Seckleredf3f7c2018-10-23 16:44:53 +0100168} // namespace base
169} // namespace perfetto