forked from LearningInfiniTensor/TinyInfiniTensor
-
Notifications
You must be signed in to change notification settings - Fork 98
Expand file tree
/
Copy pathtest_allocator.cc
More file actions
116 lines (89 loc) · 3.78 KB
/
test_allocator.cc
File metadata and controls
116 lines (89 loc) · 3.78 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
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 = freeBlocksBySize.lower_bound(size);
if (it != freeBlocksBySize.end()) {
// 找到合适的空闲块
size_t blockSize = it->first;
auto& addrSet = it->second;
// 获取第一个可用的起始地址
size_t startAddr = *addrSet.begin();
// 从空闲块集合中移除这个块
addrSet.erase(startAddr);
if (addrSet.empty()) {
freeBlocksBySize.erase(it);
}
// 从起始地址映射中移除
freeBlocksByStart.erase(startAddr);
// 如果块大小大于所需大小,将剩余部分作为新的空闲块
if (blockSize > size) {
size_t remainingSize = blockSize - size;
size_t remainingAddr = startAddr + size;
// 添加剩余部分到空闲块集合
freeBlocksByStart[remainingAddr] = remainingSize;
freeBlocksBySize[remainingSize].insert(remainingAddr);
}
return startAddr;
}
// 如果没有合适的空闲块,从当前偏移量分配
size_t startAddr = currentOffset;
currentOffset += size;
return startAddr;
// ============== 作业 ========================
}
void Allocator::free(size_t addr, size_t size) {
IT_ASSERT(this->ptr == nullptr);
size = getAlignedSize(size);
// ============== 作业 ========================
// TODO: 设计一个算法来回收内存
// 将释放的块添加到空闲块集合
freeBlocksByStart[addr] = size;
freeBlocksBySize[size].insert(addr);
// 合并相邻的空闲块
mergeFreeBlocks();
// ============== 作业 ========================
}
void Allocator::mergeFreeBlocks() {
if (freeBlocksByStart.empty()) return;
// 按起始地址排序后,合并相邻的空闲块
auto it = freeBlocksByStart.begin();
auto nextIt = std::next(it);
while (nextIt != freeBlocksByStart.end()) {
size_t currentAddr = it->first;
size_t currentSize = it->second;
size_t nextAddr = nextIt->first;
size_t nextSize = nextIt->second;
// 检查当前块和下一个块是否相邻
if (currentAddr + currentSize == nextAddr) {
// 合并两个块
size_t mergedSize = currentSize + nextSize;
// 从空闲块集合中移除原来的两个块
// 从大小映射中移除
freeBlocksBySize[currentSize].erase(currentAddr);
if (freeBlocksBySize[currentSize].empty()) {
freeBlocksBySize.erase(currentSize);
}
freeBlocksBySize[nextSize].erase(nextAddr);
if (freeBlocksBySize[nextSize].empty()) {
freeBlocksBySize.erase(nextSize);
}
// 从起始地址映射中移除
freeBlocksByStart.erase(nextAddr);
// 更新当前块的大小
it->second = mergedSize;
// 添加到大小映射
freeBlocksBySize[mergedSize].insert(currentAddr);
// 重新开始合并,因为合并后可能还能和下一个块合并
nextIt = std::next(it);
} else {
// 不合并,继续检查下一对
++it;
++nextIt;
}
}
}