UCQ debug code
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 25 Sep 2012 23:00:56 +0000 (16:00 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 25 Sep 2012 23:00:56 +0000 (16:00 -0700)
Depending on what you want, you'll probably need to update test_ucq().
As is, you can only run it, then reboot.  It's a little better at
testing chains, and we now have some debug helpers (call with kfunc) to
get a better peak at a ucq.

kern/src/testing.c
kern/src/ucq.c
tests/ucq.c
user/parlib/ucq.c

index 50440eb..4857697 100644 (file)
@@ -980,6 +980,7 @@ void test_ucq(void)
                struct event_msg msg;
 
                printk("Running the alarm handler!\n");
+               printk("NR msg per page: %d\n", NR_MSG_PER_PAGE);
                /* might not be mmaped yet, if not, abort */
                if (!user_mem_check(p, ucq, PGSIZE, 1, PTE_USER_RW)) {
                        printk("Not mmaped yet\n");
@@ -996,18 +997,29 @@ void test_ucq(void)
                /* So it's ready, time to finally do the tests... */
                printk("[kernel] Finally starting the tests... \n");
                /* 1: Send a simple message */
-               printk("[kernel] Sending simple message (7, deadbeef)\n");
+               printk("[kernel] #1 Sending simple message (7, deadbeef)\n");
                msg.ev_type = 7;
                msg.ev_arg2 = 0xdeadbeef;
                send_ucq_msg(ucq, p, &msg);
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
                /* 2: Send a bunch.  In a VM, this causes one swap, and then a bunch of
                 * mmaps. */
+               printk("[kernel] #2 \n");
                for (int i = 0; i < 5000; i++) {
                        msg.ev_type = i;
                        send_ucq_msg(ucq, p, &msg);
                }
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
+               printk("[kernel] #3 \n");
+               /* 3: make sure we chained pages (assuming 1k is enough) */
+               for (int i = 0; i < 1000; i++) {
+                       msg.ev_type = i;
+                       send_ucq_msg(ucq, p, &msg);
+               }
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
                /* other things we could do:
                 *  - concurrent producers / consumers...  ugh.
+                *  - would require a kmsg to another core, instead of a local alarm
                 */
                /* done, switch back and free things */
                switch_back(p, old_proc);
@@ -1042,6 +1054,7 @@ void test_ucq(void)
         * not get the process you created, in the event there are others floating
         * around that are runnable */
        schedule();
+       smp_idle();
        assert(0);
 }
 
index b0e64ec..59d49c7 100644 (file)
@@ -62,7 +62,8 @@ grab_lock:
        if (!new_page) {
                /* Warn if we have a ridiculous amount of pages in the ucq */
                if (atomic_fetch_and_add(&ucq->nr_extra_pgs, 1) > UCQ_WARN_THRESH)
-                       warn("Over %d pages in ucq %08p!\n", UCQ_WARN_THRESH, ucq);
+                       warn("Over %d pages in ucq %08p for pid %d!\n", UCQ_WARN_THRESH,
+                            ucq, p->pid);
                /* Giant warning: don't ask for anything other than anonymous memory at
                 * a non-fixed location.  o/w, it may cause a TLB shootdown, which grabs
                 * the proc_lock, and potentially deadlock the system. */
@@ -132,6 +133,7 @@ error_addr:
 /* Prints the status and up to 25 of the previous messages for the UCQ. */
 void print_ucq(struct proc *p, struct ucq *ucq)
 {
+       struct ucq_page *ucq_pg;
        struct proc *old_proc = switch_to(p);
 
        printk("UCQ %08p\n", ucq);
@@ -143,7 +145,17 @@ void print_ucq(struct proc *p, struct ucq *ucq)
        /* Try to see our previous ucqs */
        for (int i = atomic_read(&ucq->prod_idx), count = 0;
             slot_is_good(i), count < 25;  i--, count++) {
+               /* only attempt to print messages on the same page */
+               if (PTE_ADDR(i) != PTE_ADDR(atomic_read(&ucq->prod_idx)))
+                       break;
                printk("Prod idx %08p message ready is %08p\n", i, slot2msg(i)->ready);
        }
+       /* look at the chain, starting from cons_idx */
+       ucq_pg = (struct ucq_page*)PTE_ADDR(atomic_read(&ucq->cons_idx));
+       for (int i = 0; i < 10 && ucq_pg; i++) {
+               printk("#%02d: Cons page: %08p, nr_cons: %d, next page: %08p\n", i,
+                      ucq_pg, ucq_pg->header.nr_cons, ucq_pg->header.cons_next_pg);
+               ucq_pg = (struct ucq_page*)(ucq_pg->header.cons_next_pg);
+       }
        switch_back(p, old_proc);
 }
index d9efb37..33ec389 100644 (file)
@@ -4,11 +4,12 @@
 #include <sys/mman.h>
 #include <ucq.h>
 #include <assert.h>
+#include <arch/atomic.h>
 
 int main(int argc, char** argv)
 {
        /* this program should only be started from the kernel for tests */
-       printf("Attempting to read ucq messages from test_ucq().  "
+       printf("[user] Attempting to read ucq messages from test_ucq().  "
               "Don't call this manually.\n");
        /* Map into a known, extremely ghetto location.  The kernel knows to look
         * here. */
@@ -20,6 +21,7 @@ int main(int argc, char** argv)
                                              MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
        assert(two_pages);
        ucq_init_raw(ucq, two_pages, two_pages + PGSIZE);
+       printf("[user] UCQ %08p initialized\n", ucq);
        /* try to get a simple message */
        struct event_msg msg;
        /* 1: Spin til we can get a message (0 on success breaks) */
@@ -33,6 +35,28 @@ int main(int argc, char** argv)
                        cpu_relax();
                assert(msg.ev_type == i);
        }
-       printf("Received a bunch!  Last one was %d(4999)\n", msg.ev_type);
+       printf("[user] #2 Received a bunch!  Last one was %d(4999), "
+              "extra pages %d(6, if #3 is 1000 and was blasted already)\n",
+              msg.ev_type, atomic_read(&ucq->nr_extra_pgs));
+       /* 3: test chaining */
+       while (atomic_read(&ucq->nr_extra_pgs) < 2)
+               cpu_relax();
+       printf("[user] #3 There's now a couple pages (%d), trying to receive...\n",
+              atomic_read(&ucq->nr_extra_pgs));
+       /* this assumes 1000 is enough for a couple pages */
+       for (int i = 0; i < 1000; i++) {
+               while (get_ucq_msg(ucq, &msg))
+                       cpu_relax();
+               assert(msg.ev_type == i);
+       }
+       printf("[user] Done, extra pages: %d(0)\n", atomic_read(&ucq->nr_extra_pgs));
+       int extra = 0;
+       while (!get_ucq_msg(ucq, &msg)) {
+               printf("[user] got %d extra messages in the ucq, type %d\n", ++extra,
+                      msg.ev_type);
+       }
+       printf("[user] Spinning...\n");
+       while(1);
+
        return 0;
 }
index dc2abfe..9bcb43b 100644 (file)
@@ -21,6 +21,7 @@
  * it up over a bunch of ucqs, instead of doing a lot of little mmap() calls. */
 void ucq_init_raw(struct ucq *ucq, uintptr_t pg1, uintptr_t pg2)
 {
+       printd("[user] initializing ucq %08p for proc %d\n", ucq, getpid());
        assert(!PGOFF(pg1));
        assert(!PGOFF(pg2));
        /* Prod and cons both start on the first page, slot 0.  When they are equal,