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