lib/rbtree: enable userland test suite for rbtree related data structure

Patch series "lib/interval_tree: add some test cases and cleanup", v2.

Since rbtree/augmented tree/interval tree share similar data structure,
besides new cases for interval tree, this patch set also does cleanup for
others.


This patch (of 7):

Currently we have some tests for rbtree related data structure, e.g. 
rbtree, augmented rbtree, interval tree, in lib/ as kernel module.

To facilitate the test and debug for those fundamental data structure,
this patch enable those tests in userland.

Link: https://lkml.kernel.org/r/20250310074938.26756-1-richard.weiyang@gmail.com
Link: https://lkml.kernel.org/r/20250310074938.26756-2-richard.weiyang@gmail.com
Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <michel@lespinasse.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Wei Yang 2025-03-10 07:49:32 +00:00 committed by Andrew Morton
parent bc2f19d653
commit 4164e1525d
19 changed files with 288 additions and 13 deletions

13
tools/include/asm/timex.h Normal file
View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TOOLS_LINUX_ASM_TIMEX_H
#define __TOOLS_LINUX_ASM_TIMEX_H
#include <time.h>
#define cycles_t clock_t
static inline cycles_t get_cycles(void)
{
return clock();
}
#endif // __TOOLS_LINUX_ASM_TIMEX_H

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TOOLS_LINUX_CONTAINER_OF_H
#define _TOOLS_LINUX_CONTAINER_OF_H
#ifndef container_of
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#endif /* _TOOLS_LINUX_CONTAINER_OF_H */

View File

@ -11,6 +11,7 @@
#include <linux/panic.h>
#include <endian.h>
#include <byteswap.h>
#include <linux/container_of.h>
#ifndef UINT_MAX
#define UINT_MAX (~0U)
@ -25,19 +26,6 @@
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#ifndef container_of
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#ifndef max
#define max(x, y) ({ \
typeof(x) _max1 = (x); \

View File

@ -72,4 +72,9 @@ static inline u64 mul_u64_u64_div64(u64 a, u64 b, u64 c)
}
#endif
static inline u64 div_u64(u64 dividend, u32 divisor)
{
return dividend / divisor;
}
#endif /* _LINUX_MATH64_H */

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TOOLS_LINUX_MODULE_PARAMS_H
#define _TOOLS_LINUX_MODULE_PARAMS_H
#define MODULE_PARM_DESC(parm, desc)
#endif // _TOOLS_LINUX_MODULE_PARAMS_H

View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TOOLS_LINUX_PRANDOM_H
#define __TOOLS_LINUX_PRANDOM_H
#include <linux/types.h>
struct rnd_state {
__u32 s1, s2, s3, s4;
};
/*
* Handle minimum values for seeds
*/
static inline u32 __seed(u32 x, u32 m)
{
return (x < m) ? x + m : x;
}
/**
* prandom_seed_state - set seed for prandom_u32_state().
* @state: pointer to state structure to receive the seed.
* @seed: arbitrary 64-bit value to use as a seed.
*/
static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
{
u32 i = ((seed >> 32) ^ (seed << 10) ^ seed) & 0xffffffffUL;
state->s1 = __seed(i, 2U);
state->s2 = __seed(i, 8U);
state->s3 = __seed(i, 16U);
state->s4 = __seed(i, 128U);
}
/**
* prandom_u32_state - seeded pseudo-random number generator.
* @state: pointer to state structure holding seeded state.
*
* This is used for pseudo-randomness with no outside seeding.
* For more random results, use get_random_u32().
*/
static inline u32 prandom_u32_state(struct rnd_state *state)
{
#define TAUSWORTHE(s, a, b, c, d) (((s & c) << d) ^ (((s << a) ^ s) >> b))
state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U);
state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U);
state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U);
state->s4 = TAUSWORTHE(state->s4, 3U, 12U, 4294967168U, 13U);
return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4);
}
#endif // __TOOLS_LINUX_PRANDOM_H

View File

@ -12,6 +12,7 @@
void *kmalloc(size_t size, gfp_t gfp);
void kfree(void *p);
void *kmalloc_array(size_t n, size_t size, gfp_t gfp);
bool slab_is_available(void);

View File

