Per-CPU VFS Namecache Effectiveness Statistics:
authorHiten Pandya <hmp@dragonflybsd.org>
Fri, 2 Apr 2004 05:46:03 +0000 (05:46 +0000)
committerHiten Pandya <hmp@dragonflybsd.org>
Fri, 2 Apr 2004 05:46:03 +0000 (05:46 +0000)
* Convert nchstats into a CPU indexed array

* Export the per-CPU nchstats as a sysctl vfs.cache.nchstats
  and let user-land aggregate them.

* Add a function called kvm_nch_cpuagg() to libkvm; it is
  shared by systat(1) and vmstat(1) and the ncache-stats test
  program.  As the function name suggests, it aggregates
  the per-CPU nchstats.

* Move struct nchstats into a separate header to avoid
  header file namespace pollution; sys/nchstats.h.

* Keep a cached copy of the globaldata pointer in the VFS
  specific LOOKUP op, and use that to increment the
  namecache effectiveness counters (nchstats).

* Modify systat(1) and vmstat(1) to accomodate the new
  behavior of accessing nchstats.  Remove a (now) redundant
  sysctl to get the cpu count (hw.ncpu), instead we just divide
  the total length of the nchstats array returned by sysctl
  by sizeof(struct nchstats) to get the CPU count.

* Garbage-collect unused variables and fix nearby warnings
  in systat(1) an vmstat(1).

* Add a very-cool test program, that prints the nchstats
  per-CPU statistics to show CPU distribution.  Here is the
  output it generates on an 2-processor SMP machine:

  gray# ncache-stats
  VFS Name Cache Effectiveness Statistics
     4207370 total name lookups
  COUNTER             CPU-1       CPU-2           TOTAL
  goodhits            2477657     1060677         (3538334  )
  neghits             107531      47294           (154825   )
  badhits             28968       7720            (36688    )
  falsehits           0           0               (0        )
  misses              339671      137852          (477523   )
  longnames           0           0               (0        )
  passes 2            13104       6813            (19917    )
  2-passes            25134       15257           (40391    )

The SMP machine used for testing this commit was proudly presented
by David Rhodus <drhodus@dragonflybsd.org>.

Reviewed-by: Matthew Dillon <dillon@backplane.com>

15 files changed:
lib/libkvm/Makefile
lib/libkvm/kvm.h
lib/libkvm/kvm_util.c [new file with mode: 0644]
sys/kern/vfs_cache.c
sys/sys/globaldata.h
sys/sys/namei.h
sys/sys/nchstats.h [new file with mode: 0644]
sys/vfs/gnu/ext2fs/ext2_lookup.c
sys/vfs/isofs/cd9660/cd9660_lookup.c
sys/vfs/udf/udf_vnops.c
sys/vfs/ufs/ufs_lookup.c
test/pcpu/Makefile [new file with mode: 0644]
test/pcpu/ncache-stats.c [new file with mode: 0644]
usr.bin/systat/vmstat.c
usr.bin/vmstat/vmstat.c

index 7fc5274..c6c5521 100644 (file)
@@ -1,11 +1,11 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/4/93
 # $FreeBSD: src/lib/libkvm/Makefile,v 1.9.2.1 2001/04/25 10:04:32 ru Exp $
-# $DragonFly: src/lib/libkvm/Makefile,v 1.2 2003/06/17 04:26:49 dillon Exp $
+# $DragonFly: src/lib/libkvm/Makefile,v 1.3 2004/04/02 05:46:02 hmp Exp $
 
 LIB=   kvm
 CFLAGS+=-DLIBC_SCCS -I${.CURDIR}/../../sys
 SRCS=  kvm.c kvm_${MACHINE_ARCH}.c kvm_file.c kvm_getloadavg.c \
-       kvm_getswapinfo.c kvm_proc.c
+       kvm_getswapinfo.c kvm_proc.c kvm_util.c
 INCS=  kvm.h
 
 MAN=   kvm.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 kvm_getprocs.3 \
index 55fea82..09b3c35 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)kvm.h       8.1 (Berkeley) 6/2/93
  * $FreeBSD: src/lib/libkvm/kvm.h,v 1.11 1999/08/27 23:44:50 peter Exp $
- * $DragonFly: src/lib/libkvm/kvm.h,v 1.4 2003/11/12 20:21:30 eirikn Exp $
+ * $DragonFly: src/lib/libkvm/kvm.h,v 1.5 2004/04/02 05:46:02 hmp Exp $
  */
 
 #ifndef _KVM_H_
