2 * Copyright (c) 2018, Matthew Macy <mmacy@freebsd.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
10 * 2. Neither the name of Matthew Macy nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/counter.h>
33 #include <sys/epoch.h>
34 #include <sys/gtaskqueue.h>
35 #include <sys/kernel.h>
36 #include <sys/kthread.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
42 #include <sys/sched.h>
44 #include <sys/sysctl.h>
45 #include <sys/systm.h>
48 struct epoch_test_instance {
53 static int iterations;
54 #define ET_EXITING 0x1
55 static volatile int state_flags;
56 static struct mtx state_mtx __aligned(CACHE_LINE_SIZE*2);
57 MTX_SYSINIT(state_mtx, &state_mtx, "epoch state mutex", MTX_DEF);
58 static struct mtx mutexA __aligned(CACHE_LINE_SIZE*2);
59 MTX_SYSINIT(mutexA, &mutexA, "epoch mutexA", MTX_DEF);
60 static struct mtx mutexB __aligned(CACHE_LINE_SIZE*2);
61 MTX_SYSINIT(mutexB, &mutexB, "epoch mutexB", MTX_DEF);
65 epoch_testcase1(struct epoch_test_instance *eti)
72 if (eti->threadid & 0x1)
77 while (i < iterations) {
78 epoch_enter(test_epoch);
82 epoch_exit(test_epoch);
83 epoch_wait(test_epoch);
85 printf("test1: thread: %d took %d ticks to complete %d iterations\n",
86 eti->threadid, ticks - startticks, iterations);
90 epoch_testcase2(struct epoch_test_instance *eti)
99 while (i < iterations) {
100 epoch_enter(test_epoch);
105 epoch_exit(test_epoch);
106 epoch_wait(test_epoch);
108 printf("test2: thread: %d took %d ticks to complete %d iterations\n",
109 eti->threadid, ticks - startticks, iterations);
113 testloop(void *arg) {
115 mtx_lock(&state_mtx);
116 while ((state_flags & ET_EXITING) == 0) {
117 msleep(&state_mtx, &state_mtx, 0, "epoch start wait", 0);
118 if (state_flags & ET_EXITING)
120 mtx_unlock(&state_mtx);
121 epoch_testcase2(arg);
123 epoch_testcase1(arg);
124 mtx_lock(&state_mtx);
127 mtx_unlock(&state_mtx);
131 static struct thread *testthreads[MAXCPU];
132 static struct epoch_test_instance etilist[MAXCPU];
138 int i, error, pri_range, pri_off;
140 pri_range = PRI_MIN_TIMESHARE - PRI_MIN_REALTIME;
141 test_epoch = epoch_alloc();
142 for (i = 0; i < mp_ncpus*2; i++) {
143 etilist[i].threadid = i;
144 error = kthread_add(testloop, &etilist[i], NULL, &testthreads[i],
145 0, 0, "epoch_test_%d", i);
147 printf("%s: kthread_add(epoch_test): error %d", __func__,
150 pri_off = (i*4)%pri_range;
153 sched_prio(td, PRI_MIN_REALTIME + pri_off);
162 epochtest_execute(SYSCTL_HANDLER_ARGS)
170 error = sysctl_handle_int(oidp, &v, 0, req);
173 if (req->newptr == NULL)
177 mtx_lock(&state_mtx);
180 mtx_unlock(&state_mtx);
185 SYSCTL_NODE(_kern, OID_AUTO, epochtest, CTLFLAG_RW, 0, "Epoch Test Framework");
186 SYSCTL_PROC(_kern_epochtest, OID_AUTO, runtest, (CTLTYPE_INT | CTLFLAG_RW),
187 0, 0, epochtest_execute, "I", "Execute an epoch test");
190 epoch_test_module_event_handler(module_t mod, int what, void *arg __unused)
196 if ((err = test_modinit()) != 0)
200 mtx_lock(&state_mtx);
201 state_flags = ET_EXITING;
203 mtx_unlock(&state_mtx);
205 pause("epoch unload", 3*hz);
214 static moduledata_t epoch_test_moduledata = {
216 epoch_test_module_event_handler,
220 MODULE_VERSION(epoch_test, 1);
221 DECLARE_MODULE(epoch_test, epoch_test_moduledata, SI_SUB_PSEUDO, SI_ORDER_ANY);