1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "mem_map_arena_pool.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <sys/mman.h>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <algorithm>
22*795d594fSAndroid Build Coastguard Worker #include <cstddef>
23*795d594fSAndroid Build Coastguard Worker #include <iomanip>
24*795d594fSAndroid Build Coastguard Worker #include <numeric>
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/mem_map.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/systrace.h"
31*795d594fSAndroid Build Coastguard Worker #include "runtime_globals.h"
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
34*795d594fSAndroid Build Coastguard Worker
35*795d594fSAndroid Build Coastguard Worker class MemMapArena final : public Arena {
36*795d594fSAndroid Build Coastguard Worker public:
37*795d594fSAndroid Build Coastguard Worker MemMapArena(size_t size, bool low_4gb, const char* name);
38*795d594fSAndroid Build Coastguard Worker virtual ~MemMapArena();
39*795d594fSAndroid Build Coastguard Worker void Release() override;
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker private:
42*795d594fSAndroid Build Coastguard Worker static MemMap Allocate(size_t size, bool low_4gb, const char* name);
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Worker MemMap map_;
45*795d594fSAndroid Build Coastguard Worker };
46*795d594fSAndroid Build Coastguard Worker
MemMapArena(size_t size,bool low_4gb,const char * name)47*795d594fSAndroid Build Coastguard Worker MemMapArena::MemMapArena(size_t size, bool low_4gb, const char* name)
48*795d594fSAndroid Build Coastguard Worker : map_(Allocate(size, low_4gb, name)) {
49*795d594fSAndroid Build Coastguard Worker memory_ = map_.Begin();
50*795d594fSAndroid Build Coastguard Worker static_assert(ArenaAllocator::kArenaAlignment <= kMinPageSize,
51*795d594fSAndroid Build Coastguard Worker "Arena should not need stronger alignment than kMinPageSize.");
52*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(memory_, ArenaAllocator::kArenaAlignment);
53*795d594fSAndroid Build Coastguard Worker size_ = map_.Size();
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker
Allocate(size_t size,bool low_4gb,const char * name)56*795d594fSAndroid Build Coastguard Worker MemMap MemMapArena::Allocate(size_t size, bool low_4gb, const char* name) {
57*795d594fSAndroid Build Coastguard Worker // Round up to a full page as that's the smallest unit of allocation for mmap()
58*795d594fSAndroid Build Coastguard Worker // and we want to be able to use all memory that we actually allocate.
59*795d594fSAndroid Build Coastguard Worker size = RoundUp(size, gPageSize);
60*795d594fSAndroid Build Coastguard Worker std::string error_msg;
61*795d594fSAndroid Build Coastguard Worker // TODO(b/278665389): remove this retry logic if the root cause is found.
62*795d594fSAndroid Build Coastguard Worker constexpr int MAX_RETRY_CNT = 3;
63*795d594fSAndroid Build Coastguard Worker int retry_cnt = 0;
64*795d594fSAndroid Build Coastguard Worker while (true) {
65*795d594fSAndroid Build Coastguard Worker MemMap map = MemMap::MapAnonymous(name, size, PROT_READ | PROT_WRITE, low_4gb, &error_msg);
66*795d594fSAndroid Build Coastguard Worker if (map.IsValid()) {
67*795d594fSAndroid Build Coastguard Worker if (retry_cnt > 0) {
68*795d594fSAndroid Build Coastguard Worker LOG(WARNING) << "Succeed with retry(cnt=" << retry_cnt << ")";
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker return map;
71*795d594fSAndroid Build Coastguard Worker } else {
72*795d594fSAndroid Build Coastguard Worker if (retry_cnt == MAX_RETRY_CNT) {
73*795d594fSAndroid Build Coastguard Worker CHECK(map.IsValid()) << error_msg << "(retried " << retry_cnt << " times)";
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker }
76*795d594fSAndroid Build Coastguard Worker retry_cnt++;
77*795d594fSAndroid Build Coastguard Worker LOG(ERROR) << error_msg << " but retry(cnt=" << retry_cnt << ")";
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker
~MemMapArena()81*795d594fSAndroid Build Coastguard Worker MemMapArena::~MemMapArena() {
82*795d594fSAndroid Build Coastguard Worker // Destroys MemMap via std::unique_ptr<>.
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker
Release()85*795d594fSAndroid Build Coastguard Worker void MemMapArena::Release() {
86*795d594fSAndroid Build Coastguard Worker if (bytes_allocated_ > 0) {
87*795d594fSAndroid Build Coastguard Worker map_.MadviseDontNeedAndZero();
88*795d594fSAndroid Build Coastguard Worker bytes_allocated_ = 0;
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker
MemMapArenaPool(bool low_4gb,const char * name)92*795d594fSAndroid Build Coastguard Worker MemMapArenaPool::MemMapArenaPool(bool low_4gb, const char* name)
93*795d594fSAndroid Build Coastguard Worker : low_4gb_(low_4gb),
94*795d594fSAndroid Build Coastguard Worker name_(name),
95*795d594fSAndroid Build Coastguard Worker free_arenas_(nullptr) {
96*795d594fSAndroid Build Coastguard Worker MemMap::Init();
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker
~MemMapArenaPool()99*795d594fSAndroid Build Coastguard Worker MemMapArenaPool::~MemMapArenaPool() {
100*795d594fSAndroid Build Coastguard Worker ReclaimMemory();
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker
ReclaimMemory()103*795d594fSAndroid Build Coastguard Worker void MemMapArenaPool::ReclaimMemory() {
104*795d594fSAndroid Build Coastguard Worker while (free_arenas_ != nullptr) {
105*795d594fSAndroid Build Coastguard Worker Arena* arena = free_arenas_;
106*795d594fSAndroid Build Coastguard Worker free_arenas_ = free_arenas_->next_;
107*795d594fSAndroid Build Coastguard Worker delete arena;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker
LockReclaimMemory()111*795d594fSAndroid Build Coastguard Worker void MemMapArenaPool::LockReclaimMemory() {
112*795d594fSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(lock_);
113*795d594fSAndroid Build Coastguard Worker ReclaimMemory();
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker
AllocArena(size_t size)116*795d594fSAndroid Build Coastguard Worker Arena* MemMapArenaPool::AllocArena(size_t size) {
117*795d594fSAndroid Build Coastguard Worker Arena* ret = nullptr;
118*795d594fSAndroid Build Coastguard Worker {
119*795d594fSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(lock_);
120*795d594fSAndroid Build Coastguard Worker if (free_arenas_ != nullptr && LIKELY(free_arenas_->Size() >= size)) {
121*795d594fSAndroid Build Coastguard Worker ret = free_arenas_;
122*795d594fSAndroid Build Coastguard Worker free_arenas_ = free_arenas_->next_;
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker if (ret == nullptr) {
126*795d594fSAndroid Build Coastguard Worker ret = new MemMapArena(size, low_4gb_, name_);
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker ret->Reset();
129*795d594fSAndroid Build Coastguard Worker return ret;
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
TrimMaps()132*795d594fSAndroid Build Coastguard Worker void MemMapArenaPool::TrimMaps() {
133*795d594fSAndroid Build Coastguard Worker ScopedTrace trace(__PRETTY_FUNCTION__);
134*795d594fSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(lock_);
135*795d594fSAndroid Build Coastguard Worker for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
136*795d594fSAndroid Build Coastguard Worker arena->Release();
137*795d594fSAndroid Build Coastguard Worker }
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
GetBytesAllocated() const140*795d594fSAndroid Build Coastguard Worker size_t MemMapArenaPool::GetBytesAllocated() const {
141*795d594fSAndroid Build Coastguard Worker size_t total = 0;
142*795d594fSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(lock_);
143*795d594fSAndroid Build Coastguard Worker for (Arena* arena = free_arenas_; arena != nullptr; arena = arena->next_) {
144*795d594fSAndroid Build Coastguard Worker total += arena->GetBytesAllocated();
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker return total;
147*795d594fSAndroid Build Coastguard Worker }
148*795d594fSAndroid Build Coastguard Worker
FreeArenaChain(Arena * first)149*795d594fSAndroid Build Coastguard Worker void MemMapArenaPool::FreeArenaChain(Arena* first) {
150*795d594fSAndroid Build Coastguard Worker if (kRunningOnMemoryTool) {
151*795d594fSAndroid Build Coastguard Worker for (Arena* arena = first; arena != nullptr; arena = arena->next_) {
152*795d594fSAndroid Build Coastguard Worker MEMORY_TOOL_MAKE_UNDEFINED(arena->memory_, arena->bytes_allocated_);
153*795d594fSAndroid Build Coastguard Worker }
154*795d594fSAndroid Build Coastguard Worker }
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Worker if (arena_allocator::kArenaAllocatorPreciseTracking) {
157*795d594fSAndroid Build Coastguard Worker // Do not reuse arenas when tracking.
158*795d594fSAndroid Build Coastguard Worker while (first != nullptr) {
159*795d594fSAndroid Build Coastguard Worker Arena* next = first->next_;
160*795d594fSAndroid Build Coastguard Worker delete first;
161*795d594fSAndroid Build Coastguard Worker first = next;
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker return;
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker
166*795d594fSAndroid Build Coastguard Worker if (first != nullptr) {
167*795d594fSAndroid Build Coastguard Worker Arena* last = first;
168*795d594fSAndroid Build Coastguard Worker while (last->next_ != nullptr) {
169*795d594fSAndroid Build Coastguard Worker last = last->next_;
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(lock_);
172*795d594fSAndroid Build Coastguard Worker last->next_ = free_arenas_;
173*795d594fSAndroid Build Coastguard Worker free_arenas_ = first;
174*795d594fSAndroid Build Coastguard Worker }
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker
177*795d594fSAndroid Build Coastguard Worker } // namespace art
178