@@ -50,6 +50,7 @@ typedef struct __kvm kvm_t;
 
 struct kinfo_proc;
 struct proc;
+struct nchstats;
 
 struct kvm_swap {
        char    ksw_devname[32];
@@ -64,6 +65,7 @@ struct kvm_swap {
 #define SWIF_DEV_PREFIX        0x0002
 
 __BEGIN_DECLS
+void kvm_nch_cpuagg(struct nchstats *, struct nchstats *, int);
 int      kvm_close (kvm_t *);
 char   **kvm_getargv (kvm_t *, const struct kinfo_proc *, int);
 char   **kvm_getenvv (kvm_t *, const struct kinfo_proc *, int);
diff --git a/lib/libkvm/kvm_util.c b/lib/libkvm/kvm_util.c
new file mode 100644 (file)
index 0000000..98e4d0b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003-2004.  Hiten Pandya <hmp@backplane.com>.
+ * 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *       
+ * THIS SOFTWARE IS PROVIDED BY HITEN PANDYA AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL HITEN PANDYA OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $DragonFly: src/lib/libkvm/kvm_util.c,v 1.1 2004/04/02 05:46:02 hmp Exp $
+ */
+
+/*
+ * Useful functions that are used across the source base for
+ * various purpose.
+ */
+
+#include <sys/param.h>
+#include <sys/nchstats.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <err.h>
+
+/*
+ * Aggregate the per-cpu counters we retrieved via sysctl(2)
+ * to give the total across the CPUs.  Use a nasty trick to
+ * aggregate the counters in the structure! YYY
+ */
+void
+kvm_nch_cpuagg(struct nchstats *unagg, struct nchstats *ttl, int cpucnt)
+{
+       int i, off, siz;
+       siz = sizeof(struct nchstats);
+
+       if (!unagg && !ttl)
+               return;
+
+       bzero(ttl, siz);
+       
+       /* kick hmp@ for this nasty loop! :-) */
+       for (i = 0; i < cpucnt; ++i) {
+               for (off = 0; off < siz; off += sizeof(u_long)) {
+                       *(u_long *)((char *)(*(&ttl)) + off) +=
+                       *(u_long *)((char *)&unagg[i] + off);
+               }
+       }
+}
index 876b66c..b778cc6 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)vfs_cache.c 8.5 (Berkeley) 3/22/95
  * $FreeBSD: src/sys/kern/vfs_cache.c,v 1.42.2.6 2001/10/05 20:07:03 dillon Exp $
- * $DragonFly: src/sys/kern/vfs_cache.c,v 1.13 2004/03/01 06:33:17 dillon Exp $
+ * $DragonFly: src/sys/kern/vfs_cache.c,v 1.14 2004/04/02 05:46:02 hmp Exp $
  */
 
 #include <sys/param.h>
@@ -52,6 +52,7 @@
 #include <sys/namei.h>
 #include <sys/filedesc.h>
 #include <sys/fnv_hash.h>
+#include <sys/globaldata.h>
 
 /*
  * Random lookups in the cache are accomplished with a hash table using
@@ -73,6 +74,8 @@
 #define NCHHASH(hash)  (&nchashtbl[(hash) & nchash])
 #define MINNEG         1024
 
+MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
+
 static LIST_HEAD(nchashhead, namecache) *nchashtbl;    /* Hash Table */
 static struct namecache_list   ncneglist;              /* instead of vnode */
 static struct namecache                rootnamecache;          /* Dummy node */
@@ -95,8 +98,6 @@ SYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, "");
 static u_long  numunres;               /* number of unresolved entries */
 SYSCTL_ULONG(_debug, OID_AUTO, numunres, CTLFLAG_RD, &numunres, 0, "");
 
-struct nchstats nchstats;              /* cache effectiveness statistics */
-
 SYSCTL_INT(_debug, OID_AUTO, vnsize, CTLFLAG_RD, 0, sizeof(struct vnode), "");
 SYSCTL_INT(_debug, OID_AUTO, ncsize, CTLFLAG_RD, 0, sizeof(struct namecache), "");
 
@@ -119,11 +120,35 @@ static u_long numposhits; STATNODE(CTLFLAG_RD, numposhits, &numposhits);
 static u_long numnegzaps; STATNODE(CTLFLAG_RD, numnegzaps, &numnegzaps);
 static u_long numneghits; STATNODE(CTLFLAG_RD, numneghits, &numneghits);
 
