code: 9ferno

Download patch

ref: 99993f0d2c9b49a70a095235d90a7d0c01936d2e
parent: 8bb05d8ca955ed85c7028d74371f1d23ce66a800
author: 9ferno <[email protected]>
date: Sun Jan 23 07:50:15 EST 2022

added missing files from 9front

--- /dev/null
+++ b/include/tos.h
@@ -1,0 +1,24 @@
+typedef struct Tos Tos;
+typedef struct Plink Plink;
+
+#pragma incomplete Plink
+
+struct Tos {
+	struct			/* Per process profiling */
+	{
+		Plink	*pp;	/* known to be 0(ptr) */
+		Plink	*next;	/* known to be 4(ptr) */
+		Plink	*last;
+		Plink	*first;
+		ulong	pid;
+		ulong	what;
+	} prof;
+	uvlong	cyclefreq;	/* cycle clock frequency if there is one, 0 otherwise */
+	vlong	kcycles;	/* cycles spent in kernel */
+	vlong	pcycles;	/* cycles spent in process (kernel + user) */
+	ulong	pid;		/* might as well put the pid here */
+	ulong	clock;
+	/* top of stack is here */
+};
+
+extern Tos *_tos;
--- /dev/null
+++ b/os/port/cache.c
@@ -1,0 +1,521 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/error.h"
+
+enum
+{
+	NHASH		= 128,
+	NFILE		= 4093,		/* should be prime */
+	MAXCACHE	= 8*1024*1024,
+
+	MAPBITS		= 8*sizeof(ulong),
+	NBITMAP		= (PGROUND(MAXCACHE)/BY2PG + MAPBITS-1) / MAPBITS,
+};
+
+/* devmnt.c: parallel read ahread implementation */
+extern void mntrahinit(Mntrah *rah);
+extern long mntrahread(Mntrah *rah, Chan *c, uchar *buf, long len, vlong off);
+
+typedef struct Mntcache Mntcache;
+struct Mntcache
+{
+	Qid		qid;
+	int		dev;
+	int		type;
+
+	QLock;
+	Proc		*locked;
+	ulong		nlocked;
+
+	Mntcache	*hash;
+	Mntcache	*prev;
+	Mntcache	*next;
+
+	/* page bitmap of valid pages */
+	ulong		bitmap[NBITMAP];
+
+	/* read ahead state */
+	Mntrah		rah;
+};
+
+typedef struct Cache Cache;
+struct Cache
+{
+	Lock;
+	Mntcache	*alloc;
+	Mntcache	*head;
+	Mntcache	*tail;
+	Mntcache	*hash[NHASH];
+};
+
+Image fscache;
+
+static Cache cache;
+
+void
+cinit(void)
+{
+	int i;
+	Mntcache *m;
+
+	m = xalloc(sizeof(Mntcache)*NFILE);
+	if (m == nil)
+		panic("cinit: no memory");
+
+	cache.alloc = m;
+	cache.head = m;
+
+	for(i = 0; i < NFILE-1; i++) {
+		m->next = m+1;
+		m->prev = m-1;
+		m++;
+	}
+
+	cache.tail = m;
+	cache.tail->next = nil;
+	cache.head->prev = nil;
+
+	fscache.notext = 1;
+}
+
+static uintptr
+cacheaddr(Mntcache *m, ulong pn)
+{
+	uintptr da = pn * NFILE + (m - cache.alloc);
+	return (da << PGSHIFT) | (da >> (sizeof(da)*8 - PGSHIFT));
+}
+
+static void
+cnodata(Mntcache *m)
+{
+	memset(m->bitmap, 0, sizeof(m->bitmap));
+}
+
+static void
+ctail(Mntcache *m)
+{
+	/* Unlink and send to the tail */
+	if(m->prev != nil)
+		m->prev->next = m->next;
+	else
+		cache.head = m->next;
+	if(m->next != nil)
+		m->next->prev = m->prev;
+	else
+		cache.tail = m->prev;
+
+	if(cache.tail != nil) {
+		m->prev = cache.tail;
+		cache.tail->next = m;
+		m->next = nil;
+		cache.tail = m;
+	}
+	else {
+		cache.head = m;
+		cache.tail = m;
+		m->prev = nil;
+		m->next = nil;
+	}
+}
+
+/* called with cache locked */
+static Mntcache*
+clookup(Chan *c, int skipvers)
+{
+	Mntcache *m;
+
+	for(m = cache.hash[c->qid.path%NHASH]; m != nil; m = m->hash)
+		if(eqchantdqid(c, m->type, m->dev, m->qid, skipvers) && c->qid.type == m->qid.type)
+			return m;
+
+	return nil;
+}
+
+/*
+ * resursive Mntcache locking. Mntcache.rah is protected by the
+ * same lock and we want to call cupdate() from mntrahread()
+ * while holding the lock.
+ */
+static int
+cancachelock(Mntcache *m)
+{
+	if(m->locked == up || canqlock(m)){
+		m->locked = up;
+		m->nlocked++;
+		return 1;
+	}
+	return 0;
+}
+static void
+cachelock(Mntcache *m)
+{
+	if(m->locked != up){
+		qlock(m);
+		assert(m->nlocked == 0);
+		m->locked = up;
+	}
+	m->nlocked++;
+
+}
+static void
+cacheunlock(Mntcache *m)
+{
+	assert(m->locked == up);
+	if(--m->nlocked == 0){
+		m->locked = nil;
+		qunlock(m);
+	}
+}
+
+/* return locked Mntcache if still valid else reset mcp */
+static Mntcache*
+ccache(Chan *c)
+{
+	Mntcache *m;
+
+	m = c->mcp;
+	if(m != nil) {
+		cachelock(m);
+		if(eqchantdqid(c, m->type, m->dev, m->qid, 0) && c->qid.type == m->qid.type)
+			return m;
+		c->mcp = nil;
+		cacheunlock(m);
+	}
+	return nil;
+}
+
+int
+copen(Chan *c)
+{
+	Mntcache *m, *f, **l;
+
+	/* directories aren't cacheable */
+	if(c->qid.type&QTDIR){
+		c->mcp = nil;
+		return 0;
+	}
+
+	lock(&cache);
+	m = clookup(c, 0);
+	if(m != nil){
+		ctail(m);
+		unlock(&cache);
+		c->mcp = m;
+		return 1;
+	}
+	m = clookup(c, 1);
+	if(m == nil)
+		m = cache.head;
+	ctail(m);
+
+	l = &cache.hash[m->qid.path%NHASH];
+	for(f = *l; f != nil; f = f->hash) {
+		if(f == m) {
+			*l = m->hash;
+			break;
+		}
+		l = &f->hash;
+	}
+
+	if(!cancachelock(m)){
+		unlock(&cache);
+		cachelock(m);
+		lock(&cache);
+		f = clookup(c, 0);
+		if(f != nil) {
+			/*
+			 * someone got there first while cache lock
+			 * was released and added a updated Mntcache
+			 * for us. update LRU and use it.
+			 */
+			ctail(f);
+			unlock(&cache);
+			cacheunlock(m);
+			c->mcp = f;
+			return 1;
+		}
+	}
+
+	m->qid = c->qid;
+	m->dev = c->dev;
+	m->type = c->type;
+
+	l = &cache.hash[c->qid.path%NHASH];
+	m->hash = *l;
+	*l = m;
+
+	unlock(&cache);
+
+	m->rah.vers = m->qid.vers;
+	mntrahinit(&m->rah);
+	cnodata(m);
+	cacheunlock(m);
+	c->mcp = m;
+	return 0;
+}
+
+enum {
+	VABITS	= 8*sizeof(uintptr) - 2*PGSHIFT,
+	VAMASK	= (((uintptr)1 << VABITS)-1) << PGSHIFT,
+};
+
+static Page*
+cpage(Mntcache *m, ulong pn, ulong *po, ulong *pe)
+{
+	ulong b;
+	Page *p;
+
+	b = 1 << (pn%MAPBITS);
+	if((m->bitmap[pn/MAPBITS] & b) == 0)
+		return nil;
+	p = lookpage(&fscache, cacheaddr(m, pn));
+	if(p == nil){
+		m->bitmap[pn/MAPBITS] &= ~b;
+		return nil;
+	}
+	*po = p->va & (BY2PG-1);
+	*pe = 1 + (p->va >> (PGSHIFT+VABITS));
+	assert(*po < *pe);
+	return p;
+}
+
+static void
+cpageset(Page *p, ulong po, ulong pe)
+{
+	assert(po < pe);
+	p->va = po | (p->va & VAMASK) | ((uintptr)pe - 1) << (PGSHIFT+VABITS);
+}
+
+int
+cread(Chan *c, uchar *buf, int len, vlong off)
+{
+	KMap *k;
+	Page *p;
+	Mntcache *m;
+	int l, tot;
+	ulong offset, pn, po, pe;
+
+	if(len <= 0)
+		return 0;
+
+	m = ccache(c);
+	if(m == nil)
+		return 0;
+
+	if(waserror()){
+		cacheunlock(m);
+		nexterror();
+	}
+
+	tot = 0;
+	if(off >= MAXCACHE)
+		goto Prefetch;
+
+	offset = off;
+	if(offset+len > MAXCACHE)
+		len = MAXCACHE - offset;
+	pn = offset / BY2PG;
+	offset &= (BY2PG-1);
+
+	while(len > 0){
+		p = cpage(m, pn, &po, &pe);
+		if(p == nil)
+			break;
+		if(offset < po || offset >= pe){
+			putpage(p);
+			break;
+		}
+		l = pe - offset;
+		if(l > len)
+			l = len;
+		
+		k = kmap(p);
+		if(waserror()) {
+			kunmap(k);
+			putpage(p);
+			nexterror();
+		}
+		memmove(buf, (uchar*)VA(k) + offset, l);
+		kunmap(k);
+		putpage(p);
+		poperror();
+
+		tot += l;
+		buf += l;
+		len -= l;
+
+		offset += l;
+		offset &= (BY2PG-1);
+		if(offset != 0)
+			break;
+
+		pn++;
+	}
+
+Prefetch:
+	if(len > 0){
+		if(m->rah.vers != m->qid.vers){
+			mntrahinit(&m->rah);
+			m->rah.vers = m->qid.vers;
+		}
+		off += tot;
+		tot += mntrahread(&m->rah, c, buf, len, off);
+	}
+	cacheunlock(m);
+	poperror();
+
+	return tot;
+}
+
+/* invalidate pages in page bitmap */
+static void
+invalidate(Mntcache *m, ulong offset, int len)
+{
+	ulong pn;
+
+	for(pn = offset/BY2PG; len > 0; pn++, len -= BY2PG)
+		m->bitmap[pn/MAPBITS] &= ~(1 << (pn%MAPBITS));
+}
+
+/* replace buf data from [off, off+len) in the cache or invalidate */
+static void
+cachedata(Mntcache *m, uchar *buf, int len, vlong off)
+{
+	int l;
+	Page *p;
+	KMap *k;
+	ulong offset, pn, po, pe;
+
+	if(off >= MAXCACHE || len <= 0){
+		cacheunlock(m);
+		return;
+	}
+
+	offset = off;
+	if(offset+len > MAXCACHE)
+		len = MAXCACHE - offset;
+	pn = offset / BY2PG;
+	offset &= (BY2PG-1);
+
+	while(len > 0){
+		l = BY2PG - offset;
+		if(l > len)
+			l = len;
+		p = cpage(m, pn, &po, &pe);
+		if(p != nil){
+			if(offset > pe || (offset+l) < po){
+				/* cached range not extendable, set new cached range */
+				po = offset;
+				pe = offset+l;
+			} else {
+				/* extend cached range */
+				if(offset < po)
+					po = offset;
+				if((offset+l) > pe)
+					pe = offset+l;
+			}
+		} else {
+			if(needpages(nil)){
+				invalidate(m, offset + pn*BY2PG, len);
+				break;
+			}
+			p = newpage(0, nil, pn*BY2PG);
+			p->daddr = cacheaddr(m, pn);
+			cachedel(&fscache, p->daddr);
+			cachepage(p, &fscache);
+			m->bitmap[pn/MAPBITS] |= 1 << (pn%MAPBITS);
+
+			po = offset;
+			pe = offset+l;
+		}
+		cpageset(p, po, pe);
+
+		k = kmap(p);
+		if(waserror()) {
+			kunmap(k);
+			putpage(p);
+			invalidate(m, offset + pn*BY2PG, len);
+			cacheunlock(m);
+			nexterror();
+		}
+		memmove((uchar*)VA(k) + offset, buf, l);
+		poperror();
+		kunmap(k);
+		putpage(p);
+
+		offset = 0;
+		pn++;
+		buf += l;
+		len -= l;
+	}
+	cacheunlock(m);
+}
+
+void
+cupdate(Chan *c, uchar *buf, int len, vlong off)
+{
+	Mntcache *m;
+
+	m = ccache(c);
+	if(m == nil)
+		return;
+	cachedata(m, buf, len, off);
+}
+
+void
+cwrite(Chan* c, uchar *buf, int len, vlong off)
+{
+	Mntcache *m;
+
+	m = ccache(c);
+	if(m == nil)
+		return;
+	m->qid.vers++;
+	c->qid.vers++;
+	if(c->qid.type&QTAPPEND){
+		cacheunlock(m);
+		return;
+	}
+	cachedata(m, buf, len, off);
+}
+
+void
+ctrunc(Chan *c)
+{
+	Mntcache *m;
+
+	if(c->qid.type&QTDIR)
+		return;
+
+	if((c->flag&COPEN) == 0){
+		lock(&cache);
+		c->mcp = clookup(c, 0);
+		unlock(&cache);
+	}
+
+	m = ccache(c);
+	if(m == nil)
+		return;
+	mntrahinit(&m->rah);
+	cnodata(m);
+	cacheunlock(m);
+
+	if((c->flag&COPEN) == 0)
+		c->mcp = nil;
+}
+
+void
+cclunk(Chan *c)
+{
+	Mntcache *m;
+
+	m = ccache(c);
+	if(m == nil)
+		return;
+	mntrahinit(&m->rah);
+	cacheunlock(m);
+	c->mcp = nil;
+}
--- /dev/null
+++ b/tests/bigloop.c
@@ -1,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(int, void**)
+{
+	uvlong n, t, s;
+
+	s = nsec();
+	print("start nanoseconds %zd\n", s);
+	for(n = 0; n<1000*1000*1000; n++){
+		;
+	}
+	print("n %zd\n", n);
+	t = nsec();
+	print("end   nanoseconds %zd taken %zd\n", t, t -s);
+	exits(0);
+}
--- /dev/null
+++ b/tests/diskthroughput.c
@@ -1,0 +1,173 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+
+/*
+	ori disk throughput script
+17:54 < ori> single proc random reads with the test program => 130 megs/sec
+17:54 < h9ro> ah, that wasn't clear
+17:54 < ori> gefs => 50 megs/sec
+17:54 < h9ro> ok, then you're right of course :)
+17:55 < ori> no, gefs doesn't do parallel reads, but it clearly does something dumb.
+17:55 < h9ro> if your random offsets are ok and same blocksize...
+17:55 < ori> oh. that's actually a good thing to check.
+17:55 < ori> I should make sure that the offsets ARE aligned.
+17:55 < ori> pretty sure they are.
+17:55 < ori> but it'd be dumb if I'm wrong.
+17:55 < h9ro> try some really big alignments
+17:55 < h9ro> just in case
+17:55 < h9ro> you never know how dumb the SSD is!!!
+17:56 < h9ro> maybe make a test to find the internal ssd blocksizes
+17:56 < ori> yeah, but the test program is doing the same alignments I *think* I'm doing in gefs.
+17:56 < h9ro> and the ssd might have implemented readahead
+17:56 < ori> no worries. I'll figure it out.
+
+20:10 < ori> when you have multiple procs
+20:11 < ori> eg, for gefs testing one of the tests I use is '{for(i in *){cat $i&}} | tput'
+
+ */
+enum {
+        KiB = 1024,
+        MiB = 1024*KiB,
+        GiB = 1024*MiB,
+};
+
+int     nproc   = 1;
+int     iosize  = 8*1024;
+char    *order  = "seq";
+vlong   fsize   = 0;
+
+int     fd;
+char    *buf;
+vlong   nbytes  = 0;
+long    (*iofn)(int, void*, long, vlong);
+
+void
+usage(void)
+{
+        fprint(2, "usage: %s [-p procs] [-s iosize] [-o order] path\n", argv0);
+        exits("usage");
+}
+
+void
+inc64(vlong *v, vlong dv)
+{
+        vlong ov, nv;
+
+        while(1){
+                ov = *v;
+                nv = ov + dv;
+                extern int cas64(u64int*, u64int, u64int);
+                if(cas64((u64int*)v, ov, nv))
+                        break;
+        }
+}
+
+vlong
+seq(vlong off)
+{
+        return off + iosize;
+}
+
+vlong
+skip(vlong off)
+{
+        return off + 2*iosize;
+}
+
+vlong
+randoff(vlong off)
+{
+        return (fastrand()<<32)|fastrand();
+}
+
+void
+io(vlong (*next)(vlong))
+{
+        vlong off = 0;
+
+        while(1){
+                pwrite(fd, buf, iosize, off);
+                inc64(&nbytes, iosize);
+                off = next(off);
+                if(off > fsize + iosize)
+                        off -= fsize;
+                off -= off % iosize;
+        }
+}
+
+void
+showstats(void)
+{
+        double speed;
+        int sec;
+
+        sec = 0;
+        while(1){
+                sleep(1000);
+                sec++;
+                speed = (double)nbytes/(double)sec;
+                print("%lld/%d\n", nbytes, sec);
+                if(speed > GiB)
+                        print("%f GiB/s\n", speed/GiB);
+                else if(speed > MiB)
+                        print("%f MiB/s\n", speed/MiB);
+                else if(speed > KiB)
+                        print("%f KiB/s\n", speed/KiB);
+        }
+}
+
+void
+main(int argc, char **argv)
+{
+        Dir *d;
+        int i, pid;
+
+        iofn = pwrite;
+        ARGBEGIN{
+        case 'p':
+                nproc = atoi(EARGF(usage()));
+                break;
+        case 's':
+                iosize = atoi(EARGF(usage()));
+                break;
+        case 'o':
+                order = EARGF(usage());
+                break;
+        case 'r':
+                iofn = pread;
+                break;
+        default:
+                usage();
+                break;
+        }ARGEND;
+
+        if(argc != 1)
+                usage();
+        if((fd = open(argv[0], OWRITE)) == -1)
+                sysfatal("open %s: %r", argv[0]);
+        if((d = dirfstat(fd)) == nil)
+                sysfatal("stat %s: %r", argv[0]);
+        if((buf = malloc(iosize)) == nil)
+                sysfatal("alloc buf: %r");
+        fsize = d->length;
+
+        for(i = 0; i < nproc; i++){
+                if((pid = rfork(RFPROC|RFMEM)) == -1)
+                        sysfatal("rfork: %r");
+                if(pid == 0){
+                        if(strcmp(order, "seq") == 0)
+                                io(seq);
+                        else if(strcmp(order, "skip") == 0)
+                                io(skip);
+                        else if(strcmp(order, "rand") == 0)
+                                io(randoff);
+                        else
+                                sysfatal("unknown order %s\n", order);
+                        exits(nil);
+                }
+        }
+        showstats();
+        exits(nil);
+}
+