blob: 3a3e3858b3274acc02476ecd39a0bfc095b43181 [file] [log] [blame]
buzbee862a7602013-04-05 10:58:54 -07001/*
2 * Copyright (C) 2013 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
17#include "compiler_internals.h"
18#include "dex_file-inl.h"
19#include "arena_allocator.h"
20#include "base/logging.h"
21
22namespace art {
23
24static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = {
25 "Misc ",
26 "BasicBlock ",
27 "LIR ",
28 "MIR ",
29 "DataFlow ",
30 "GrowList ",
31 "GrowBitMap ",
32 "Dalvik2SSA ",
33 "DebugInfo ",
34 "Successor ",
35 "RegAlloc ",
36 "Data ",
37 "Preds ",
38};
39
40ArenaAllocator::ArenaAllocator(size_t default_size)
41 : default_size_(default_size),
42 block_size_(default_size - sizeof(ArenaMemBlock)),
43 arena_head_(NULL),
buzbeea5abf702013-04-12 14:39:29 -070044 current_block_(NULL),
buzbee862a7602013-04-05 10:58:54 -070045 num_arena_blocks_(0),
buzbeea5abf702013-04-12 14:39:29 -070046 malloc_bytes_(0),
47 lost_bytes_(0),
48 num_allocations_(0) {
buzbee862a7602013-04-05 10:58:54 -070049 memset(&alloc_stats_[0], 0, sizeof(alloc_stats_));
50 // Start with an empty arena.
buzbeea5abf702013-04-12 14:39:29 -070051 arena_head_ = current_block_ = EmptyArenaBlock();
buzbee862a7602013-04-05 10:58:54 -070052 num_arena_blocks_++;
53}
54
Ian Rogerse7a5b7d2013-04-18 20:09:02 -070055ArenaAllocator::~ArenaAllocator() {
56 // Reclaim all the arena blocks allocated so far.
57 ArenaMemBlock* head = arena_head_;
58 while (head != NULL) {
59 ArenaMemBlock* p = head;
60 head = head->next;
61 free(p);
62 }
buzbeea5abf702013-04-12 14:39:29 -070063 arena_head_ = NULL;
Ian Rogerse7a5b7d2013-04-18 20:09:02 -070064 num_arena_blocks_ = 0;
65}
66
buzbee862a7602013-04-05 10:58:54 -070067// Return an arena with no storage for use as a sentinal.
buzbeea5abf702013-04-12 14:39:29 -070068ArenaAllocator::ArenaMemBlock* ArenaAllocator::EmptyArenaBlock() {
buzbee862a7602013-04-05 10:58:54 -070069 ArenaMemBlock* res = static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock)));
70 malloc_bytes_ += sizeof(ArenaMemBlock);
71 res->block_size = 0;
72 res->bytes_allocated = 0;
73 res->next = NULL;
74 return res;
75}
76
77// Arena-based malloc for compilation tasks.
78void* ArenaAllocator::NewMem(size_t size, bool zero, ArenaAllocKind kind) {
buzbeea5abf702013-04-12 14:39:29 -070079 DCHECK(current_block_ != NULL);
buzbee862a7602013-04-05 10:58:54 -070080 DCHECK(arena_head_ != NULL);
81 size = (size + 3) & ~3;
82 alloc_stats_[kind] += size;
buzbeea5abf702013-04-12 14:39:29 -070083 ArenaMemBlock* allocation_block = current_block_; // Assume we'll fit.
84 size_t remaining_space = current_block_->block_size - current_block_->bytes_allocated;
85 if (remaining_space < size) {
86 /*
87 * Time to allocate a new block. If this is a large allocation or we have
88 * significant space remaining in the current block then fulfill the allocation
89 * request with a custom-sized malloc() - otherwise grab a new standard block.
90 */
91 size_t allocation_size = sizeof(ArenaMemBlock);
92 if ((remaining_space >= ARENA_HIGH_WATER) || (size > block_size_)) {
93 allocation_size += size;
94 } else {
95 allocation_size += block_size_;
96 }
97 ArenaMemBlock *new_block = static_cast<ArenaMemBlock*>(malloc(allocation_size));
98 if (new_block == NULL) {
buzbee862a7602013-04-05 10:58:54 -070099 LOG(FATAL) << "Arena allocation failure";
100 }
101 malloc_bytes_ += allocation_size;
buzbeea5abf702013-04-12 14:39:29 -0700102 new_block->block_size = allocation_size - sizeof(ArenaMemBlock);
103 new_block->bytes_allocated = 0;
104 new_block->next = NULL;
buzbee862a7602013-04-05 10:58:54 -0700105 num_arena_blocks_++;
buzbeea5abf702013-04-12 14:39:29 -0700106 /*
107 * If the new block is completely full, insert it into the head of the list so we don't
108 * bother trying to fit more and won't hide the potentially allocatable space on the
109 * last (current_block_) block. TUNING: if we move to a mark scheme, revisit
110 * this code to keep allocation order intact.
111 */
112 if (new_block->block_size == size) {
113 new_block->next = arena_head_;
114 arena_head_ = new_block;
115 } else {
116 int lost = (current_block_->block_size - current_block_->bytes_allocated);
117 lost_bytes_ += lost;
118 current_block_->next = new_block;
119 current_block_ = new_block;
120 }
121 allocation_block = new_block;
buzbee862a7602013-04-05 10:58:54 -0700122 }
buzbeea5abf702013-04-12 14:39:29 -0700123 void* ptr = &allocation_block->ptr[allocation_block->bytes_allocated];
124 allocation_block->bytes_allocated += size;
buzbee862a7602013-04-05 10:58:54 -0700125 if (zero) {
126 memset(ptr, 0, size);
127 }
buzbeea5abf702013-04-12 14:39:29 -0700128 num_allocations_++;
buzbee862a7602013-04-05 10:58:54 -0700129 return ptr;
130}
131
buzbee862a7602013-04-05 10:58:54 -0700132// Dump memory usage stats.
133void ArenaAllocator::DumpMemStats(std::ostream& os) const {
134 size_t total = 0;
135 for (int i = 0; i < kNumAllocKinds; i++) {
136 total += alloc_stats_[i];
137 }
buzbeea5abf702013-04-12 14:39:29 -0700138 os << " MEM: used: " << total << ", allocated: " << malloc_bytes_
139 << ", lost: " << lost_bytes_ << "\n";
140 os << "Number of blocks allocated: " << num_arena_blocks_ << ", Number of allocations: "
141 << num_allocations_ << ", avg: " << total / num_allocations_ << "\n";
buzbee862a7602013-04-05 10:58:54 -0700142 os << "===== Allocation by kind\n";
143 for (int i = 0; i < kNumAllocKinds; i++) {
144 os << alloc_names[i] << std::setw(10) << alloc_stats_[i] << "\n";
145 }
146}
147
148} // namespace art