Date: Wed, 17 Mar 2010 07:08:57 +0000 (UTC) From: Lawrence Stewart <lstewart@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r205243 - in user/lstewart/alq_varlen_head/tools/test: . alq Message-ID: <201003170708.o2H78vC6029861@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: lstewart Date: Wed Mar 17 07:08:57 2010 New Revision: 205243 URL: http://svn.freebsd.org/changeset/base/205243 Log: Commit ALQ testing code. Sponsored by: FreeBSD Foundation Added: user/lstewart/alq_varlen_head/tools/test/alq/ user/lstewart/alq_varlen_head/tools/test/alq/Makefile (contents, props changed) user/lstewart/alq_varlen_head/tools/test/alq/alq_varlen_test.c (contents, props changed) Modified: user/lstewart/alq_varlen_head/tools/test/README Modified: user/lstewart/alq_varlen_head/tools/test/README ============================================================================== --- user/lstewart/alq_varlen_head/tools/test/README Wed Mar 17 06:41:10 2010 (r205242) +++ user/lstewart/alq_varlen_head/tools/test/README Wed Mar 17 07:08:57 2010 (r205243) @@ -7,6 +7,7 @@ and try to break it and/or measuring per Please make a subdir per program, and add a brief description to this file. +alq A kernel module to put ALQ(9) through its paces. devrandom Programs to test /dev/*random. dtrace DTrace test suite malloc A program to test and benchmark malloc(). Added: user/lstewart/alq_varlen_head/tools/test/alq/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/lstewart/alq_varlen_head/tools/test/alq/Makefile Wed Mar 17 07:08:57 2010 (r205243) @@ -0,0 +1,17 @@ +# $FreeBSD$ + +.include <bsd.own.mk> + +KMOD=alqtest +SRCS=alq_varlen_test.c alq_varlen_test.h +CLEANFILES=alq_varlen_test.h + +alq_varlen_test.h: + @awk -F "\n" '{ if(index($$0, "struct alq {") > 0) p=1; if(p == 1) { print $$0; if($$0 == "};") exit; } }' ${.CURDIR}/../../../sys/kern/kern_alq.c >> ${.TARGET} + grep "#define AQ_" ${.CURDIR}/../../../sys/kern/kern_alq.c >> ${.TARGET} + +#KMOD=alqmodtest +#SRCS=alq_mod_test.c + +.include <bsd.kmod.mk> + Added: user/lstewart/alq_varlen_head/tools/test/alq/alq_varlen_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/lstewart/alq_varlen_head/tools/test/alq/alq_varlen_test.c Wed Mar 17 07:08:57 2010 (r205243) @@ -0,0 +1,536 @@ +/*- + * Copyright (c) 2008-2009 Lawrence Stewart <lstewart@freebsd.org> + * Copyright (c) 2009-2010, The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed at the Centre for Advanced + * Internet Architectures, Swinburne University of Technology, Melbourne, + * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. + * + * 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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/param.h> +#include <sys/alq.h> +#include <sys/errno.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/module.h> +#include <sys/proc.h> +#include <sys/sbuf.h> +#include <sys/systm.h> +#include <sys/unistd.h> + +#include <machine/stdarg.h> + +#include "alq_varlen_test.h" + +MALLOC_DECLARE(M_ALQTEST); +MALLOC_DEFINE(M_ALQTEST, "alqtest", "dynamic memory used by alqtest"); + +#define ENABLE 0x01 +#define DISABLE 0x02 + +#define NUM_TEST_RUNS 1 + +static volatile uint8_t run_test_thread; + +static char logfile[PATH_MAX] = "/tmp/alqtest.log"; + +static struct thread *alq_test_thr = NULL; + +static struct mtx alqtestmtx; + +typedef int (*testfunc)(struct sbuf *, struct sbuf *); + +struct writen_thr_data { + char name[20]; + struct mtx dlock; + struct alq *q; + u_int id; + struct thread *thr; + volatile u_int finished; + char *buf; + u_int buflen; + u_int nwrites; +}; + +typedef const enum { + BLACK = 30, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + WHITE +} fgcolor_t; + +static int +alqtest_printf(struct sbuf *s, fgcolor_t c, const char *fmt, ...) +{ + int ret; + va_list ap1, ap2; + + va_start(ap1, fmt); + va_copy(ap2, ap1); + + printf("\033[%dm", c); + vprintf(fmt, ap1); + printf("\033[0m"); + + sbuf_printf(s, "\033[%dm", c); + ret = sbuf_vprintf(s, fmt, ap2); + sbuf_printf(s, "\033[0m"); + + va_end(ap2); + va_end(ap1); + + return (ret); +} + +static char +alqtest_randchar(void) +{ + uint32_t c; + + /* generate a random character in the ascii range [32, 126] */ + while ((c = arc4random() % 126) < 32); + + return ((char)c); +} + +static uint32_t +alqtest_rand(uint32_t lower, uint32_t upper) +{ + uint32_t n; + + while ((n = arc4random() % (upper+1)) < lower); + + return (n); +} + +/*static void +alqtest_doio_callback(void) +{ + printf("doing io baby!\n"); +}*/ + +static void +alqtest_writen_thread(void *arg) +{ + uint32_t n, i; + + struct writen_thr_data *data = (struct writen_thr_data *)arg; + printf("tid %d id %d started\n", data->thr->td_tid, data->id); + + for (i = 0; i < data->nwrites; i++) { + n = alqtest_rand(1, data->buflen); + //sbuf_printf(s, "--- msg==%d,msglen==%d\n", i, n); + //printf("--- thread==%d,msg==%d,msglen==%d\n", data->id, i, n); + alq_writen(data->q, data->buf, n, ALQ_WAITOK); + } + + mtx_lock(&data->dlock); + data->finished = 1; + mtx_unlock(&data->dlock); + kthread_exit(); +} + +static int +alqtest_writen(struct sbuf *s, struct sbuf *debug) +{ +#define NMSGS 10000 +#define MAX_THREADS 50 + struct alq *testalq; + const int buflen = 100; + int i, n, ret, errors, nthreads, threadsactive, nsecs; + char buf[buflen+1]; + struct writen_thr_data *thrdata[MAX_THREADS]; + ret = errors = 0; + nthreads = 1; + + for (i = 0; i < MAX_THREADS; i++) { + thrdata[i] = malloc(sizeof(struct writen_thr_data), M_ALQTEST, + M_WAITOK|M_ZERO); + sprintf(thrdata[i]->name, "writen_thr_data_%d", i); + mtx_init(&thrdata[i]->dlock, thrdata[i]->name, NULL, MTX_DEF); + } + + alqtest_printf(s, 0, "- variable length message writing\n"); + + /* test variable length message writing */ + ret = alq_open_flags(&testalq, logfile, curthread->td_ucred, 0600, buflen, + 0, ALQ_ORDERED); + + /*testalq->doio_debugcallback = &alqtest_doio_callback;*/ + + for (i = 0; i < sizeof(buf); i++) + buf[i] = alqtest_randchar(); + + alqtest_printf(s, 0, "-- nthreads==1,nmsgs==1,msglen==1,buflen=%d," + "flags==ALQ_WAITOK|ALQ_NOACTIVATE\n", buflen); + alq_writen(testalq, buf, 1, ALQ_WAITOK|ALQ_NOACTIVATE); + + if ((buflen-1 != testalq->aq_freebytes) && + (1 != testalq->aq_writehead) && + (0 != testalq->aq_writetail)) { + errors++; + sbuf_printf(debug, + "alq->%-15s\texpected=%d\tactual=%d\n", "aq_freebytes", + buflen-1, testalq->aq_freebytes); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 1, testalq->aq_writehead); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + + alq_flush(testalq); + + if ((buflen != testalq->aq_freebytes) && + (0 != testalq->aq_writehead) && + (0 != testalq->aq_writetail)) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_freebytes", buflen, testalq->aq_freebytes); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 0, testalq->aq_writehead); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + + alqtest_printf(s, 0, "-- nthreads==1,nmsgs==1,msglen==%d,buflen=%d,flags==ALQ_WAITOK|ALQ_NOACTIVATE\n", buflen, buflen); + alq_writen(testalq, buf, buflen, ALQ_WAITOK | ALQ_NOACTIVATE); + + if ((0 != testalq->aq_freebytes) && + (0 != testalq->aq_writehead) && + (0 != testalq->aq_writetail)) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_freebytes", 0, testalq->aq_freebytes); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 0, testalq->aq_writehead); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + + alq_flush(testalq); + + if ((buflen != testalq->aq_freebytes) && + (0 != testalq->aq_writehead) && + (0 != testalq->aq_writetail)) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_freebytes", buflen, testalq->aq_freebytes); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 0, testalq->aq_writehead); + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + + alqtest_printf(s, 0, "-- nthreads==1,nmsgs==%d,buflen=%d,msglen==[1,%d]," + "flags==ALQ_WAITOK|ALQ_NOACTIVATE\n", NMSGS, buflen, buflen); + + for (i = 0; i < NMSGS; i++) { + n = alqtest_rand(1, buflen); + sbuf_printf(debug, "--- msg==%d,msglen==%d\n", i, n); + alq_writen(testalq, buf, n, ALQ_WAITOK|ALQ_NOACTIVATE); + + alq_flush(testalq); + + if ((buflen != testalq->aq_freebytes) && + (0 != testalq->aq_writehead) && + (0 != testalq->aq_writetail)) { + errors++; + sbuf_printf(debug, + "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_freebytes", buflen, testalq->aq_freebytes); + sbuf_printf(debug, + "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 0, testalq->aq_writehead); + sbuf_printf(debug, + "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + } + + alqtest_printf(s, 0, + "-- nthreads==1,nmsgs==%d,buflen=%d,msglen==[1,%d],flags==ALQ_WAITOK\n", + NMSGS, buflen, buflen); + + for (i = 0; i < NMSGS; i++) { + n = alqtest_rand(1, buflen); + sbuf_printf(s, "--- msg==%d,msglen==%d\n", i, n); + alq_writen(testalq, buf, n, ALQ_WAITOK); + } + + alq_flush(testalq); + + nthreads = 5; + threadsactive = 0; + alqtest_printf(s, 0, + "-- nthreads=%d,nmsgs==%d,buflen=%d,msglen==[1,%d],flags==ALQ_WAITOK\n", + nthreads, NMSGS, buflen, buflen); + for (i = 0; i < nthreads; i++) { + thrdata[i]->q = testalq; + thrdata[i]->id = i; + thrdata[i]->finished = 0; + thrdata[i]->buf = buf; + thrdata[i]->buflen = buflen; + thrdata[i]->nwrites = NMSGS; + kthread_add(&alqtest_writen_thread, thrdata[i], NULL, + &thrdata[i]->thr, RFNOWAIT, 0, thrdata[i]->name); + threadsactive++; + } + + nsecs = 0; + while (threadsactive) { + //printf("threadsactive: %d\n", threadsactive); + for (i = 0; i < nthreads; i++) { + mtx_lock(&thrdata[i]->dlock); + if (thrdata[i]->thr != NULL && + thrdata[i]->finished) { + printf("tid %d id %d finished\n", + thrdata[i]->thr->td_tid, thrdata[i]->id); + threadsactive--; + thrdata[i]->thr = NULL; + } + mtx_unlock(&thrdata[i]->dlock); + } + pause("alqtest", hz); + nsecs++; + + if (nsecs > 20) { + printf("It is likely that a bug has stalled one or more " + "of the writing threads. Calling alq_flush() to see if " + "we can loosen things up\n"); + alq_flush(testalq); + + if (nsecs > 22) { + printf("Also trying wakeup_one(&aq_waiters) and" + "wakeup_one(alq)\n"); + wakeup_one(&testalq->aq_waiters); + wakeup_one(testalq); + nsecs = 0; + } + } + } + + /* Cleanup. */ + alq_close(testalq); + for (i = 0; i < MAX_THREADS; i++) { + mtx_destroy(&thrdata[i]->dlock); + free(thrdata[i], M_ALQTEST); + } + + return (errors); +} + +static int +alqtest_open(struct sbuf *s, struct sbuf *debug) +{ + struct alq *testalq; + const int buflen = 100; + int ret = 0, errors = 0; + + alqtest_printf(s, 0, "- variable length message queue creation\n"); + + /* test variable length message queue creation */ + ret = alq_open(&testalq, logfile, curthread->td_ucred, 0600, buflen, + 0); + + if (0 != testalq->aq_entmax) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_entmax", 0, testalq->aq_entmax); + } + + if (0 != testalq->aq_entlen) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_entlen", 0, testalq->aq_entlen); + } + + if (buflen != testalq->aq_freebytes) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_freebytes", buflen, testalq->aq_freebytes); + } + + if (buflen != testalq->aq_buflen) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_buflen", buflen, testalq->aq_buflen); + } + + if (0 != testalq->aq_writehead) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writehead", 0, testalq->aq_writehead); + } + + if (0 != testalq->aq_writetail) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_writetail", 0, testalq->aq_writetail); + } + + if (AQ_VARLEN != testalq->aq_flags) { + errors++; + sbuf_printf(debug, "alq->%-15s\texpected=%d\tactual=%d\n", + "aq_flags", 0, testalq->aq_flags); + } + + alq_close(testalq); + + return (errors); +} + +static void +run_test(struct sbuf *s, const char *test_banner, testfunc test) +{ + struct sbuf *debug = NULL; + + if ((debug = sbuf_new(NULL, NULL, 1024, SBUF_AUTOEXTEND)) != NULL) { + alqtest_printf(s, 0, "########################################\n"); + alqtest_printf(s, GREEN, "%s\n", test_banner); + if (test(s, debug)) { + sbuf_finish(debug); + alqtest_printf(s, RED, "!!ERROR(S) FOUND!!\n"); + alqtest_printf(s, 0, "%s", sbuf_data(debug)); + alqtest_printf(s, RED, "!!ERROR(S) FOUND!!\n"); + } + alqtest_printf(s, 0, "########################################\n\n"); + sbuf_delete(debug); + } +} + +static void +alqtest_thread(void *arg) +{ + struct sbuf *s = NULL; + long runs = 0; + + /* loop until thread is signalled to exit */ + while (run_test_thread && runs < NUM_TEST_RUNS) { + if ((s = sbuf_new(NULL, NULL, 1024, SBUF_AUTOEXTEND)) != NULL) { + alqtest_printf(s, 0, "TEST RUN: %ld\n", ++runs); + + run_test(s, "alq_open", &alqtest_open); + run_test(s, "alq_writen", &alqtest_writen); + + sbuf_finish(s); + /*printf("%s", sbuf_data(s));*/ + sbuf_delete(s); + } + } + + kthread_exit(); +} + +static int +manage_test_ops(uint8_t action) +{ + int error = 0; + //struct sbuf *s = NULL; + + /* init an autosizing sbuf that initially holds 200 chars */ + //if ((s = sbuf_new(NULL, NULL, 200, SBUF_AUTOEXTEND)) == NULL) + // return -1; + + if (action == ENABLE) { + + run_test_thread = 1; + + kthread_add(&alqtest_thread, NULL, NULL, &alq_test_thr, + RFNOWAIT, 0, "alq_test_thr"); + } + else if (action == DISABLE && alq_test_thr != NULL) { + /* tell the test thread that it should exit now */ + run_test_thread = 0; + alq_test_thr = NULL; + } + + return (error); +} + +static int +deinit(void) +{ + manage_test_ops(DISABLE); + mtx_destroy(&alqtestmtx); + return (0); +} + +static int +init(void) +{ + mtx_init(&alqtestmtx, "alqtestmtx", NULL, MTX_DEF); + manage_test_ops(ENABLE); + return (0); +} + +/* + * This is the function that is called to load and unload the module. + * When the module is loaded, this function is called once with + * "what" == MOD_LOAD + * When the module is unloaded, this function is called twice with + * "what" = MOD_QUIESCE first, followed by "what" = MOD_UNLOAD second + * When the system is shut down e.g. CTRL-ALT-DEL or using the shutdown command, + * this function is called once with "what" = MOD_SHUTDOWN + * When the system is shut down, the handler isn't called until the very end + * of the shutdown sequence i.e. after the disks have been synced. + */ +static int alqtest_load_handler(module_t mod, int what, void *arg) +{ + switch(what) { + case MOD_LOAD: + return init(); + break; + + case MOD_QUIESCE: + case MOD_SHUTDOWN: + return deinit(); + break; + + case MOD_UNLOAD: + return (0); + break; + + default: + return (EINVAL); + break; + } +} + +static moduledata_t alqtest_mod = +{ + "alqtest", + alqtest_load_handler, + NULL +}; + +DECLARE_MODULE(alqtest, alqtest_mod, SI_SUB_SMP, SI_ORDER_ANY); +MODULE_DEPEND(alqtest, alq, 1, 1, 1);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201003170708.o2H78vC6029861>