Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add support for kernel hash statistics generation for vm...
details: https://anonhg.NetBSD.org/src/rev/774c1b32c632
branches: trunk
changeset: 960877:774c1b32c632
user: simonb <simonb%NetBSD.org@localhost>
date: Thu Apr 01 06:22:09 2021 +0000
description:
Add support for kernel hash statistics generation for vmstat -h/-H. As
well as not needing any kmem grovelling, also much faster as it doesn't
need a kmem read for hash bucket and for each item in the hash bucket
chains.
diffstat:
sys/kern/subr_hash.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++-
sys/sys/sysctl.h | 24 +++++++++-
2 files changed, 145 insertions(+), 3 deletions(-)
diffs (186 lines):
diff -r d30aebbf4293 -r 774c1b32c632 sys/kern/subr_hash.c
--- a/sys/kern/subr_hash.c Thu Apr 01 05:33:50 2021 +0000
+++ b/sys/kern/subr_hash.c Thu Apr 01 06:22:09 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_hash.c,v 1.7 2016/07/06 05:20:48 ozaki-r Exp $ */
+/* $NetBSD: subr_hash.c,v 1.8 2021/04/01 06:22:09 simonb Exp $ */
/*
* Copyright (c) 1982, 1986, 1991, 1993
@@ -37,13 +37,17 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_hash.c,v 1.7 2016/07/06 05:20:48 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_hash.c,v 1.8 2021/04/01 06:22:09 simonb Exp $");
#include <sys/param.h>
#include <sys/bitops.h>
#include <sys/kmem.h>
#include <sys/systm.h>
#include <sys/pslist.h>
+#include <sys/rwlock.h>
+#include <sys/sysctl.h>
+
+static int hashstat_sysctl(SYSCTLFN_PROTO);
static size_t
hash_list_size(enum hashtype htype)
@@ -138,3 +142,119 @@
const size_t esize = hash_list_size(htype);
kmem_free(hashtbl, esize * (hashmask + 1));
}
+
+/*
+ * Support for hash statistics (vmstat -H / vmstat -h hashname).
+ */
+
+struct hashstat {
+ const char *hs_name;
+ hashstat_func_t hs_func;
+ TAILQ_ENTRY(hashstat) hs_next;
+};
+TAILQ_HEAD(, hashstat) hashstat_list =
+ TAILQ_HEAD_INITIALIZER(hashstat_list);
+static krwlock_t hashstat_lock;
+
+void
+hashstat_register(const char *name, hashstat_func_t func)
+{
+ struct hashstat *hs;
+
+ hs = kmem_alloc(sizeof(*hs), KM_SLEEP);
+
+ hs->hs_name = name;
+ hs->hs_func = func;
+
+ rw_enter(&hashstat_lock, RW_WRITER);
+ TAILQ_INSERT_TAIL(&hashstat_list, hs, hs_next);
+ rw_exit(&hashstat_lock);
+}
+
+/*
+ * sysctl support for returning kernel hash statistics.
+ *
+ * We (ab)use CTL_DESCRIBE and CTL_QUERY:
+ * When passed an OID of CTL_DESCRIBE, return a list and description
+ * of the available hashes.
+ * When passed an OID of CTL_QUERY, use the hash name passed in the
+ * "new" hash input as the name of a single hash to return stats on.
+ */
+static int
+hashstat_sysctl(SYSCTLFN_ARGS)
+{
+ struct hashstat_sysctl hs;
+ struct hashstat *hash;
+ char queryname[SYSCTL_NAMELEN];
+ size_t written;
+ bool fill, query;
+ int error;
+
+ if (oldp == NULL) {
+ *oldlenp = 0;
+ TAILQ_FOREACH(hash, &hashstat_list, hs_next)
+ *oldlenp += sizeof(hs);
+ return 0;
+ }
+
+ error = 0;
+ written = 0;
+
+ if (namelen > 0 && name[0] == CTL_DESCRIBE)
+ fill = false;
+ else
+ fill = true;
+
+ if (namelen > 0 && name[0] == CTL_QUERY) {
+ const struct hashstat_sysctl *h = newp;
+
+ if (h == NULL) {
+ /* Can't QUERY one hash without supplying the hash name. */
+ return EINVAL;
+ }
+ query = true;
+ h = newp;
+ strlcpy(queryname, h->hash_name, sizeof(queryname));
+ } else {
+ query = false;
+ }
+
+ sysctl_unlock();
+ rw_enter(&hashstat_lock, RW_READER);
+ TAILQ_FOREACH(hash, &hashstat_list, hs_next) {
+ if (query &&
+ (strncmp(hash->hs_name, queryname, sizeof(hash->hs_name)) != 0)) {
+ continue;
+ }
+
+ memset(&hs, 0, sizeof(hs));
+ error = hash->hs_func(&hs, fill);
+ if (error)
+ break;
+
+ error = sysctl_copyout(l, &hs, oldp, sizeof(hs));
+ if (error)
+ break;
+ written += sizeof(hs);
+ oldp = (char *)oldp + sizeof(hs);
+ }
+ rw_exit(&hashstat_lock);
+ sysctl_relock();
+
+ *oldlenp = written;
+ return error;
+}
+
+
+SYSCTL_SETUP(sysctl_hash_setup, "sysctl hash stats setup")
+{
+
+ rw_init(&hashstat_lock); /* as good a place as any for this */
+
+ sysctl_createv(NULL, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_STRUCT,
+ "hashstat", SYSCTL_DESCR("kernel hash statistics"),
+ hashstat_sysctl, 0, NULL, 0,
+ CTL_KERN, CTL_CREATE, CTL_EOL);
+}
diff -r d30aebbf4293 -r 774c1b32c632 sys/sys/sysctl.h
--- a/sys/sys/sysctl.h Thu Apr 01 05:33:50 2021 +0000
+++ b/sys/sys/sysctl.h Thu Apr 01 06:22:09 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sysctl.h,v 1.231 2020/10/17 09:06:15 mlelstv Exp $ */
+/* $NetBSD: sysctl.h,v 1.232 2021/04/01 06:22:10 simonb Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -727,6 +727,28 @@
#define KERN_EVCNT_COUNT_ANY 0
#define KERN_EVCNT_COUNT_NONZERO 1
+
+/*
+ * kern.hashstat returns an array of these structures, which are designed
+ * to be immune to 32/64 bit emulation issues.
+ *
+ * Hash users can register a filler function to fill the hashstat_sysctl
+ * which can then be exposed via vmstat(1).
+ *
+ * See comments for hashstat_sysctl() in kern/subr_hash.c for details
+ * on sysctl(3) usage.
+ */
+struct hashstat_sysctl {
+ char hash_name[SYSCTL_NAMELEN];
+ char hash_desc[SYSCTL_NAMELEN];
+ uint64_t hash_size;
+ uint64_t hash_used;
+ uint64_t hash_items;
+ uint64_t hash_maxchain;
+};
+typedef int (*hashstat_func_t)(struct hashstat_sysctl *, bool);
+void hashstat_register(const char *, hashstat_func_t);
+
/*
* CTL_VM identifiers in <uvm/uvm_param.h>
*/
Home |
Main Index |
Thread Index |
Old Index