svn commit: r205243 - in user/lstewart/alq_varlen_head/tools/test:
. alq
Lawrence Stewart
lstewart at FreeBSD.org
Wed Mar 17 07:08:57 UTC 2010
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 at 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);
More information about the svn-src-user
mailing list