Line data Source code
1 : /*
2 : * (C) Copyright 2010 Xilexio
3 : *
4 : * This file is part of CoherentDB.
5 : *
6 : * CoherentDB is free software: you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * CoherentDB is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public
17 : * License along with CoherentDB. If not, see
18 : * http://www.gnu.org/licenses/.
19 : */
20 :
21 : #include <sys/mman.h>
22 : #include <memory_manager/manager.h>
23 : #include <memory_manager/session.h>
24 : #include <memory_manager/sub_session.h>
25 : #include <debug/asserts.h>
26 :
27 : // TODO to config
28 : static const double max_small_alloc_pages = 0.75;
29 : static const size_t single_small_alloc_pages = 64;
30 :
31 : namespace coherent
32 : {
33 : namespace memory_manager
34 : {
35 :
36 : typedef boost::shared_lock<boost::shared_mutex> scoped_read_lock;
37 : typedef boost::unique_lock<boost::shared_mutex> scoped_write_lock;
38 : typedef boost::unique_lock<boost::mutex> scoped_lock;
39 :
40 0 : memory_sub_session::memory_sub_session(bool autostart) : allocated_bytes(0), parent(memory_session::current())
41 : {
42 0 : internal_init(autostart);
43 0 : }
44 :
45 8 : memory_sub_session::memory_sub_session(memory_session* session, bool autostart) : allocated_bytes(0), parent(session)
46 : {
47 8 : internal_init(autostart);
48 8 : }
49 :
50 8 : memory_sub_session::~memory_sub_session()
51 : {
52 8 : end();
53 8 : }
54 :
55 8325866 : memory_sub_session* memory_sub_session::current()
56 : {
57 8325866 : return memory_session::current_sub_session.get();
58 : }
59 :
60 35 : void memory_sub_session::begin()
61 : {
62 35 : activate();
63 :
64 33 : scoped_lock am(active_threads_mutex);
65 35 : ++active_threads_count;
66 35 : }
67 :
68 8 : void memory_sub_session::end()
69 : {
70 8 : deactivate();
71 :
72 16 : scoped_lock am(active_threads_mutex);
73 8 : if (active_threads_count > 0)
74 8 : --active_threads_count;
75 8 : }
76 :
77 0 : void memory_sub_session::stop()
78 : {
79 0 : deactivate();
80 :
81 0 : scoped_lock am(active_threads_mutex);
82 : d_assert(active_threads_count > 0);
83 0 : --active_threads_count;
84 :
85 0 : if (active_threads_count == 0)
86 : {
87 0 : scoped_read_lock al(alloc_lock);
88 :
89 0 : for (std::map<byte*, size_t>::const_iterator i = allocs.begin(); i != allocs.end(); ++i)
90 : {
91 0 : if (madvise(i->first, i->second, MADV_DONTNEED))
92 : LOG(WARN, "madvise error on freezing\n");
93 : }
94 : }
95 0 : }
96 :
97 0 : void memory_sub_session::resume()
98 : {
99 : {
100 0 : scoped_lock am(active_threads_mutex);
101 0 : ++active_threads_count;
102 :
103 0 : if (active_threads_count == 1)
104 : {
105 0 : scoped_read_lock al(alloc_lock);
106 :
107 0 : for (std::map<byte*, size_t>::const_iterator i = allocs.begin(); i != allocs.end(); ++i)
108 : {
109 0 : if (madvise(i->first, i->second, MADV_NORMAL))
110 : LOG(ERROR, "madvise error on unfreezing\n");
111 : }
112 : }
113 : }
114 :
115 0 : activate();
116 0 : }
117 :
118 36 : void memory_sub_session::set_current()
119 : {
120 36 : activate();
121 36 : }
122 :
123 0 : size_t memory_sub_session::get_allocated_bytes() const
124 : {
125 0 : scoped_read_lock al(alloc_lock);
126 0 : return allocated_bytes;
127 : }
128 :
129 8348092 : memory_session* memory_sub_session::get_parent() const
130 : {
131 8348092 : return parent;
132 : }
133 :
134 8 : void memory_sub_session::internal_init(bool autostart)
135 : {
136 8 : if (autostart)
137 0 : begin();
138 8 : }
139 :
140 71 : void memory_sub_session::activate()
141 : {
142 71 : memory_session::current_sub_session.reset(this);
143 69 : }
144 :
145 8 : void memory_sub_session::deactivate()
146 : {
147 8 : if (memory_session::current_sub_session.get() == this)
148 0 : memory_session::current_sub_session.reset();
149 8 : }
150 :
151 4180382 : byte* memory_sub_session::allocate(size_t needed_bytes)
152 : {
153 4180382 : size_t page_size = memory_manager::instance->get_page_size();
154 :
155 : byte* res;
156 :
157 4182791 : if (needed_bytes > max_small_alloc_pages * page_size)
158 : {
159 8239 : size_t bytes = (needed_bytes + page_size - 1) / page_size * page_size;
160 :
161 8239 : byte* p = reinterpret_cast<byte*> (mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
162 :
163 8240 : if (p == MAP_FAILED)
164 0 : throw std::bad_alloc();
165 :
166 8240 : add_alloc(p, bytes);
167 :
168 8240 : res = p;
169 : }
170 : else
171 : {
172 4174552 : std::pair<size_t, byte*> optimal_chunk = smallest_sufficent_free_small_chunk(needed_bytes);
173 :
174 : size_t remainder_size;
175 :
176 4162134 : if (optimal_chunk.first == 0)
177 : {
178 7 : size_t bytes = single_small_alloc_pages * page_size;
179 :
180 7 : byte* p = reinterpret_cast<byte*> (mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
181 :
182 8 : if (p == MAP_FAILED)
183 0 : throw std::bad_alloc();
184 :
185 8 : add_alloc(p, bytes);
186 8 : add_small_alloc(p, needed_bytes);
187 :
188 8 : res = p;
189 :
190 8 : remainder_size = bytes - needed_bytes;
191 : }
192 : else
193 : {
194 4162127 : remainder_size = optimal_chunk.first - needed_bytes;
195 :
196 4162127 : add_small_alloc(optimal_chunk.second, needed_bytes);
197 4168924 : remove_free_small_chunk(optimal_chunk.second);
198 :
199 4151403 : res = optimal_chunk.second;
200 : }
201 :
202 4151411 : if (remainder_size != 0)
203 : {
204 1703407 : byte* remainder_pointer = res + needed_bytes;
205 :
206 1703407 : add_free_small_chunk(remainder_pointer, remainder_size);
207 : }
208 : }
209 :
210 4159780 : return res;
211 : }
212 :
213 4185168 : void memory_sub_session::deallocate(byte* p, size_t bytes)
214 : {
215 : // TODO assertions for bytes
216 :
217 4185168 : if (is_small_alloc(p))
218 : {
219 : // removing chunk
220 4171198 : remove_small_alloc(p);
221 :
222 4165086 : std::pair<byte*, size_t> chunk_alloc = free_small_chunk_alloc(p);
223 4160813 : std::pair<byte*, size_t> remainder = add_merge_remove_free_small_chunk(p, bytes);
224 :
225 4174070 : if (chunk_alloc.second == remainder.second)
226 : {
227 8 : if (munmap(chunk_alloc.first, chunk_alloc.second))
228 : LOG(WARN, "unmap error\n");
229 :
230 8 : remove_alloc(chunk_alloc.first);
231 : }
232 : else
233 : {
234 4174062 : add_free_small_chunk(remainder.first, remainder.second);
235 : }
236 : }
237 : else
238 : {
239 8240 : if (munmap(reinterpret_cast<void*> (p), bytes))
240 : LOG(WARN, "unmap error\n");
241 :
242 8240 : remove_alloc(p);
243 : }
244 4167846 : }
245 :
246 8247 : void memory_sub_session::add_alloc(byte* p, size_t bytes)
247 : {
248 8247 : allocated_bytes += bytes;
249 8247 : allocs.insert(std::make_pair(p, bytes));
250 :
251 8246 : parent->allocated_bytes += bytes;
252 8246 : parent->allocs.insert(std::make_pair(p, this));
253 8247 : }
254 :
255 8248 : void memory_sub_session::remove_alloc(byte* p)
256 : {
257 8248 : std::map<byte*, size_t>::iterator i = allocs.find(p);
258 : d_assert(i != allocs.end());
259 :
260 8247 : size_t bytes = i->second;
261 :
262 8248 : allocated_bytes -= bytes;
263 8248 : allocs.erase(i);
264 :
265 8248 : parent->allocated_bytes -= bytes;
266 8248 : parent->allocs.insert(std::make_pair(p, this));
267 8248 : }
268 :
269 4170335 : std::pair<size_t, byte*> memory_sub_session::smallest_sufficent_free_small_chunk(size_t bytes)
270 : {
271 4170335 : std::set<std::pair<size_t, byte*> >::iterator i = free_small_chunks_inv.upper_bound(std::make_pair(bytes, (byte*) 0));
272 :
273 4176512 : if (i == free_small_chunks_inv.end())
274 7 : return std::make_pair(0, (byte*) 0);
275 : else
276 4165565 : return *i;
277 : }
278 :
279 4160235 : void memory_sub_session::add_small_alloc(byte* p, size_t bytes)
280 : {
281 4160235 : small_allocs.insert(std::make_pair(p, bytes));
282 4177599 : }
283 :
284 4167824 : void memory_sub_session::remove_small_alloc(byte* p)
285 : {
286 4167824 : std::set<std::pair<byte*, size_t> >::const_iterator i = small_allocs.upper_bound(std::make_pair(p, 0));
287 : d_assert(i != small_allocs.end());
288 : d_assert(i->first == p);
289 :
290 4171414 : small_allocs.erase(i);
291 4168383 : }
292 :
293 4184261 : bool memory_sub_session::is_small_alloc(byte* p) const
294 : {
295 4184261 : std::set<std::pair<byte*, size_t> >::iterator sa = small_allocs.upper_bound(std::make_pair(p, 0));
296 :
297 4182114 : return sa != small_allocs.end() && sa->first == p;
298 : }
299 :
300 5857846 : void memory_sub_session::add_free_small_chunk(byte* p, size_t bytes)
301 : {
302 5857846 : free_small_chunks.insert(std::make_pair(p, bytes));
303 5860341 : free_small_chunks_inv.insert(std::make_pair(bytes, p));
304 5849840 : }
305 :
306 4164203 : void memory_sub_session::remove_free_small_chunk(byte* p)
307 : {
308 4164203 : free_small_chunks_inv.erase(std::make_pair(free_small_chunks[p], p));
309 4158450 : free_small_chunks.erase(p);
310 4156741 : }
311 :
312 8311988 : std::pair<byte*, size_t> memory_sub_session::free_small_chunk_alloc(byte* p) const
313 : {
314 8311988 : std::map<byte*, size_t>::const_iterator chunk_alloc = allocs.upper_bound(p);
315 : d_assert(chunk_alloc != allocs.begin());
316 8318485 : --chunk_alloc;
317 :
318 8316567 : return *chunk_alloc;
319 : }
320 :
321 4160758 : std::pair<byte*, size_t> memory_sub_session::add_merge_remove_free_small_chunk(byte* p, size_t bytes)
322 : {
323 4160758 : std::pair<byte*, size_t> chunk_alloc = free_small_chunk_alloc(p);
324 :
325 4167428 : size_t remainder_size = bytes;
326 4167428 : byte* remainder_pointer = p;
327 :
328 4167428 : if (!free_small_chunks.empty())
329 : {
330 : // adding and merging free space
331 4164407 : std::map<byte*, size_t>::iterator next = free_small_chunks.upper_bound(remainder_pointer);
332 :
333 4166408 : if (next != free_small_chunks.begin())
334 : {
335 2269952 : std::map<byte*, size_t>::iterator previous = next;
336 2269952 : --previous;
337 :
338 2270918 : if (previous->first >= chunk_alloc.first)
339 : {
340 : d_assert(remainder_pointer > previous->first);
341 :
342 2271204 : size_t diff = remainder_pointer - previous->first;
343 : d_assert(diff >= previous->second);
344 :
345 2267311 : if (diff == previous->second)
346 : {
347 183089 : remainder_pointer = previous->first;
348 183088 : remainder_size += previous->second;
349 :
350 183100 : free_small_chunks_inv.erase(std::make_pair(previous->second, previous->first));
351 183084 : free_small_chunks.erase(previous);
352 :
353 183086 : next = free_small_chunks.upper_bound(remainder_pointer);
354 : }
355 : }
356 : }
357 :
358 4172017 : if (next != free_small_chunks.end() && remainder_size != chunk_alloc.second)
359 : {
360 : d_assert(next->first > remainder_pointer);
361 :
362 4168155 : size_t diff = next->first - remainder_pointer;
363 :
364 4167286 : if (diff == remainder_size)
365 : {
366 1523607 : remainder_size += next->second;
367 :
368 1523587 : free_small_chunks_inv.erase(std::make_pair(next->second, next->first));
369 1524082 : free_small_chunks.erase(next);
370 : }
371 : }
372 : }
373 :
374 4168917 : return std::make_pair(remainder_pointer, remainder_size);
375 : }
376 :
377 : }
378 3 : }
|