Commit fc877ef8 authored by Philippe Gerum's avatar Philippe Gerum
Browse files

testsuite/smokey: add test suite for memory allocators

parent a409c18d
......@@ -931,6 +931,10 @@ AC_CONFIG_FILES([ \
testsuite/smokey/timerfd/Makefile \
testsuite/smokey/tsc/Makefile \
testsuite/smokey/leaks/Makefile \
testsuite/smokey/memcheck/Makefile \
testsuite/smokey/memory-heapmem/Makefile \
testsuite/smokey/memory-tlsf/Makefile \
testsuite/smokey/memory-pshared/Makefile \
testsuite/smokey/fpu-stress/Makefile \
testsuite/smokey/net_udp/Makefile \
testsuite/smokey/net_packet_dgram/Makefile \
......
......@@ -5,6 +5,10 @@ CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
smokey_SOURCES = main.c
# Make sure to list modules from the most dependent to the
# least. e.g. net_common should appear after all net_* modules,
# memcheck should appear after all heapmem-* modules.
COBALT_SUBDIRS = \
arith \
bufp \
......@@ -12,6 +16,9 @@ COBALT_SUBDIRS = \
fpu-stress \
iddp \
leaks \
memory-heapmem \
memory-tlsf \
memcheck \
net_packet_dgram\
net_packet_raw \
net_udp \
......@@ -31,9 +38,20 @@ COBALT_SUBDIRS = \
vdso-access \
xddp
MERCURY_SUBDIRS =
MERCURY_SUBDIRS = \
memcheck \
memory-heapmem \
memory-tlsf
LEFTOUT_SUBDIRS =
if XENO_PSHARED
COBALT_SUBDIRS += memory-pshared
MERCURY_SUBDIRS += memory-pshared
else
LEFTOUT_SUBDIRS += memory-pshared
endif
if CONFIG_XENO_LIBS_DLOPEN
COBALT_SUBDIRS += dlopen
else
......
noinst_LIBRARIES = libmemcheck.a
noinst_HEADERS = memcheck.h
AM_CPPFLAGS = \
@XENO_USER_CFLAGS@ \
-I$(top_srcdir)/include
libmemcheck_a_SOURCES = memcheck.c
This diff is collapsed.
/*
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*
* SPDX-License-Identifier: MIT
*/
#ifndef SMOKEY_MEMCHECK_H
#define SMOKEY_MEMCHECK_H
#include <sys/types.h>
#include <boilerplate/ancillaries.h>
#include <smokey/smokey.h>
#define MEMCHECK_ZEROOVRD 1
#define MEMCHECK_SHUFFLE 2
#define MEMCHECK_PATTERN 4
#define MEMCHECK_REALLOC 8
#define MEMCHECK_ALL_FLAGS 0xf
struct memcheck_descriptor {
const char *name;
int (*init)(void *heap, void *mem, size_t heap_size);
void (*destroy)(void *heap);
void *(*alloc)(void *heap, size_t size);
int (*free)(void *heap, void *block);
size_t (*get_used_size)(void *heap);
size_t (*get_usable_size)(void *heap);
size_t (*get_arena_size)(size_t heap_size);
size_t seq_min_heap_size;
size_t seq_max_heap_size;
int random_rounds;
size_t pattern_heap_size;
int pattern_rounds;
void *heap;
int valid_flags;
};
#define HEAP_INIT_T(__p) ((int (*)(void *heap, void *mem, size_t size))(__p))
#define HEAP_DESTROY_T(__p) ((void (*)(void *heap))(__p))
#define HEAP_ALLOC_T(__p) ((void *(*)(void *heap, size_t size))(__p))
#define HEAP_FREE_T(__p) ((int (*)(void *heap, void *block))(__p))
#define HEAP_USED_T(__p) ((size_t (*)(void *heap))(__p))
#define HEAP_USABLE_T(__p) ((size_t (*)(void *heap))(__p))
#define MEMCHECK_ARGS \
SMOKEY_ARGLIST( \
SMOKEY_SIZE(seq_heap_size), \
SMOKEY_SIZE(pattern_heap_size), \
SMOKEY_INT(random_alloc_rounds), \
SMOKEY_INT(pattern_check_rounds), \
SMOKEY_INT(max_results), \
)
#define MEMCHECK_HELP_STRINGS \
"\tseq_heap_size=<size[K|M|G]>\tmax. heap size for sequential alloc tests\n" \
"\tpattern_heap_size=<size[K|M|G]>\tmax. heap size for pattern check test\n" \
"\trandom_alloc_rounds=<N>\t\t# of rounds of random-size allocations\n" \
"\tpattern_check_rounds=<N>\t# of rounds of pattern check tests\n" \
"\tmax_results=<N>\t# of result lines (worst-case first, -1=all)\n" \
"\tSet --verbose=2 for detailed runtime statistics.\n"
int memcheck_run(struct memcheck_descriptor *md,
struct smokey_test *t,
int argc, char *const argv[]);
#endif /* SMOKEY_MEMCHECK_H */
noinst_LIBRARIES = libmemory-heapmem.a
libmemory_heapmem_a_SOURCES = heapmem.c
libmemory_heapmem_a_CPPFLAGS = \
@XENO_USER_CFLAGS@ \
-I$(srcdir)/.. \
-I$(top_srcdir)/include
/*
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*
* SPDX-License-Identifier: MIT
*/
#include <boilerplate/heapmem.h>
#include "memcheck/memcheck.h"
smokey_test_plugin(memory_heapmem,
MEMCHECK_ARGS,
"Check for the heapmem allocator sanity.\n"
MEMCHECK_HELP_STRINGS
);
#define MIN_HEAP_SIZE 8192
#define MAX_HEAP_SIZE (1024 * 1024 * 2)
#define RANDOM_ROUNDS 1024
#define PATTERN_HEAP_SIZE (128*1024)
#define PATTERN_ROUNDS 128
static struct heap_memory heap;
static size_t get_arena_size(size_t heap_size)
{
return HEAPMEM_ARENA_SIZE(heap_size);
}
static struct memcheck_descriptor heapmem_descriptor = {
.name = "heapmem",
.init = HEAP_INIT_T(heapmem_init),
.destroy = HEAP_DESTROY_T(heapmem_destroy),
.alloc = HEAP_ALLOC_T(heapmem_alloc),
.free = HEAP_FREE_T(heapmem_free),
.get_usable_size = HEAP_USABLE_T(heapmem_usable_size),
.get_used_size = HEAP_USED_T(heapmem_used_size),
.seq_min_heap_size = MIN_HEAP_SIZE,
.seq_max_heap_size = MAX_HEAP_SIZE,
.random_rounds = RANDOM_ROUNDS,
.pattern_heap_size = PATTERN_HEAP_SIZE,
.pattern_rounds = PATTERN_ROUNDS,
.heap = &heap,
.get_arena_size = get_arena_size,
.valid_flags = MEMCHECK_ALL_FLAGS,
};
static int run_memory_heapmem(struct smokey_test *t,
int argc, char *const argv[])
{
return memcheck_run(&heapmem_descriptor, t, argc, argv);
}
noinst_LIBRARIES = libmemory-pshared.a
libmemory_pshared_a_SOURCES = pshared.c
libmemory_pshared_a_CPPFLAGS = \
@XENO_USER_CFLAGS@ \
-I$(srcdir)/.. \
-I$(top_srcdir)/include
/*
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*
* SPDX-License-Identifier: MIT
*/
#include <xenomai/init.h>
#include <xenomai/tunables.h>
#include <copperplate/heapobj.h>
#include "memcheck/memcheck.h"
smokey_test_plugin(memory_pshared,
MEMCHECK_ARGS,
"Check for the pshared allocator sanity.\n"
MEMCHECK_HELP_STRINGS
);
#define MIN_HEAP_SIZE 8192
#define MAX_HEAP_SIZE (1024 * 1024 * 2)
#define RANDOM_ROUNDS 128
#define PATTERN_HEAP_SIZE (128*1024)
#define PATTERN_ROUNDS 128
static struct heapobj heap;
static int do_pshared_init(void *heap, void *mem, size_t arena_size)
{
/* mem is ignored, pshared uses its own memory. */
return heapobj_init(heap, "memcheck", arena_size);
}
static void do_pshared_destroy(void *heap)
{
heapobj_destroy(heap);
}
static void *do_pshared_alloc(void *heap, size_t size)
{
return heapobj_alloc(heap, size);
}
static int do_pshared_free(void *heap, void *block)
{
heapobj_free(heap, block);
return 0; /* Hope for the best. */
}
static size_t do_pshared_used_size(void *heap)
{
return heapobj_inquire(heap);
}
static size_t do_pshared_usable_size(void *heap)
{
return heapobj_get_size(heap);
}
static size_t do_pshared_arena_size(size_t heap_size)
{
struct heapobj h;
size_t overhead;
int ret;
ret = heapobj_init(&h, "memcheck", heap_size);
if (ret)
return 0;
overhead = heap_size - heapobj_get_size(&h);
heapobj_destroy(&h);
/*
* pshared must have no external overhead, since
* heapobj_init() allocates the memory it needs. Make sure
* this assumption is correct for any tested size.
*/
return overhead == 0 ? heap_size : 0;
}
static struct memcheck_descriptor pshared_descriptor = {
.name = "pshared",
.init = HEAP_INIT_T(do_pshared_init),
.destroy = HEAP_DESTROY_T(do_pshared_destroy),
.alloc = HEAP_ALLOC_T(do_pshared_alloc),
.free = HEAP_FREE_T(do_pshared_free),
.get_usable_size = HEAP_USABLE_T(do_pshared_usable_size),
.get_used_size = HEAP_USED_T(do_pshared_used_size),
.get_arena_size = do_pshared_arena_size,
.seq_min_heap_size = MIN_HEAP_SIZE,
.seq_max_heap_size = MAX_HEAP_SIZE,
.random_rounds = RANDOM_ROUNDS,
.pattern_heap_size = PATTERN_HEAP_SIZE,
.pattern_rounds = PATTERN_ROUNDS,
/* heapobj-pshared has overgead even for ^2 sizes, can't check for ZEROOVRD. */
.valid_flags = MEMCHECK_ALL_FLAGS & ~MEMCHECK_ZEROOVRD,
.heap = &heap,
};
static int run_memory_pshared(struct smokey_test *t,
int argc, char *const argv[])
{
return memcheck_run(&pshared_descriptor, t, argc, argv);
}
static int memcheck_pshared_tune(void)
{
/*
* We create test pools from the main one: make sure the
* latter is large enough.
*/
set_config_tunable(mem_pool_size, MAX_HEAP_SIZE + 1024 * 1024);
return 0;
}
static struct setup_descriptor memcheck_pshared_setup = {
.name = "memcheck_pshared",
.tune = memcheck_pshared_tune,
};
user_setup_call(memcheck_pshared_setup);
noinst_LIBRARIES = libmemory-tlsf.a
libmemory_tlsf_a_SOURCES = tlsf.c
libmemory_tlsf_a_CPPFLAGS = \
@XENO_USER_CFLAGS@ \
-I$(top_srcdir)/lib/boilerplate \
-I$(srcdir)/.. \
-I$(top_srcdir)/include
/*
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*
* SPDX-License-Identifier: MIT
*/
#include <tlsf/tlsf.h>
#include <stdlib.h>
#include <pthread.h>
#include "memcheck/memcheck.h"
smokey_test_plugin(memory_tlsf,
MEMCHECK_ARGS,
"Check for the TLSF allocator sanity.\n"
MEMCHECK_HELP_STRINGS
);
#define MIN_HEAP_SIZE 8192
#define MAX_HEAP_SIZE (1024 * 1024 * 2)
#define RANDOM_ROUNDS 1024
#define PATTERN_HEAP_SIZE (128*1024)
#define PATTERN_ROUNDS 128
static struct memcheck_descriptor tlsf_descriptor;
static pthread_mutex_t tlsf_lock = PTHREAD_MUTEX_INITIALIZER;
static size_t overhead;
static size_t test_pool_size; /* TLSF does not save this information. */
static int do_tlsf_init(void *dummy, void *mem, size_t pool_size)
{
tlsf_descriptor.heap = mem;
return init_memory_pool(pool_size, mem) == -1L ? -ENOMEM : 0;
}
static void do_tlsf_destroy(void *pool)
{
destroy_memory_pool(pool);
}
static void *do_tlsf_alloc(void *pool, size_t size)
{
void *p;
pthread_mutex_lock(&tlsf_lock);
p = malloc_ex(size, pool);
pthread_mutex_unlock(&tlsf_lock);
return p;
}
static int do_tlsf_free(void *pool, void *block)
{
pthread_mutex_lock(&tlsf_lock);
free_ex(block, pool);
pthread_mutex_unlock(&tlsf_lock);
return 0; /* Yeah, well... */
}
static size_t do_tlsf_used_size(void *pool)
{
/* Do not count the overhead memory for the TLSF header. */
return get_used_size(pool) - overhead;
}
static size_t do_tlsf_usable_size(void *pool)
{
return test_pool_size;
}
static size_t do_tlsf_arena_size(size_t pool_size)
{
size_t available_size;
void *pool;
/*
* The area size is the total amount of memory some allocator
* may need for managing a heap, including its metadata. We
* need to figure out how much memory overhead TLSF has for a
* given pool size, which we add to the ideal pool_size for
* determining the arena size.
*/
test_pool_size = pool_size;
pool = __STD(malloc(pool_size));
available_size = init_memory_pool(pool_size, pool);
if (available_size == (size_t)-1) {
__STD(free(pool));
return 0;
}
destroy_memory_pool(pool);
overhead = pool_size - available_size;
__STD(free(pool));
return pool_size + overhead;
}
static struct memcheck_descriptor tlsf_descriptor = {
.name = "tlsf",
.init = HEAP_INIT_T(do_tlsf_init),
.destroy = HEAP_DESTROY_T(do_tlsf_destroy),
.alloc = HEAP_ALLOC_T(do_tlsf_alloc),
.free = HEAP_FREE_T(do_tlsf_free),
.get_usable_size = HEAP_USABLE_T(do_tlsf_usable_size),
.get_used_size = HEAP_USED_T(do_tlsf_used_size),
.get_arena_size = do_tlsf_arena_size,
.seq_min_heap_size = MIN_HEAP_SIZE,
.seq_max_heap_size = MAX_HEAP_SIZE,
.random_rounds = RANDOM_ROUNDS,
.pattern_heap_size = PATTERN_HEAP_SIZE,
.pattern_rounds = PATTERN_ROUNDS,
/* TLSF always has overhead, can't check for ZEROOVRD. */
.valid_flags = MEMCHECK_ALL_FLAGS & ~MEMCHECK_ZEROOVRD,
};
static int run_memory_tlsf(struct smokey_test *t,
int argc, char *const argv[])
{
return memcheck_run(&tlsf_descriptor, t, argc, argv);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment