Skip to content

small: improve real_size calculation in small_alloc_info #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions include/small/small.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,36 +211,6 @@ smalloc(struct small_alloc *alloc, size_t size);
void
smfree(struct small_alloc *alloc, void *ptr, size_t size);

/**
* @brief Return an unique index associated with a chunk allocated
* by the allocator.
*
* This index space is more dense than the pointers space,
* especially in the least significant bits. This number is
* needed because some types of box's indexes (e.g. BITSET) have
* better performance then they operate on sequential offsets
* (i.e. dense space) instead of memory pointers (sparse space).
*
* The calculation is based on SLAB number and the position of an
* item within it. Current implementation only guarantees that
* adjacent chunks from one SLAB will have consecutive indexes.
* That is, if two chunks were sequentially allocated from one
* chunk they will have sequential ids. If a second chunk was
* allocated from another SLAB thеn the difference between indexes
* may be more than one.
*
* @param ptr pointer to memory allocated in small_alloc
* @return unique index
*/
size_t
small_ptr_compress(struct small_alloc *alloc, void *ptr);

/**
* Perform the opposite action of small_ptr_compress().
*/
void *
small_ptr_decompress(struct small_alloc *alloc, size_t val);

void
small_stats(struct small_alloc *alloc,
struct small_stats *totals,
Expand All @@ -255,8 +225,6 @@ small_alloc_check(struct small_alloc *alloc)
/**
* Fill `info' with the information about allocation `ptr' of size `size'.
* See `struct small_alloc_info' for the description of each field.
* Note that this function can return different `info->real_size' for the same
* input, depending on the current `small_mempool->used_pool'.
*/
void
small_alloc_info(struct small_alloc *alloc, void *ptr, size_t size,
Expand Down
10 changes: 6 additions & 4 deletions small/small.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,14 @@ void
small_alloc_info(struct small_alloc *alloc, void *ptr, size_t size,
struct small_alloc_info *info)
{
(void)ptr;
struct small_mempool *small_mempool = small_mempool_search(alloc, size);
info->is_large = small_mempool == NULL;
if (info->is_large)
if (info->is_large) {
info->real_size = size;
else
info->real_size = small_mempool->used_pool->pool.objsize;
} else {
struct mslab *mslab = (struct mslab *)
slab_from_ptr(ptr, small_mempool->pool.slab_ptr_mask);
info->real_size = mslab->mempool->objsize;
}
assert(info->real_size >= size);
}
49 changes: 47 additions & 2 deletions test/small_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ static inline void
check_small_alloc_info(struct small_alloc *alloc, size_t size, bool is_large,
size_t real_size)
{
void *ptr = smalloc(alloc, size);
struct small_alloc_info info;
small_alloc_info(alloc, NULL, size, &info);
small_alloc_info(alloc, ptr, size, &info);
smfree(alloc, ptr, size);
fail_unless(info.is_large == is_large);
fail_unless(info.real_size == real_size);
}
Expand Down Expand Up @@ -185,6 +187,48 @@ test_small_alloc_info(void)
check_plan();
}

/**
* Make sure `info.real_size' is calculated correctly.
* See https://github.com/tarantool/tarantool/issues/10217
*/
static void
test_small_alloc_info_gh_10217(void)
{
plan(1);
header();
/*
* One of the mempool groups consists of two mempools with objsizes
* 3072 and 4096. The largest objsize in the previous group is 2048.
*/
float actual_alloc_factor;
small_alloc_create(&alloc, &cache, 64, 64, 1.5f, &actual_alloc_factor);

const size_t size = 2240;
const size_t count = 200;
struct small_alloc_info info;

for (size_t i = 0; i < count; i++) {
ptrs[i] = smalloc(&alloc, size);
small_alloc_info(&alloc, ptrs[i], size, &info);
fail_unless(info.real_size == (i > 127 ? 3072 : 4096));
}
/*
* Check that all "real sizes" are still correct after `used_pool' was
* switched.
*/
for (size_t i = 0; i < count; i++) {
small_alloc_info(&alloc, ptrs[i], size, &info);
fail_unless(info.real_size == (i > 127 ? 3072 : 4096));
}
ok(true);

for (size_t i = 0; i < count; i++)
smfree(&alloc, ptrs[i], size);
small_alloc_destroy(&alloc);
footer();
check_plan();
}

/**
* Make sure allocator works with low alloc_factor and high memory
* pressure.
Expand Down Expand Up @@ -317,7 +361,7 @@ int main()
#ifdef ENABLE_ASAN
plan(3);
#else
plan(4);
plan(5);
#endif
header();

Expand All @@ -334,6 +378,7 @@ int main()
#ifndef ENABLE_ASAN
small_alloc_large();
test_small_alloc_info();
test_small_alloc_info_gh_10217();
small_alloc_low_alloc_factor();
#else
small_wrong_size_in_free();
Expand Down