summaryrefslogtreecommitdiff
path: root/user
diff options
context:
space:
mode:
Diffstat (limited to 'user')
-rw-r--r--user/bcachetest.c318
-rw-r--r--user/init.c1
-rw-r--r--user/kalloctest.c161
-rw-r--r--user/statistics.c24
-rw-r--r--user/stats.c24
-rw-r--r--user/user.h4
6 files changed, 532 insertions, 0 deletions
diff --git a/user/bcachetest.c b/user/bcachetest.c
new file mode 100644
index 0000000..ccf7516
--- /dev/null
+++ b/user/bcachetest.c
@@ -0,0 +1,318 @@
+#include "kernel/fcntl.h"
+#include "kernel/param.h"
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "kernel/riscv.h"
+#include "kernel/fs.h"
+#include "user/user.h"
+
+void test0();
+void test1();
+void test2();
+
+#define SZ 4096
+char buf[SZ];
+
+int
+main(int argc, char *argv[])
+{
+ test0();
+ test1();
+ test2();
+ exit(0);
+}
+
+void
+createfile(char *file, int nblock)
+{
+ int fd;
+ char buf[BSIZE];
+ int i;
+
+ fd = open(file, O_CREATE | O_RDWR);
+ if(fd < 0){
+ printf("createfile %s failed\n", file);
+ exit(-1);
+ }
+ for(i = 0; i < nblock; i++) {
+ if(write(fd, buf, sizeof(buf)) != sizeof(buf)) {
+ printf("write %s failed\n", file);
+ exit(-1);
+ }
+ }
+ close(fd);
+}
+
+void
+readfile(char *file, int nbytes, int inc)
+{
+ char buf[BSIZE];
+ int fd;
+ int i;
+
+ if(inc > BSIZE) {
+ printf("readfile: inc too large\n");
+ exit(-1);
+ }
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ printf("readfile open %s failed\n", file);
+ exit(-1);
+ }
+ for (i = 0; i < nbytes; i += inc) {
+ if(read(fd, buf, inc) != inc) {
+ printf("read %s failed for block %d (%d)\n", file, i, nbytes);
+ exit(-1);
+ }
+ }
+ close(fd);
+}
+
+int ntas(int print)
+{
+ int n;
+ char *c;
+
+ if (statistics(buf, SZ) <= 0) {
+ fprintf(2, "ntas: no stats\n");
+ }
+ c = strchr(buf, '=');
+ n = atoi(c+2);
+ if(print)
+ printf("%s", buf);
+ return n;
+}
+
+// Test reading small files concurrently
+void
+test0()
+{
+ char file[2];
+ char dir[2];
+ enum { N = 10, NCHILD = 3 };
+ int m, n;
+
+ dir[0] = '0';
+ dir[1] = '\0';
+ file[0] = 'F';
+ file[1] = '\0';
+
+ printf("start test0\n");
+ for(int i = 0; i < NCHILD; i++){
+ dir[0] = '0' + i;
+ mkdir(dir);
+ if (chdir(dir) < 0) {
+ printf("chdir failed\n");
+ exit(1);
+ }
+ unlink(file);
+ createfile(file, N);
+ if (chdir("..") < 0) {
+ printf("chdir failed\n");
+ exit(1);
+ }
+ }
+ m = ntas(0);
+ for(int i = 0; i < NCHILD; i++){
+ dir[0] = '0' + i;
+ int pid = fork();
+ if(pid < 0){
+ printf("fork failed");
+ exit(-1);
+ }
+ if(pid == 0){
+ if (chdir(dir) < 0) {
+ printf("chdir failed\n");
+ exit(1);
+ }
+
+ readfile(file, N*BSIZE, 1);
+
+ exit(0);
+ }
+ }
+
+ for(int i = 0; i < NCHILD; i++){
+ wait(0);
+ }
+ printf("test0 results:\n");
+ n = ntas(1);
+ if (n-m < 500)
+ printf("test0: OK\n");
+ else
+ printf("test0: FAIL\n");
+}
+
+// Test bcache evictions by reading a large file concurrently
+void test1()
+{
+ char file[3];
+ enum { N = 200, BIG=100, NCHILD=2 };
+
+ printf("start test1\n");
+ file[0] = 'B';
+ file[2] = '\0';
+ for(int i = 0; i < NCHILD; i++){
+ file[1] = '0' + i;
+ unlink(file);
+ if (i == 0) {
+ createfile(file, BIG);
+ } else {
+ createfile(file, 1);
+ }
+ }
+ for(int i = 0; i < NCHILD; i++){
+ file[1] = '0' + i;
+ int pid = fork();
+ if(pid < 0){
+ printf("fork failed");
+ exit(-1);
+ }
+ if(pid == 0){
+ if (i==0) {
+ for (i = 0; i < N; i++) {
+ readfile(file, BIG*BSIZE, BSIZE);
+ }
+ unlink(file);
+ exit(0);
+ } else {
+ for (i = 0; i < N*20; i++) {
+ readfile(file, 1, BSIZE);
+ }
+ unlink(file);
+ }
+ exit(0);
+ }
+ }
+
+ for(int i = 0; i < NCHILD; i++){
+ wait(0);
+ }
+ printf("test1 OK\n");
+}
+
+//
+// test concurrent creates.
+//
+void
+test2()
+{
+ int nc = 4;
+ char file[16];
+
+ printf("start test2\n");
+
+ mkdir("d2");
+
+ file[0] = 'd';
+ file[1] = '2';
+ file[2] = '/';
+
+ // remove any stale existing files.
+ for(int i = 0; i < 50; i++){
+ for(int ci = 0; ci < nc; ci++){
+ file[3] = 'a' + ci;
+ file[4] = '0' + i;
+ file[5] = '\0';
+ unlink(file);
+ }
+ }
+
+ int pids[nc];
+ for(int ci = 0; ci < nc; ci++){
+ pids[ci] = fork();
+ if(pids[ci] < 0){
+ printf("test2: fork failed\n");
+ exit(1);
+ }
+ if(pids[ci] == 0){
+ char me = "abcdefghijklmnop"[ci];
+ int pid = getpid();
+ int nf = (ci == 0 ? 10 : 15);
+
+ // create nf files.
+ for(int i = 0; i < nf; i++){
+ file[3] = me;
+ file[4] = '0' + i;
+ file[5] = '\0';
+ // printf("w %s\n", file);
+ int fd = open(file, O_CREATE | O_RDWR);
+ if(fd < 0){
+ printf("test2: create %s failed\n", file);
+ exit(1);
+ }
+ int xx = (pid << 16) | i;
+ for(int nw = 0; nw < 2; nw++){
+ // the sleep() increases the chance of simultaneous
+ // calls to bget().
+ sleep(1);
+ if(write(fd, &xx, sizeof(xx)) <= 0){
+ printf("test2: write %s failed\n", file);
+ exit(1);
+ }
+ }
+ close(fd);
+ }
+
+ // read back the nf files.
+ for(int i = 0; i < nf; i++){
+ file[3] = me;
+ file[4] = '0' + i;
+ file[5] = '\0';
+ // printf("r %s\n", file);
+ int fd = open(file, O_RDWR);
+ if(fd < 0){
+ printf("test2: open %s failed\n", file);
+ exit(1);
+ }
+ int xx = (pid << 16) | i;
+ for(int nr = 0; nr < 2; nr++){
+ int z = 0;
+ sleep(1);
+ int n = read(fd, &z, sizeof(z));
+ if(n != sizeof(z)){
+ printf("test2: read %s returned %d, expected %d\n", file, n, sizeof(z));
+ exit(1);
+ }
+ if(z != xx){
+ printf("test2: file %s contained %d, not %d\n", file, z, xx);
+ exit(1);
+ }
+ }
+ close(fd);
+ }
+
+ // delete the nf files.
+ for(int i = 0; i < nf; i++){
+ file[3] = me;
+ file[4] = '0' + i;
+ file[5] = '\0';
+ //printf("u %s\n", file);
+ if(unlink(file) != 0){
+ printf("test2: unlink %s failed\n", file);
+ exit(1);
+ }
+ }
+
+ exit(0);
+ }
+ }
+
+ int ok = 1;
+
+ for(int ci = 0; ci < nc; ci++){
+ int st = 0;
+ int ret = wait(&st);
+ if(ret <= 0){
+ printf("test2: wait() failed\n");
+ ok = 0;
+ }
+ if(st != 0)
+ ok = 0;
+ }
+
+ if(ok){
+ printf("test2 OK\n");
+ } else {
+ printf("test2 failed\n");
+ }
+}
diff --git a/user/init.c b/user/init.c
index e0a5689..fc1c3db 100644
--- a/user/init.c
+++ b/user/init.c
@@ -18,6 +18,7 @@ main(void)
if(open("console", O_RDWR) < 0){
mknod("console", CONSOLE, 0);
+ mknod("statistics", STATS, 0);
open("console", O_RDWR);
}
dup(0); // stdout
diff --git a/user/kalloctest.c b/user/kalloctest.c
new file mode 100644
index 0000000..a82f1d5
--- /dev/null
+++ b/user/kalloctest.c
@@ -0,0 +1,161 @@
+#include "kernel/param.h"
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "kernel/riscv.h"
+#include "kernel/memlayout.h"
+#include "kernel/fcntl.h"
+#include "user/user.h"
+
+#define NCHILD 2
+#define N 100000
+#define SZ 4096
+
+void test1(void);
+void test2(void);
+void test3(void);
+char buf[SZ];
+
+int
+main(int argc, char *argv[])
+{
+ test1();
+ test2();
+ test3();
+ exit(0);
+}
+
+int ntas(int print)
+{
+ int n;
+ char *c;
+
+ if (statistics(buf, SZ) <= 0) {
+ fprintf(2, "ntas: no stats\n");
+ }
+ c = strchr(buf, '=');
+ n = atoi(c+2);
+ if(print)
+ printf("%s", buf);
+ return n;
+}
+
+// Test concurrent kallocs and kfrees
+void test1(void)
+{
+ void *a, *a1;
+ int n, m;
+ printf("start test1\n");
+ m = ntas(0);
+ for(int i = 0; i < NCHILD; i++){
+ int pid = fork();
+ if(pid < 0){
+ printf("fork failed");
+ exit(-1);
+ }
+ if(pid == 0){
+ for(i = 0; i < N; i++) {
+ a = sbrk(4096);
+ *(int *)(a+4) = 1;
+ a1 = sbrk(-4096);
+ if (a1 != a + 4096) {
+ printf("wrong sbrk\n");
+ exit(-1);
+ }
+ }
+ exit(-1);
+ }
+ }
+
+ for(int i = 0; i < NCHILD; i++){
+ wait(0);
+ }
+ printf("test1 results:\n");
+ n = ntas(1);
+ if(n-m < 10)
+ printf("test1 OK\n");
+ else
+ printf("test1 FAIL\n");
+}
+
+//
+// countfree() from usertests.c
+//
+int
+countfree()
+{
+ uint64 sz0 = (uint64)sbrk(0);
+ int n = 0;
+
+ while(1){
+ uint64 a = (uint64) sbrk(4096);
+ if(a == 0xffffffffffffffff){
+ break;
+ }
+ // modify the memory to make sure it's really allocated.
+ *(char *)(a + 4096 - 1) = 1;
+ n += 1;
+ }
+ sbrk(-((uint64)sbrk(0) - sz0));
+ return n;
+}
+
+// Test stealing
+void test2() {
+ int free0 = countfree();
+ int free1;
+ int n = (PHYSTOP-KERNBASE)/PGSIZE;
+ printf("start test2\n");
+ printf("total free number of pages: %d (out of %d)\n", free0, n);
+ if(n - free0 > 1000) {
+ printf("test2 FAILED: cannot allocate enough memory");
+ exit(-1);
+ }
+ for (int i = 0; i < 50; i++) {
+ free1 = countfree();
+ if(i % 10 == 9)
+ printf(".");
+ if(free1 != free0) {
+ printf("test2 FAIL: losing pages\n");
+ exit(-1);
+ }
+ }
+ printf("\ntest2 OK\n");
+}
+
+// Test concurrent kalloc/kfree and stealing
+void test3(void)
+{
+ void *a, *a1;
+ printf("start test3\n");
+ for(int i = 0; i < NCHILD; i++){
+ int pid = fork();
+ if(pid < 0){
+ printf("fork failed");
+ exit(-1);
+ }
+ if(pid == 0){
+ if (i == 0) {
+ for(i = 0; i < N; i++) {
+ a = sbrk(4096);
+ *(int *)(a+4) = 1;
+ a1 = sbrk(-4096);
+ if (a1 != a + 4096) {
+ printf("wrong sbrk\n");
+ exit(-1);
+ }
+ }
+ printf("child done %d\n", i);
+ exit(0);
+ } else {
+ countfree();
+ printf("child done %d\n", i);
+ exit(0);
+ }
+ }
+ }
+
+ for(int i = 0; i < NCHILD; i++){
+ wait(0);
+ }
+ printf("test3 OK\n");
+}
diff --git a/user/statistics.c b/user/statistics.c
new file mode 100644
index 0000000..e22681a
--- /dev/null
+++ b/user/statistics.c
@@ -0,0 +1,24 @@
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "kernel/fcntl.h"
+#include "user/user.h"
+
+int
+statistics(void *buf, int sz)
+{
+ int fd, i, n;
+
+ fd = open("statistics", O_RDONLY);
+ if(fd < 0) {
+ fprintf(2, "stats: open failed\n");
+ exit(1);
+ }
+ for (i = 0; i < sz; ) {
+ if ((n = read(fd, buf+i, sz-i)) < 0) {
+ break;
+ }
+ i += n;
+ }
+ close(fd);
+ return i;
+}
diff --git a/user/stats.c b/user/stats.c
new file mode 100644
index 0000000..f8c9138
--- /dev/null
+++ b/user/stats.c
@@ -0,0 +1,24 @@
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "kernel/fcntl.h"
+#include "user/user.h"
+
+#define SZ 4096
+char buf[SZ];
+
+int
+main(void)
+{
+ int i, n;
+
+ while (1) {
+ n = statistics(buf, SZ);
+ for (i = 0; i < n; i++) {
+ write(1, buf+i, 1);
+ }
+ if (n != SZ)
+ break;
+ }
+
+ exit(0);
+}
diff --git a/user/user.h b/user/user.h
index 34591fd..31453f5 100644
--- a/user/user.h
+++ b/user/user.h
@@ -1,3 +1,7 @@
+#ifdef LAB_MMAP
+typedef unsigned long size_t;
+typedef long int off_t;
+#endif
struct stat;
struct sysinfo;