diff options
| author | Matt Macy <mmacy@FreeBSD.org> | 2018-05-10 17:55:24 +0000 |
|---|---|---|
| committer | Matt Macy <mmacy@FreeBSD.org> | 2018-05-10 17:55:24 +0000 |
| commit | 06bf2a6aefbf98f0717954368a8791cd70bfba30 (patch) | |
| tree | 1da1c21da6bb2700c9d8dcf0a8eaebb5f492c38a /sys/tests | |
| parent | 137c41d763307e201d12dece785cebe729ae7d73 (diff) | |
Notes
Diffstat (limited to 'sys/tests')
| -rw-r--r-- | sys/tests/epoch/epoch_test.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/sys/tests/epoch/epoch_test.c b/sys/tests/epoch/epoch_test.c new file mode 100644 index 000000000000..8085183dc7a9 --- /dev/null +++ b/sys/tests/epoch/epoch_test.c @@ -0,0 +1,211 @@ +/*- + * Copyright (c) 2018, Matthew Macy <mmacy@freebsd.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Neither the name of Matthew Macy nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/counter.h> +#include <sys/epoch.h> +#include <sys/gtaskqueue.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/smp.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + + +struct epoch_test_instance { + int threadid; +}; + +static int inited; +static int iterations; +#define ET_EXITING 0x1 +static volatile int state_flags; +static struct mtx state_mtx __aligned(CACHE_LINE_SIZE*2); +MTX_SYSINIT(state_mtx, &state_mtx, "epoch state mutex", MTX_DEF); +static struct mtx mutexA __aligned(CACHE_LINE_SIZE*2); +MTX_SYSINIT(mutexA, &mutexA, "epoch mutexA", MTX_DEF); +static struct mtx mutexB __aligned(CACHE_LINE_SIZE*2); +MTX_SYSINIT(mutexB, &mutexB, "epoch mutexB", MTX_DEF); +epoch_t test_epoch; + +static void +epoch_testcase1(struct epoch_test_instance *eti) +{ + int i, startticks; + struct mtx *mtxp; + + startticks = ticks; + i = 0; + if (eti->threadid & 0x1) + mtxp = &mutexA; + else + mtxp = &mutexB; + + while (i < iterations) { + epoch_enter(test_epoch); + mtx_lock(mtxp); + i++; + mtx_unlock(mtxp); + epoch_exit(test_epoch); + epoch_wait(test_epoch); + } + printf("test1: thread: %d took %d ticks to complete %d iterations\n", + eti->threadid, ticks - startticks, iterations); +} + +static void +epoch_testcase2(struct epoch_test_instance *eti) +{ + int i, startticks; + struct mtx *mtxp; + + startticks = ticks; + i = 0; + mtxp = &mutexA; + + while (i < iterations) { + epoch_enter(test_epoch); + mtx_lock(mtxp); + DELAY(1); + i++; + mtx_unlock(mtxp); + epoch_exit(test_epoch); + epoch_wait(test_epoch); + } + printf("test2: thread: %d took %d ticks to complete %d iterations\n", + eti->threadid, ticks - startticks, iterations); +} + +static void +testloop(void *arg) { + + mtx_lock(&state_mtx); + while ((state_flags & ET_EXITING) == 0) { + msleep(&state_mtx, &state_mtx, 0, "epoch start wait", 0); + if (state_flags & ET_EXITING) + goto out; + mtx_unlock(&state_mtx); + epoch_testcase2(arg); + pause("W", 500); + epoch_testcase1(arg); + mtx_lock(&state_mtx); + } + out: + mtx_unlock(&state_mtx); + kthread_exit(); +} + +static struct thread *testthreads[MAXCPU]; +static struct epoch_test_instance etilist[MAXCPU]; + +static int +test_modinit(void) +{ + int i, error; + + test_epoch = epoch_alloc(); + for (i = 0; i < mp_ncpus; i++) { + etilist[i].threadid = i; + error = kthread_add(testloop, &etilist[i], NULL, &testthreads[i], + 0, 0, "epoch_test_%d", i); + if (error) { + printf("%s: kthread_add(epoch_test): error %d", __func__, + error); + } + } + inited = 1; + return (0); +} + +static int +epochtest_execute(SYSCTL_HANDLER_ARGS) +{ + int error, v; + + if (inited == 0) + return (ENOENT); + + v = 0; + error = sysctl_handle_int(oidp, &v, 0, req); + if (error) + return (error); + if (req->newptr == NULL) + return (error); + if (v == 0) + return (0); + mtx_lock(&state_mtx); + iterations = v; + wakeup(&state_mtx); + mtx_unlock(&state_mtx); + + return (0); +} + +SYSCTL_NODE(_kern, OID_AUTO, epochtest, CTLFLAG_RW, 0, "Epoch Test Framework"); +SYSCTL_PROC(_kern_epochtest, OID_AUTO, runtest, (CTLTYPE_INT | CTLFLAG_RW), + 0, 0, epochtest_execute, "I", "Execute an epoch test"); + +static int +epoch_test_module_event_handler(module_t mod, int what, void *arg __unused) +{ + int err; + + switch (what) { + case MOD_LOAD: + if ((err = test_modinit()) != 0) + return (err); + break; + case MOD_UNLOAD: + mtx_lock(&state_mtx); + state_flags = ET_EXITING; + wakeup(&state_mtx); + mtx_unlock(&state_mtx); + /* yes --- gross */ + pause("epoch unload", 3*hz); + break; + default: + return (EOPNOTSUPP); + } + + return (0); +} + +static moduledata_t epoch_test_moduledata = { + "epoch_test", + epoch_test_module_event_handler, + NULL +}; + +MODULE_VERSION(epoch_test, 1); +DECLARE_MODULE(epoch_test, epoch_test_moduledata, SI_SUB_PSEUDO, SI_ORDER_ANY); |
