Skip to content

Commit

Permalink
small: add granularity option to small_alloc_create
Browse files Browse the repository at this point in the history
Granularity is an option that allows user to set
multiplicity of memory allocation in small allocator.
Granulatiry must be power of two and >= sizeof(intptr_t)
in case when we used small allocator for all allocation
types and >= 4 in case when we used it for packed structs,
or types which size <= 4.
  • Loading branch information
EvgenyMekhanik committed Mar 9, 2021
1 parent 29bf0cb commit 8ef2ec4
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 17 deletions.
10 changes: 7 additions & 3 deletions perf/small_alloc_perf.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ small_alloc_basic(unsigned int slab_size)
for (unsigned int i = 0; i < SZR(slab_alloc_factor); i++) {
float actual_alloc_factor;
small_alloc_create(&alloc, &cache,
OBJSIZE_MIN, slab_alloc_factor[i],
OBJSIZE_MIN, sizeof(intptr_t),
slab_alloc_factor[i],
&actual_alloc_factor);
int size_min = OBJSIZE_MIN;
int size_max = (int)alloc.objsize_max - 1;
Expand Down Expand Up @@ -252,7 +253,8 @@ small_alloc_basic(unsigned int slab_size)
for (unsigned int i = 0; i < SZR(slab_alloc_factor); i++) {
float actual_alloc_factor;
small_alloc_create(&alloc, &cache,
OBJSIZE_MIN, slab_alloc_factor[i],
OBJSIZE_MIN, sizeof(intptr_t),
slab_alloc_factor[i],
&actual_alloc_factor);
int size_min = OBJSIZE_MIN;
int size_max = (int)alloc.objsize_max - 1;
Expand Down Expand Up @@ -301,7 +303,9 @@ small_alloc_large()
for (unsigned int i = 0; i < SZR(slab_alloc_factor); i++) {
float actual_alloc_factor;
small_alloc_create(&alloc, &cache, OBJSIZE_MIN,
slab_alloc_factor[i], &actual_alloc_factor);
sizeof(intptr_t),
slab_alloc_factor[i],
&actual_alloc_factor);
fail_unless(clock_gettime (CLOCK_MONOTONIC, &tm1) == 0);
small_alloc_test(large_size_min, large_size_max, 200, 1, 25);
fail_unless(clock_gettime (CLOCK_MONOTONIC, &tm2) == 0);
Expand Down
19 changes: 16 additions & 3 deletions small/mempool.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ mslab_alloc(struct mempool *pool, struct mslab *slab)
if (slab->free_list) {
/* Recycle an object from the garbage pool. */
result = slab->free_list;
slab->free_list = *(void **)slab->free_list;
/*
* In case when pool objsize is not aligned sizeof(intptr_t)
* boundary we can't use *(void **)slab->free_list construction,
* because (void **)slab->free_list has not necessary aligment.
* memcpy can work with misaligned address.
*/
memcpy(&slab->free_list, (void **)slab->free_list,
sizeof(void *));
} else {
/* Use an object from the "untouched" area of the slab. */
result = (char *)slab + slab->free_offset;
Expand All @@ -90,8 +97,14 @@ mslab_alloc(struct mempool *pool, struct mslab *slab)
void
mslab_free(struct mempool *pool, struct mslab *slab, void *ptr)
{
/* put object to garbage list */
*(void **)ptr = slab->free_list;
/*
* Put object to garbage list.
* In case when pool objsize is not aligned sizeof(intptr_t) boundary
* we can't use *(void **)ptr = slab->free_list construction,
* because ptr has not necessary aligment. memcpy can work
* with misaligned address.
*/
memcpy((void **)ptr, &slab->free_list, sizeof(void *));
slab->free_list = ptr;
VALGRIND_FREELIKE_BLOCK(ptr, 0);
VALGRIND_MAKE_MEM_DEFINED(ptr, sizeof(void *));
Expand Down
13 changes: 7 additions & 6 deletions small/small.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,25 @@ factor_pool_create(struct small_alloc *alloc)
/** Initialize the small allocator. */
void
small_alloc_create(struct small_alloc *alloc, struct slab_cache *cache,
uint32_t objsize_min, float alloc_factor,
float *actual_alloc_factor)
uint32_t objsize_min, unsigned granularity,
float alloc_factor, float *actual_alloc_factor)
{
alloc->cache = cache;
/* Align sizes. */
objsize_min = small_align(objsize_min, sizeof(intptr_t));
objsize_min = small_align(objsize_min, granularity);
/* Make sure at least 4 largest objects can fit in a slab. */
alloc->objsize_max =
mempool_objsize_max(slab_order_size(cache, cache->order_max));
alloc->objsize_max = small_align(alloc->objsize_max, granularity);

assert((granularity & (granularity - 1)) == 0);
assert(alloc_factor > 1. && alloc_factor <= 2.);

alloc->factor = alloc_factor;
/*
* Second parameter (uintptr_t) - granularity,
* determines alignment.
* Second parameter granularity, determines alignment.
*/
small_class_create(&alloc->small_class, sizeof(intptr_t),
small_class_create(&alloc->small_class, granularity,
alloc->factor, objsize_min, actual_alloc_factor);
factor_pool_create(alloc);

Expand Down
5 changes: 3 additions & 2 deletions small/small.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,16 @@ struct small_alloc {
* @param alloc - instance to create.
* @param cache - pointer to used slab cache.
* @param objsize_min - minimal object size.
* @param granularity - alignment of objects in pools
* @param alloc_factor - desired factor of growth object size.
* Must be in (1, 2] range.
* @param actual_alloc_factor real allocation factor calculated the basis of
* desired alloc_factor
*/
void
small_alloc_create(struct small_alloc *alloc, struct slab_cache *cache,
uint32_t objsize_min, float alloc_factor,
float *actual_alloc_factor);
uint32_t objsize_min, unsigned granularity,
float alloc_factor, float *actual_alloc_factor);

/**
* Enter or leave delayed mode - in delayed mode smfree_delayed()
Expand Down
8 changes: 6 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ target_compile_definitions(small_class_branchless.test PUBLIC SMALL_CLASS_BRANCH
add_executable(small_alloc.test small_alloc.c)
target_link_libraries(small_alloc.test small)

add_executable(small_granularity.test small_granularity.c)
target_link_libraries(small_granularity.test small)

add_executable(lf_lifo.test lf_lifo.c)

add_executable(slab_arena.test slab_arena.c)
Expand Down Expand Up @@ -74,6 +77,7 @@ add_test(mempool ${CMAKE_CURRENT_BUILD_DIR}/mempool.test)
add_test(small_class ${CMAKE_CURRENT_BUILD_DIR}/small_class.test)
add_test(small_class_branchless ${CMAKE_CURRENT_BUILD_DIR}/small_class_branchless.test)
add_test(small_alloc ${CMAKE_CURRENT_BUILD_DIR}/small_alloc.test)
add_test(small_granularity ${CMAKE_CURRENT_BUILD_DIR}/small_granularity.test)
add_test(lf_lifo ${CMAKE_CURRENT_BUILD_DIR}/lf_lifo.test)
add_test(slab_cache ${CMAKE_CURRENT_BUILD_DIR}/slab_cache.test)
add_test(arena_mt ${CMAKE_CURRENT_BUILD_DIR}/arena_mt.test)
Expand All @@ -99,6 +103,6 @@ add_custom_target(test
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
COMMAND ctest
DEPENDS slab_cache.test region.test ibuf.test obuf.test mempool.test
small_alloc.test lf_lifo.test slab_arena.test arena_mt.test
matras.test lsregion.test quota.test rb.test
small_alloc.test small_granularity.test lf_lifo.test slab_arena.test
arena_mt.test matras.test lsregion.test quota.test rb.test
)
4 changes: 3 additions & 1 deletion test/small_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ small_alloc_test(int size_min, int size_max, int objects_max,
int oscillation_max, int iterations_max)
{
float actual_alloc_factor;
small_alloc_create(&alloc, &cache, OBJSIZE_MIN, 1.3, &actual_alloc_factor);
small_alloc_create(&alloc, &cache, OBJSIZE_MIN,
sizeof(intptr_t), 1.3,
&actual_alloc_factor);

for (int i = 0; i < iterations_max; i++) {
small_alloc_setopt(&alloc, SMALL_DELAYED_FREE_MODE, i % 5 == 0);
Expand Down
147 changes: 147 additions & 0 deletions test/small_granularity.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#include <small/small.h>
#include <small/quota.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "unit.h"

enum {
GRANULARITY_MIN = 4,
GRANULARITY_MAX = 1024,
ALLOCATION_COUNT = 10,
};

struct slab_arena arena;
struct slab_cache cache;
struct small_alloc alloc;
struct quota quota;

static unsigned *ptrs[FACTOR_POOL_MAX];

static inline void
free_checked(struct mempool *pool, unsigned *ptr)
{
/*
* Checking previous saved data.
*/
fail_unless(ptr[0] < FACTOR_POOL_MAX &&
ptr[pool->objsize/sizeof(unsigned)-1] == ptr[0]);
int pos = ptr[0];
fail_unless(ptrs[pos] == ptr);
ptrs[pos][0] = ptrs[pos][pool->objsize/sizeof(unsigned)-1] = INT_MAX;
mempool_free(pool, ptrs[pos]);
ptrs[pos] = NULL;
}

static inline void *
alloc_checked(struct mempool *pool, unsigned pos)
{
fail_unless(ptrs[pos] == NULL);
ptrs[pos] = mempool_alloc(pool);
fail_unless(ptrs[pos] != NULL);
/*
* Saving some data for test purposes
*/
ptrs[pos][0] = pos;
ptrs[pos][pool->objsize/sizeof(unsigned)-1] = pos;
return ptrs[pos];
}

static void
small_granularity_aligment_test(void)
{
header();
const float alloc_factor = 1.3;
for(unsigned int granularity = GRANULARITY_MIN;
granularity <= GRANULARITY_MAX;
granularity <<= 1) {
float actual_alloc_factor;
/*
* Creates small_alloc with different granularity,
* which must be power of two.
*/
small_alloc_create(&alloc, &cache, granularity,
granularity, alloc_factor, &actual_alloc_factor);
/*
* Checks aligment of all mempools in small alloc.
*/
for (unsigned int mempool = 0;
mempool < alloc.factor_pool_cache_size;
mempool++) {
/*
* Allocates memory in each of mempools for
* several objects. Each object must have at
* least granularity alignment
*/
struct mempool *pool =
&alloc.factor_pool_cache[mempool].pool;
for (unsigned cnt = 0; cnt < ALLOCATION_COUNT; cnt++) {
ptrs[cnt] = mempool_alloc(pool);
uintptr_t addr = (uintptr_t)ptrs[cnt];
fail_unless ((addr % granularity) == 0);
}
/*
* Frees previous allocated objects.
*/
for (unsigned cnt = 0; cnt < ALLOCATION_COUNT; cnt++) {
mempool_free(pool, ptrs[cnt]);
ptrs[cnt] = NULL;
}
}
small_alloc_destroy(&alloc);
}
footer();
}

static void
small_granularity_allocation_test(void)
{
header();
const float alloc_factor = 1.3;
for(unsigned int granularity = GRANULARITY_MIN;
granularity <= GRANULARITY_MAX;
granularity <<= 1) {
float actual_alloc_factor;
/*
* Creates small_alloc with different granularity,
* which must be power of two.
*/
small_alloc_create(&alloc, &cache, granularity,
granularity, alloc_factor, &actual_alloc_factor);
/*
* Checks allocation of all mempools in small_alloc
*/
for (unsigned int mempool = 0;
mempool < alloc.factor_pool_cache_size;
mempool++) {
struct mempool *pool =
&alloc.factor_pool_cache[mempool].pool;
ptrs[mempool] = alloc_checked(pool, mempool);
}
for (unsigned int mempool = 0;
mempool < alloc.factor_pool_cache_size;
mempool++) {
struct mempool *pool =
&alloc.factor_pool_cache[mempool].pool;
free_checked(pool, ptrs[mempool]);
fail_unless(mempool_used(pool) == 0);
}
small_alloc_destroy(&alloc);
}
footer();
}

int main()
{
quota_init(&quota, UINT_MAX);

slab_arena_create(&arena, &quota, 0, 4000000,
MAP_PRIVATE);
slab_cache_create(&cache, &arena);

small_granularity_aligment_test();
small_granularity_allocation_test();

slab_cache_destroy(&cache);
slab_arena_destroy(&arena);
}
4 changes: 4 additions & 0 deletions test/small_granularity.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*** small_granularity_aligment_test ***
*** small_granularity_aligment_test: done ***
*** small_granularity_allocation_test ***
*** small_granularity_allocation_test: done ***

0 comments on commit 8ef2ec4

Please sign in to comment.