xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_selftest.h (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 
13 /*
14  * Copyright (c) 2026 by Garth Snyder. All rights reserved.
15  */
16 
17 #ifndef	_ZSTREAM_SELFTEST_H
18 #define	_ZSTREAM_SELFTEST_H
19 
20 #ifdef	__cplusplus
21 extern "C" {
22 #endif
23 
24 #include <stdint.h>
25 
26 /*
27  * Shared harness for "zstream selftest". Each module under test supplies a
28  * NULL-terminated array of named test cases. The harness in
29  * zstream_selftest.c handles argument parsing, test selection, seeding of
30  * pseudo-random number generators, watchdog timeouts, and status output.
31  *
32  * Test cases report failure by exiting with a nonzero exit code. Any test
33  * case that returns has passed.
34  */
35 
36 typedef void test_function_f(void);
37 
38 typedef struct {
39 	const char	*tc_name;
40 	test_function_f	*tc_func;
41 } test_case_t;
42 
43 /*
44  * Modules with test cases to offer. Each array ends with a NULL tc_name.
45  */
46 extern const test_case_t selftest_queue_cases[];
47 
48 /*
49  * The seed for this run, set by the harness before any test runs. Printed
50  * at startup and settable with -s so failures can be replayed.
51  */
52 extern uint64_t selftest_seed;
53 
54 /*
55  * A small deterministic PRNG (splitmix64). Tests derive per-thread
56  * generators from selftest_seed plus a caller-chosen stream number, so
57  * workloads are reproducible for a given seed regardless of scheduling.
58  */
59 typedef struct {
60 	uint64_t	sr_state;
61 } selftest_rng_t;
62 
63 static inline uint64_t
selftest_mix64(uint64_t z)64 selftest_mix64(uint64_t z)
65 {
66 	z += 0x9e3779b97f4a7c15ULL;
67 	z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
68 	z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
69 	return (z ^ (z >> 31));
70 }
71 
72 static inline void
selftest_rng_init(selftest_rng_t * rng,uint64_t stream)73 selftest_rng_init(selftest_rng_t *rng, uint64_t stream)
74 {
75 	rng->sr_state = selftest_seed ^ selftest_mix64(stream);
76 }
77 
78 static inline uint64_t
selftest_rng_next(selftest_rng_t * rng)79 selftest_rng_next(selftest_rng_t *rng)
80 {
81 	rng->sr_state += 0x9e3779b97f4a7c15ULL;
82 	return (selftest_mix64(rng->sr_state));
83 }
84 
85 /* Uniform value in [0, bound); returns 0 if bound is 0 */
86 static inline uint64_t
selftest_rng_below(selftest_rng_t * rng,uint64_t bound)87 selftest_rng_below(selftest_rng_t *rng, uint64_t bound)
88 {
89 	return (bound ? selftest_rng_next(rng) % bound : 0);
90 }
91 
92 #ifdef	__cplusplus
93 }
94 #endif
95 
96 #endif	/* _ZSTREAM_SELFTEST_H */
97