forked from LearningInfiniTensor/TinyInfiniTensor
-
Notifications
You must be signed in to change notification settings - Fork 98
Expand file tree
/
Copy pathallocator.cc
More file actions
151 lines (132 loc) · 4.29 KB
/
allocator.cc
File metadata and controls
151 lines (132 loc) · 4.29 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "core/allocator.h"
#include <utility>
namespace infini
{
Allocator::Allocator(Runtime runtime) : runtime(runtime)
{
used = 0;
peak = 0;
ptr = nullptr;
// 'alignment' defaults to sizeof(uint64_t), because it is the length of
// the longest data type currently supported by the DataType field of
// the tensor
alignment = sizeof(uint64_t);
}
Allocator::~Allocator()
{
if (this->ptr != nullptr)
{
runtime->dealloc(this->ptr);
}
}
size_t Allocator::alloc(size_t size)
{
IT_ASSERT(this->ptr == nullptr);
// pad the size to the multiple of alignment
size = this->getAlignedSize(size);
// =================================== 作业 ===================================
// TODO: 设计一个算法来分配内存,返回起始地址偏移量
// =================================== 作业 ===================================
auto it = findFreeBlock(size);
if (it != freeBlocks.end())
{
const size_t addr = it->first;
const size_t blockSize = it->second;
IT_ASSERT(blockSize >= size);
freeBlocks.erase(it);
const size_t remain = blockSize - size;
if (remain > 0)
{
freeBlocks.emplace(addr + size, remain);
}
used += size;
return addr;
}
const size_t addr = peak;
peak += size;
used += size;
return addr;
}
void Allocator::free(size_t addr, size_t size)
{
IT_ASSERT(this->ptr == nullptr);
size = getAlignedSize(size);
IT_ASSERT(used >= size);
used -= size;
addFreeBlock(addr, size);
}
std::map<size_t, size_t>::iterator Allocator::findFreeBlock(size_t size)
{
// first-fit: 找到第一个 size 足够的空闲块
for (auto it = freeBlocks.begin(); it != freeBlocks.end(); ++it)
{
if (it->second >= size)
return it;
}
return freeBlocks.end();
}
void Allocator::addFreeBlock(size_t addr, size_t size)
{
// 插入一个 free block,并与左右相邻块合并(coalescing)
auto it = freeBlocks.lower_bound(addr);
// 尝试与左侧块合并
if (it != freeBlocks.begin())
{
auto left = std::prev(it);
const size_t leftAddr = left->first;
const size_t leftSize = left->second;
if (leftAddr + leftSize == addr)
{
addr = leftAddr;
size += leftSize;
freeBlocks.erase(left);
}
}
// 尝试与右侧块合并(重新定位迭代器)
it = freeBlocks.lower_bound(addr);
if (it != freeBlocks.end())
{
const size_t rightAddr = it->first;
const size_t rightSize = it->second;
if (addr + size == rightAddr)
{
size += rightSize;
freeBlocks.erase(it);
}
}
freeBlocks.emplace(addr, size);
// 若空闲块位于堆顶(addr+size==peak),则可以把 peak 往回收缩。
// 进一步:如果收缩后的新 peak 仍然与另一个空闲块相邻,也可以继续收缩。
while (!freeBlocks.empty())
{
auto it = freeBlocks.upper_bound(peak);
if (it == freeBlocks.begin())
break;
--it;
const size_t blockAddr = it->first;
const size_t blockSize = it->second;
if (blockAddr + blockSize != peak)
break;
peak = blockAddr;
freeBlocks.erase(it);
}
}
void *Allocator::getPtr()
{
if (this->ptr == nullptr)
{
this->ptr = runtime->alloc(this->peak);
printf("Allocator really alloc: %p %lu bytes\n", this->ptr, peak);
}
return this->ptr;
}
size_t Allocator::getAlignedSize(size_t size)
{
return ((size - 1) / this->alignment + 1) * this->alignment;
}
void Allocator::info()
{
std::cout << "Used memory: " << this->used
<< ", peak memory: " << this->peak << std::endl;
}
}