xref: /freebsd/share/man/man9/kern_testfrwk.9 (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
1.\"
2.\" Copyright (c) 2015 Netflix, Inc.
3.\"
4.\" Redistribution and use in source and binary forms, with or without
5.\" modification, are permitted provided that the following conditions
6.\" are met:
7.\" 1. Redistributions of source code must retain the above copyright
8.\"    notice, this list of conditions and the following disclaimer.
9.\" 2. Redistributions in binary form must reproduce the above copyright
10.\"    notice, this list of conditions and the following disclaimer in the
11.\"    documentation and/or other materials provided with the distribution.
12.\"
13.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
14.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
17.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23.\"
24.Dd November 12, 2015
25.Dt KERN_TESTFRWK 9
26.Os
27.Sh NAME
28.Nm kern_testfrwk
29.Nd A kernel testing framework
30.Sh SYNOPSIS
31kldload kern_testfrwk
32.Sh DESCRIPTION
33.\" This whole section is not written in manual page style and should be ripped
34.\" out and replaced. -CEM
35So what is this sys/tests directory in the kernel all about?
36.Pp
37Have you ever wanted to test a part of the
38.Fx
39kernel in some way and you
40had no real way from user-land to make what you want to occur happen?
41Say an error path or situation where locking occurs in a particular manner that
42happens only once in a blue moon?
43.Pp
44If so, then the kernel test framework is just what you are looking for.
45It is designed to help you create the situation you want.
46.Pp
47There are two components to the system: the test framework and your test.
48This document will describe both components and use the test submitted with the
49initial commit of this code to discuss the test
50.Xr ( callout_test 4 ) .
51All of the tests become kernel loadable modules.
52The test you write should have a dependency on the test framework.
53That way it will be loaded automatically with your test.
54For example, you can see how to do this in the bottom of callout_test.c in
55.Pa sys/tests/callout_test/callout_test.c .
56.Pp
57The framework itself is in
58.Pa sys/tests/framework/kern_testfrwk.c .
59Its job is to manage the tests that are loaded.
60(More than one can be loaded.)
61The idea is pretty simple; you load the test framework and then load your test.
62.Pp
63When your test loads, you register your tests with the kernel test framework.
64You do that through a call to
65.Fn kern_testframework_register .
66Usually this is done at the module load event as shown below:
67.Bd -literal -offset indent
68	switch (type) {
69	case MOD_LOAD:
70		err = kern_testframework_register("callout_test",
71		    run_callout_test);
72.Ed
73.Pp
74Here the test is "callout_test" and it is registered to run the function
75.Fn run_callout_test
76passing it a
77.Fa struct kern_test *ptr .
78The
79.Vt kern_test
80structure is defined in
81.Pa kern_testfrwk.h .
82.Bd -literal -offset indent
83struct kern_test {
84	char name[TEST_NAME_LEN];
85	int num_threads;  /* Fill in how many threads you want */
86	int tot_threads_running;       /* Private to framework */
87	uint8_t test_options[TEST_OPTION_SPACE];
88};
89.Ed
90.Pp
91The user sends this structure down via a sysctl to start your test.
92He or she places the same name you registered ("callout_test"
93in our example) in the
94.Va name
95field.
96The user can also set the number of threads to run with
97.Va num_threads .
98.Pp
99The framework will start the requested number of kernel threads, all running
100your test at the same time.
101The user does not specify anything in
102.Va tot_threads_running ;
103it is private to the framework.
104As the framework calls each of your tests, it will set the
105.Va tot_threads_running
106to the index of the thread that your call is made from.
107For example, if the user sets
108.Va num_threads
109to 2, then the function
110.Fn run_callout_test
111will be called once with
112.Va tot_threads_running
113to 0, and a second time with
114.Va tot_threads_running
115set to 1.
116.Pp
117The
118.Va test_options
119field is a test-specific set of information that is an opaque blob.
120It is passed in from user space and has a maximum size of 256 bytes.
121You can pass arbitrary test input in the space.
122In the case of callout_test we reshape that to:
123.Bd -literal -offset indent
124struct callout_test {
125	int number_of_callouts;
126	int test_number;
127};
128.Ed
129.Pp
130So the first lines of
131.Fn run_callout_test
132does the following to get at the user specific data:
133.\" This is a bad example and violates strict aliasing.  It should be replaced.
134.Bd -literal -offset indent
135	struct callout_test *u;
136	size_t sz;
137	int i;
138	struct callout_run *rn;
139	int index = test->tot_threads_running;
140
141	u = (struct callout_test *)test->test_options;
142.Ed
143.Pp
144That way it can access:
145.Va u->test_number
146(there are two types of tests provided with this test)
147and
148.Va u->number_of_callouts
149(how many simultaneous callouts to run).
150.Pp
151Your test can do anything with these bytes.
152So the callout_test in question wants to create a situation where multiple
153callouts are all run, that is the
154.Va number_of_callouts ,
155and it tries to cancel the callout with the new
156.Fn callout_async_drain .
157The threads do this by acquiring the lock in question, and then
158starting each of the callouts.
159It waits for the callouts to all go off (the executor spins waits).
160This forces the situation that the callouts have expired and are all waiting on
161the lock that the executor holds.
162After the callouts are all blocked, the executor calls
163.Fn callout_async_drain
164on each callout and releases the lock.
165.Pp
166.\" callout_test(4) specific documentation should probably be moved to its own
167.\" page.
168After all the callouts are done, a total status is printed
169showing the results via
170.Xr printf 9 .
171The human tester can run
172.Xr dmesg 8
173to see the results.
174In this case it is expected that if you are running test 0, all the callouts
175expire on the same CPU so only one callout_drain function would have been
176called.
177the number of zero_returns should match the number of callout_drains that were
178called, i.e., 1.
179The one_returns should be the remainder of the callouts.
180If the test number was 1, the callouts were spread across all CPUs.
181The number of zero_returns will again match the number of drain calls made
182which matches the number of CPUs that were put in use.
183.Pp
184More than one thread can be used with this test, though in the example case it
185is probably not necessary.
186.Pp
187You should not need to change the framework.
188Just add tests and register them after loading.
189.Sh AUTHORS
190The kernel test framework was written by
191.An Randall Stewart Aq Mt rrs@FreeBSD.org
192with help from
193.An John Mark Gurney Aq Mt jmg@FreeBSD.org .
194