diff options
author | dillon <dillon@FreeBSD.org> | 1999-12-13 17:34:45 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 1999-12-13 17:34:45 +0000 |
commit | bab004e7294b9a4e8172382b0cb3c56e712c7dee (patch) | |
tree | e58f124699f778dea87aafa11777502c37675990 /sys/nfs | |
parent | 0a7cf7b8591f3e931974448e2634431df25c3c30 (diff) | |
download | FreeBSD-src-bab004e7294b9a4e8172382b0cb3c56e712c7dee.zip FreeBSD-src-bab004e7294b9a4e8172382b0cb3c56e712c7dee.tar.gz |
Add a readahead heuristic to the NFS server side code. While the server
cannot unilaterally pass data to a client it can reduce the physical
disk transaction overhead by reading larger blocks. This results in
better pipelining of requests/responses over the network and an almost
100% increase in cpu efficiency on the server. On a 100BaseTX network
NFS read performance increases from 8.5 MBytes/sec to 10 MB/sec (maxed
out), and cpu efficiency increases from 72% idle to 80% idle on the server.
Reviewed by: Alfred Perlstein <bright@wintelcom.net>
Diffstat (limited to 'sys/nfs')
-rw-r--r-- | sys/nfs/nfs_serv.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c index e0aa5ab..ffaeea7 100644 --- a/sys/nfs/nfs_serv.c +++ b/sys/nfs/nfs_serv.c @@ -115,6 +115,18 @@ #define MAX_COMMIT_COUNT (1024 * 1024) +#define NUM_HEURISTIC 64 +#define NHUSE_INIT 64 +#define NHUSE_INC 16 +#define NHUSE_MAX 2048 + +static struct nfsheur { + struct vnode *nh_vp; /* vp to match (unreferenced pointer) */ + off_t nh_nextr; /* next offset for sequential detection */ + int nh_use; /* use count for selection */ + int nh_seqcount; /* heuristic */ +} nfsheur[NUM_HEURISTIC]; + nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON }; #ifndef NFS_NOSERVER @@ -780,7 +792,9 @@ nfsrv_read(nfsd, slp, procp, mrq) fhandle_t *fhp; struct uio io, *uiop = &io; struct vattr va, *vap = &va; + struct nfsheur *nh; off_t off; + int ioflag = 0; u_quad_t frev; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); @@ -833,12 +847,73 @@ nfsrv_read(nfsd, slp, procp, mrq) error = 0; goto nfsmout; } + + /* + * Calculate byte count to read + */ + if (off >= vap->va_size) cnt = 0; else if ((off + reqlen) > vap->va_size) cnt = vap->va_size - off; else cnt = reqlen; + + /* + * Calculate seqcount for heuristic + */ + + { + int hi; + int try = 4; + + /* + * Locate best candidate + */ + + hi = ((int)vp / sizeof(struct vnode)) & (NUM_HEURISTIC - 1); + nh = &nfsheur[hi]; + + while (try--) { + if (nfsheur[hi].nh_vp == vp) { + nh = &nfsheur[hi]; + break; + } + if (nfsheur[hi].nh_use > 0) + --nfsheur[hi].nh_use; + hi = (hi + 1) & (NUM_HEURISTIC - 1); + if (nfsheur[hi].nh_use < nh->nh_use) + nh = &nfsheur[hi]; + } + + if (nh->nh_vp != vp) { + nh->nh_vp = vp; + nh->nh_nextr = off; + nh->nh_use = NHUSE_INIT; + if (off == 0) + nh->nh_seqcount = 4; + else + nh->nh_seqcount = 1; + } + + /* + * Calculate heuristic + */ + + if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) { + if (++nh->nh_seqcount > 127) + nh->nh_seqcount = 127; + } else if (nh->nh_seqcount > 1) { + nh->nh_seqcount = 1; + } else { + nh->nh_seqcount = 0; + } + nh->nh_use += NHUSE_INC; + if (nh->nh_use > NHUSE_MAX) + nh->nh_use = NHUSE_MAX; + ioflag |= nh->nh_seqcount << 16; + } + nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)); if (v3) { nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); @@ -896,8 +971,9 @@ nfsrv_read(nfsd, slp, procp, mrq) uiop->uio_resid = len; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; - error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); + error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); off = uiop->uio_offset; + nh->nh_nextr = off; FREE((caddr_t)iv2, M_TEMP); if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) { if (!error) |