summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_turnstile.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2004-06-29 02:30:12 +0000
committerjhb <jhb@FreeBSD.org>2004-06-29 02:30:12 +0000
commit6502f84a50fcc2d8c900075cb5c32b5f27b6412d (patch)
tree3244993b69f32cb332dc725fe0d3875355d19b32 /sys/kern/subr_turnstile.c
parent348466ddef9897fd09915a421127252c9507072e (diff)
downloadFreeBSD-src-6502f84a50fcc2d8c900075cb5c32b5f27b6412d.zip
FreeBSD-src-6502f84a50fcc2d8c900075cb5c32b5f27b6412d.tar.gz
Add two new kernel options to allow rudimentary profiling of the internal
hash tables used in the sleep queue and turnstile code. Each option adds a sysctl tree under debug containing the maximum depth of any bucket in the hash table as well as a separate node for each bucket (or chain) containing the current depth and maximum depth for that bucket.
Diffstat (limited to 'sys/kern/subr_turnstile.c')
-rw-r--r--sys/kern/subr_turnstile.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/sys/kern/subr_turnstile.c b/sys/kern/subr_turnstile.c
index 8994a1e..5ed4393 100644
--- a/sys/kern/subr_turnstile.c
+++ b/sys/kern/subr_turnstile.c
@@ -56,6 +56,8 @@
* it from the hash table.
*/
+#include "opt_turnstile_profiling.h"
+
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -69,8 +71,9 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/queue.h>
#include <sys/resourcevar.h>
-#include <sys/turnstile.h>
#include <sys/sched.h>
+#include <sys/sysctl.h>
+#include <sys/turnstile.h>
/*
* Constants for the hash table of turnstile chains. TC_SHIFT is a magic
@@ -116,8 +119,20 @@ struct turnstile {
struct turnstile_chain {
LIST_HEAD(, turnstile) tc_turnstiles; /* List of turnstiles. */
struct mtx tc_lock; /* Spin lock for this chain. */
+#ifdef TURNSTILE_PROFILING
+ u_int tc_depth; /* Length of tc_queues. */
+ u_int tc_max_depth; /* Max length of tc_queues. */
+#endif
};
+#ifdef TURNSTILE_PROFILING
+u_int turnstile_max_depth;
+SYSCTL_NODE(_debug, OID_AUTO, turnstile, CTLFLAG_RD, 0, "turnstile profiling");
+SYSCTL_NODE(_debug_turnstile, OID_AUTO, chains, CTLFLAG_RD, 0,
+ "turnstile chain stats");
+SYSCTL_UINT(_debug_turnstile, OID_AUTO, max_depth, CTLFLAG_RD,
+ &turnstile_max_depth, 0, "maxmimum depth achieved of a single chain");
+#endif
static struct mtx td_contested_lock;
static struct turnstile_chain turnstile_chains[TC_TABLESIZE];
@@ -292,12 +307,28 @@ propagate_priority(struct thread *td)
void
init_turnstiles(void)
{
+#ifdef TURNSTILE_PROFILING
+ struct sysctl_oid *chain_oid;
+ char chain_name[10];
+#endif
int i;
for (i = 0; i < TC_TABLESIZE; i++) {
LIST_INIT(&turnstile_chains[i].tc_turnstiles);
mtx_init(&turnstile_chains[i].tc_lock, "turnstile chain",
NULL, MTX_SPIN);
+#ifdef TURNSTILE_PROFILING
+ snprintf(chain_name, sizeof(chain_name), "%d", i);
+ chain_oid = SYSCTL_ADD_NODE(NULL,
+ SYSCTL_STATIC_CHILDREN(_debug_turnstile_chains), OID_AUTO,
+ chain_name, CTLFLAG_RD, NULL, "turnstile chain stats");
+ SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
+ "depth", CTLFLAG_RD, &turnstile_chains[i].tc_depth, 0,
+ NULL);
+ SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(chain_oid), OID_AUTO,
+ "max_depth", CTLFLAG_RD, &turnstile_chains[i].tc_max_depth,
+ 0, NULL);
+#endif
}
mtx_init(&td_contested_lock, "td_contested", NULL, MTX_SPIN);
thread0.td_turnstile = NULL;
@@ -438,6 +469,14 @@ turnstile_wait(struct turnstile *ts, struct lock_object *lock,
/* If the passed in turnstile is NULL, use this thread's turnstile. */
if (ts == NULL) {
+#ifdef TURNSTILE_PROFILING
+ tc->tc_depth++;
+ if (tc->tc_depth > tc->tc_max_depth) {
+ tc->tc_max_depth = tc->tc_depth;
+ if (tc->tc_max_depth > turnstile_max_depth)
+ turnstile_max_depth = tc->tc_max_depth;
+ }
+#endif
ts = td->td_turnstile;
LIST_INSERT_HEAD(&tc->tc_turnstiles, ts, ts_hash);
KASSERT(TAILQ_EMPTY(&ts->ts_pending),
@@ -551,9 +590,12 @@ turnstile_signal(struct turnstile *ts)
* turnstile from the free list and give it to the thread.
*/
empty = TAILQ_EMPTY(&ts->ts_blocked);
- if (empty)
+ if (empty) {
MPASS(LIST_EMPTY(&ts->ts_free));
- else
+#ifdef TURNSTILE_PROFILING
+ tc->tc_depth--;
+#endif
+ } else
ts = LIST_FIRST(&ts->ts_free);
MPASS(ts != NULL);
LIST_REMOVE(ts, ts_hash);
@@ -594,6 +636,9 @@ turnstile_broadcast(struct turnstile *ts)
if (LIST_EMPTY(&ts->ts_free)) {
MPASS(TAILQ_NEXT(td, td_lockq) == NULL);
ts1 = ts;
+#ifdef TURNSTILE_PROFILING
+ tc->tc_depth--;
+#endif
} else
ts1 = LIST_FIRST(&ts->ts_free);
MPASS(ts1 != NULL);
OpenPOWER on IntegriCloud