1 /******************************************
2 Copyright (c) 2016, Mate Soos
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 ***********************************************/
22
23 #ifndef __WATCHARRAY_H__
24 #define __WATCHARRAY_H__
25
26 #include <stdlib.h>
27 #include "watched.h"
28 #include <vector>
29
30 namespace CMSat {
31 using std::vector;
32
33 struct watch_array;
34
35 struct Elem
36 {
ElemElem37 Elem() :
38 num(0)
39 , offset(0)
40 {}
41
42 uint32_t num:8;
43 uint32_t offset:24;
44 uint32_t size = 0;
45 uint32_t alloc = 0;
46 //uint32_t accessed = 0;
47
print_statElem48 void print_stat() const
49 {
50 cout
51 << "c elem."
52 << " num: " << num
53 << " offset:" << offset
54 << " size" << size
55 << " alloc" << alloc
56 << endl;
57 }
58 };
59
60 struct Mem
61 {
62 uint32_t alloc = 0;
63 Watched* base_ptr = NULL;
64 uint32_t next_space_offset = 0;
65 };
66
67 struct OffsAndNum
68 {
OffsAndNumOffsAndNum69 OffsAndNum() :
70 offset(0)
71 , num(0)
72 {}
73
OffsAndNumOffsAndNum74 OffsAndNum(uint32_t _offset, uint32_t _num) :
75 offset(_offset)
76 , num(_num)
77 {}
78
79 uint32_t offset;
80 uint32_t num;
81 };
82
83 struct watch_subarray
84 {
85 vector<Elem>::iterator base_at;
86 watch_array* base;
watch_subarraywatch_subarray87 explicit watch_subarray(vector<Elem>::iterator _base_at, watch_array* _base) :
88 base_at(_base_at)
89 , base(_base)
90 {}
91
92 Watched& operator[](const uint32_t at);
93 void clear();
94 uint32_t size() const;
95 bool empty() const;
96 Watched* begin();
97 Watched* end();
98 const Watched* begin() const;
99 const Watched* end() const;
100 void shrink(const uint32_t num);
101 void shrink_(const uint32_t num);
102 void push(const Watched& watched);
103 void get_space_for_push();
104
105 typedef Watched* iterator;
106 typedef const Watched* const_iterator;
107 };
108
109 struct watch_subarray_const
110 {
111 vector<Elem>::const_iterator base_at;
112 const watch_array* base;
watch_subarray_constwatch_subarray_const113 explicit watch_subarray_const(vector<Elem>::const_iterator _base_at, const watch_array* _base) :
114 base_at(_base_at)
115 , base(_base)
116 {}
117
watch_subarray_constwatch_subarray_const118 watch_subarray_const(const watch_subarray& other) :
119 base_at(other.base_at)
120 , base(other.base)
121 {}
122
123 void print_stat() const;
124 const Watched& operator[](const uint32_t at) const;
125 uint32_t size() const;
126 bool empty() const;
127 const Watched* begin() const;
128 const Watched* end() const;
129 typedef const Watched* const_iterator;
130 };
131
132 struct watch_array
133 {
134 const static size_t WATCH_MIN_SIZE_ONE_ALLOC_FIRST = 1ULL*1000ULL*1000ULL;
135 const static size_t WATCH_MIN_SIZE_ONE_ALLOC_LATER = 50ULL*1000ULL*1000ULL;
136 const static size_t WATCH_MAX_SIZE_ONE_ALLOC = (1ULL<<24)-1;
137
138 vector<Elem> watches;
139 vector<Mem> mems;
140 size_t free_mem_used = 0;
141 size_t free_mem_not_used = 0;
142
143 //at least 2**N elements in there
144 vector<vector<OffsAndNum> > free_mem;
145
watch_arraywatch_array146 watch_array()
147 {
148 //We need at least 1
149 Mem new_mem;
150 size_t elems = WATCH_MIN_SIZE_ONE_ALLOC_FIRST;
151 new_mem.base_ptr = (Watched*)malloc(elems*sizeof(Watched));
152 new_mem.alloc = elems;
153 mems.push_back(new_mem);
154
155 free_mem.resize(20);
156 }
157
~watch_arraywatch_array158 ~watch_array()
159 {
160 for(size_t i = 0; i < mems.size(); i++) {
161 free(mems[i].base_ptr);
162 }
163 }
164
get_suitable_basewatch_array165 uint32_t get_suitable_base(uint32_t elems)
166 {
167 //print_stat();
168
169 assert(mems.size() > 0);
170 size_t last_alloc = mems[0].alloc;
171 for(size_t i = 0; i < mems.size(); i++) {
172 if (mems[i].next_space_offset + elems < mems[i].alloc) {
173 return i;
174 }
175 last_alloc = mems[i].alloc;
176 }
177 assert(mems.size() < 255);
178
179 Mem new_mem;
180 new_mem.alloc = std::max<size_t>(3*last_alloc, WATCH_MIN_SIZE_ONE_ALLOC_LATER);
181 new_mem.alloc = std::min<size_t>(3*last_alloc, WATCH_MAX_SIZE_ONE_ALLOC);
182 new_mem.base_ptr = (Watched*)malloc(new_mem.alloc*sizeof(Watched));
183 assert(new_mem.base_ptr != NULL);
184 mems.push_back(new_mem);
185 return mems.size()-1;
186 }
187
find_free_spacewatch_array188 bool find_free_space(OffsAndNum& toret, uint32_t size)
189 {
190 size_t bucket = get_bucket(size);
191 if (free_mem.size() <= bucket
192 || free_mem[bucket].empty()
193 ) {
194 free_mem_not_used++;
195 return false;
196 }
197
198 toret = free_mem[bucket].back();
199 free_mem[bucket].pop_back();
200 free_mem_used++;
201 return true;
202 }
203
get_spacewatch_array204 OffsAndNum get_space(uint32_t elems)
205 {
206 OffsAndNum toret;
207 if (find_free_space(toret, elems))
208 return toret;
209
210 uint32_t num = get_suitable_base(elems);
211 Mem& mem = mems[num];
212 assert(mem.next_space_offset + elems < mem.alloc);
213
214 uint32_t off_to_ret = mem.next_space_offset;
215 mem.next_space_offset += elems;
216
217 toret = OffsAndNum(off_to_ret, num);
218 return toret;
219 }
220
extra_space_during_consolidatewatch_array221 size_t extra_space_during_consolidate(size_t orig_size)
222 {
223 if (orig_size == 1)
224 return 2;
225
226 unsigned bucket = get_bucket(orig_size);
227 if (2U<<bucket == orig_size)
228 return orig_size;
229 else
230 return 2U<<(bucket+1);
231 }
232
total_needed_during_consolidatewatch_array233 size_t total_needed_during_consolidate()
234 {
235 size_t total_needed = 0;
236 for(size_t i = 0; i < watches.size(); i++) {
237 if (watches[i].size != 0) {
238 total_needed += extra_space_during_consolidate(watches[i].size);
239 }
240 }
241 total_needed *= 1.2;
242 total_needed = std::max<size_t>(total_needed, WATCH_MIN_SIZE_ONE_ALLOC_FIRST);
243
244 return total_needed;
245 }
246
247 void consolidate();
248 void print_stat(bool detailed = false) const;
249
get_bucketwatch_array250 unsigned get_bucket(unsigned size)
251 {
252 //assert(size >= 2);
253 int at = ((int)((sizeof(unsigned)*8))-__builtin_clz(size))-2;
254 //assert(at >= 0);
255 return at;
256 }
257
delete_offsetwatch_array258 void delete_offset(uint32_t num, uint32_t offs, uint32_t size)
259 {
260 size_t bucket = get_bucket(size);
261 //assert(size == 2U<<bucket);
262
263 if (bucket >= free_mem.size()) {
264 return;
265 }
266
267 free_mem[bucket].push_back(OffsAndNum(offs, num));
268 }
269
mem_used_allocwatch_array270 size_t mem_used_alloc() const
271 {
272 size_t total = 0;
273 for(size_t i = 0; i < mems.size(); i++) {
274 total += mems[i].alloc*sizeof(Watched);
275 }
276 return total;
277 }
278
mem_used_arraywatch_array279 size_t mem_used_array() const
280 {
281 size_t total = 0;
282 total += watches.capacity() * sizeof(Elem);
283 total += mems.capacity() * sizeof(Mem);
284 return total;
285 }
286
287 watch_subarray operator[](size_t at)
288 {
289 assert(watches.size() > at);
290 return watch_subarray(watches.begin() + at, this);
291 }
292
293 watch_subarray_const operator[](size_t at) const
294 {
295 assert(watches.size() > at);
296 return watch_subarray_const(watches.begin() + at, this);
297 }
298
resizewatch_array299 void resize(const size_t new_size)
300 {
301 watches.resize(new_size);
302 }
303
sizewatch_array304 uint32_t size() const
305 {
306 return watches.size();
307 }
308
shrink_to_fitwatch_array309 void shrink_to_fit()
310 {
311 watches.shrink_to_fit();
312 }
313
prefetchwatch_array314 void prefetch(const size_t at) const
315 {
316 __builtin_prefetch(mems[watches[at].num].base_ptr + watches[at].offset);
317 }
318
319 struct iterator
320 {
321 vector<Elem>::iterator it;
322 watch_array* base;
iteratorwatch_array::iterator323 explicit iterator(vector<Elem>::iterator _it, watch_array* _base) :
324 it(_it)
325 , base(_base)
326 {}
327
328 iterator operator++()
329 {
330 ++it;
331 return *this;
332 }
333
334 watch_subarray operator*()
335 {
336 return watch_subarray(it, base);
337 }
338
339 bool operator==(const iterator& it2) const
340 {
341 return it == it2.it;
342 }
343
344 bool operator!=(const iterator& it2) const
345 {
346 return it != it2.it;
347 }
348
349 friend size_t operator-(const iterator& lhs, const iterator& rhs);
350 };
351
352 struct const_iterator
353 {
354 vector<Elem>::const_iterator it;
355 const watch_array* base;
const_iteratorwatch_array::const_iterator356 explicit const_iterator(vector<Elem>::const_iterator _it, const watch_array* _base) :
357 it(_it)
358 , base(_base)
359 {}
360
const_iteratorwatch_array::const_iterator361 const_iterator(const iterator& other) :
362 it(other.it)
363 , base(other.base)
364 {}
365
366 const_iterator operator++()
367 {
368 ++it;
369 return *this;
370 }
371
372 const watch_subarray_const operator*() const
373 {
374 return watch_subarray_const(it, base);
375 }
376
377 bool operator==(const const_iterator& it2) const
378 {
379 return it == it2.it;
380 }
381
382 bool operator!=(const const_iterator& it2) const
383 {
384 return it != it2.it;
385 }
386
387 friend size_t operator-(const const_iterator& lhs, const const_iterator& rhs);
388 };
389
beginwatch_array390 iterator begin()
391 {
392 return iterator(watches.begin(), this);
393 }
394
endwatch_array395 iterator end()
396 {
397 return iterator(watches.end(), this);
398 }
399
beginwatch_array400 const_iterator begin() const
401 {
402 return const_iterator(watches.begin(), this);
403 }
404
endwatch_array405 const_iterator end() const
406 {
407 return const_iterator(watches.end(), this);
408 }
409
fitToSizewatch_array410 void fitToSize()
411 {
412 //TODO shirnk
413 }
414 };
415
416 inline size_t operator-(const watch_array::iterator& lhs, const watch_array::iterator& rhs)
417 {
418 return lhs.it-rhs.it;
419 }
420
421 inline size_t operator-(const watch_array::const_iterator& lhs, const watch_array::const_iterator& rhs)
422 {
423 return lhs.it-rhs.it;
424 }
425
426 inline Watched& watch_subarray::operator[](const uint32_t at)
427 {
428 //base_at->accessed++;
429 return *(begin() + at);
430 }
431
clear()432 inline void watch_subarray::clear()
433 {
434 base_at->size = 0;
435 }
436
size()437 inline uint32_t watch_subarray::size() const
438 {
439 return base_at->size;
440 }
441
empty()442 inline bool watch_subarray::empty() const
443 {
444 return size() == 0;
445 }
446
begin()447 inline Watched* watch_subarray::begin()
448 {
449 return base->mems[base_at->num].base_ptr + base_at->offset;
450 }
451
end()452 inline Watched* watch_subarray::end()
453 {
454 return begin() + size();
455 }
456
begin()457 inline const Watched* watch_subarray::begin() const
458 {
459 return base->mems[base_at->num].base_ptr + base_at->offset;
460 }
461
end()462 inline const Watched* watch_subarray::end() const
463 {
464 return begin() + size();
465 }
466
shrink(const uint32_t num)467 inline void watch_subarray::shrink(const uint32_t num)
468 {
469 base_at->size -= num;
470 }
471
shrink_(const uint32_t num)472 inline void watch_subarray::shrink_(const uint32_t num)
473 {
474 shrink(num);
475 }
476
get_space_for_push()477 inline void watch_subarray::get_space_for_push()
478 {
479 uint32_t new_alloc = std::max<uint32_t>(base_at->alloc*2, 2U);
480 OffsAndNum off_and_num = base->get_space(new_alloc);
481
482 //Copy
483 if (base_at->size > 0) {
484 Watched* newptr = base->mems[off_and_num.num].base_ptr + off_and_num.offset;
485 Watched* oldptr = begin();
486 memmove(newptr, oldptr, size() * sizeof(Watched));
487 base->delete_offset(base_at->num, base_at->offset, base_at->alloc);
488 }
489
490 //Update
491 base_at->num = off_and_num.num;
492 base_at->offset = off_and_num.offset;
493 base_at->alloc = new_alloc;
494 }
495
push(const Watched & watched)496 inline void watch_subarray::push(const Watched& watched)
497 {
498 //Make space
499 if (base_at->alloc <= base_at->size) {
500 get_space_for_push();
501 }
502
503 //There is enough space
504 //assert(base_at->alloc > base_at->size);
505
506 //Append to the end
507 operator[](size()) = watched;
508 base_at->size++;
509 }
510
511 inline const Watched& watch_subarray_const::operator[](const uint32_t at) const
512 {
513 return *(begin() + at);
514 }
size()515 inline uint32_t watch_subarray_const::size() const
516 {
517 return base_at->size;
518 }
519
empty()520 inline bool watch_subarray_const::empty() const
521 {
522 return size() == 0;
523 }
begin()524 inline const Watched* watch_subarray_const::begin() const
525 {
526 return base->mems[base_at->num].base_ptr + base_at->offset;
527 }
528
end()529 inline const Watched* watch_subarray_const::end() const
530 {
531 return begin() + size();
532 }
533
print_stat()534 inline void watch_subarray_const::print_stat() const
535 {
536 base->print_stat();
537 base_at->print_stat();
538 }
539
swap(watch_subarray a,watch_subarray b)540 inline void swap(watch_subarray a, watch_subarray b)
541 {
542 Elem tmp;
543 tmp = *(a.base_at);
544 *(a.base_at) = *(b.base_at);
545 *(b.base_at) = tmp;
546 }
547
548
549 } //End of namespace
550
551 #endif //__WATCHARRAY_H__
552