@ -36,3 +36,19 @@ void kfree(void *p)
printf("Freeing %p to malloc\n", p);
free(p);
}
void *kmalloc_array(size_t n, size_t size, gfp_t gfp)
{
void *ret;
if (!(gfp & __GFP_DIRECT_RECLAIM))
return NULL;
ret = calloc(n, size);
uatomic_inc(&kmalloc_nr_allocated);
if (kmalloc_verbose)
printf("Allocating %p from calloc\n", ret);
if (gfp & __GFP_ZERO)
memset(ret, 0, n * size);
return ret;
}

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: GPL-2.0
.PHONY: clean
TARGETS = rbtree_test interval_tree_test
OFILES = $(LIBS) rbtree-shim.o interval_tree-shim.o
DEPS = ../../../include/linux/rbtree.h \
../../../include/linux/rbtree_types.h \
../../../include/linux/rbtree_augmented.h \
../../../include/linux/interval_tree.h \
../../../include/linux/interval_tree_generic.h \
../../../lib/rbtree.c \
../../../lib/interval_tree.c
targets: $(TARGETS)
include ../shared/shared.mk
ifeq ($(DEBUG), 1)
CFLAGS += -g
endif
$(TARGETS): $(OFILES)
rbtree-shim.o: $(DEPS)
rbtree_test.o: ../../../lib/rbtree_test.c
interval_tree-shim.o: $(DEPS)
interval_tree_test.o: ../../../lib/interval_tree_test.c
clean:
$(RM) $(TARGETS) *.o generated/*

View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0
/*
* interval_tree.c: Userspace Interval Tree test-suite
* Copyright (c) 2025 Wei Yang <richard.weiyang@gmail.com>
*/
#include <linux/math64.h>
#include <linux/kern_levels.h>
#include "shared.h"
#include "../../../lib/interval_tree_test.c"
int usage(void)
{
fprintf(stderr, "Userland interval tree test cases\n");
fprintf(stderr, " -n: Number of nodes in the interval tree\n");
fprintf(stderr, " -p: Number of iterations modifying the tree\n");
fprintf(stderr, " -q: Number of searches to the interval tree\n");
fprintf(stderr, " -s: Number of iterations searching the tree\n");
fprintf(stderr, " -a: Searches will iterate all nodes in the tree\n");
fprintf(stderr, " -m: Largest value for the interval's endpoint\n");
exit(-1);
}
void interval_tree_tests(void)
{
interval_tree_test_init();
interval_tree_test_exit();
}
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:p:q:s:am:")) != -1) {
if (opt == 'n')
nnodes = strtoul(optarg, NULL, 0);
else if (opt == 'p')
perf_loops = strtoul(optarg, NULL, 0);
else if (opt == 'q')
nsearches = strtoul(optarg, NULL, 0);
else if (opt == 's')
search_loops = strtoul(optarg, NULL, 0);
else if (opt == 'a')
search_all = true;
else if (opt == 'm')
max_endpoint = strtoul(optarg, NULL, 0);
else
usage();
}
interval_tree_tests();
return 0;
}

View File

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0
/*
* rbtree_test.c: Userspace Red Black Tree test-suite
* Copyright (c) 2025 Wei Yang <richard.weiyang@gmail.com>
*/
#include <linux/init.h>
#include <linux/math64.h>
#include <linux/kern_levels.h>
#include "shared.h"
#include "../../../lib/rbtree_test.c"
int usage(void)
{
fprintf(stderr, "Userland rbtree test cases\n");
fprintf(stderr, " -n: Number of nodes in the rb-tree\n");
fprintf(stderr, " -p: Number of iterations modifying the rb-tree\n");
fprintf(stderr, " -c: Number of iterations modifying and verifying the rb-tree\n");
exit(-1);
}
void rbtree_tests(void)
{
rbtree_test_init();
rbtree_test_exit();
}
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:p:c:")) != -1) {
if (opt == 'n')
nnodes = strtoul(optarg, NULL, 0);
else if (opt == 'p')
perf_loops = strtoul(optarg, NULL, 0);
else if (opt == 'c')
check_loops = strtoul(optarg, NULL, 0);
else
usage();
}
rbtree_tests();
return 0;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
void rbtree_tests(void);
void interval_tree_tests(void);

View File

@ -0,0 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
/* Very simple shim around the interval tree. */
#include "../../../lib/interval_tree.c"

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TEST_INTERVAL_TREE_H
#define _TEST_INTERVAL_TREE_H
#include "../../../../include/linux/interval_tree.h"
#endif /* _TEST_INTERVAL_TREE_H */

View File

@ -0,0 +1,2 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include "../../../../include/linux/interval_tree_generic.h"

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TEST_RBTREE_H
#define _TEST_RBTREE_H
#include <linux/kernel.h>
#include "../../../../include/linux/rbtree.h"
#endif /* _TEST_RBTREE_H */

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TEST_RBTREE_AUGMENTED_H
#define _TEST_RBTREE_AUGMENTED_H
#include "../../../../include/linux/rbtree_augmented.h"
#endif /* _TEST_RBTREE_AUGMENTED_H */

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TEST_RBTREE_TYPES_H
#define _TEST_RBTREE_TYPES_H
#include "../../../../include/linux/rbtree_types.h"
#endif /* _TEST_RBTREE_TYPES_H */

View File

@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/* Very simple shim around the rbtree. */
#include "../../../lib/rbtree.c"