+struct nchstats nchstats[SMP_MAXCPU];
+/*
+ * Export VFS cache effectiveness statistics to user-land.
+ *
+ * The statistics are left for aggregation to user-land so
+ * neat things can be achieved, like observing per-CPU cache
+ * distribution.
+ */
+static int
+nchstats_agg(SYSCTL_HANDLER_ARGS)
+{
+       struct globaldata *gd;
+       int i, error;
+
+       error = 0;
+       for (i = 0; i < ncpus; ++i) {
+               gd = globaldata_find(i);
+               if ((error = SYSCTL_OUT(req, (void *)&(*gd->gd_nchstats),
+                       sizeof(struct nchstats))))
+                       break;
+       }
+
+       return (error);
+}
+SYSCTL_PROC(_vfs_cache, OID_AUTO, nchstats, CTLTYPE_OPAQUE|CTLFLAG_RD,
+  0, 0, nchstats_agg, "S,nchstats", "VFS cache effectiveness statistics");
 
 static void cache_zap(struct namecache *ncp);
 
-MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
-
 /*
  * cache_hold() and cache_drop() prevent the premature deletion of a
  * namecache entry but do not prevent operations (such as zapping) on
@@ -284,6 +309,7 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
 {
        struct namecache *ncp;
        u_int32_t hash;
+       globaldata_t gd = mycpu;
 
        numcalls++;
 
@@ -330,14 +356,14 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
                } else {
                        nummiss++;
                }
-               nchstats.ncs_miss++;
+               gd->gd_nchstats->ncs_miss++;
                return (0);
        }
 
        /* We don't want to have an entry, so dump it */
        if ((cnp->cn_flags & CNP_MAKEENTRY) == 0) {
                numposzaps++;
-               nchstats.ncs_badhits++;
+               gd->gd_nchstats->ncs_badhits++;
                cache_zap(ncp);
                return (0);
        }
