Skip to content

Commit a9fdb11

Browse files
committed
replace chunks bool array, with bit fields
Signed-off-by: Łukasz Plewa <[email protected]>
1 parent cf66845 commit a9fdb11

File tree

3 files changed

+64
-37
lines changed

3 files changed

+64
-37
lines changed

src/pool/pool_disjoint.c

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@ static slab_t *create_slab(bucket_t *bucket) {
7474
umf_result_t res = UMF_RESULT_SUCCESS;
7575
umf_memory_provider_handle_t provider = bucket->pool->provider;
7676

77-
slab_t *slab = umf_ba_global_alloc(sizeof(*slab));
77+
size_t num_chunks_total =
78+
utils_max(bucket_slab_min_size(bucket) / bucket->size, 1);
79+
size_t chunks_size_in_64_increments =
80+
num_chunks_total / 8 + (num_chunks_total % 8 != 0);
81+
82+
slab_t *slab = umf_ba_global_alloc(
83+
sizeof(*slab) + chunks_size_in_64_increments * sizeof(slab->chunks[0]));
7884
if (slab == NULL) {
7985
LOG_ERR("allocation of new slab failed!");
8086
return NULL;
@@ -87,15 +93,10 @@ static slab_t *create_slab(bucket_t *bucket) {
8793
slab->iter.val = slab;
8894
slab->iter.prev = slab->iter.next = NULL;
8995

90-
slab->num_chunks_total =
91-
utils_max(bucket_slab_min_size(bucket) / bucket->size, 1);
92-
slab->chunks =
93-
umf_ba_global_alloc(sizeof(*slab->chunks) * slab->num_chunks_total);
94-
if (slab->chunks == NULL) {
95-
LOG_ERR("allocation of slab chunks failed!");
96-
goto free_slab;
97-
}
98-
memset(slab->chunks, 0, sizeof(*slab->chunks) * slab->num_chunks_total);
96+
slab->num_chunks_total = num_chunks_total;
97+
98+
memset(slab->chunks, 0,
99+
chunks_size_in_64_increments * sizeof(slab->chunks[0]));
99100

100101
// if slab_min_size is not a multiple of bucket size, we would have some
101102
// padding at the end of the slab
@@ -107,7 +108,7 @@ static slab_t *create_slab(bucket_t *bucket) {
107108
res = umfMemoryProviderAlloc(provider, slab->slab_size, 0, &slab->mem_ptr);
108109
if (res != UMF_RESULT_SUCCESS) {
109110
LOG_ERR("allocation of slab data failed!");
110-
goto free_slab_chunks;
111+
goto free_slab;
111112
}
112113

113114
// raw allocation is not available for user so mark it as inaccessible
@@ -116,9 +117,6 @@ static slab_t *create_slab(bucket_t *bucket) {
116117
LOG_DEBUG("bucket: %p, slab_size: %zu", (void *)bucket, slab->slab_size);
117118
return slab;
118119

119-
free_slab_chunks:
120-
umf_ba_global_free(slab->chunks);
121-
122120
free_slab:
123121
umf_ba_global_free(slab);
124122
return NULL;
@@ -135,25 +133,32 @@ static void destroy_slab(slab_t *slab) {
135133
LOG_ERR("deallocation of slab data failed!");
136134
}
137135

138-
umf_ba_global_free(slab->chunks);
139136
umf_ba_global_free(slab);
140137
}
141138

142-
// return the index of the first available chunk, SIZE_MAX otherwise
143139
static size_t slab_find_first_available_chunk_idx(const slab_t *slab) {
144-
// use the first free chunk index as a hint for the search
145-
for (bool *chunk = slab->chunks + slab->first_free_chunk_idx;
146-
chunk != slab->chunks + slab->num_chunks_total; chunk++) {
147-
148-
// false means not used
149-
if (*chunk == false) {
150-
size_t idx = chunk - slab->chunks;
151-
LOG_DEBUG("idx: %zu", idx);
152-
return idx;
140+
// Calculate the number of 64-bit words needed.
141+
size_t num_words = (slab->num_chunks_total + 63) / 64;
142+
for (size_t i = 0; i < num_words; i++) {
143+
// Invert the word: free bits (0 in the allocated mask) become 1.
144+
uint64_t word = ~(slab->chunks[i]);
145+
146+
// For the final word, clear out bits that exceed num_chunks_total.
147+
if (i == num_words - 1) {
148+
size_t bits_in_last_word = slab->num_chunks_total - (i * 64);
149+
if (bits_in_last_word < 64) {
150+
word &= (((uint64_t)1 << bits_in_last_word) - 1);
151+
}
152+
}
153+
if (word != 0) {
154+
size_t bit_index = utils_get_rightmost_set_bit_pos(word);
155+
size_t free_chunk = i * 64 + bit_index;
156+
if (free_chunk < slab->num_chunks_total) {
157+
return free_chunk;
158+
}
153159
}
154160
}
155-
156-
LOG_DEBUG("idx: SIZE_MAX");
161+
// No free chunk was found.
157162
return SIZE_MAX;
158163
}
159164

@@ -166,7 +171,7 @@ static void *slab_get_chunk(slab_t *slab) {
166171
(void *)((uintptr_t)slab->mem_ptr + chunk_idx * slab->bucket->size);
167172

168173
// mark chunk as used
169-
slab->chunks[chunk_idx] = true;
174+
slab_set_chunk_bit(slab, chunk_idx, true);
170175
slab->num_chunks_allocated += 1;
171176

172177
// use the found index as the next hint
@@ -194,8 +199,8 @@ static void slab_free_chunk(slab_t *slab, void *ptr) {
194199
size_t chunk_idx = ptr_diff / slab->bucket->size;
195200

196201
// Make sure that the chunk was allocated
197-
assert(slab->chunks[chunk_idx] && "double free detected");
198-
slab->chunks[chunk_idx] = false;
202+
assert(slab_read_chunk_bit(slab, chunk_idx) && "double free detected");
203+
slab_set_chunk_bit(slab, chunk_idx, false);
199204
slab->num_chunks_allocated -= 1;
200205

201206
if (chunk_idx < slab->first_free_chunk_idx) {
@@ -467,7 +472,7 @@ static size_t size_to_idx(disjoint_pool_t *pool, size_t size) {
467472
}
468473

469474
// get the position of the leftmost set bit
470-
size_t position = getLeftmostSetBitPos(size);
475+
size_t position = utils_get_leftmost_set_bit_pos(size);
471476

472477
bool is_power_of_2 = 0 == (size & (size - 1));
473478
bool larger_than_halfway_between_powers_of_2 =
@@ -623,7 +628,8 @@ umf_result_t disjoint_pool_initialize(umf_memory_provider_handle_t provider,
623628
Size1 = utils_max(Size1, UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE);
624629

625630
// Calculate the exponent for min_bucket_size used for finding buckets.
626-
disjoint_pool->min_bucket_size_exp = (size_t)log2Utils(Size1);
631+
disjoint_pool->min_bucket_size_exp =
632+
(size_t)utils_get_leftmost_set_bit_pos(Size1);
627633
disjoint_pool->default_shared_limits =
628634
umfDisjointPoolSharedLimitsCreate(SIZE_MAX);
629635

src/pool/pool_disjoint_internal.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,6 @@ typedef struct slab_t {
8181
void *mem_ptr;
8282
size_t slab_size;
8383

84-
// Represents the current state of each chunk: if the bit is set, the
85-
// chunk is allocated; otherwise, the chunk is free for allocation
86-
bool *chunks;
8784
size_t num_chunks_total;
8885

8986
// Total number of allocated chunks at the moment.
@@ -98,6 +95,10 @@ typedef struct slab_t {
9895
// Store iterator to the corresponding node in avail/unavail list
9996
// to achieve O(1) removal
10097
slab_list_item_t iter;
98+
99+
// Represents the current state of each chunk: if the bit is set, the
100+
// chunk is allocated; otherwise, the chunk is free for allocation
101+
uint64_t chunks[];
101102
} slab_t;
102103

103104
typedef struct umf_disjoint_pool_shared_limits_t {
@@ -158,4 +159,24 @@ typedef struct disjoint_pool_t {
158159
size_t provider_min_page_size;
159160
} disjoint_pool_t;
160161

162+
static inline void slab_set_chunk_bit(slab_t *slab, size_t index, bool value) {
163+
assert(index < slab->num_chunks_total && "Index out of range");
164+
165+
size_t word_index = index / 64;
166+
unsigned bit_index = index % 64;
167+
if (value) {
168+
slab->chunks[word_index] |= (1ULL << bit_index);
169+
} else {
170+
slab->chunks[word_index] &= ~(1ULL << bit_index);
171+
}
172+
}
173+
174+
static inline int slab_read_chunk_bit(const slab_t *slab, size_t index) {
175+
assert(index < slab->num_chunks_total && "Index out of range");
176+
177+
size_t word_index = index / 64;
178+
unsigned bit_index = index % 64;
179+
return (slab->chunks[word_index] >> bit_index) & 1;
180+
}
181+
161182
#endif // UMF_POOL_DISJOINT_INTERNAL_H

test/pools/disjoint_pool.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ TEST_F(test, internals) {
113113
EXPECT_GE(slab->num_chunks_total, slab->slab_size / bucket->size);
114114

115115
// check allocation in slab
116-
EXPECT_EQ(slab->chunks[0], true);
117-
EXPECT_EQ(slab->chunks[1], false);
116+
EXPECT_EQ(slab_read_chunk_bit(slab, 0), true);
117+
EXPECT_EQ(slab_read_chunk_bit(slab, 1), false);
118118
EXPECT_EQ(slab->first_free_chunk_idx, 1);
119119

120120
// TODO:

0 commit comments

Comments
 (0)