23 block_allocator *static_block_allocator::palloc = 0;
25 static_block_allocator::static_block_allocator() {
28 void static_block_allocator::memstats() {
29 if (palloc) palloc->memstats();
31 block_allocator& static_block_allocator::allocator()
const {
34 bool static_block_allocator::allocator_destroyed()
const {
37 void static_block_allocator::destroy() {
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;
45 blocks.push_back(block(0)); blocks.front().init();
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();
54 GMM_ASSERT1(n < OBJ_SIZE_LIMIT,
55 "attempt to allocate a supposedly \"small\" object of "
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.");
66 block &b = blocks[first_unfilled[n]]; SVEC_ASSERT(b.objsz == n);
67 if (b.empty()) b.init();
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));
75 b.first_unused_chunk = BLOCKSZ;
76 remove_block_from_unfilled(first_unfilled[n]);
79 SVEC_ASSERT(obj_data(
id));
80 memset(obj_data(
id), 0, n);
84 void block_allocator::deallocate(block_allocator::node_id nid) {
88 block &b = blocks[bid];
90 SVEC_ASSERT(b.refcnt(vid) == 1);
92 if (b.count_unused_chunk++ == 0) {
93 insert_block_into_unfilled(bid);
94 b.first_unused_chunk = gmm::uint16_type(vid);
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();
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;
114 mem_total = gmm::uint32_type(mem_total +
sizeof(block));
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";
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;
135 first_unfilled[dim] = bid;
139 SVEC_ASSERT(bid < blocks.size());
140 dim_type dim = dim_type(blocks[bid].objsz);
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; }
static T & instance()
Instance from the current thread.
size_t size_type
used as the common size type in the library