From d273fd4b32514fef526c0111dc8b4708ca48dd43 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 8 Mar 2024 08:51:33 -0500 Subject: [PATCH] Introduce mempool test Signed-off-by: Mathieu Desnoyers --- .gitignore | 3 + tests/Makefile.am | 8 ++ tests/list.h | 198 +++++++++++++++++++++++++++++++++++++ tests/mempool_test.c | 100 +++++++++++++++++++ tests/mempool_test_cxx.cpp | 4 + 5 files changed, 313 insertions(+) create mode 100644 tests/list.h create mode 100644 tests/mempool_test.c create mode 100644 tests/mempool_test_cxx.cpp diff --git a/.gitignore b/.gitignore index 31dd8a4..7dd4d39 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,8 @@ dkms.conf /tests/basic_percpu_ops_mm_cid_test_cxx.tap /tests/basic_test.tap /tests/basic_test_cxx.tap +/tests/mempool_test.tap +/tests/mempool_test_cxx.tap /tests/param_test /tests/param_test_cxx /tests/param_test_benchmark @@ -116,3 +118,4 @@ Makefile /autom4te.cache/ /config *~ +.*.swp diff --git a/tests/Makefile.am b/tests/Makefile.am index 67da31a..1d213f4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,6 +19,8 @@ noinst_PROGRAMS = \ basic_percpu_ops_mm_cid_test_cxx.tap \ basic_test.tap \ basic_test_cxx.tap \ + mempool_test.tap \ + mempool_test_cxx.tap \ param_test \ param_test_cxx \ param_test_mm_cid \ @@ -86,6 +88,12 @@ basic_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/util basic_test_cxx_tap_SOURCES = basic_test_cxx.cpp basic_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) +mempool_test_tap_SOURCES = mempool_test.c list.h +mempool_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) + +mempool_test_cxx_tap_SOURCES = mempool_test_cxx.cpp list.h +mempool_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS) + param_test_SOURCES = param_test.c param_test_LDADD = $(top_builddir)/src/librseq.la $(DL_LIBS) diff --git a/tests/list.h b/tests/list.h new file mode 100644 index 0000000..39a456b --- /dev/null +++ b/tests/list.h @@ -0,0 +1,198 @@ +// SPDX-FileCopyrightText: 2002 Free Software Foundation, Inc. +// SPDX-FileCopyrightText: 2009 Pierre-Marc Fournier +// SPDX-FileCopyrightText: 2010 Mathieu Desnoyers +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +/* + * (originally part of the GNU C Library) + * Contributed by Ulrich Drepper , 2002. + */ + +#ifndef _LIST_H +#define _LIST_H 1 + +/* + * container_of - Get the address of an object containing a field. + * + * @ptr: pointer to the field. + * @type: type of the object. + * @member: name of the field within the object. + */ +#define container_of(ptr, type, member) \ + __extension__ \ + ({ \ + const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \ + (type *)((char *)__ptr - offsetof(type, member)); \ + }) + +/* + * The definitions of this file are adopted from those which can be + * found in the Linux kernel headers to enable people familiar with the + * latter find their way in these sources as well. + */ + +/* Basic type for the double-link list. */ +struct list_head { + struct list_head *next, *prev; +}; + +/* Define a variable with the head and tail of the list. */ +#define LIST_HEAD(name) \ + struct list_head name = { &(name), &(name) } + +/* Initialize a new list head. */ +#define INIT_LIST_HEAD(ptr) \ + (ptr)->next = (ptr)->prev = (ptr) + +#define LIST_HEAD_INIT(name) { .next = &(name), .prev = &(name) } + +/* Add new element at the head of the list. */ +static inline +void list_add(struct list_head *newp, struct list_head *head) +{ + head->next->prev = newp; + newp->next = head->next; + newp->prev = head; + head->next = newp; +} + +/* Add new element at the tail of the list. */ +static inline +void list_add_tail(struct list_head *newp, struct list_head *head) +{ + head->prev->next = newp; + newp->next = head; + newp->prev = head->prev; + head->prev = newp; +} + +/* Remove element from list. */ +static inline +void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/* Remove element from list. */ +static inline +void list_del(struct list_head *elem) +{ + __list_del(elem->prev, elem->next); +} + +/* Remove element from list, initializing the element's list pointers. */ +static inline +void list_del_init(struct list_head *elem) +{ + list_del(elem); + INIT_LIST_HEAD(elem); +} + +/* Delete from list, add to another list as head. */ +static inline +void list_move(struct list_head *elem, struct list_head *head) +{ + __list_del(elem->prev, elem->next); + list_add(elem, head); +} + +/* Replace an old entry. */ +static inline +void list_replace(struct list_head *old, struct list_head *_new) +{ + _new->next = old->next; + _new->prev = old->prev; + _new->prev->next = _new; + _new->next->prev = _new; +} + +/* Join two lists. */ +static inline +void list_splice(struct list_head *add, struct list_head *head) +{ + /* Do nothing if the list which gets added is empty. */ + if (add != add->next) { + add->next->prev = head; + add->prev->next = head->next; + head->next->prev = add->prev; + head->next = add->next; + } +} + +/* Get typed element from list at a given position. */ +#define list_entry(ptr, type, member) container_of(ptr, type, member) + +/* Get first entry from a list. */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/* Iterate forward over the elements of the list. */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; (pos) != (head); pos = (pos)->next) + +/* + * Iterate forward over the elements list. The list elements can be + * removed from the list while doing this. + */ +#define list_for_each_safe(pos, p, head) \ + for (pos = (head)->next, p = (pos)->next; \ + (pos) != (head); \ + pos = (p), p = (pos)->next) + +/* Iterate backward over the elements of the list. */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; (pos) != (head); pos = (pos)->prev) + +/* + * Iterate backwards over the elements list. The list elements can be + * removed from the list while doing this. + */ +#define list_for_each_prev_safe(pos, p, head) \ + for (pos = (head)->prev, p = (pos)->prev; \ + (pos) != (head); \ + pos = (p), p = (pos)->prev) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, __typeof__(*(pos)), member); \ + &(pos)->member != (head); \ + pos = list_entry((pos)->member.next, __typeof__(*(pos)), member)) + +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, __typeof__(*(pos)), member); \ + &(pos)->member != (head); \ + pos = list_entry((pos)->member.prev, __typeof__(*(pos)), member)) + +#define list_for_each_entry_safe(pos, p, head, member) \ + for (pos = list_entry((head)->next, __typeof__(*(pos)), member), \ + p = list_entry((pos)->member.next, __typeof__(*(pos)), member); \ + &(pos)->member != (head); \ + pos = (p), p = list_entry((pos)->member.next, __typeof__(*(pos)), member)) + +/* + * Same as list_for_each_entry_safe, but starts from "pos" which should + * point to an entry within the list. + */ +#define list_for_each_entry_safe_from(pos, p, head, member) \ + for (p = list_entry((pos)->member.next, __typeof__(*(pos)), member); \ + &(pos)->member != (head); \ + pos = (p), p = list_entry((pos)->member.next, __typeof__(*(pos)), member)) + +static inline +int list_empty(struct list_head *head) +{ + return head == head->next; +} + +static inline +void list_replace_init(struct list_head *old, struct list_head *_new) +{ + struct list_head *head = old->next; + + list_del(old); + list_add_tail(_new, head); + INIT_LIST_HEAD(old); +} + +#endif /* _LIST_H */ diff --git a/tests/mempool_test.c b/tests/mempool_test.c new file mode 100644 index 0000000..691c391 --- /dev/null +++ b/tests/mempool_test.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2024 Mathieu Desnoyers +/* + * rseq memory pool test. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "list.h" +#include "tap.h" + +struct test_data { + uintptr_t value; + struct test_data __rseq_percpu *backref; + struct list_head node; +}; + +static void test_mempool_fill(size_t len) +{ + struct test_data __rseq_percpu *ptr; + struct test_data *iter; + struct rseq_percpu_pool *mempool; + struct rseq_pool_attr *attr; + uint64_t count = 0; + LIST_HEAD(list); + int ret, i; + + attr = rseq_pool_attr_create(); + ret = rseq_pool_attr_set_robust(attr); + ok(ret == 0, "Setting mempool robust attribute"); + + mempool = rseq_percpu_pool_create("test_data", + sizeof(struct test_data), + len, CPU_SETSIZE, attr); + ok(mempool, "Create mempool of size %zu", len); + rseq_pool_attr_destroy(attr); + + for (;;) { + struct test_data *cpuptr; + + ptr = (struct test_data __rseq_percpu *) rseq_percpu_zmalloc(mempool); + if (!ptr) + break; + /* Link items in cpu 0. */ + cpuptr = rseq_percpu_ptr(ptr, 0); + cpuptr->backref = ptr; + /* Randomize items in list. */ + if (count & 1) + list_add(&cpuptr->node, &list); + else + list_add_tail(&cpuptr->node, &list); + count++; + } + + ok(count * sizeof(struct test_data) == len, "Allocated %" PRIu64 " objects in pool", count); + + list_for_each_entry(iter, &list, node) { + ptr = iter->backref; + for (i = 0; i < CPU_SETSIZE; i++) { + struct test_data *cpuptr = rseq_percpu_ptr(ptr, i); + + if (cpuptr->value != 0) + abort(); + cpuptr->value++; + } + } + + ok(1, "Check for pool content corruption"); + + list_for_each_entry(iter, &list, node) { + ptr = iter->backref; + rseq_percpu_free(ptr); + } + ret = rseq_percpu_pool_destroy(mempool); + ok(ret == 0, "Destroy mempool"); +} + +int main(void) +{ + size_t len; + + /* From 4kB to 4MB */ + for (len = 4096; len < 4096 * 1024; len <<= 1) { + test_mempool_fill(len); + } + + exit(exit_status()); +} diff --git a/tests/mempool_test_cxx.cpp b/tests/mempool_test_cxx.cpp new file mode 100644 index 0000000..3eed2b8 --- /dev/null +++ b/tests/mempool_test_cxx.cpp @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: MIT */ +// SPDX-FileCopyrightText: 2024 EfficiOS Inc. + +#include "mempool_test.c" -- 2.34.1