Add stupid tests.
authorPierre Habouzit <pierre.habouzit@intersec.com>
Sun, 15 Jan 2012 19:06:25 +0000 (20:06 +0100)
committerPierre Habouzit <pierre.habouzit@intersec.com>
Sun, 15 Jan 2012 19:32:47 +0000 (20:32 +0100)
Signed-off-by: Pierre Habouzit <pierre.habouzit@intersec.com>
.gitignore
Makefile
kernel/pwqr.c
test/Makefile [new file with mode: 0644]
test/test.c [new file with mode: 0644]

index 4afe4d5..bc8b55e 100644 (file)
@@ -8,3 +8,4 @@ Module.symvers
 modules.order
 
 /Documentation/pwqr.html
 modules.order
 
 /Documentation/pwqr.html
+/test/test
index 7558a97..e03609c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
 all clean:
        $(MAKE) -C kernel $@
        $(MAKE) -C lib $@
 all clean:
        $(MAKE) -C kernel $@
        $(MAKE) -C lib $@
+       $(MAKE) -C test $@
 
 .PHONY: all clean
 
 .PHONY: all clean
index e5a232e..8248482 100644 (file)
@@ -192,6 +192,7 @@ static void pwqr_sb_timer_cb(unsigned long arg)
                        wake_up_locked(&sb->wqh);
        }
        if (sb->running > sb->concurrency) {
                        wake_up_locked(&sb->wqh);
        }
        if (sb->running > sb->concurrency) {
+               printk(KERN_DEBUG "wake up poll");
                wake_up_poll(&sb->wqh_poll, POLLIN);
        }
        pwqr_sb_unlock_irqrestore(sb, flags);
                wake_up_poll(&sb->wqh_poll, POLLIN);
        }
        pwqr_sb_unlock_irqrestore(sb, flags);
diff --git a/test/Makefile b/test/Makefile
new file mode 100644 (file)
index 0000000..b008934
--- /dev/null
@@ -0,0 +1,9 @@
+all: test
+
+test: test.c
+       $(CC) -Wall -Werror -Wextra -Wno-unused-parameter -std=gnu99 $(CFLAGS) -O2 -g -lpthread -o $@ $<
+
+clean:
+       $(RM) test
+
+.PHONY: all clean
diff --git a/test/test.c b/test/test.c
new file mode 100644 (file)
index 0000000..b4f2f67
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012   Pierre Habouzit <pierre.habouzit@intersec.com>
+ * Copyright (C) 2012   Intersec SAS
+ *
+ * This file is part of the Linux Pthread Workqueue Regulator tests.
+ *
+ * The Linux Pthread Workqueue Regulator is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser
+ * General Public License as published by the Free Software Foundation,
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * The Linux Pthread Workqueue Regulator is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The Linux Pthread Workqueue Regultaor.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../kernel/pwqr.h"
+
+/* pwqr wrapping {{{ */
+
+static int pwqr_create(int flags)
+{
+    if (flags & ~PWQR_FL__SET) {
+        errno = -EINVAL;
+        return -1;
+    }
+    return open("/dev/"PWQR_DEVICE_NAME, O_RDWR | flags);
+}
+
+static int pwqr_ctl(int fd, int op, int val, void *uaddr)
+{
+    struct pwqr_ioc_wait wait;
+
+    switch (op) {
+      case PWQR_CTL_GET_CONC:
+      case PWQR_CTL_REGISTER:
+      case PWQR_CTL_UNREGISTER:
+      case PWQR_CTL_PARK:
+        return ioctl(fd, op);
+      case PWQR_CTL_SET_CONC:
+      case PWQR_CTL_WAKE:
+      case PWQR_CTL_WAKE_OC:
+        return ioctl(fd, op, val);
+      case PWQR_CTL_WAIT:
+        wait.pwqr_ticket = val;
+        wait.pwqr_uaddr  = uaddr;
+        return ioctl(fd, op, &wait);
+      default:
+        errno = EINVAL;
+        return -1;
+    }
+}
+
+/* }}} */
+
+static int pwqr_fd_g = -1;
+static int pi_g;
+
+static void *thr_main(void *unused)
+{
+    if (pwqr_ctl(pwqr_fd_g, PWQR_CTL_REGISTER, 0, NULL) < 0)
+        err(-1, "pwqr_ctl(PWQR_CTL_REGISTER)");
+
+    /* busy-loop */
+    for (;;)
+        pthread_testcancel();
+    return NULL;
+}
+
+static uint64_t tv_diff(const struct timeval *t1, const struct timeval *t2)
+{
+    return (t1->tv_sec - t2->tv_sec) * 1000000ULL + t1->tv_usec - t2->tv_usec;
+}
+
+int main(void)
+{
+    pthread_t tids[32];
+    struct pollfd pfd;
+    struct timeval start, tv;
+    int rc;
+
+    pwqr_fd_g = pwqr_create(PWQR_FL_NONBLOCK);
+    if (pwqr_fd_g < 0)
+        err(-1, "pwqr_create");
+
+    pi_g = pwqr_ctl(pwqr_fd_g, PWQR_CTL_GET_CONC, 0, NULL);
+    if (pi_g < 1)
+        err(-1, "pwqr_ctl(PWQR_CTL_GET_CONC)");
+
+    for (int i = 0; i < pi_g + 1; i++) {
+        pthread_create(&tids[i], NULL, thr_main, NULL);
+    }
+
+    pfd.fd     = pwqr_fd_g;
+    pfd.events = POLLIN;
+    gettimeofday(&start, NULL);
+    for (;;) {
+        pfd.revents = 0;
+        rc = poll(&pfd, 1, -1);
+        if (rc < 0) {
+            warn("poll");
+            continue;
+        }
+        if (rc == 1) {
+            if (pfd.revents & POLLIN) {
+                if (read(pwqr_fd_g, &rc, sizeof(rc)) != sizeof(rc)) {
+                    warn("read");
+                } else {
+                    gettimeofday(&tv, NULL);
+                    warnx("[%06jd.%06jd] overcommit of %d",
+                          tv_diff(&tv, &start) / 1000000,
+                          tv_diff(&tv, &start) % 1000000, rc);
+                }
+            }
+            if (pfd.revents & POLLHUP) {
+                errx(-1, "poll returned POLLHUP");
+            }
+        }
+    }
+
+    for (int i = 0; i < pi_g + 1; i++) {
+        pthread_join(tids[i], NULL);
+    }
+    return 0;
+}