24 block_allocator *static_block_allocator::palloc = 0;
26 static_block_allocator::static_block_allocator() {
29 void static_block_allocator::memstats() {
30 if (palloc) palloc->memstats();
32 block_allocator& static_block_allocator::allocator()
const {
35 bool static_block_allocator::allocator_destroyed()
const {
38 void static_block_allocator::destroy() {
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;
46 blocks.push_back(block(0)); blocks.front().init();
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();
55 GMM_ASSERT1(n < OBJ_SIZE_LIMIT,
56 "attempt to allocate a supposedly \"small\" object of "
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.");
67 block &b = blocks[first_unfilled[n]]; SVEC_ASSERT(b.objsz == n);
68 if (b.empty()) b.init();
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));
76 b.first_unused_chunk = BLOCKSZ;
77 remove_block_from_unfilled(first_unfilled[n]);
80 SVEC_ASSERT(obj_data(
id));
81 memset(obj_data(
id), 0, n);
85 void block_allocator::deallocate(block_allocator::node_id nid) {
89 block &b = blocks[bid];
91 SVEC_ASSERT(b.refcnt(vid) == 1);
93 if (b.count_unused_chunk++ == 0) {
94 insert_block_into_unfilled(bid);
95 b.first_unused_chunk = gmm::uint16_type(vid);
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();
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;
115 mem_total = gmm::uint32_type(mem_total +
sizeof(block));
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";
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;
136 first_unfilled[dim] = bid;
140 SVEC_ASSERT(bid < blocks.size());
141 dim_type dim = dim_type(blocks[bid].objsz);
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; }
static T & instance()
Instance from the current thread.
size_t size_type
used as the common size type in the library