Fixes random reads
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 21 Jan 2014 17:40:45 +0000 (09:40 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 21 Jan 2014 19:04:03 +0000 (11:04 -0800)
This is the old plan9 style, with two 'independent' processes working at
the same time, and not using apipes.

But it's way too slow:

/ $ trandom 16
Read 16 bytes of random in 822003 microseconds
dc6bd80d 9b541b97 a063d7ab 27d7bbea
/ $
/ $ trandom 100
Read 100 bytes of random in 5192485 microseconds
fe50907c 5c5c7473 5d40b3fe 307fbf4c

I think it's slow since genrandom doesn't yield to processes.  When
we're done with our 16 bytes, we pause a bit before returning to
userspace.

kern/src/ns/random.c
tests/trandom.c [new file with mode: 0644]

index eaabae4..8004dc2 100644 (file)
@@ -12,6 +12,7 @@
 #include <pmap.h>
 #include <smp.h>
 #include <ip.h>
+#include <alarm.h>
 
 static struct
 {
@@ -28,7 +29,6 @@ static struct
        uint8_t wakeme;
        uint8_t filled;
        int     target;
-       int     kprocstarted;
        uint32_t        randn;
 } rb;
 
@@ -52,7 +52,7 @@ rbnotempty(void*unused)
 static void
 genrandom(void*unused)
 {
-#warning "priority?"
+       /* TODO: set this to low priority, if we ever have something like that */
        //setpri(PriBackground);
 
        for(;;) {
@@ -60,7 +60,7 @@ genrandom(void*unused)
                        if(++rb.randomcount > 100000)
                                break;
                //if(anyhigher())
-               //      sched();
+                       kthread_yield();
                if(rb.filled || !rbnotfull(0))
                        rendez_sleep(&rb.producer, rbnotfull, 0);
        }
@@ -100,17 +100,33 @@ randomclock(void)
                rendez_wakeup(&rb.consumer);
 }
 
+struct alarm_waiter random_waiter;
+static void __random_alarm(struct alarm_waiter *waiter)
+{
+       randomclock();
+       /* Set our alarm to go off, incrementing from our last tick (instead of
+        * setting it relative to now, since some time has passed since the alarm
+        * first went off.  Note, this may be now or in the past! */
+       set_awaiter_inc(&random_waiter, 13000);
+       __set_alarm(&per_cpu_info[core_id()].tchain, &random_waiter);
+}
+
 void
 randominit(void)
 {
        qlock_init(&rb.qlock);
        rendez_init(&rb.producer);
        rendez_init(&rb.consumer);
-       /* Frequency close but not equal to HZ */
-       //addclock0link(randomclock, 13);
        rb.target = 16;
        rb.ep = rb.buf + sizeof(rb.buf);
        rb.rp = rb.wp = rb.buf;
+       /* Run randomclock every 13 ms */
+       /* Frequency close but not equal to HZ */
+       init_awaiter(&random_waiter, __random_alarm);
+       set_awaiter_rel(&random_waiter, 13000);
+       set_alarm(&per_cpu_info[core_id()].tchain, &random_waiter);
+       /* instead of waiting for randomread to kick it off */
+       ktask("genrand", genrandom, NULL);
 }
 
 /*
@@ -130,10 +146,6 @@ randomread(void *xp, uint32_t n)
                qunlock(&(&rb)->qlock);
                nexterror();
        }
-       if(!rb.kprocstarted){
-               rb.kprocstarted = 1;
-               ktask("genrand", genrandom, NULL);
-       }
 
        for(sofar = 0; sofar < n; sofar += i){
                i = rb.wp - rb.rp;
diff --git a/tests/trandom.c b/tests/trandom.c
new file mode 100644 (file)
index 0000000..d7390c4
--- /dev/null
@@ -0,0 +1,53 @@
+
+#define _LARGEFILE64_SOURCE /* needed to use lseek64 */
+
+#include <stdio.h> 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arch/arch.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ros/syscall.h>
+#include <sys/time.h>
+
+int main(int argc, char *argv[]) 
+{ 
+       int fd;
+       int i;
+       static uint32_t data[1048576];
+       struct timeval start_tv = {0};
+       struct timeval end_tv = {0};
+       int usecs;
+       int amt = 4096;
+
+       if (argc > 1)
+               amt = strtol(argv[1], 0, 0);
+       if (amt > sizeof(data))
+               printf("max amt to read is %d\n", sizeof(data));
+       if (amt > sizeof(data))
+               amt = sizeof(data);
+       fd = open("#c/random", 0);
+       if (fd < 0){
+               perror("random");
+               exit(1);
+       }
+       if (gettimeofday(&start_tv, 0))
+               perror("Start time error...");
+       amt = read(fd, data, amt);
+       if (amt < 0){
+               perror("read random");
+               exit(1);
+       }
+       if (gettimeofday(&end_tv, 0))
+               perror("End time error...");
+       usecs = (end_tv.tv_sec - start_tv.tv_sec)*1000000 + (end_tv.tv_usec - start_tv.tv_usec);
+       printf("Read %d bytes of random in %d microseconds\n", amt, usecs);
+       for(i = 0; i < 4; i++)
+               printf("%08x ", data[i]);
+       printf("\n");
+
+}