GetFEM  5.5
bgeot_small_vector.cc
1 /*===========================================================================
2 
3  Copyright (C) 2004-2026 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, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
22 namespace bgeot {
23  block_allocator *static_block_allocator::palloc = 0;
24 
25  static_block_allocator::static_block_allocator() {
26  if (!palloc) palloc = &dal::singleton<block_allocator, 1000>::instance();
27  }
28  void static_block_allocator::memstats() {
29  if (palloc) palloc->memstats();
30  }
31  block_allocator& static_block_allocator::allocator() const {
32  return *palloc;
33  }
34  bool static_block_allocator::allocator_destroyed() const {
35  return palloc == 0;
36  }
37  void static_block_allocator::destroy() {
38  palloc = 0;
39  }
40 
41  block_allocator::block_allocator() {
42  for (size_type i=0; i < OBJ_SIZE_LIMIT; ++i)
43  first_unfilled[i] = i ? size_type(-1) : 0;
44  /* bloc 0 is reserved for objects of size 0 -- it won't grow */
45  blocks.push_back(block(0)); blocks.front().init();
46  }
47  block_allocator::~block_allocator() {
48  for (size_type i=0; i < blocks.size(); ++i)
49  if (!blocks[i].empty()) blocks[i].clear();
50  static_block_allocator().destroy();
51  }
52  block_allocator::node_id block_allocator::allocate(block_allocator::size_type n) {
53  if (n == 0) return 0;
54  GMM_ASSERT1(n < OBJ_SIZE_LIMIT,
55  "attempt to allocate a supposedly \"small\" object of "
56  << n << " bytes\n");
57  if (first_unfilled[n] == size_type(-1)) {
58  blocks.push_back(block(n)); blocks.back().init();
59  insert_block_into_unfilled(gmm::uint32_type(blocks.size()-1));
60  GMM_ASSERT1(first_unfilled[n] <
61  (node_id(1)<<(sizeof(node_id)*CHAR_BIT - p2_BLOCKSZ)),
62  "allocation slots exhausted for objects of size " << n
63  << " (" << first_unfilled[n] << " allocated!),\n" << "either"
64  " increase the limit or check for a leak in your code.");
65  }
66  block &b = blocks[first_unfilled[n]]; SVEC_ASSERT(b.objsz == n);
67  if (b.empty()) b.init(); /* realloc memory if needed */
68  size_type vid = b.first_unused_chunk; SVEC_ASSERT(vid < BLOCKSZ);
69  size_type id = vid + first_unfilled[n]*BLOCKSZ;
70  SVEC_ASSERT(b.refcnt(b.first_unused_chunk)==0);
71  b.refcnt(vid) = 1; b.count_unused_chunk--;
72  if (b.count_unused_chunk) {
73  do b.first_unused_chunk++; while (b.refcnt(b.first_unused_chunk));
74  } else {
75  b.first_unused_chunk = BLOCKSZ;
76  remove_block_from_unfilled(first_unfilled[n]);
77  }
78  //cout << "allocated " << first_unfilled[n] << ", " << vid << " @" << obj_data(id) << "\n";
79  SVEC_ASSERT(obj_data(id));
80  memset(obj_data(id), 0, n);
81  //SVEC_ASSERT(refcnt(id) == 0);
82  return id;
83  }
84  void block_allocator::deallocate(block_allocator::node_id nid) {
85  if (nid == 0) return;
86  size_type bid = nid / BLOCKSZ;
87  size_type vid = nid % BLOCKSZ;
88  block &b = blocks[bid];
89  //cout << "deallocate " << bid << "/dim=" << b.dim << ", " << vid << ", unused=" << b.unused << "\n";
90  SVEC_ASSERT(b.refcnt(vid) == 1);
91  b.refcnt(vid) = 0;
92  if (b.count_unused_chunk++ == 0) {
93  insert_block_into_unfilled(bid);
94  b.first_unused_chunk = gmm::uint16_type(vid);
95  } else {
96  b.first_unused_chunk = std::min(b.first_unused_chunk,
97  gmm::uint16_type(vid));
98  if (b.count_unused_chunk == BLOCKSZ) b.clear();
99  }
100  }
101  void block_allocator::memstats() {
102  cout << "block_allocator memory statistics:\ntotal number of blocks: "
103  << blocks.size() << ", each blocks stores " << BLOCKSZ
104  << " chuncks; size of a block header is " << sizeof(block) << " bytes\n";
105  for (size_type d = 0; d < OBJ_SIZE_LIMIT; ++d) {
106  size_type total_cnt=0, used_cnt=0, mem_total = 0, bcnt = 0;
107  for (size_type i=0; i < blocks.size(); ++i) {
108  if (blocks[i].objsz != d) continue; else bcnt++;
109  if (!blocks[i].empty()) {
110  total_cnt += BLOCKSZ;
111  used_cnt += BLOCKSZ - blocks[i].count_unused_chunk;
112  mem_total += (BLOCKSZ+1)*blocks[i].objsz;
113  }
114  mem_total = gmm::uint32_type(mem_total + sizeof(block));
115  }
116  if (mem_total)
117  cout << " sz " << d << ", memory used = " << mem_total << " bytes for "
118  << total_cnt << " nodes, unused space = "
119  << (total_cnt == 0 ? 100. : 100. - 100.* used_cnt / total_cnt)
120  << "%, bcnt=" << bcnt << "\n";
121  }
122  }
123  void block_allocator::insert_block_into_unfilled(block_allocator::size_type bid) {
124  SVEC_ASSERT(bid < blocks.size());
125  dim_type dim = dim_type(blocks[bid].objsz);
126  SVEC_ASSERT(bid != first_unfilled[dim]);
127  SVEC_ASSERT(blocks[bid].prev_unfilled+1 == 0);
128  SVEC_ASSERT(blocks[bid].next_unfilled+1 == 0);
129  blocks[bid].prev_unfilled = size_type(-1);
130  blocks[bid].next_unfilled = first_unfilled[dim];
131  if (first_unfilled[dim] != size_type(-1)) {
132  SVEC_ASSERT(blocks[first_unfilled[dim]].prev_unfilled+1 == 0);
133  blocks[first_unfilled[dim]].prev_unfilled = bid;
134  }
135  first_unfilled[dim] = bid;
136  //cout << "** bloc " << bid << " has been INSERTED in unfilled list, which is now"; show_unfilled(bid);
137  }
138  void block_allocator::remove_block_from_unfilled(block_allocator::size_type bid) {
139  SVEC_ASSERT(bid < blocks.size());
140  dim_type dim = dim_type(blocks[bid].objsz);
141  //cout << "** bloc " << bid << " is going to be REMOVE unfilled list, which is now"; show_unfilled(bid);
142  size_type p = blocks[bid].prev_unfilled; blocks[bid].prev_unfilled = size_type(-1);
143  size_type n = blocks[bid].next_unfilled; blocks[bid].next_unfilled = size_type(-1);
144  if (p != size_type(-1)) { blocks[p].next_unfilled = n; }
145  if (n != size_type(-1)) { blocks[n].prev_unfilled = p; }
146  if (first_unfilled[dim] == bid) { SVEC_ASSERT(p+1==0); first_unfilled[dim] = n; }
147  //cout << "** bloc " << bid << " has been REMOVED in unfilled list, which is now"; show_unfilled(bid);
148  }
149 }
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:48