26
26
#include < unistd.h> // for sysconf
27
27
#endif
28
28
29
+ #include < algorithm>
30
+
29
31
LockedPoolManager* LockedPoolManager::_instance = nullptr ;
30
32
std::once_flag LockedPoolManager::init_flag;
31
33
@@ -45,7 +47,7 @@ Arena::Arena(void *base_in, size_t size_in, size_t alignment_in):
45
47
base(static_cast <char *>(base_in)), end(static_cast <char *>(base_in) + size_in), alignment(alignment_in)
46
48
{
47
49
// Start with one free chunk that covers the entire arena
48
- chunks .emplace (base, Chunk ( size_in, false ) );
50
+ chunks_free .emplace (base, size_in);
49
51
}
50
52
51
53
Arena::~Arena ()
@@ -57,24 +59,30 @@ void* Arena::alloc(size_t size)
57
59
// Round to next multiple of alignment
58
60
size = align_up (size, alignment);
59
61
60
- // Don't handle zero-sized chunks, or those bigger than MAX_SIZE
61
- if (size == 0 || size >= Chunk::MAX_SIZE) {
62
+ // Don't handle zero-sized chunks
63
+ if (size == 0 )
62
64
return nullptr ;
63
- }
64
65
65
- for (auto & chunk: chunks) {
66
- if (!chunk.second .isInUse () && size <= chunk.second .getSize ()) {
67
- char * _base = chunk.first ;
68
- size_t leftover = chunk.second .getSize () - size;
69
- if (leftover > 0 ) { // Split chunk
70
- chunks.emplace (_base + size, Chunk (leftover, false ));
71
- chunk.second .setSize (size);
72
- }
73
- chunk.second .setInUse (true );
74
- return reinterpret_cast <void *>(_base);
75
- }
66
+ // Pick a large enough free-chunk
67
+ auto it = std::find_if (chunks_free.begin (), chunks_free.end (),
68
+ [=](const std::map<char *, size_t >::value_type& chunk){ return chunk.second >= size; });
69
+ if (it == chunks_free.end ())
70
+ return nullptr ;
71
+
72
+ // Create the used-chunk, taking its space from the end of the free-chunk
73
+ auto alloced = chunks_used.emplace (it->first + it->second - size, size).first ;
74
+ if (!(it->second -= size))
75
+ chunks_free.erase (it);
76
+ return reinterpret_cast <void *>(alloced->first );
77
+ }
78
+
79
+ /* extend the Iterator if other begins at its end */
80
+ template <class Iterator , class Pair > bool extend (Iterator it, const Pair& other) {
81
+ if (it->first + it->second == other.first ) {
82
+ it->second += other.second ;
83
+ return true ;
76
84
}
77
- return nullptr ;
85
+ return false ;
78
86
}
79
87
80
88
void Arena::free (void *ptr)
@@ -83,65 +91,49 @@ void Arena::free(void *ptr)
83
91
if (ptr == nullptr ) {
84
92
return ;
85
93
}
86
- auto i = chunks.find (static_cast <char *>(ptr));
87
- if (i == chunks.end () || !i->second .isInUse ()) {
88
- throw std::runtime_error (" Arena: invalid or double free" );
89
- }
90
94
91
- i->second .setInUse (false );
92
-
93
- if (i != chunks.begin ()) { // Absorb into previous chunk if exists and free
94
- auto prev = i;
95
- --prev;
96
- if (!prev->second .isInUse ()) {
97
- // Absorb current chunk size into previous chunk.
98
- prev->second .setSize (prev->second .getSize () + i->second .getSize ());
99
- // Erase current chunk. Erasing does not invalidate current
100
- // iterators for a map, except for that pointing to the object
101
- // itself, which will be overwritten in the next statement.
102
- chunks.erase (i);
103
- // From here on, the previous chunk is our current chunk.
104
- i = prev;
105
- }
106
- }
107
- auto next = i;
108
- ++next;
109
- if (next != chunks.end ()) { // Absorb next chunk if exists and free
110
- if (!next->second .isInUse ()) {
111
- // Absurb next chunk size into current chunk
112
- i->second .setSize (i->second .getSize () + next->second .getSize ());
113
- // Erase next chunk.
114
- chunks.erase (next);
115
- }
95
+ // Remove chunk from used map
96
+ auto i = chunks_used.find (static_cast <char *>(ptr));
97
+ if (i == chunks_used.end ()) {
98
+ throw std::runtime_error (" Arena: invalid or double free" );
116
99
}
100
+ auto freed = *i;
101
+ chunks_used.erase (i);
102
+
103
+ // Add space to free map, coalescing contiguous chunks
104
+ auto next = chunks_free.upper_bound (freed.first );
105
+ auto prev = (next == chunks_free.begin ()) ? chunks_free.end () : std::prev (next);
106
+ if (prev == chunks_free.end () || !extend (prev, freed))
107
+ prev = chunks_free.emplace_hint (next, freed);
108
+ if (next != chunks_free.end () && extend (prev, *next))
109
+ chunks_free.erase (next);
117
110
}
118
111
119
112
Arena::Stats Arena::stats () const
120
113
{
121
- Arena::Stats r;
122
- r.used = r.free = r.total = r.chunks_used = r.chunks_free = 0 ;
123
- for (const auto & chunk: chunks) {
124
- if (chunk.second .isInUse ()) {
125
- r.used += chunk.second .getSize ();
126
- r.chunks_used += 1 ;
127
- } else {
128
- r.free += chunk.second .getSize ();
129
- r.chunks_free += 1 ;
130
- }
131
- r.total += chunk.second .getSize ();
132
- }
114
+ Arena::Stats r{ 0 , 0 , 0 , chunks_used.size (), chunks_free.size () };
115
+ for (const auto & chunk: chunks_used)
116
+ r.used += chunk.second ;
117
+ for (const auto & chunk: chunks_free)
118
+ r.free += chunk.second ;
119
+ r.total = r.used + r.free ;
133
120
return r;
134
121
}
135
122
136
123
#ifdef ARENA_DEBUG
124
+ void printchunk (char * base, size_t sz, bool used) {
125
+ std::cout <<
126
+ " 0x" << std::hex << std::setw (16 ) << std::setfill (' 0' ) << base <<
127
+ " 0x" << std::hex << std::setw (16 ) << std::setfill (' 0' ) << sz <<
128
+ " 0x" << used << std::endl;
129
+ }
137
130
void Arena::walk () const
138
131
{
139
- for (const auto & chunk: chunks) {
140
- std::cout <<
141
- " 0x" << std::hex << std::setw (16 ) << std::setfill (' 0' ) << chunk.first <<
142
- " 0x" << std::hex << std::setw (16 ) << std::setfill (' 0' ) << chunk.second .getSize () <<
143
- " 0x" << chunk.second .isInUse () << std::endl;
144
- }
132
+ for (const auto & chunk: chunks_used)
133
+ printchunk (chunk.first , chunk.second , true );
134
+ std::cout << std::endl;
135
+ for (const auto & chunk: chunks_free)
136
+ printchunk (chunk.first , chunk.second , false );
145
137
std::cout << std::endl;
146
138
}
147
139
#endif
@@ -312,9 +304,7 @@ void LockedPool::free(void *ptr)
312
304
LockedPool::Stats LockedPool::stats () const
313
305
{
314
306
std::lock_guard<std::mutex> lock (mutex);
315
- LockedPool::Stats r;
316
- r.used = r.free = r.total = r.chunks_used = r.chunks_free = 0 ;
317
- r.locked = cumulative_bytes_locked;
307
+ LockedPool::Stats r{0 , 0 , 0 , cumulative_bytes_locked, 0 , 0 };
318
308
for (const auto &arena: arenas) {
319
309
Arena::Stats i = arena.stats ();
320
310
r.used += i.used ;
0 commit comments