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