Skip to content

Commit 216b33d

Browse files
committed
small: improve real_size calculation in small_alloc_info
Currently `real_size` is calculated as the size of a memory block that would be allocated for the requested number of bytes. However, this calculation is non-idempotent. For details see commit df7ba1f ("small: implement new allocator strategy"). This patch switches `small_alloc_info()` to `slab_from_ptr()` that returns the actual slab that contains the requested `ptr`, so now `real_size` is always correct. Needed for tarantool/tarantool#10217
1 parent d4f8217 commit 216b33d

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

include/small/small.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ small_alloc_check(struct small_alloc *alloc)
225225
/**
226226
* Fill `info' with the information about allocation `ptr' of size `size'.
227227
* See `struct small_alloc_info' for the description of each field.
228-
* Note that this function can return different `info->real_size' for the same
229-
* input, depending on the current `small_mempool->used_pool'.
230228
*/
231229
void
232230
small_alloc_info(struct small_alloc *alloc, void *ptr, size_t size,

small/small.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,14 @@ void
468468
small_alloc_info(struct small_alloc *alloc, void *ptr, size_t size,
469469
struct small_alloc_info *info)
470470
{
471-
(void)ptr;
472471
struct small_mempool *small_mempool = small_mempool_search(alloc, size);
473472
info->is_large = small_mempool == NULL;
474-
if (info->is_large)
473+
if (info->is_large) {
475474
info->real_size = size;
476-
else
477-
info->real_size = small_mempool->used_pool->pool.objsize;
475+
} else {
476+
struct mslab *mslab = (struct mslab *)
477+
slab_from_ptr(ptr, small_mempool->pool.slab_ptr_mask);
478+
info->real_size = mslab->mempool->objsize;
479+
}
478480
assert(info->real_size >= size);
479481
}

test/small_alloc.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ static inline void
141141
check_small_alloc_info(struct small_alloc *alloc, size_t size, bool is_large,
142142
size_t real_size)
143143
{
144+
void *ptr = smalloc(alloc, size);
144145
struct small_alloc_info info;
145-
small_alloc_info(alloc, NULL, size, &info);
146+
small_alloc_info(alloc, ptr, size, &info);
147+
smfree(alloc, ptr, size);
146148
fail_unless(info.is_large == is_large);
147149
fail_unless(info.real_size == real_size);
148150
}
@@ -185,6 +187,48 @@ test_small_alloc_info(void)
185187
check_plan();
186188
}
187189

190+
/**
191+
* Make sure `info.real_size' is calculated correctly.
192+
* See https://github.com/tarantool/tarantool/issues/10217
193+
*/
194+
static void
195+
test_small_alloc_info_gh_10217(void)
196+
{
197+
plan(1);
198+
header();
199+
/*
200+
* One of the mempool groups consists of two mempools with objsizes
201+
* 3072 and 4096. The largest objsize in the previous group is 2048.
202+
*/
203+
float actual_alloc_factor;
204+
small_alloc_create(&alloc, &cache, 64, 64, 1.5f, &actual_alloc_factor);
205+
206+
const size_t size = 2240;
207+
const size_t count = 200;
208+
struct small_alloc_info info;
209+
210+
for (size_t i = 0; i < count; i++) {
211+
ptrs[i] = smalloc(&alloc, size);
212+
small_alloc_info(&alloc, ptrs[i], size, &info);
213+
fail_unless(info.real_size == (i > 127 ? 3072 : 4096));
214+
}
215+
/*
216+
* Check that all "real sizes" are still correct after `used_pool' was
217+
* switched.
218+
*/
219+
for (size_t i = 0; i < count; i++) {
220+
small_alloc_info(&alloc, ptrs[i], size, &info);
221+
fail_unless(info.real_size == (i > 127 ? 3072 : 4096));
222+
}
223+
ok(true);
224+
225+
for (size_t i = 0; i < count; i++)
226+
smfree(&alloc, ptrs[i], size);
227+
small_alloc_destroy(&alloc);
228+
footer();
229+
check_plan();
230+
}
231+
188232
/**
189233
* Make sure allocator works with low alloc_factor and high memory
190234
* pressure.
@@ -334,6 +378,7 @@ int main()
334378
#ifndef ENABLE_ASAN
335379
small_alloc_large();
336380
test_small_alloc_info();
381+
test_small_alloc_info_gh_10217();
337382
small_alloc_low_alloc_factor();
338383
#else
339384
small_wrong_size_in_free();

0 commit comments

Comments
 (0)