@@ -345,7 +371,7 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
        /* We found a "positive" match, return the vnode */
        if (ncp->nc_vp) {
                numposhits++;
-               nchstats.ncs_goodhits++;
+               gd->gd_nchstats->ncs_goodhits++;
                *vpp = ncp->nc_vp;
                cache_drop(ncp);
                return (-1);
@@ -354,7 +380,7 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
        /* We found a negative match, and want to create it, so purge */
        if (cnp->cn_nameiop == NAMEI_CREATE) {
                numnegzaps++;
-               nchstats.ncs_badhits++;
+               gd->gd_nchstats->ncs_badhits++;
                cache_zap(ncp);
                return (0);
        }
@@ -368,7 +394,7 @@ cache_lookup(struct vnode *dvp, struct namecache *par, struct vnode **vpp,
         */
        TAILQ_REMOVE(&ncneglist, ncp, nc_vnode);
        TAILQ_INSERT_TAIL(&ncneglist, ncp, nc_vnode);
-       nchstats.ncs_neghits++;
+       gd->gd_nchstats->ncs_neghits++;
        if (ncp->nc_flag & NCF_WHITEOUT)
                cnp->cn_flags |= CNP_ISWHITEOUT;
        cache_drop(ncp);
@@ -578,13 +604,22 @@ again:
 }
 
 /*
- * Name cache initialization, from vfs_init() when we are booting
+ * Name cache initialization, from vfsinit() when we are booting
  *
  * rootnamecache is initialized such that it cannot be recursively deleted.
  */
 void
 nchinit(void)
 {
+       int i;
+       globaldata_t gd;
+
+       /* initialise per-cpu namecache effectiveness statistics. */
+       for (i = 0; i < ncpus; ++i) {
+               gd = globaldata_find(i);
+               gd->gd_nchstats = &nchstats[i];
+       }
+       
        TAILQ_INIT(&ncneglist);
        nchashtbl = hashinit(desiredvnodes*2, M_VFSCACHE, &nchash);
        TAILQ_INIT(&rootnamecache.nc_list);
index 0066fa7..13cda08 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $
- * $DragonFly: src/sys/sys/globaldata.h,v 1.30 2004/04/01 17:40:59 dillon Exp $
+ * $DragonFly: src/sys/sys/globaldata.h,v 1.31 2004/04/02 05:46:02 hmp Exp $
  */
 
 #ifndef _SYS_GLOBALDATA_H_
@@ -50,6 +50,9 @@
 #ifndef _SYS_SYSTIMER_H_
 #include <sys/systimer.h> /* fine-grained system timers */
 #endif
+#ifndef _SYS_NCHSTATS_H_
+#include <sys/nchstats.h>
+#endif
 
 /*
  * This structure maps out the global data that needs to be kept on a
@@ -122,6 +125,7 @@ struct globaldata {
        volatile sysclock_t gd_cpuclock_base;   /* cpuclock relative base */
 
        struct pipe     *gd_pipeq;              /* cache pipe structures */
+       struct nchstats *gd_nchstats;           /* namecache effectiveness */
        int             gd_pipeqcount;          /* number of structures */
        lwkt_tokref_t   gd_tokreqbase;          /* requests from other cpus */
        struct proc     *gd_uschedcp;           /* userland scheduler */
index dda7540..b4d7899 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)namei.h     8.5 (Berkeley) 1/9/95
  * $FreeBSD: src/sys/sys/namei.h,v 1.29.2.2 2001/09/30 21:12:54 luigi Exp $
- * $DragonFly: src/sys/sys/namei.h,v 1.10 2004/03/16 17:53:51 dillon Exp $
+ * $DragonFly: src/sys/sys/namei.h,v 1.11 2004/04/02 05:46:02 hmp Exp $
  */
 
 #ifndef _SYS_NAMEI_H_
 #endif
 #endif
 
+#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
+#ifndef _SYS_NCHSTATS_H_
+#include <sys/nchstats.h>
+#endif
+#endif
+
 struct componentname {
        /*
         * Arguments to lookup.
@@ -155,6 +161,7 @@ struct nameidata {
        /* (WANTDNCP)       0x00400000 */
        /* (WANTNCP)        0x00800000 */
 #define CNP_PARAMASK       0x001fff00 /* mask of parameter descriptors */
+
 /*
  * Initialization of an nameidata structure.
  */
@@ -212,20 +219,4 @@ int        relookup (struct vnode *dvp, struct vnode **vpp,
            struct componentname *cnp);
 #endif
 
-/*
- * Stats on usefulness of namei caches.
- */
-struct nchstats {
-       long    ncs_goodhits;           /* hits that we can really use */
-       long    ncs_neghits;            /* negative hits that we can use */
-       long    ncs_badhits;            /* hits we must drop */
-       long    ncs_falsehits;          /* hits with id mismatch */
-       long    ncs_miss;               /* misses */
-       long    ncs_long;               /* long names that ignore cache */
-       long    ncs_pass2;              /* names found with passes == 2 */
-       long    ncs_2passes;            /* number of times we attempt it */
-};
-
-extern struct nchstats nchstats;
-
 #endif /* !_SYS_NAMEI_H_ */
diff --git a/sys/sys/nchstats.h b/sys/sys/nchstats.h
new file mode 100644 (file)
index 0000000..93176a0
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2004.  Hiten Pandya <hmp@backplane.com>.
+ * 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *       
+ * THIS SOFTWARE IS PROVIDED BY HITEN PANDYA AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL HITEN PANDYA OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $DragonFly: src/sys/sys/nchstats.h,v 1.1 2004/04/02 05:46:02 hmp Exp $
+ */
+#ifndef _SYS_NCHSTATS_H_
+#define _SYS_NCHSTATS_H_
+
+/*
+ * Statistics on the usefulness of namei caches.
+ * (per-cpu)
+ */
+struct nchstats {
+       unsigned long   ncs_goodhits;   /* hits that we can really use */
+       unsigned long   ncs_neghits;    /* negative hits that we can use */
+       unsigned long   ncs_badhits;    /* hits we must drop */
+       unsigned long   ncs_falsehits;  /* hits with id mismatch */
+       unsigned long   ncs_miss;       /* misses */
+       unsigned long   ncs_long;       /* long names that ignore cache */
+       unsigned long   ncs_pass2;      /* names found with passes == 2 */
+       unsigned long   ncs_2passes;    /* number of times we attempt it */
+};
+
+#endif /* _SYS_NCHSTATS_H_ */
index 7b9d866..cabd8bd 100644 (file)
@@ -5,7 +5,7 @@
  *  University of Utah, Department of Computer Science
  *
  * $FreeBSD: src/sys/gnu/ext2fs/ext2_lookup.c,v 1.21.2.3 2002/11/17 02:02:42 bde Exp $
- * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_lookup.c,v 1.9 2004/03/01 06:33:20 dillon Exp $
+ * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_lookup.c,v 1.10 2004/04/02 05:46:03 hmp Exp $
  */
 /*
  * Copyright (c) 1989, 1993
@@ -322,6 +322,7 @@ ext2_lookup(ap)
        int flags = cnp->cn_flags;
        int nameiop = cnp->cn_nameiop;
        struct thread *td = cnp->cn_td;
+       globaldata_t gd = mycpu;
 
        int     DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->s_blocksize;
 
@@ -377,7 +378,7 @@ ext2_lookup(ap)
                    (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
                        return (error);
                numdirpasses = 2;
-               nchstats.ncs_2passes++;
+               gd->gd_nchstats.ncs_2passes++;
        }
        prevoff = dp->i_offset;
        endsearch = roundup(dp->i_size, DIRBLKSIZ);
@@ -551,7 +552,7 @@ searchloop:
 
 found:
        if (numdirpasses == 2)
-               nchstats.ncs_pass2++;
+               gd->gd_nchstats.ncs_pass2++;
        /*
         * Check that directory length properly reflects presence
         * of this entry.
index ffe6862..fa7aef6 100644 (file)
@@ -39,7 +39,7 @@
  *
  *     @(#)cd9660_lookup.c     8.2 (Berkeley) 1/23/94
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_lookup.c,v 1.23.2.2 2001/11/04 06:19:47 dillon Exp $
- * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_lookup.c,v 1.9 2004/03/01 06:33:21 dillon Exp $
+ * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_lookup.c,v 1.10 2004/04/02 05:46:03 hmp Exp $
  */
 
 #include <sys/param.h>
@@ -95,6 +95,7 @@ cd9660_lookup(ap)
        } */ *ap;
 {
        struct vnode *vdp;      /* vnode for directory being searched */
+       globaldata_t gd = mycpu;
        struct iso_node *dp;    /* inode for directory being searched */
        struct iso_mnt *imp;    /* file system that directory is in */
        struct buf *bp;                 /* a buffer of directory entries */
@@ -170,7 +171,7 @@ cd9660_lookup(ap)
                    (error = cd9660_blkatoff(vdp, (off_t)dp->i_offset, NULL, &bp)))
                                return (error);
                numdirpasses = 2;
-               nchstats.ncs_2passes++;
+               gd->gd_nchstats->ncs_2passes++;
        }
        endsearch = dp->i_size;
        
