Date: 01 Apr 2002 00:07:18 +0200 From: Dag-Erling Smorgrav <des@ofug.org> To: arch@freebsd.org Subject: mutex profiling Message-ID: <xzp8z88e6i1.fsf@flood.ping.uio.no>
index | next in thread | raw e-mail
[-- Attachment #1 --]
des@des ~% sysctl kern.mtx.trace
kern.mtx.trace.enable: 1
kern.mtx.trace.max: 20880774 kern/kern_fork.c:467
12632714 dev/sound/pcm/channel.c:677
10653798 i386/i386/machdep.c:1715
2222570 kern/kern_descrip.c:748
1101574 pci/if_xl.c:1259
812677 vm/uma_core.c:232
723969 dev/random/yarrow.c:265
523384 vm/uma_core.c:1179
500278 kern/kern_lock.c:227
427118 kern/vfs_subr.c:936
357190 kern/vfs_syscalls.c:1692
141822 vm/uma_core.c:985
79442 kern/vfs_lookup.c:149
65260 dev/sound/pcm/sound.c:134
52277 vm/uma_core.c:1301
36987 kern/kern_fork.c:535
kern.mtx.trace.total: 5472784414 i386/i386/machdep.c:1715 # Giant
1155767274 kern/kern_descrip.c:748 # filedesc lock
400100257 kern/kern_fork.c:467 # proc lock
352664142 kern/kern_lock.c:227
229755648 kern/sys_generic.c:800 # select(2) lock
226619967 kern/vfs_syscalls.c:1692 # file lock
116591756 vm/uma_core.c:1179 # zone lock
113001343 kern/vfs_subr.c:1857 # vnode lock
68279100 kern/kern_descrip.c:1108
28700835 pci/if_xl.c:1259
25726912 kern/vfs_lookup.c:149
25351235 kern/vfs_subr.c:1805
24323335 dev/sound/pcm/channel.c:677
21193642 kern/kern_sx.c:147
20097794 kern/vfs_subr.c:1788
18994392 kern/subr_mbuf.c:452
kern.mtx.trace.count: 1780724 kern/kern_fork.c:467 # proc lock
1127992 i386/i386/machdep.c:1715 # Giant
753901 kern/kern_lock.c:227
592171 kern/sys_generic.c:800 # select(2) lock
438879 vm/uma_core.c:1179 # zone lock
419580 kern/kern_descrip.c:748 # filedesc lock
407064 kern/vfs_syscalls.c:1692
258866 kern/vfs_subr.c:1857
104235 kern/kern_sx.c:147
86810 kern/vfs_subr.c:1788
61475 kern/vfs_subr.c:1805
52572 kern/subr_mbuf.c:452
36992 kern/vfs_vnops.c:762
36415 sys/buf.h:278
28884 kern/kern_resource.c:900
28421 kern/kern_descrip.c:1108
kern.mtx.trace.average: 3040416 dev/sound/pcm/channel.c:677
126265 vm/uma_core.c:985 # zone lock
38844 dev/random/yarrow.c:265
11743 pci/if_xl.c:1259
8335 dev/sound/pcm/sound.c:134
6292 kern/kern_fork.c:535
6069 kern/subr_disklabel.c:95
4852 i386/i386/machdep.c:1715
4554 kern/vfs_subr.c:936
3575 vm/uma_core.c:232
3337 vm/uma_core.c:1761
2787 vm/swap_pager.c:306
2754 kern/kern_descrip.c:748
2552 net/bpf.c:254
2402 kern/kern_descrip.c:1108
2321 kern/sys_pipe.c:1302
DES
--
Dag-Erling Smorgrav - des@ofug.org
[-- Attachment #2 --]
Index: sys/_mutex.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/_mutex.h,v
retrieving revision 1.4
diff -u -r1.4 _mutex.h
--- sys/_mutex.h 18 Dec 2001 00:27:18 -0000 1.4
+++ sys/_mutex.h 23 Mar 2002 17:41:05 -0000
@@ -41,6 +41,10 @@
volatile u_int mtx_recurse; /* number of recursive holds */
TAILQ_HEAD(, thread) mtx_blocked; /* threads blocked on this lock */
LIST_ENTRY(mtx) mtx_contested; /* list of all contested locks */
+#ifdef TRACE_MUTEX_TIME
+ u_int64_t tsc;
+ char name[64];
+#endif
};
#endif /* !_SYS_MUTEX_TYPES_H_ */
Index: kern/kern_mutex.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_mutex.c,v
retrieving revision 1.83
diff -u -r1.83 kern_mutex.c
--- kern/kern_mutex.c 27 Mar 2002 09:23:38 -0000 1.83
+++ kern/kern_mutex.c 31 Mar 2002 21:42:56 -0000
@@ -37,17 +37,18 @@
#include "opt_ddb.h"
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
+#include <sys/sbuf.h>
#include <sys/sysctl.h>
-#include <sys/systm.h>
#include <sys/vmmeter.h>
-#include <sys/ktr.h>
#include <machine/atomic.h>
#include <machine/bus.h>
@@ -196,6 +197,121 @@
}
}
+#ifdef TRACE_MUTEX_TIME
+#define TRACE_HASH_SIZE 1009
+SYSCTL_NODE(_kern, OID_AUTO, mtx, CTLFLAG_RD, NULL, "mutex manipulation");
+SYSCTL_NODE(_kern_mtx, OID_AUTO, trace, CTLFLAG_RD, NULL, "mutex tracing");
+static int kern_mtx_trace_enable = 0;
+SYSCTL_INT(_kern_mtx_trace, OID_AUTO, enable, CTLFLAG_RW,
+ &kern_mtx_trace_enable, 0, "Enable tracing of mutex holdtime");
+static int kern_mtx_trace_numtraced = 0;
+#ifdef DIAGNOSTICS
+SYSCTL_INT(_kern_mtx_trace, OID_AUTO, numtraced, CTLFLAG_RD,
+ &kern_mtx_trace_numtraced, 0, "Number of traced mutices");
+static int kern_mtx_trace_hashsize = TRACE_HASH_SIZE;
+SYSCTL_INT(_kern_mtx_trace, OID_AUTO, hashsize, CTLFLAG_RD,
+ &kern_mtx_trace_hashsize, 0, "Trace hash size");
+static int kern_mtx_trace_collisions = 0;
+SYSCTL_INT(_kern_mtx_trace, OID_AUTO, collisions, CTLFLAG_RD,
+ &kern_mtx_trace_collisions, 0, "Number of hash collisions");
+#endif
+
+static struct mutex_trace {
+ char name[64];
+#define TRACE_MAX 0
+#define TRACE_TOT 1
+#define TRACE_CNT 2
+#define TRACE_AVG 3
+ u_int64_t tsc[4];
+ struct mutex_trace *next;
+} *mutex_traces[TRACE_HASH_SIZE];
+
+static struct mtx trace_mtx;
+
+static void
+mutex_trace_init(void *arg __unused)
+{
+ mtx_init(&trace_mtx, "mutex trace lock", MTX_SPIN|MTX_QUIET);
+}
+SYSINIT(mtxtraceinit, SI_SUB_LOCK, SI_ORDER_ANY, mutex_trace_init, NULL);
+
+/*
+ * tracebuf is the pool of trace records we have;
+ * we cannot (reliably) handle more than this number
+ * of places in the code where mutexes are aquired.
+ *
+ * We use a static allocation to avoid interacting
+ * with the rest of the system.
+ */
+#define NUM_TRACE_BUFFERS 1000
+static struct mutex_trace tracebuf[NUM_TRACE_BUFFERS];
+static int first_free_mutex_trace = 0;
+
+static const char *unknown = "(unknown)";
+
+/* Number of locks to show in the sysctl. */
+#define NUM_LOCKS_TO_DUMP 16
+
+/*
+ * Output statistics of mutex holders that keep the mutex the longest.
+ */
+static int dump_mtx_trace(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_kern_mtx_trace, OID_AUTO, max, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, TRACE_MAX, dump_mtx_trace, "A", "");
+SYSCTL_PROC(_kern_mtx_trace, OID_AUTO, total, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, TRACE_TOT, dump_mtx_trace, "A", "");
+SYSCTL_PROC(_kern_mtx_trace, OID_AUTO, count, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, TRACE_CNT, dump_mtx_trace, "A", "");
+SYSCTL_PROC(_kern_mtx_trace, OID_AUTO, average, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, TRACE_AVG, dump_mtx_trace, "A", "");
+static int
+dump_mtx_trace(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf *sb;
+ struct mutex_trace *mtp;
+ int traces[NUM_LOCKS_TO_DUMP];
+ int error, i, j, k, n;
+
+ if (kern_mtx_trace_numtraced == 0)
+ return SYSCTL_OUT(req, "No locking recorded",
+ sizeof("No locking recorded"));
+ n = arg2;
+
+ /*
+ * Find the 10 largest
+ */
+ mtx_lock_spin(&trace_mtx);
+ for (i = 0; i < NUM_LOCKS_TO_DUMP; ++i)
+ traces[i] = -1;
+ for (k = 0; k < first_free_mutex_trace; ++k) {
+ for (i = 0; i < NUM_LOCKS_TO_DUMP; ++i) {
+ if (traces[i] == -1) {
+ traces[i] = k;
+ break;
+ }
+ if (tracebuf[k].tsc[n] < tracebuf[traces[i]].tsc[n])
+ continue;
+ for (j = NUM_LOCKS_TO_DUMP - 1; j > i; --j)
+ traces[j] = traces[j - 1];
+ traces[i] = k;
+ break;
+ }
+ }
+
+ /* Now dump the garbage */
+ sb = sbuf_new(NULL, NULL, 256, SBUF_AUTOEXTEND);
+ for (i = 0; i < NUM_LOCKS_TO_DUMP && traces[i] != -1; ++i) {
+ mtp = &tracebuf[traces[i]];
+ sbuf_printf(sb, "%12llu %s\n", mtp->tsc[n], mtp->name);
+ }
+ sbuf_finish(sb);
+ mtx_unlock_spin(&trace_mtx);
+ error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
+ sbuf_delete(sb);
+ return (error);
+}
+#endif /* TRACE_MUTEX_TIME */
+
/*
* Function versions of the inlined __mtx_* macros. These are used by
* modules and can also be called from assembly language if needed.
@@ -209,6 +325,18 @@
LOCK_LOG_LOCK("LOCK", &m->mtx_object, opts, m->mtx_recurse, file,
line);
WITNESS_LOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
+#ifdef TRACE_MUTEX_TIME
+ m->tsc = kern_mtx_trace_enable ? rdtsc() : 0;
+ if (m->name[0] == '\0') {
+ const char *p = file;
+
+ while (p && strncmp(p, "../", 3) == 0)
+ p += 3;
+ if (p == NULL || *p == '\0')
+ p = unknown;
+ snprintf(m->name, sizeof m->name, "%s:%d", p, line);
+ }
+#endif
}
void
@@ -217,6 +345,53 @@
MPASS(curthread != NULL);
mtx_assert(m, MA_OWNED);
+#ifdef TRACE_MUTEX_TIME
+ if (m->tsc != 0 && m->name[0] != '\0') {
+ struct mutex_trace *mtp;
+ u_int64_t tsc, mtsc;
+ volatile u_int hash;
+ char *p;
+
+ tsc = rdtsc();
+ mtsc = m->tsc;
+ m->tsc = 0;
+ if (tsc <= mtsc)
+ goto out;
+ hash = 0;
+ for (p = m->name; *p != '\0'; ++p)
+ hash = ((hash << 1) | *p) % TRACE_HASH_SIZE;
+ mtx_lock_spin(&trace_mtx);
+ for (mtp = mutex_traces[hash]; mtp != NULL; mtp = mtp->next)
+ if (strcmp(mtp->name, m->name) == 0)
+ break;
+ if (mtp == NULL) {
+ /* Just exit if we cannot get a trace buffer */
+ if (first_free_mutex_trace >= NUM_TRACE_BUFFERS)
+ goto unlock;
+ mtp = &tracebuf[first_free_mutex_trace++];
+ strcpy(mtp->name, m->name);
+#ifdef DIAGNOSTICS
+ if (mutex_traces[hash] != NULL)
+ ++kern_mtx_trace_collisions;
+#endif
+ mtp->next = mutex_traces[hash];
+ mutex_traces[hash] = mtp;
+ ++kern_mtx_trace_numtraced;
+ }
+ /*
+ * Record if the mutex has been held longer now than ever
+ * before
+ */
+ if ((tsc - mtsc) > mtp->tsc[TRACE_MAX])
+ mtp->tsc[TRACE_MAX] = tsc - mtsc;
+ mtp->tsc[TRACE_TOT] += tsc - mtsc;
+ mtp->tsc[TRACE_CNT] += 1;
+ mtp->tsc[TRACE_AVG] = mtp->tsc[TRACE_TOT] / mtp->tsc[TRACE_CNT];
+unlock:
+ mtx_unlock_spin(&trace_mtx);
+ }
+out:
+#endif
WITNESS_UNLOCK(&m->mtx_object, opts | LOP_EXCLUSIVE, file, line);
LOCK_LOG_LOCK("UNLOCK", &m->mtx_object, opts, m->mtx_recurse, file,
line);
Index: conf/options.i386
===================================================================
RCS file: /home/ncvs/src/sys/conf/options.i386,v
retrieving revision 1.169
diff -u -r1.169 options.i386
--- conf/options.i386 27 Feb 2002 09:51:31 -0000 1.169
+++ conf/options.i386 23 Mar 2002 18:04:45 -0000
@@ -188,6 +188,9 @@
# SMB/CIFS filesystem
SMBFS
+# Mutex profiling
+TRACE_MUTEX_TIME opt_global.h
+
# -------------------------------
# EOF
# -------------------------------
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?xzp8z88e6i1.fsf>
