1*06bf2a6aSMatt Macy /*- 2*06bf2a6aSMatt Macy * Copyright (c) 2018, Matthew Macy <mmacy@freebsd.org> 3*06bf2a6aSMatt Macy * 4*06bf2a6aSMatt Macy * Redistribution and use in source and binary forms, with or without 5*06bf2a6aSMatt Macy * modification, are permitted provided that the following conditions are met: 6*06bf2a6aSMatt Macy * 7*06bf2a6aSMatt Macy * 1. Redistributions of source code must retain the above copyright notice, 8*06bf2a6aSMatt Macy * this list of conditions and the following disclaimer. 9*06bf2a6aSMatt Macy * 10*06bf2a6aSMatt Macy * 2. Neither the name of Matthew Macy nor the names of its 11*06bf2a6aSMatt Macy * contributors may be used to endorse or promote products derived from 12*06bf2a6aSMatt Macy * this software without specific prior written permission. 13*06bf2a6aSMatt Macy * 14*06bf2a6aSMatt Macy * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15*06bf2a6aSMatt Macy * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*06bf2a6aSMatt Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*06bf2a6aSMatt Macy * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18*06bf2a6aSMatt Macy * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19*06bf2a6aSMatt Macy * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20*06bf2a6aSMatt Macy * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21*06bf2a6aSMatt Macy * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22*06bf2a6aSMatt Macy * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23*06bf2a6aSMatt Macy * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24*06bf2a6aSMatt Macy * POSSIBILITY OF SUCH DAMAGE. 25*06bf2a6aSMatt Macy */ 26*06bf2a6aSMatt Macy 27*06bf2a6aSMatt Macy #include <sys/cdefs.h> 28*06bf2a6aSMatt Macy __FBSDID("$FreeBSD$"); 29*06bf2a6aSMatt Macy 30*06bf2a6aSMatt Macy #include <sys/param.h> 31*06bf2a6aSMatt Macy #include <sys/types.h> 32*06bf2a6aSMatt Macy #include <sys/counter.h> 33*06bf2a6aSMatt Macy #include <sys/epoch.h> 34*06bf2a6aSMatt Macy #include <sys/gtaskqueue.h> 35*06bf2a6aSMatt Macy #include <sys/kernel.h> 36*06bf2a6aSMatt Macy #include <sys/kthread.h> 37*06bf2a6aSMatt Macy #include <sys/lock.h> 38*06bf2a6aSMatt Macy #include <sys/malloc.h> 39*06bf2a6aSMatt Macy #include <sys/module.h> 40*06bf2a6aSMatt Macy #include <sys/mutex.h> 41*06bf2a6aSMatt Macy #include <sys/smp.h> 42*06bf2a6aSMatt Macy #include <sys/sysctl.h> 43*06bf2a6aSMatt Macy #include <sys/systm.h> 44*06bf2a6aSMatt Macy 45*06bf2a6aSMatt Macy 46*06bf2a6aSMatt Macy struct epoch_test_instance { 47*06bf2a6aSMatt Macy int threadid; 48*06bf2a6aSMatt Macy }; 49*06bf2a6aSMatt Macy 50*06bf2a6aSMatt Macy static int inited; 51*06bf2a6aSMatt Macy static int iterations; 52*06bf2a6aSMatt Macy #define ET_EXITING 0x1 53*06bf2a6aSMatt Macy static volatile int state_flags; 54*06bf2a6aSMatt Macy static struct mtx state_mtx __aligned(CACHE_LINE_SIZE*2); 55*06bf2a6aSMatt Macy MTX_SYSINIT(state_mtx, &state_mtx, "epoch state mutex", MTX_DEF); 56*06bf2a6aSMatt Macy static struct mtx mutexA __aligned(CACHE_LINE_SIZE*2); 57*06bf2a6aSMatt Macy MTX_SYSINIT(mutexA, &mutexA, "epoch mutexA", MTX_DEF); 58*06bf2a6aSMatt Macy static struct mtx mutexB __aligned(CACHE_LINE_SIZE*2); 59*06bf2a6aSMatt Macy MTX_SYSINIT(mutexB, &mutexB, "epoch mutexB", MTX_DEF); 60*06bf2a6aSMatt Macy epoch_t test_epoch; 61*06bf2a6aSMatt Macy 62*06bf2a6aSMatt Macy static void 63*06bf2a6aSMatt Macy epoch_testcase1(struct epoch_test_instance *eti) 64*06bf2a6aSMatt Macy { 65*06bf2a6aSMatt Macy int i, startticks; 66*06bf2a6aSMatt Macy struct mtx *mtxp; 67*06bf2a6aSMatt Macy 68*06bf2a6aSMatt Macy startticks = ticks; 69*06bf2a6aSMatt Macy i = 0; 70*06bf2a6aSMatt Macy if (eti->threadid & 0x1) 71*06bf2a6aSMatt Macy mtxp = &mutexA; 72*06bf2a6aSMatt Macy else 73*06bf2a6aSMatt Macy mtxp = &mutexB; 74*06bf2a6aSMatt Macy 75*06bf2a6aSMatt Macy while (i < iterations) { 76*06bf2a6aSMatt Macy epoch_enter(test_epoch); 77*06bf2a6aSMatt Macy mtx_lock(mtxp); 78*06bf2a6aSMatt Macy i++; 79*06bf2a6aSMatt Macy mtx_unlock(mtxp); 80*06bf2a6aSMatt Macy epoch_exit(test_epoch); 81*06bf2a6aSMatt Macy epoch_wait(test_epoch); 82*06bf2a6aSMatt Macy } 83*06bf2a6aSMatt Macy printf("test1: thread: %d took %d ticks to complete %d iterations\n", 84*06bf2a6aSMatt Macy eti->threadid, ticks - startticks, iterations); 85*06bf2a6aSMatt Macy } 86*06bf2a6aSMatt Macy 87*06bf2a6aSMatt Macy static void 88*06bf2a6aSMatt Macy epoch_testcase2(struct epoch_test_instance *eti) 89*06bf2a6aSMatt Macy { 90*06bf2a6aSMatt Macy int i, startticks; 91*06bf2a6aSMatt Macy struct mtx *mtxp; 92*06bf2a6aSMatt Macy 93*06bf2a6aSMatt Macy startticks = ticks; 94*06bf2a6aSMatt Macy i = 0; 95*06bf2a6aSMatt Macy mtxp = &mutexA; 96*06bf2a6aSMatt Macy 97*06bf2a6aSMatt Macy while (i < iterations) { 98*06bf2a6aSMatt Macy epoch_enter(test_epoch); 99*06bf2a6aSMatt Macy mtx_lock(mtxp); 100*06bf2a6aSMatt Macy DELAY(1); 101*06bf2a6aSMatt Macy i++; 102*06bf2a6aSMatt Macy mtx_unlock(mtxp); 103*06bf2a6aSMatt Macy epoch_exit(test_epoch); 104*06bf2a6aSMatt Macy epoch_wait(test_epoch); 105*06bf2a6aSMatt Macy } 106*06bf2a6aSMatt Macy printf("test2: thread: %d took %d ticks to complete %d iterations\n", 107*06bf2a6aSMatt Macy eti->threadid, ticks - startticks, iterations); 108*06bf2a6aSMatt Macy } 109*06bf2a6aSMatt Macy 110*06bf2a6aSMatt Macy static void 111*06bf2a6aSMatt Macy testloop(void *arg) { 112*06bf2a6aSMatt Macy 113*06bf2a6aSMatt Macy mtx_lock(&state_mtx); 114*06bf2a6aSMatt Macy while ((state_flags & ET_EXITING) == 0) { 115*06bf2a6aSMatt Macy msleep(&state_mtx, &state_mtx, 0, "epoch start wait", 0); 116*06bf2a6aSMatt Macy if (state_flags & ET_EXITING) 117*06bf2a6aSMatt Macy goto out; 118*06bf2a6aSMatt Macy mtx_unlock(&state_mtx); 119*06bf2a6aSMatt Macy epoch_testcase2(arg); 120*06bf2a6aSMatt Macy pause("W", 500); 121*06bf2a6aSMatt Macy epoch_testcase1(arg); 122*06bf2a6aSMatt Macy mtx_lock(&state_mtx); 123*06bf2a6aSMatt Macy } 124*06bf2a6aSMatt Macy out: 125*06bf2a6aSMatt Macy mtx_unlock(&state_mtx); 126*06bf2a6aSMatt Macy kthread_exit(); 127*06bf2a6aSMatt Macy } 128*06bf2a6aSMatt Macy 129*06bf2a6aSMatt Macy static struct thread *testthreads[MAXCPU]; 130*06bf2a6aSMatt Macy static struct epoch_test_instance etilist[MAXCPU]; 131*06bf2a6aSMatt Macy 132*06bf2a6aSMatt Macy static int 133*06bf2a6aSMatt Macy test_modinit(void) 134*06bf2a6aSMatt Macy { 135*06bf2a6aSMatt Macy int i, error; 136*06bf2a6aSMatt Macy 137*06bf2a6aSMatt Macy test_epoch = epoch_alloc(); 138*06bf2a6aSMatt Macy for (i = 0; i < mp_ncpus; i++) { 139*06bf2a6aSMatt Macy etilist[i].threadid = i; 140*06bf2a6aSMatt Macy error = kthread_add(testloop, &etilist[i], NULL, &testthreads[i], 141*06bf2a6aSMatt Macy 0, 0, "epoch_test_%d", i); 142*06bf2a6aSMatt Macy if (error) { 143*06bf2a6aSMatt Macy printf("%s: kthread_add(epoch_test): error %d", __func__, 144*06bf2a6aSMatt Macy error); 145*06bf2a6aSMatt Macy } 146*06bf2a6aSMatt Macy } 147*06bf2a6aSMatt Macy inited = 1; 148*06bf2a6aSMatt Macy return (0); 149*06bf2a6aSMatt Macy } 150*06bf2a6aSMatt Macy 151*06bf2a6aSMatt Macy static int 152*06bf2a6aSMatt Macy epochtest_execute(SYSCTL_HANDLER_ARGS) 153*06bf2a6aSMatt Macy { 154*06bf2a6aSMatt Macy int error, v; 155*06bf2a6aSMatt Macy 156*06bf2a6aSMatt Macy if (inited == 0) 157*06bf2a6aSMatt Macy return (ENOENT); 158*06bf2a6aSMatt Macy 159*06bf2a6aSMatt Macy v = 0; 160*06bf2a6aSMatt Macy error = sysctl_handle_int(oidp, &v, 0, req); 161*06bf2a6aSMatt Macy if (error) 162*06bf2a6aSMatt Macy return (error); 163*06bf2a6aSMatt Macy if (req->newptr == NULL) 164*06bf2a6aSMatt Macy return (error); 165*06bf2a6aSMatt Macy if (v == 0) 166*06bf2a6aSMatt Macy return (0); 167*06bf2a6aSMatt Macy mtx_lock(&state_mtx); 168*06bf2a6aSMatt Macy iterations = v; 169*06bf2a6aSMatt Macy wakeup(&state_mtx); 170*06bf2a6aSMatt Macy mtx_unlock(&state_mtx); 171*06bf2a6aSMatt Macy 172*06bf2a6aSMatt Macy return (0); 173*06bf2a6aSMatt Macy } 174*06bf2a6aSMatt Macy 175*06bf2a6aSMatt Macy SYSCTL_NODE(_kern, OID_AUTO, epochtest, CTLFLAG_RW, 0, "Epoch Test Framework"); 176*06bf2a6aSMatt Macy SYSCTL_PROC(_kern_epochtest, OID_AUTO, runtest, (CTLTYPE_INT | CTLFLAG_RW), 177*06bf2a6aSMatt Macy 0, 0, epochtest_execute, "I", "Execute an epoch test"); 178*06bf2a6aSMatt Macy 179*06bf2a6aSMatt Macy static int 180*06bf2a6aSMatt Macy epoch_test_module_event_handler(module_t mod, int what, void *arg __unused) 181*06bf2a6aSMatt Macy { 182*06bf2a6aSMatt Macy int err; 183*06bf2a6aSMatt Macy 184*06bf2a6aSMatt Macy switch (what) { 185*06bf2a6aSMatt Macy case MOD_LOAD: 186*06bf2a6aSMatt Macy if ((err = test_modinit()) != 0) 187*06bf2a6aSMatt Macy return (err); 188*06bf2a6aSMatt Macy break; 189*06bf2a6aSMatt Macy case MOD_UNLOAD: 190*06bf2a6aSMatt Macy mtx_lock(&state_mtx); 191*06bf2a6aSMatt Macy state_flags = ET_EXITING; 192*06bf2a6aSMatt Macy wakeup(&state_mtx); 193*06bf2a6aSMatt Macy mtx_unlock(&state_mtx); 194*06bf2a6aSMatt Macy /* yes --- gross */ 195*06bf2a6aSMatt Macy pause("epoch unload", 3*hz); 196*06bf2a6aSMatt Macy break; 197*06bf2a6aSMatt Macy default: 198*06bf2a6aSMatt Macy return (EOPNOTSUPP); 199*06bf2a6aSMatt Macy } 200*06bf2a6aSMatt Macy 201*06bf2a6aSMatt Macy return (0); 202*06bf2a6aSMatt Macy } 203*06bf2a6aSMatt Macy 204*06bf2a6aSMatt Macy static moduledata_t epoch_test_moduledata = { 205*06bf2a6aSMatt Macy "epoch_test", 206*06bf2a6aSMatt Macy epoch_test_module_event_handler, 207*06bf2a6aSMatt Macy NULL 208*06bf2a6aSMatt Macy }; 209*06bf2a6aSMatt Macy 210*06bf2a6aSMatt Macy MODULE_VERSION(epoch_test, 1); 211*06bf2a6aSMatt Macy DECLARE_MODULE(epoch_test, epoch_test_moduledata, SI_SUB_PSEUDO, SI_ORDER_ANY); 212