@@ -317,7 +318,7 @@ notfound:
 
 found:
        if (numdirpasses == 2)
-               nchstats.ncs_pass2++;
+               gd->gd_nchstats->ncs_pass2++;
        
        /*
         * Found component in pathname.
index a426729..235af57 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/fs/udf/udf_vnops.c,v 1.33 2003/12/07 05:04:49 scottl Exp $
- * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.3 2004/03/29 16:38:36 dillon Exp $
+ * $DragonFly: src/sys/vfs/udf/udf_vnops.c,v 1.4 2004/04/02 05:46:03 hmp Exp $
  */
 
 /* udf_vnops.c */
@@ -913,6 +913,7 @@ udf_lookup(struct vop_cachedlookup_args *a)
        struct fileid_desc *fid = NULL;
        struct udf_dirstream *ds;
        struct thread *td;
+       globaldata_t gd = mycpu;
        u_long nameiop;
        u_long flags;
        char *nameptr;
@@ -944,7 +945,7 @@ udf_lookup(struct vop_cachedlookup_args *a)
        } else {
                offset = node->diroff;
                numdirpasses = 2;
-               nchstats.ncs_2passes++;
+               gd->gd_nchstats->ncs_2passes++;
        }
 
 lookloop:
@@ -996,7 +997,7 @@ lookloop:
                        if ((flags & CNP_ISLASTCN) && nameiop == NAMEI_LOOKUP)
                                node->diroff = ds->offset + ds->off;
                        if (numdirpasses == 2)
