Skip to content

Commit 9086201

Browse files
committed
Now using lower_bound
1 parent ef74771 commit 9086201

File tree

2 files changed

+110
-69
lines changed

2 files changed

+110
-69
lines changed

include/DataFrame/Utils/FixedSizeAllocator.h

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929

3030
#pragma once
3131

32-
#include <iostream>
3332
#include <algorithm>
3433
#include <cstring>
3534
#include <functional>
@@ -51,7 +50,8 @@ struct StaticStorage {
5150
using value_type = T;
5251
using size_type = std::size_t;
5352

54-
inline static constexpr size_type max_size = MAX_SIZE * sizeof(value_type);
53+
inline static constexpr size_type max_size =
54+
MAX_SIZE * sizeof(value_type);
5555
inline static constexpr bool is_static = true;
5656

5757
StaticStorage() = default;
@@ -76,7 +76,8 @@ struct StackStorage {
7676
using value_type = T;
7777
using size_type = std::size_t;
7878

79-
inline static constexpr size_type max_size = MAX_SIZE * sizeof(value_type);
79+
inline static constexpr size_type max_size =
80+
MAX_SIZE * sizeof(value_type);
8081
inline static constexpr bool is_static = false;
8182

8283
StackStorage() = default;
@@ -103,36 +104,42 @@ struct BestFitMemoryBlock {
103104
value_type address { nullptr };
104105
size_type size { 0 };
105106

106-
value_type get_end() const { return (address + size); }
107-
value_type get_start() const { return (address - size); }
107+
inline value_type
108+
get_end() const { return (address + size); }
109+
inline value_type
110+
get_start() const { return (address - size); }
108111

109112
// Hash function
110113
//
111-
size_type operator() (const BestFitMemoryBlock &mb) const {
114+
inline size_type
115+
operator() (const BestFitMemoryBlock &mb) const {
112116

113117
return (std::hash<value_type>{ }(mb.address));
114118
}
115119

116120
inline friend bool
117-
operator < (const BestFitMemoryBlock &lhs, const BestFitMemoryBlock &rhs) {
121+
operator < (const BestFitMemoryBlock &lhs,
122+
const BestFitMemoryBlock &rhs) {
118123

119124
return (lhs.size < rhs.size);
120125
}
121126
inline friend bool
122-
operator > (const BestFitMemoryBlock &lhs, const BestFitMemoryBlock &rhs) {
127+
operator > (const BestFitMemoryBlock &lhs,
128+
const BestFitMemoryBlock &rhs) {
123129

124130
return (lhs.size > rhs.size);
125131
}
126132
inline friend bool
127-
operator == (const BestFitMemoryBlock &lhs, const BestFitMemoryBlock &rhs) {
133+
operator == (const BestFitMemoryBlock &lhs,
134+
const BestFitMemoryBlock &rhs) {
128135

129136
return (lhs.address == rhs.address);
130137
}
131138
};
132139

133140
// ----------------------------------------------------------------------------
134141

135-
template<typename S>
142+
template<typename S> // Storage class
136143
struct BestFitAlgo : public S {
137144

138145
using Base = S;
@@ -142,6 +149,8 @@ struct BestFitAlgo : public S {
142149
BestFitAlgo() : Base() {
143150

144151
free_blocks_start_.insert({ Base::buffer_, Base::max_size });
152+
free_blocks_assist_.insert(
153+
std::make_pair(Base::buffer_, free_blocks_start_.begin()));
145154
free_blocks_end_.insert(std::make_pair(Base::buffer_ + Base::max_size,
146155
Base::max_size));
147156
}
@@ -152,28 +161,31 @@ struct BestFitAlgo : public S {
152161
[[nodiscard]] pointer
153162
get_space (size_type requested_size) {
154163

155-
for (auto iter = free_blocks_start_.begin();
156-
iter != free_blocks_start_.end();
157-
++iter) {
158-
if (iter->size >= requested_size) {
159-
auto found_end = iter->get_end();
164+
auto free_iter =
165+
free_blocks_start_.lower_bound({ nullptr, requested_size });
160166

161-
if (iter->size > requested_size) {
162-
auto remaining = iter->size - requested_size;
163-
auto new_address = iter->address + requested_size;
167+
if (free_iter != free_blocks_start_.end()) {
168+
auto found_end = free_iter->get_end();
164169

170+
if (free_iter->size > requested_size) {
171+
auto remaining = free_iter->size - requested_size;
172+
auto new_address = free_iter->address + requested_size;
173+
const auto insert_ret =
165174
free_blocks_start_.insert({ new_address, remaining });
166-
free_blocks_end_[found_end] = remaining;
167-
}
168-
else // Exact size match
169-
free_blocks_end_.erase(found_end);
170-
171-
auto ret = iter->address;
172175

173-
free_blocks_start_.erase(iter);
174-
used_blocks_.insert({ ret, requested_size });
175-
return (ret);
176+
free_blocks_assist_.insert(
177+
std::make_pair(new_address, insert_ret));
178+
free_blocks_end_[found_end] = remaining;
176179
}
180+
else // Exact size match
181+
free_blocks_end_.erase(found_end);
182+
183+
auto ret = free_iter->address;
184+
185+
free_blocks_assist_.erase(free_iter->address);
186+
free_blocks_start_.erase(free_iter);
187+
used_blocks_.insert({ ret, requested_size });
188+
return (ret);
177189
}
178190
throw std::bad_alloc();
179191
}
@@ -188,53 +200,58 @@ struct BestFitAlgo : public S {
188200
if (used_iter != used_blocks_.end()) {
189201
const pointer tail_ptr = to_be_freed + used_iter->size;
190202
bool found_tail = false;
203+
const auto tail_block = free_blocks_assist_.find(tail_ptr);
191204

192-
// Try to find a free block that starts where to_be_freed block ends.
193-
// If there is such a free block, join it with to_be_freed block
205+
// Try to find a free block that starts where to_be_freed block
206+
// ends. If there is such a free block, join it with to_be_freed
207+
// block
194208
//
195-
for (auto tail_block = free_blocks_start_.begin();
196-
tail_block != free_blocks_start_.end();
197-
++tail_block) {
198-
if (tail_block->address == tail_ptr) {
199-
const size_type new_len =
200-
used_iter->size + tail_block->size;
201-
const BestFitMemoryBlock to_insert { to_be_freed, new_len };
202-
203-
free_blocks_start_.erase(tail_block);
204-
free_blocks_start_.insert(to_insert);
205-
free_blocks_end_[to_insert.get_end()] = new_len;
206-
found_tail = true;
207-
break;
208-
}
209+
if (tail_block != free_blocks_assist_.end()) {
210+
const size_type new_len =
211+
used_iter->size + tail_block->second->size;
212+
const BestFitMemoryBlock to_insert { to_be_freed, new_len };
213+
214+
free_blocks_start_.erase(tail_block->second);
215+
free_blocks_assist_.erase(tail_block);
216+
217+
const auto insert_ret = free_blocks_start_.insert(to_insert);
218+
219+
free_blocks_assist_.insert(
220+
std::make_pair(to_be_freed, insert_ret));
221+
free_blocks_end_[to_insert.get_end()] = new_len;
222+
found_tail = true;
209223
}
210224

211-
// Try to find a free block that ends where to_be_freed block starts.
212-
// If there is such a free block, join it with to_be_freed block
225+
// Try to find a free block that ends where to_be_freed block
226+
// starts. If there is such a free block, join it with to_be_freed
227+
// block
213228
//
214229
const auto end_iter = free_blocks_end_.find(to_be_freed);
215230
bool found_head = false;
216231

217232
if (end_iter != free_blocks_end_.end()) {
218-
const pointer head_address =
233+
const pointer head_ptr =
219234
end_iter->first - end_iter->second;
235+
const auto head_block = free_blocks_assist_.find(head_ptr);
236+
237+
if (head_block != free_blocks_assist_.end()) {
238+
const size_type new_len =
239+
used_iter->size + head_block->second->size;
240+
const auto new_head = head_block->second->address;
241+
const auto new_end =
242+
end_iter->first + used_iter->size;
220243

221-
for (auto head_block = free_blocks_start_.begin();
222-
head_block != free_blocks_start_.end();
223-
++head_block) {
224-
if (head_block->address == head_address) {
225-
const size_type new_len =
226-
used_iter->size + head_block->size;
227-
const auto new_head = head_block->address;
228-
const auto new_end =
229-
end_iter->first + used_iter->size;
230-
231-
free_blocks_start_.erase(head_block);
244+
free_blocks_start_.erase(head_block->second);
245+
free_blocks_assist_.erase(head_block);
246+
247+
const auto insert_ret =
232248
free_blocks_start_.insert({ new_head, new_len });
233-
free_blocks_end_.erase(end_iter);
234-
free_blocks_end_[new_end] = new_len;
235-
found_head = true;
236-
break;
237-
}
249+
250+
free_blocks_assist_.insert(
251+
std::make_pair(new_head, insert_ret));
252+
free_blocks_end_.erase(end_iter);
253+
free_blocks_end_[new_end] = new_len;
254+
found_head = true;
238255
}
239256
}
240257

@@ -244,9 +261,12 @@ struct BestFitAlgo : public S {
244261
if (! (found_tail || found_head)) {
245262
const pointer end_address =
246263
used_iter->address + used_iter->size;
264+
const auto insert_ret =
265+
free_blocks_start_.insert(
266+
{ used_iter->address, used_iter->size });
247267

248-
free_blocks_start_.insert(
249-
{ used_iter->address, used_iter->size });
268+
free_blocks_assist_.insert(
269+
std::make_pair(used_iter->address, insert_ret));
250270
free_blocks_end_[end_address] = used_iter->size;
251271
}
252272

@@ -263,12 +283,29 @@ struct BestFitAlgo : public S {
263283
// It is based on size, so it must be multi-set
264284
//
265285
using blk_set = std::multiset<BestFitMemoryBlock>;
266-
using blk_uoset = std::unordered_set<BestFitMemoryBlock, BestFitMemoryBlock>;
286+
using blk_uoset =
287+
std::unordered_set<BestFitMemoryBlock, BestFitMemoryBlock>;
267288
using blk_uomap = std::unordered_map<pointer, std::size_t>;
289+
using blk_assist = std::unordered_map<pointer, blk_set::const_iterator>;
268290

269-
blk_set free_blocks_start_ { }; // Pointres to free block beginnings.
270-
blk_uomap free_blocks_end_ { }; // Pointres to free block ends.
271-
blk_uoset used_blocks_ { }; // Set of used blocks
291+
// Set of free blocks, keyed by size of the block. There could be multiple
292+
// blocks with the same size.
293+
//
294+
blk_set free_blocks_start_ { };
295+
296+
// Map of free blocks to size, keyed by the pointer to the end of the block.
297+
//
298+
blk_uomap free_blocks_end_ { };
299+
300+
// Hash set of used blocks, keyed by the pointer to the beginning of
301+
// the block.
302+
//
303+
blk_uoset used_blocks_ { };
304+
305+
// Map of free blocks to iterators of free_blocks_start_, keyed pointers
306+
// to the beginning of free blocks
307+
//
308+
blk_assist free_blocks_assist_ { };
272309
};
273310

274311
// ----------------------------------------------------------------------------
@@ -333,7 +370,7 @@ struct FirstFitStackBase : public StackStorage<T, MAX_SIZE> {
333370

334371
// ----------------------------------------------------------------------------
335372

336-
template<typename S>
373+
template<typename S> // Storage class
337374
struct FirstFitAlgo : public S {
338375

339376
using Base = S;

test/allocator_tester.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ static void test_first_fit_static_allocator() {
245245
for (int i = 0; i < 1000; ++i)
246246
assert((my_map.find(i)->second == i * 10));
247247

248+
// Test how badly it fragments the memory
249+
//
248250
FirstFitAlgo<FirstFitStaticBase<int, 10000>> allocator;
249251
std::vector<std::pair<unsigned char *, std::size_t>> ptr_vec;
250252
std::mt19937 gen { 98 };
@@ -438,6 +440,8 @@ static void test_best_fit_static_allocator() {
438440
for (int i = 0; i < 1000; ++i)
439441
assert((my_map.find(i)->second == i * 10));
440442

443+
// Test how badly it fragments the memory
444+
//
441445
BestFitAlgo<StaticStorage<int, 10000>> allocator;
442446
std::vector<std::pair<unsigned char *, std::size_t>> ptr_vec;
443447
std::mt19937 gen { 98 };

0 commit comments

Comments
 (0)