From 9a815ed696b03a0db2a98560575e13de0db2bf88 Mon Sep 17 00:00:00 2001 From: thorpej Date: Thu, 30 Jan 1997 04:00:52 +0000 Subject: [PATCH] A performance optimization, inspired by a conversation with Thor Simon: - Keep a freelist of component buffer headers, defaulting to 8 headers per component (tunable with the CCDNBUF kernel compile option). - When allocating a component buffer, try to pull a header off the freelist first, falling back on MALLOC() if the freelist is empty. Use MALLOC() rather than malloc(), because it will attempt to short-cut the allocation before actually making a full-blown malloc() call. - Keep statistics on how many component buffer headers have been allocated and how many of those allocations have resulted in freelist misses. With these changes, I observed measurable decreases in system and wall clock time on operations on an 8G ccd, as well as a measurable drop in the time spent in ccdbuffer() (measured with kernel profiling). --- sys/dev/ccd.c | 79 +++++++++++++++++++++++++++++++++++++++++------- sys/dev/ccdvar.h | 15 +++++++-- 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/sys/dev/ccd.c b/sys/dev/ccd.c index 83375e9478d9..4d9233fcd3d0 100644 --- a/sys/dev/ccd.c +++ b/sys/dev/ccd.c @@ -1,7 +1,7 @@ -/* $NetBSD: ccd.c,v 1.37 1997/01/30 03:32:56 thorpej Exp $ */ +/* $NetBSD: ccd.c,v 1.38 1997/01/30 04:00:52 thorpej Exp $ */ /*- - * Copyright (c) 1996 The NetBSD Foundation, Inc. + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -132,14 +132,46 @@ struct ccdbuf { int cb_unit; /* target unit */ int cb_comp; /* target component */ int cb_flags; /* misc. flags */ - -#define CBF_MIRROR 0x01 /* we're for a mirror component */ + LIST_ENTRY(ccdbuf) cb_list; /* entry on freelist */ }; -#define getccdbuf() \ - ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) -#define putccdbuf(cbp) \ - free((caddr_t)(cbp), M_DEVBUF) +/* cb_flags */ +#define CBF_MIRROR 0x01 /* we're for a mirror component */ + +/* + * Number of freelist buffers per component. Overridable in kernel + * config file and patchable. + */ +#ifndef CCDNBUF +#define CCDNBUF 8 +#endif +int ccdnbuf = CCDNBUF; + +/* + * XXX Is it OK to wait here? + * XXX maybe set up a timeout when we hit some lowater? + * XXX --thorpej + */ +#define CCDGETBUF(cs, cbp) do { \ + (cs)->sc_ngetbuf++; \ + if (((cbp) = (cs)->sc_freelist.lh_first) != NULL) { \ + LIST_REMOVE((cbp), cb_list); \ + (cs)->sc_freecount--; \ + } else { \ + (cs)->sc_nmisses++; \ + MALLOC((cbp), struct ccdbuf *, \ + sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK); \ + } \ + } while (0) + +#define CCDPUTBUF(cs, cbp) do { \ + if ((cs)->sc_freecount == (cs)->sc_hiwat) { \ + FREE((cbp), M_DEVBUF); \ + } else { \ + LIST_INSERT_HEAD(&(cs)->sc_freelist, (cbp), cb_list); \ + (cs)->sc_freecount++; \ + } \ + } while (0) #define CCDLABELDEV(dev) \ (MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) @@ -221,6 +253,7 @@ ccdinit(ccd, cpaths, p) struct partinfo dpart; struct ccdgeom *ccg = &cs->sc_geom; char tmppath[MAXPATHLEN]; + struct ccdbuf *cbp; int error; #ifdef DEBUG @@ -410,6 +443,23 @@ ccdinit(ccd, cpaths, p) ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; + /* + * Allocate the component buffer header freelist. We allocate + * ccdnbuf buffers per component. + */ + LIST_INIT(&cs->sc_freelist); + cs->sc_hiwat = cs->sc_nccdisks * ccdnbuf; + cs->sc_freecount = cs->sc_hiwat; + for (ix = 0; ix < cs->sc_hiwat; ix++) { + MALLOC(cbp, struct ccdbuf *, sizeof(struct ccdbuf), + M_DEVBUF, M_WAITOK); + LIST_INSERT_HEAD(&cs->sc_freelist, cbp, cb_list); + } + + /* Reset statistics. */ + cs->sc_nmisses = 0; + cs->sc_ngetbuf = 0; + cs->sc_flags |= CCDF_INITED; cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */ cs->sc_unit = ccd->ccd_unit; @@ -808,7 +858,7 @@ ccdbuffer(cs, bp, bn, addr, bcount, cbpp) /* * Fill in the component buf structure. */ - cbp = getccdbuf(); + CCDGETBUF(cs, cbp); cbp->cb_flags = 0; cbp->cb_buf.b_flags = bp->b_flags | B_CALL; cbp->cb_buf.b_iodone = ccdiodone; @@ -847,7 +897,7 @@ ccdbuffer(cs, bp, bn, addr, bcount, cbpp) */ if ((cs->sc_cflags & CCDF_MIRROR) && ((cbp->cb_buf.b_flags & B_READ) == 0)) { - cbp = getccdbuf(); + CCDGETBUF(cs, cbp); *cbp = *cbpp[0]; cbp->cb_flags = CBF_MIRROR; cbp->cb_buf.b_dev = ci2->ci_dev; /* XXX */ @@ -924,7 +974,7 @@ ccdiodone(vbp) } count = cbp->cb_buf.b_bcount; cbflags = cbp->cb_flags; - putccdbuf(cbp); + CCDPUTBUF(cs, cbp); /* * If all done, "interrupt". @@ -1014,6 +1064,7 @@ ccdioctl(dev, cmd, data, flag, p) struct ccd_softc *cs; struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; struct ccddevice ccd; + struct ccdbuf *cbp; char **cpp; struct vnode **vpp; @@ -1165,6 +1216,12 @@ ccdioctl(dev, cmd, data, flag, p) free(cs->sc_cinfo[i].ci_path, M_DEVBUF); } + /* Free component buffer freelist. */ + while ((cbp = cs->sc_freelist.lh_first) != NULL) { + LIST_REMOVE(cbp, cb_list); + FREE(cbp, M_DEVBUF); + } + /* Free interleave index. */ for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) free(cs->sc_itable[i].ii_index, M_DEVBUF); diff --git a/sys/dev/ccdvar.h b/sys/dev/ccdvar.h index 85893c6c243f..32ff78194588 100644 --- a/sys/dev/ccdvar.h +++ b/sys/dev/ccdvar.h @@ -1,7 +1,7 @@ -/* $NetBSD: ccdvar.h,v 1.11 1996/02/28 01:08:32 thorpej Exp $ */ +/* $NetBSD: ccdvar.h,v 1.12 1997/01/30 04:00:53 thorpej Exp $ */ /*- - * Copyright (c) 1996 The NetBSD Foundation, Inc. + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -78,6 +78,8 @@ * @(#)cdvar.h 8.1 (Berkeley) 6/10/93 */ +#include + /* * Dynamic configuration and disklabel support by: * Jason R. Thorpe @@ -174,6 +176,8 @@ struct ccdgeom { u_int32_t ccg_ncylinders; /* # cylinders per unit */ }; +struct ccdbuf; + /* * A concatenated disk is described after initialization by this structure. */ @@ -189,6 +193,13 @@ struct ccd_softc { struct ccdgeom sc_geom; /* pseudo geometry info */ char sc_xname[8]; /* XXX external name */ struct disk sc_dkdev; /* generic disk device info */ + LIST_HEAD(, ccdbuf) sc_freelist; /* component buffer freelist */ + int sc_freecount; /* number of entries */ + int sc_hiwat; /* freelist high water mark */ + + /* Statistics */ + u_long sc_nmisses; /* number of freelist misses */ + u_long sc_ngetbuf; /* number of ccdbuf allocs */ }; /* sc_flags */