-                               nchstats.ncs_pass2++;
+                               gd->gd_nchstats->ncs_pass2++;
                        if (!(flags & CNP_LOCKPARENT) || !(flags & CNP_ISLASTCN)) {
                                a->a_cnp->cn_flags |= CNP_PDIRUNLOCK;
                                VOP_UNLOCK(dvp, NULL, 0, td);
index 16f09dc..beb6f47 100644 (file)
@@ -37,7 +37,7 @@
  *
  *     @(#)ufs_lookup.c        8.15 (Berkeley) 6/16/95
  * $FreeBSD: src/sys/ufs/ufs/ufs_lookup.c,v 1.33.2.7 2001/09/22 19:22:13 iedowse Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_lookup.c,v 1.9 2004/03/01 06:33:23 dillon Exp $
+ * $DragonFly: src/sys/vfs/ufs/ufs_lookup.c,v 1.10 2004/04/02 05:46:03 hmp Exp $
  */
 
 #include "opt_ufs.h"
@@ -155,6 +155,7 @@ ufs_lookup(ap)
        int flags = cnp->cn_flags;
        int nameiop = cnp->cn_nameiop;
        struct thread *td = cnp->cn_td;
+       globaldata_t gd = mycpu;
 
        bp = NULL;
        slotoffset = -1;
@@ -247,7 +248,7 @@ ufs_lookup(ap)
                    (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
                        return (error);
                numdirpasses = 2;
-               nchstats.ncs_2passes++;
+               gd->gd_nchstats->ncs_2passes++;
        }
        prevoff = dp->i_offset;
        endsearch = roundup2(dp->i_size, DIRBLKSIZ);
@@ -457,7 +458,7 @@ notfound:
 
 found:
        if (numdirpasses == 2)
-               nchstats.ncs_pass2++;
+               gd->gd_nchstats->ncs_pass2++;
        /*
         * Check that directory length properly reflects presence
         * of this entry.
diff --git a/test/pcpu/Makefile b/test/pcpu/Makefile
new file mode 100644 (file)
index 0000000..f9acdb3
--- /dev/null
@@ -0,0 +1,14 @@
+# $DragonFly: src/test/pcpu/Makefile,v 1.1 2004/04/02 05:46:03 hmp Exp $
+#
+
+TARGETS=/usr/local/bin/ncache-stats
+
+CFLAGS= -O -g -lkvm -I/usr/src/sys
+
+all:   $(TARGETS)
+
+/usr/local/bin/ncache-stats: ncache-stats.c
+       $(CC) $(CFLAGS) ncache-stats.c -o ${.TARGET}
+
+clean:
+       rm -f $(TARGETS)
diff --git a/test/pcpu/ncache-stats.c b/test/pcpu/ncache-stats.c
new file mode 100644 (file)
index 0000000..4ce19fb
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2003-2004.  Hiten Pandya <hmp@backplane.com>.
+ * 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *       
+ * THIS SOFTWARE IS PROVIDED BY HITEN PANDYA AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL HITEN PANDYA OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $DragonFly: src/test/pcpu/ncache-stats.c,v 1.1 2004/04/02 05:46:03 hmp Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/nchstats.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <err.h>
+#include <kvm.h>
+
+#define _NCH_ENT(t, n, tt)                       \
+    printf("%-20s", t);                          \
+    for (i = 1; i <= ncpus; ++i) {               \
+        printf("%-9ld%s", nch[i-1]. ## n, "\t"); \
+               if (i == ncpus)                          \
+                       printf("(%-9ld)\n", tt. ## n);       \
+       }                                            \
+
+/*
+ * Aggregate the per-cpu counters we retrieved via sysctl(2)
+ * to give the total across the CPUs.  Use a nasty trick to
+ * aggregate the counters in the structure! YYY
+ */
+#if 0
+static void
+nch_cpuagg(struct nchstats *unagg, struct nchstats *ttl, int cpucnt)
+{
+       int i, off, siz;
+       siz = sizeof(struct nchstats);
+
+       if (!unagg && !ttl)
+               return;
+
+       bzero(ttl, siz);
+       
+       /* kick hmp@ for this nasty loop! :-) */
+       for (i = 0; i < cpucnt; ++i) {
+               for (off = 0; off < siz; off += sizeof(u_long)) {
+                       *(u_long *)((char *)(*(&ttl)) + off) +=
+                       *(u_long *)((char *)&unagg[i] + off);
+               }
+       }
+}
+#endif
+
+int main(void)
+{
+       int i, ncpus;
+       struct nchstats *nch, total;
+       size_t nch_len = SMP_MAXCPU * sizeof(struct nchstats);
+       u_long nchtotal;
+
+       nch = malloc(nch_len);
+       if (!nch)
+               exit(-1);
+
+       /* retrieve the statistics */
+       if (sysctlbyname("vfs.cache.nchstats", nch, &nch_len, NULL, 0) < 0) {
+               warn("sysctl");
+               exit(-1);
+       } else {
+               nch = realloc(nch, nch_len);
+               if (!nch)
+                       exit(-1);
+       }
+
+       ncpus = nch_len / sizeof(struct nchstats);
+
+#if defined(DEBUG)
+       printf("Number of processors = %d\n", ncpus);
+#endif
+
+       kvm_nch_cpuagg(nch, &total, ncpus);
+       nchtotal = total.ncs_goodhits + total.ncs_neghits +
+           total.ncs_badhits + total.ncs_falsehits +
+           total.ncs_miss + total.ncs_long;
+
+       printf("VFS Name Cache Effectiveness Statistics\n");
+       printf("%9ld total name lookups\n",nchtotal);
+
+       printf("%-20s", "COUNTER");
+       
+       for (i = 1; i <= ncpus; ++i) {
+               printf("%3s-%-2d%s", "CPU", i, "\t");
+               if (i == ncpus)
+                       printf("\t%-9s\n", "TOTAL");
+       }
+
+       _NCH_ENT("goodhits", ncs_goodhits, total);
+       _NCH_ENT("neghits", ncs_neghits, total);
+       _NCH_ENT("badhits", ncs_badhits, total);
+       _NCH_ENT("falsehits", ncs_falsehits, total);
+       _NCH_ENT("misses", ncs_miss, total);
+       _NCH_ENT("longnames", ncs_long, total);
+       _NCH_ENT("passes 2", ncs_pass2, total);
+       _NCH_ENT("2-passes", ncs_2passes, total);
+
+       free(nch);
+
+       return 0;
+}
index 292266c..078d509 100644 (file)
@@ -32,7 +32,7 @@
  *
  * @(#)vmstat.c        8.2 (Berkeley) 1/12/94
  * $FreeBSD: src/usr.bin/systat/vmstat.c,v 1.38.2.4 2002/03/12 19:50:23 phantom Exp $
- * $DragonFly: src/usr.bin/systat/vmstat.c,v 1.6 2003/11/21 22:46:14 dillon Exp $
+ * $DragonFly: src/usr.bin/systat/vmstat.c,v 1.7 2004/04/02 05:46:03 hmp Exp $
  */
 
 /*
@@ -213,7 +213,7 @@ initkre(void)
                }
        }
 
-       if (num_devices = getnumdevs() < 0) {
+       if ((num_devices = getnumdevs()) < 0) {
                warnx("%s", devstat_errbuf);
                return(0);
        }
@@ -723,10 +723,11 @@ static void
 getinfo(struct Info *s, enum state st)
 {
        struct devinfo *tmp_dinfo;
+       struct nchstats *nch_tmp;
        size_t size;
-       int mib[2];
        int vms_size = sizeof(s->Vms);
        int vmm_size = sizeof(s->Vmm);
+       size_t nch_size = sizeof(s->nchstats) * SMP_MAXCPU;
 
         if (sysctlbyname("vm.vmstats", &s->Vms, &vms_size, NULL, 0)) {
                 perror("sysctlbyname: vm.vmstats");
@@ -743,7 +744,6 @@ getinfo(struct Info *s, enum state st)
        NREAD(X_DESIREDVNODES, &s->desiredvnodes, sizeof(s->desiredvnodes));
        NREAD(X_NUMVNODES, &s->numvnodes, LONG);
        NREAD(X_FREEVNODES, &s->freevnodes, LONG);
-       NREAD(X_NCHSTATS, &s->nchstats, sizeof s->nchstats);
        NREAD(X_INTRCNT, s->intrcnt, nintr * LONG);
        NREAD(X_NUMDIRTYBUFFERS, &s->numdirtybuffers, sizeof(s->numdirtybuffers));
        size = sizeof(s->Total);
@@ -751,9 +751,30 @@ getinfo(struct Info *s, enum state st)
                error("Can't get kernel info: %s\n", strerror(errno));
                bzero(&s->Total, sizeof(s->Total));
        }
-       size = sizeof(ncpu);
-       if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0)
-               ncpu = 1;
+       
+       if ((nch_tmp = malloc(nch_size)) == NULL) {
+               perror("malloc");
+               exit(1);
+       } else {
+               if (sysctlbyname("vfs.cache.nchstats", nch_tmp, &nch_size, NULL, 0)) {
+                       perror("sysctlbyname vfs.cache.nchstats");
+                       free(nch_tmp);
+                       exit(1);
+               } else {
+                       if ((nch_tmp = realloc(nch_tmp, nch_size)) == NULL) {
+                               perror("realloc");
+                               exit(1);
+                       }
+               }
+       }
+
+       /* 
+        * Since the nchstats is a per-cpu array, we can just divide
+        * and get the number of cpus, saving us a sysctl(2) call.
+        */
+       ncpu = nch_size / sizeof(struct nchstats);
+       kvm_nch_cpuagg(nch_tmp, &s->nchstats, ncpu);
+       free(nch_tmp);
 
        tmp_dinfo = last.dinfo;
        last.dinfo = cur.dinfo;
index 818024c..3a38dc9 100644 (file)
@@ -33,7 +33,7 @@
  * @(#) Copyright (c) 1980, 1986, 1991, 1993 The Regents of the University of California.  All rights reserved.
  * @(#)vmstat.c        8.1 (Berkeley) 6/6/93
  * $FreeBSD: src/usr.bin/vmstat/vmstat.c,v 1.38.2.4 2001/07/31 19:52:41 tmm Exp $
- * $DragonFly: src/usr.bin/vmstat/vmstat.c,v 1.9 2003/11/21 22:46:15 dillon Exp $
+ * $DragonFly: src/usr.bin/vmstat/vmstat.c,v 1.10 2004/04/02 05:46:03 hmp Exp $
  */
 
 #define _KERNEL_STRUCTURES
@@ -390,8 +390,6 @@ dovmstat(u_int interval, int reps)
        time_t uptime, halfuptime;
        struct devinfo *tmp_dinfo;
        void needhdr();
-       int mib[2];
-       size_t size;
        int vmm_size = sizeof(vmm);
        int vms_size = sizeof(vms);
        int vmt_size = sizeof(total);
@@ -559,10 +557,12 @@ pct(long top, long bot)
 void
 dosum(void)
 {
-       struct nchstats nchstats;
-       long nchtotal;
+       struct nchstats *nch_tmp, nchstats;
        int vms_size = sizeof(vms);
        int vmm_size = sizeof(vmm);
+       int cpucnt;
+       u_long nchtotal;
+       size_t nch_size = sizeof(struct nchstats) * SMP_MAXCPU;
 
        if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0)) {
                perror("sysctlbyname: vm.vmstats");
@@ -571,7 +571,7 @@ dosum(void)
        if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) {
                perror("sysctlbyname: vm.vmstats");
                exit(1);
-       } 
+       }
        (void)printf("%9u cpu context switches\n", vmm.v_swtch);
        (void)printf("%9u device interrupts\n", vmm.v_intr);
        (void)printf("%9u software interrupts\n", vmm.v_soft);
@@ -611,7 +611,26 @@ dosum(void)
        (void)printf("%9u pages wired down\n", vms.v_wire_count);
        (void)printf("%9u pages free\n", vms.v_free_count);
        (void)printf("%9u bytes per page\n", vms.v_page_size);
-       kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
+       
+       if ((nch_tmp = malloc(nch_size)) == NULL) {
+               perror("malloc");
+               exit(1);
+       } else {
+               if (sysctlbyname("vfs.cache.nchstats", nch_tmp, &nch_size, NULL, 0)) {
+                       perror("sysctlbyname vfs.cache.nchstats");
+                       free(nch_tmp);
+                       exit(1);
+               } else {
+                       if ((nch_tmp = realloc(nch_tmp, nch_size)) == NULL) {
+                               perror("realloc");
+                               exit(1);
+                       }
+               }
+       }
+       
+       cpucnt = nch_size / sizeof(struct nchstats);
+       kvm_nch_cpuagg(nch_tmp, &nchstats, cpucnt);
+
        nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
            nchstats.ncs_badhits + nchstats.ncs_falsehits +
            nchstats.ncs_miss + nchstats.ncs_long;
@@ -625,6 +644,7 @@ dosum(void)
            PCT(nchstats.ncs_badhits, nchtotal),
            PCT(nchstats.ncs_falsehits, nchtotal),
            PCT(nchstats.ncs_long, nchtotal));
+       free(nch_tmp);
 }
 
 #ifdef notyet
@@ -748,9 +768,8 @@ domem(void)
 {
        register struct malloc_type *ks;
        register int i, j;
-       int len, size, first, nkms;
+       int first, nkms;
        long totuse = 0, totfree = 0, totreq = 0;
-       const char *name;
        struct malloc_type kmemstats[MAX_KMSTATS], *kmsp;
        char buf[1024];