@@ -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-
122120free_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
143139static 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
0 commit comments