]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
lib/rbtree: enable userland test suite for rbtree related data structure
authorWei Yang <richard.weiyang@gmail.com>
Mon, 10 Mar 2025 07:49:32 +0000 (07:49 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 14 Mar 2025 22:56:12 +0000 (15:56 -0700)
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>
19 files changed:
tools/include/asm/timex.h [new file with mode: 0644]
tools/include/linux/container_of.h [new file with mode: 0644]
tools/include/linux/kernel.h
tools/include/linux/math64.h
tools/include/linux/moduleparam.h [new file with mode: 0644]
tools/include/linux/prandom.h [new file with mode: 0644]
tools/include/linux/slab.h
tools/lib/slab.c
tools/testing/rbtree/Makefile [new file with mode: 0644]
tools/testing/rbtree/interval_tree_test.c [new file with mode: 0644]
tools/testing/rbtree/rbtree_test.c [new file with mode: 0644]
tools/testing/rbtree/test.h [new file with mode: 0644]
tools/testing/shared/interval_tree-shim.c [new file with mode: 0644]
tools/testing/shared/linux/interval_tree.h [new file with mode: 0644]
tools/testing/shared/linux/interval_tree_generic.h [new file with mode: 0644]
tools/testing/shared/linux/rbtree.h [new file with mode: 0644]
tools/testing/shared/linux/rbtree_augmented.h [new file with mode: 0644]
tools/testing/shared/linux/rbtree_types.h [new file with mode: 0644]
tools/testing/shared/rbtree-shim.c [new file with mode: 0644]

diff --git a/tools/include/asm/timex.h b/tools/include/asm/timex.h
new file mode 100644 (file)
index 0000000..5adfe3c
--- /dev/null
@@ -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
diff --git a/tools/include/linux/container_of.h b/tools/include/linux/container_of.h
new file mode 100644 (file)
index 0000000..c879e14
--- /dev/null
@@ -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 */
index 07cfad817d53908f2325505d2b9cb644a808a689..c8c18d3908a904edc0f08af26f581706b854574a 100644 (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)
 #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);                  \
index 4ad45d5943dc371e20154bf131bedcb0fb6f7ff6..8a67d478bf191b4fcc79f370700c3099b90b03f8 100644 (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 */
diff --git a/tools/include/linux/moduleparam.h b/tools/include/linux/moduleparam.h
new file mode 100644 (file)
index 0000000..4c4d05b
--- /dev/null
@@ -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
diff --git a/tools/include/linux/prandom.h b/tools/include/linux/prandom.h
new file mode 100644 (file)
index 0000000..b745041
--- /dev/null
@@ -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
index 51b25e9c4ec7b66bdf4c68cc1353c6faf1ca7bb8..c87051e2b26f5a7fee0362697fae067076b8e84d 100644 (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);
 
index 959997fb0652fa43df9398615ccab8d063506681..981a21404f3207aa2579fa91f37dd3ace9151103 100644 (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;
+}
diff --git a/tools/testing/rbtree/Makefile b/tools/testing/rbtree/Makefile
new file mode 100644 (file)
index 0000000..bac6931
--- /dev/null
@@ -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/*
diff --git a/tools/testing/rbtree/interval_tree_test.c b/tools/testing/rbtree/interval_tree_test.c
new file mode 100644 (file)
index 0000000..f1c41f5
--- /dev/null
@@ -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;
+}
diff --git a/tools/testing/rbtree/rbtree_test.c b/tools/testing/rbtree/rbtree_test.c
new file mode 100644 (file)
index 0000000..c723e75
--- /dev/null
@@ -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;
+}
diff --git a/tools/testing/rbtree/test.h b/tools/testing/rbtree/test.h
new file mode 100644 (file)
index 0000000..f1f1b54
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+void rbtree_tests(void);
+void interval_tree_tests(void);
diff --git a/tools/testing/shared/interval_tree-shim.c b/tools/testing/shared/interval_tree-shim.c
new file mode 100644 (file)
index 0000000..122e747
--- /dev/null
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Very simple shim around the interval tree. */
+
+#include "../../../lib/interval_tree.c"
diff --git a/tools/testing/shared/linux/interval_tree.h b/tools/testing/shared/linux/interval_tree.h
new file mode 100644 (file)
index 0000000..129faf9
--- /dev/null
@@ -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 */
diff --git a/tools/testing/shared/linux/interval_tree_generic.h b/tools/testing/shared/linux/interval_tree_generic.h
new file mode 100644 (file)
index 0000000..34cd654
--- /dev/null
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include "../../../../include/linux/interval_tree_generic.h"
diff --git a/tools/testing/shared/linux/rbtree.h b/tools/testing/shared/linux/rbtree.h
new file mode 100644 (file)
index 0000000..d644bb7
--- /dev/null
@@ -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 */
diff --git a/tools/testing/shared/linux/rbtree_augmented.h b/tools/testing/shared/linux/rbtree_augmented.h
new file mode 100644 (file)
index 0000000..ad138fc
--- /dev/null
@@ -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 */
diff --git a/tools/testing/shared/linux/rbtree_types.h b/tools/testing/shared/linux/rbtree_types.h
new file mode 100644 (file)
index 0000000..194194a
--- /dev/null
@@ -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 */
+
diff --git a/tools/testing/shared/rbtree-shim.c b/tools/testing/shared/rbtree-shim.c
new file mode 100644 (file)
index 0000000..7692a99
--- /dev/null
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Very simple shim around the rbtree. */
+
+#include "../../../lib/rbtree.c"
+