@@ -74,7 +74,13 @@ static slab_t *create_slab(bucket_t *bucket) {
74
74
umf_result_t res = UMF_RESULT_SUCCESS ;
75
75
umf_memory_provider_handle_t provider = bucket -> pool -> provider ;
76
76
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 ]));
78
84
if (slab == NULL ) {
79
85
LOG_ERR ("allocation of new slab failed!" );
80
86
return NULL ;
@@ -87,15 +93,10 @@ static slab_t *create_slab(bucket_t *bucket) {
87
93
slab -> iter .val = slab ;
88
94
slab -> iter .prev = slab -> iter .next = NULL ;
89
95
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 ]));
99
100
100
101
// if slab_min_size is not a multiple of bucket size, we would have some
101
102
// padding at the end of the slab
@@ -107,7 +108,7 @@ static slab_t *create_slab(bucket_t *bucket) {
107
108
res = umfMemoryProviderAlloc (provider , slab -> slab_size , 0 , & slab -> mem_ptr );
108
109
if (res != UMF_RESULT_SUCCESS ) {
109
110
LOG_ERR ("allocation of slab data failed!" );
110
- goto free_slab_chunks ;
111
+ goto free_slab ;
111
112
}
112
113
113
114
// raw allocation is not available for user so mark it as inaccessible
@@ -116,9 +117,6 @@ static slab_t *create_slab(bucket_t *bucket) {
116
117
LOG_DEBUG ("bucket: %p, slab_size: %zu" , (void * )bucket , slab -> slab_size );
117
118
return slab ;
118
119
119
- free_slab_chunks :
120
- umf_ba_global_free (slab -> chunks );
121
-
122
120
free_slab :
123
121
umf_ba_global_free (slab );
124
122
return NULL ;
@@ -135,25 +133,32 @@ static void destroy_slab(slab_t *slab) {
135
133
LOG_ERR ("deallocation of slab data failed!" );
136
134
}
137
135
138
- umf_ba_global_free (slab -> chunks );
139
136
umf_ba_global_free (slab );
140
137
}
141
138
142
- // return the index of the first available chunk, SIZE_MAX otherwise
143
139
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
+ }
153
159
}
154
160
}
155
-
156
- LOG_DEBUG ("idx: SIZE_MAX" );
161
+ // No free chunk was found.
157
162
return SIZE_MAX ;
158
163
}
159
164
@@ -166,7 +171,7 @@ static void *slab_get_chunk(slab_t *slab) {
166
171
(void * )((uintptr_t )slab -> mem_ptr + chunk_idx * slab -> bucket -> size );
167
172
168
173
// mark chunk as used
169
- slab -> chunks [ chunk_idx ] = true;
174
+ slab_set_chunk_bit ( slab , chunk_idx , true) ;
170
175
slab -> num_chunks_allocated += 1 ;
171
176
172
177
// use the found index as the next hint
@@ -194,8 +199,8 @@ static void slab_free_chunk(slab_t *slab, void *ptr) {
194
199
size_t chunk_idx = ptr_diff / slab -> bucket -> size ;
195
200
196
201
// 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) ;
199
204
slab -> num_chunks_allocated -= 1 ;
200
205
201
206
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) {
467
472
}
468
473
469
474
// 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 );
471
476
472
477
bool is_power_of_2 = 0 == (size & (size - 1 ));
473
478
bool larger_than_halfway_between_powers_of_2 =
@@ -623,7 +628,8 @@ umf_result_t disjoint_pool_initialize(umf_memory_provider_handle_t provider,
623
628
Size1 = utils_max (Size1 , UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE );
624
629
625
630
// 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 );
627
633
disjoint_pool -> default_shared_limits =
628
634
umfDisjointPoolSharedLimitsCreate (SIZE_MAX );
629
635
0 commit comments