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).
This commit is contained in:
thorpej 1997-01-30 04:00:52 +00:00
parent e911ec0bfe
commit 9a815ed696
2 changed files with 81 additions and 13 deletions

View File

@ -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);

View File

@ -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 <sys/queue.h>
/*
* Dynamic configuration and disklabel support by:
* Jason R. Thorpe <thorpej@nas.nasa.gov>
@ -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 */