GetFEM  5.4.3
bgeot_small_vector.cc
1 /*===========================================================================
2 
3  Copyright (C) 2004-2020 Julien Pommier
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
23 namespace bgeot {
24  block_allocator *static_block_allocator::palloc = 0;
25 
26  static_block_allocator::static_block_allocator() {
27  if (!palloc) palloc = &dal::singleton<block_allocator, 1000>::instance();
28  }
29  void static_block_allocator::memstats() {
30  if (palloc) palloc->memstats();
31  }
32  block_allocator& static_block_allocator::allocator() const {
33  return *palloc;
34  }
35  bool static_block_allocator::allocator_destroyed() const {
36  return palloc == 0;
37  }
38  void static_block_allocator::destroy() {
39  palloc = 0;
40  }
41 
42  block_allocator::block_allocator() {
43  for (size_type i=0; i < OBJ_SIZE_LIMIT; ++i)
44  first_unfilled[i] = i ? size_type(-1) : 0;
45  /* bloc 0 is reserved for objects of size 0 -- it won't grow */
46  blocks.push_back(block(0)); blocks.front().init();
47  }
48  block_allocator::~block_allocator() {
49  for (size_type i=0; i < blocks.size(); ++i)
50  if (!blocks[i].empty()) blocks[i].clear();
51  static_block_allocator().destroy();
52  }
53  block_allocator::node_id block_allocator::allocate(block_allocator::size_type n) {
54  if (n == 0) return 0;
55  GMM_ASSERT1(n < OBJ_SIZE_LIMIT,
56  "attempt to allocate a supposedly \"small\" object of "
57  << n << " bytes\n");
58  if (first_unfilled[n] == size_type(-1)) {
59  blocks.push_back(block(n)); blocks.back().init();
60  insert_block_into_unfilled(gmm::uint32_type(blocks.size()-1));
61  GMM_ASSERT1(first_unfilled[n] <
62  (node_id(1)<<(sizeof(node_id)*CHAR_BIT - p2_BLOCKSZ)),
63  "allocation slots exhausted for objects of size " << n
64  << " (" << first_unfilled[n] << " allocated!),\n" << "either"
65  " increase the limit or check for a leak in your code.");
66  }
67  block &b = blocks[first_unfilled[n]]; SVEC_ASSERT(b.objsz == n);
68  if (b.empty()) b.init(); /* realloc memory if needed */
69  size_type vid = b.first_unused_chunk; SVEC_ASSERT(vid < BLOCKSZ);
70  size_type id = vid + first_unfilled[n]*BLOCKSZ;
71  SVEC_ASSERT(b.refcnt(b.first_unused_chunk)==0);
72  b.refcnt(vid) = 1; b.count_unused_chunk--;
73  if (b.count_unused_chunk) {
74  do b.first_unused_chunk++; while (b.refcnt(b.first_unused_chunk));
75  } else {
76  b.first_unused_chunk = BLOCKSZ;
77  remove_block_from_unfilled(first_unfilled[n]);
78  }
79  //cout << "allocated " << first_unfilled[n] << ", " << vid << " @" << obj_data(id) << "\n";
80  SVEC_ASSERT(obj_data(id));
81  memset(obj_data(id), 0, n);
82  //SVEC_ASSERT(refcnt(id) == 0);
83  return id;
84  }
85  void block_allocator::deallocate(block_allocator::node_id nid) {
86  if (nid == 0) return;
87  size_type bid = nid / BLOCKSZ;
88  size_type vid = nid % BLOCKSZ;
89  block &b = blocks[bid];
90  //cout << "deallocate " << bid << "/dim=" << b.dim << ", " << vid << ", unused=" << b.unused << "\n";
91  SVEC_ASSERT(b.refcnt(vid) == 1);
92  b.refcnt(vid) = 0;
93  if (b.count_unused_chunk++ == 0) {
94  insert_block_into_unfilled(bid);
95  b.first_unused_chunk = gmm::uint16_type(vid);
96  } else {
97  b.first_unused_chunk = std::min(b.first_unused_chunk,
98  gmm::uint16_type(vid));
99  if (b.count_unused_chunk == BLOCKSZ) b.clear();
100  }
101  }
102  void block_allocator::memstats() {
103  cout << "block_allocator memory statistics:\ntotal number of blocks: "
104  << blocks.size() << ", each blocks stores " << BLOCKSZ
105  << " chuncks; size of a block header is " << sizeof(block) << " bytes\n";
106  for (size_type d = 0; d < OBJ_SIZE_LIMIT; ++d) {
107  size_type total_cnt=0, used_cnt=0, mem_total = 0, bcnt = 0;
108  for (size_type i=0; i < blocks.size(); ++i) {
109  if (blocks[i].objsz != d) continue; else bcnt++;
110  if (!blocks[i].empty()) {
111  total_cnt += BLOCKSZ;
112  used_cnt += BLOCKSZ - blocks[i].count_unused_chunk;
113  mem_total += (BLOCKSZ+1)*blocks[i].objsz;
114  }
115  mem_total = gmm::uint32_type(mem_total + sizeof(block));
116  }
117  if (mem_total)
118  cout << " sz " << d << ", memory used = " << mem_total << " bytes for "
119  << total_cnt << " nodes, unused space = "
120  << (total_cnt == 0 ? 100. : 100. - 100.* used_cnt / total_cnt)
121  << "%, bcnt=" << bcnt << "\n";
122  }
123  }
124  void block_allocator::insert_block_into_unfilled(block_allocator::size_type bid) {
125  SVEC_ASSERT(bid < blocks.size());
126  dim_type dim = dim_type(blocks[bid].objsz);
127  SVEC_ASSERT(bid != first_unfilled[dim]);
128  SVEC_ASSERT(blocks[bid].prev_unfilled+1 == 0);
129  SVEC_ASSERT(blocks[bid].next_unfilled+1 == 0);
130  blocks[bid].prev_unfilled = size_type(-1);
131  blocks[bid].next_unfilled = first_unfilled[dim];
132  if (first_unfilled[dim] != size_type(-1)) {
133  SVEC_ASSERT(blocks[first_unfilled[dim]].prev_unfilled+1 == 0);
134  blocks[first_unfilled[dim]].prev_unfilled = bid;
135  }
136  first_unfilled[dim] = bid;
137  //cout << "** bloc " << bid << " has been INSERTED in unfilled list, which is now"; show_unfilled(bid);
138  }
139  void block_allocator::remove_block_from_unfilled(block_allocator::size_type bid) {
140  SVEC_ASSERT(bid < blocks.size());
141  dim_type dim = dim_type(blocks[bid].objsz);
142  //cout << "** bloc " << bid << " is going to be REMOVE unfilled list, which is now"; show_unfilled(bid);
143  size_type p = blocks[bid].prev_unfilled; blocks[bid].prev_unfilled = size_type(-1);
144  size_type n = blocks[bid].next_unfilled; blocks[bid].next_unfilled = size_type(-1);
145  if (p != size_type(-1)) { blocks[p].next_unfilled = n; }
146  if (n != size_type(-1)) { blocks[n].prev_unfilled = p; }
147  if (first_unfilled[dim] == bid) { SVEC_ASSERT(p+1==0); first_unfilled[dim] = n; }
148  //cout << "** bloc " << bid << " has been REMOVED in unfilled list, which is now"; show_unfilled(bid);
149  }
150 }
Small (dim < 8) vectors.
static T & instance()
Instance from the current thread.
Basic Geometric Tools.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49