aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorStacey Son <sson@FreeBSD.org>2009-05-26 20:28:22 +0000
committerStacey Son <sson@FreeBSD.org>2009-05-26 20:28:22 +0000
commita5aedd68b4eb5bb0cafdc51eb8f325c32543ad9a (patch)
treeb7873baadff878509f8c7b930ddeeaa84074e546 /sys/kern
parente8cdb7739f0b50ae5650edc6207d6617770442f7 (diff)
Notes
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_lock.c18
-rw-r--r--sys/kern/kern_lockstat.c64
-rw-r--r--sys/kern/kern_mutex.c79
-rw-r--r--sys/kern/kern_rmlock.c16
-rw-r--r--sys/kern/kern_rwlock.c97
-rw-r--r--sys/kern/kern_sx.c94
6 files changed, 339 insertions, 29 deletions
diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c
index f4e5ea9903e2..f03ddbca687d 100644
--- a/sys/kern/kern_lock.c
+++ b/sys/kern/kern_lock.c
@@ -27,6 +27,7 @@
*/
#include "opt_ddb.h"
+#include "opt_kdtrace.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -126,6 +127,9 @@ static void assert_lockmgr(struct lock_object *lock, int how);
static void db_show_lockmgr(struct lock_object *lock);
#endif
static void lock_lockmgr(struct lock_object *lock, int how);
+#ifdef KDTRACE_HOOKS
+static int owner_lockmgr(struct lock_object *lock, struct thread **owner);
+#endif
static int unlock_lockmgr(struct lock_object *lock);
struct lock_class lock_class_lockmgr = {
@@ -136,7 +140,10 @@ struct lock_class lock_class_lockmgr = {
.lc_ddb_show = db_show_lockmgr,
#endif
.lc_lock = lock_lockmgr,
- .lc_unlock = unlock_lockmgr
+ .lc_unlock = unlock_lockmgr,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_lockmgr,
+#endif
};
static __inline struct thread *
@@ -293,6 +300,15 @@ unlock_lockmgr(struct lock_object *lock)
panic("lockmgr locks do not support sleep interlocking");
}
+#ifdef KDTRACE_HOOKS
+static int
+owner_lockmgr(struct lock_object *lock, struct thread **owner)
+{
+
+ panic("lockmgr locks do not support owner inquiring");
+}
+#endif
+
void
lockinit(struct lock *lk, int pri, const char *wmesg, int timo, int flags)
{
diff --git a/sys/kern/kern_lockstat.c b/sys/kern/kern_lockstat.c
new file mode 100644
index 000000000000..1f3589331f58
--- /dev/null
+++ b/sys/kern/kern_lockstat.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright 2008-2009 Stacey Son <sson@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Backend for the lock tracing (lockstat) kernel support. This is required
+ * to allow a module to load even though DTrace kernel support may not be
+ * present.
+ *
+ */
+
+#include "opt_kdtrace.h"
+
+#ifdef KDTRACE_HOOKS
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/lockstat.h>
+
+/*
+ * The following must match the type definition of dtrace_probe. It is
+ * defined this way to avoid having to rely on CDDL code.
+ */
+uint32_t lockstat_probemap[LS_NPROBES];
+void (*lockstat_probe_func)(uint32_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t, uintptr_t);
+
+
+uint64_t
+lockstat_nsecs(void)
+{
+ struct bintime bt;
+ uint64_t ns;
+
+ binuptime(&bt);
+ ns = bt.sec * (uint64_t)1000000000;
+ ns += ((uint64_t)1000000000 * (uint32_t)(bt.frac >> 32)) >> 32;
+ return (ns);
+}
+
+#endif /* KDTRACE_HOOKS */
diff --git a/sys/kern/kern_mutex.c b/sys/kern/kern_mutex.c
index ea85268e4555..49f9c59e30bd 100644
--- a/sys/kern/kern_mutex.c
+++ b/sys/kern/kern_mutex.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include "opt_adaptive_mutexes.h"
#include "opt_ddb.h"
#include "opt_global.h"
+#include "opt_kdtrace.h"
#include "opt_sched.h"
#include <sys/param.h>
@@ -90,6 +91,9 @@ static void db_show_mtx(struct lock_object *lock);
#endif
static void lock_mtx(struct lock_object *lock, int how);
static void lock_spin(struct lock_object *lock, int how);
+#ifdef KDTRACE_HOOKS
+static int owner_mtx(struct lock_object *lock, struct thread **owner);
+#endif
static int unlock_mtx(struct lock_object *lock);
static int unlock_spin(struct lock_object *lock);
@@ -105,6 +109,9 @@ struct lock_class lock_class_mtx_sleep = {
#endif
.lc_lock = lock_mtx,
.lc_unlock = unlock_mtx,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_mtx,
+#endif
};
struct lock_class lock_class_mtx_spin = {
.lc_name = "spin mutex",
@@ -115,6 +122,9 @@ struct lock_class lock_class_mtx_spin = {
#endif
.lc_lock = lock_spin,
.lc_unlock = unlock_spin,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_mtx,
+#endif
};
/*
@@ -162,6 +172,17 @@ unlock_spin(struct lock_object *lock)
panic("spin locks can only use msleep_spin");
}
+#ifdef KDTRACE_HOOKS
+int
+owner_mtx(struct lock_object *lock, struct thread **owner)
+{
+ struct mtx *m = (struct mtx *)lock;
+
+ *owner = mtx_owner(m);
+ return (mtx_unowned(m) == 0);
+}
+#endif
+
/*
* Function versions of the inlined __mtx_* macros. These are used by
* modules and can also be called from assembly language if needed.
@@ -202,7 +223,7 @@ _mtx_unlock_flags(struct mtx *m, int opts, const char *file, int line)
mtx_assert(m, MA_OWNED);
if (m->mtx_recurse == 0)
- lock_profile_release_lock(&m->lock_object);
+ LOCKSTAT_PROFILE_RELEASE_LOCK(LS_MTX_UNLOCK_RELEASE, m);
_rel_sleep_lock(m, curthread, opts, file, line);
}
@@ -280,8 +301,8 @@ _mtx_trylock(struct mtx *m, int opts, const char *file, int line)
file, line);
curthread->td_locks++;
if (m->mtx_recurse == 0)
- lock_profile_obtain_lock_success(&m->lock_object, contested,
- waittime, file, line);
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_LOCK_ACQUIRE,
+ m, contested, waittime, file, line);
}
@@ -310,6 +331,11 @@ _mtx_lock_sleep(struct mtx *m, uintptr_t tid, int opts, const char *file,
int contested = 0;
uint64_t waittime = 0;
#endif
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+ uint64_t sleep_cnt = 0;
+ int64_t sleep_time = 0;
+#endif
if (mtx_owned(m)) {
KASSERT((m->lock_object.lo_flags & LO_RECURSABLE) != 0,
@@ -330,6 +356,9 @@ _mtx_lock_sleep(struct mtx *m, uintptr_t tid, int opts, const char *file,
m->lock_object.lo_name, (void *)m->mtx_lock, file, line);
while (!_obtain_lock(m, tid)) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
#ifdef ADAPTIVE_MUTEXES
/*
* If the owner is running on another CPU, spin until the
@@ -344,8 +373,12 @@ _mtx_lock_sleep(struct mtx *m, uintptr_t tid, int opts, const char *file,
"%s: spinning on %p held by %p",
__func__, m, owner);
while (mtx_owner(m) == owner &&
- TD_IS_RUNNING(owner))
+ TD_IS_RUNNING(owner)) {
cpu_spinwait();
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
+ }
continue;
}
}
@@ -408,7 +441,14 @@ _mtx_lock_sleep(struct mtx *m, uintptr_t tid, int opts, const char *file,
/*
* Block on the turnstile.
*/
+#ifdef KDTRACE_HOOKS
+ sleep_time -= lockstat_nsecs();
+#endif
turnstile_wait(ts, mtx_owner(m), TS_EXCLUSIVE_QUEUE);
+#ifdef KDTRACE_HOOKS
+ sleep_time += lockstat_nsecs();
+ sleep_cnt++;
+#endif
}
#ifdef KTR
if (cont_logged) {
@@ -417,8 +457,18 @@ _mtx_lock_sleep(struct mtx *m, uintptr_t tid, int opts, const char *file,
m->lock_object.lo_name, (void *)tid, file, line);
}
#endif
- lock_profile_obtain_lock_success(&m->lock_object, contested,
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_LOCK_ACQUIRE, m, contested,
waittime, file, line);
+#ifdef KDTRACE_HOOKS
+ if (sleep_time)
+ LOCKSTAT_RECORD1(LS_MTX_LOCK_BLOCK, m, sleep_time);
+
+ /*
+ * Only record the loops spinning and not sleeping.
+ */
+ if (spin_cnt > sleep_cnt)
+ LOCKSTAT_RECORD1(LS_MTX_LOCK_SPIN, m, (spin_cnt - sleep_cnt));
+#endif
}
static void
@@ -482,8 +532,9 @@ _mtx_lock_spin(struct mtx *m, uintptr_t tid, int opts, const char *file,
if (LOCK_LOG_TEST(&m->lock_object, opts))
CTR1(KTR_LOCK, "_mtx_lock_spin: %p spin done", m);
- lock_profile_obtain_lock_success(&m->lock_object, contested,
- waittime, (file), (line));
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_SPIN_LOCK_ACQUIRE, m,
+ contested, waittime, (file), (line));
+ LOCKSTAT_RECORD1(LS_MTX_SPIN_LOCK_SPIN, m, i);
}
#endif /* SMP */
@@ -497,6 +548,9 @@ _thread_lock_flags(struct thread *td, int opts, const char *file, int line)
int contested = 0;
uint64_t waittime = 0;
#endif
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+#endif
i = 0;
tid = (uintptr_t)curthread;
@@ -516,6 +570,9 @@ retry:
WITNESS_CHECKORDER(&m->lock_object,
opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL);
while (!_obtain_lock(m, tid)) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
if (m->mtx_lock == tid) {
m->mtx_recurse++;
break;
@@ -541,13 +598,17 @@ retry:
if (m == td->td_lock)
break;
_rel_spin_lock(m); /* does spinlock_exit() */
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
}
if (m->mtx_recurse == 0)
- lock_profile_obtain_lock_success(&m->lock_object, contested,
- waittime, (file), (line));
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_MTX_SPIN_LOCK_ACQUIRE,
+ m, contested, waittime, (file), (line));
LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
line);
WITNESS_LOCK(&m->lock_object, opts | LOP_EXCLUSIVE, file, line);
+ LOCKSTAT_RECORD1(LS_THREAD_LOCK_SPIN, m, spin_cnt);
}
struct mtx *
diff --git a/sys/kern/kern_rmlock.c b/sys/kern/kern_rmlock.c
index 0a33c601716d..3d0a10df2f09 100644
--- a/sys/kern/kern_rmlock.c
+++ b/sys/kern/kern_rmlock.c
@@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include "opt_ddb.h"
+#include "opt_kdtrace.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -71,6 +72,9 @@ static __inline void compiler_memory_barrier(void) {
static void assert_rm(struct lock_object *lock, int what);
static void lock_rm(struct lock_object *lock, int how);
+#ifdef KDTRACE_HOOKS
+static int owner_rm(struct lock_object *lock, struct thread **owner);
+#endif
static int unlock_rm(struct lock_object *lock);
struct lock_class lock_class_rm = {
@@ -84,6 +88,9 @@ struct lock_class lock_class_rm = {
#endif
.lc_lock = lock_rm,
.lc_unlock = unlock_rm,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_rm,
+#endif
};
static void
@@ -107,6 +114,15 @@ unlock_rm(struct lock_object *lock)
panic("unlock_rm called");
}
+#ifdef KDTRACE_HOOKS
+static int
+owner_rm(struct lock_object *lock, struct thread **owner)
+{
+
+ panic("owner_rm called");
+}
+#endif
+
static struct mtx rm_spinlock;
MTX_SYSINIT(rm_spinlock, &rm_spinlock, "rm_spinlock", MTX_SPIN);
diff --git a/sys/kern/kern_rwlock.c b/sys/kern/kern_rwlock.c
index ccaa6906841c..993acfa42603 100644
--- a/sys/kern/kern_rwlock.c
+++ b/sys/kern/kern_rwlock.c
@@ -35,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include "opt_ddb.h"
+#include "opt_kdtrace.h"
#include "opt_no_adaptive_rwlocks.h"
#include <sys/param.h>
@@ -71,6 +72,9 @@ static void db_show_rwlock(struct lock_object *lock);
#endif
static void assert_rw(struct lock_object *lock, int what);
static void lock_rw(struct lock_object *lock, int how);
+#ifdef KDTRACE_HOOKS
+static int owner_rw(struct lock_object *lock, struct thread **owner);
+#endif
static int unlock_rw(struct lock_object *lock);
struct lock_class lock_class_rw = {
@@ -82,6 +86,9 @@ struct lock_class lock_class_rw = {
#endif
.lc_lock = lock_rw,
.lc_unlock = unlock_rw,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_rw,
+#endif
};
/*
@@ -149,6 +156,19 @@ unlock_rw(struct lock_object *lock)
}
}
+#ifdef KDTRACE_HOOKS
+int
+owner_rw(struct lock_object *lock, struct thread **owner)
+{
+ struct rwlock *rw = (struct rwlock *)lock;
+ uintptr_t x = rw->rw_lock;
+
+ *owner = rw_wowner(rw);
+ return ((x & RW_LOCK_READ) != 0 ? (RW_READERS(x) != 0) :
+ (*owner != NULL));
+}
+#endif
+
void
rw_init_flags(struct rwlock *rw, const char *name, int opts)
{
@@ -258,7 +278,7 @@ _rw_wunlock(struct rwlock *rw, const char *file, int line)
LOCK_LOG_LOCK("WUNLOCK", &rw->lock_object, 0, rw->rw_recurse, file,
line);
if (!rw_recursed(rw))
- lock_profile_release_lock(&rw->lock_object);
+ LOCKSTAT_PROFILE_RELEASE_LOCK(LS_RW_WUNLOCK_RELEASE, rw);
__rw_wunlock(rw, curthread, file, line);
}
/*
@@ -287,6 +307,11 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
int contested = 0;
#endif
uintptr_t v;
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+ uint64_t sleep_cnt = 0;
+ int64_t sleep_time = 0;
+#endif
KASSERT(rw->rw_lock != RW_DESTROYED,
("rw_rlock() of destroyed rwlock @ %s:%d", file, line));
@@ -296,6 +321,9 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER, file, line, NULL);
for (;;) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
/*
* Handle the easy case. If no other thread has a write
* lock, then try to bump up the count of read locks. Note
@@ -342,8 +370,12 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
"%s: spinning on %p held by %p",
__func__, rw, owner);
while ((struct thread*)RW_OWNER(rw->rw_lock) ==
- owner && TD_IS_RUNNING(owner))
+ owner && TD_IS_RUNNING(owner)) {
cpu_spinwait();
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
+ }
continue;
}
} else if (spintries < rowner_retries) {
@@ -423,7 +455,14 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
if (LOCK_LOG_TEST(&rw->lock_object, 0))
CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__,
rw);
+#ifdef KDTRACE_HOOKS
+ sleep_time -= lockstat_nsecs();
+#endif
turnstile_wait(ts, rw_owner(rw), TS_SHARED_QUEUE);
+#ifdef KDTRACE_HOOKS
+ sleep_time += lockstat_nsecs();
+ sleep_cnt++;
+#endif
if (LOCK_LOG_TEST(&rw->lock_object, 0))
CTR2(KTR_LOCK, "%s: %p resuming from turnstile",
__func__, rw);
@@ -434,12 +473,22 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
* however. turnstiles don't like owners changing between calls to
* turnstile_wait() currently.
*/
- lock_profile_obtain_lock_success( &rw->lock_object, contested,
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_RW_RLOCK_ACQUIRE, rw, contested,
waittime, file, line);
LOCK_LOG_LOCK("RLOCK", &rw->lock_object, 0, 0, file, line);
WITNESS_LOCK(&rw->lock_object, 0, file, line);
curthread->td_locks++;
curthread->td_rw_rlocks++;
+#ifdef KDTRACE_HOOKS
+ if (sleep_time)
+ LOCKSTAT_RECORD1(LS_RW_RLOCK_BLOCK, rw, sleep_time);
+
+ /*
+ * Record only the loops spinning and not sleeping.
+ */
+ if (spin_cnt > sleep_cnt)
+ LOCKSTAT_RECORD1(LS_RW_RLOCK_SPIN, rw, (spin_cnt - sleep_cnt));
+#endif
}
int
@@ -569,7 +618,7 @@ _rw_runlock(struct rwlock *rw, const char *file, int line)
turnstile_chain_unlock(&rw->lock_object);
break;
}
- lock_profile_release_lock(&rw->lock_object);
+ LOCKSTAT_PROFILE_RELEASE_LOCK(LS_RW_RUNLOCK_RELEASE, rw);
}
/*
@@ -591,6 +640,11 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
uint64_t waittime = 0;
int contested = 0;
#endif
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+ uint64_t sleep_cnt = 0;
+ int64_t sleep_time = 0;
+#endif
if (rw_wlocked(rw)) {
KASSERT(rw->lock_object.lo_flags & RW_RECURSE,
@@ -607,6 +661,9 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
rw->lock_object.lo_name, (void *)rw->rw_lock, file, line);
while (!_rw_write_lock(rw, tid)) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
lock_profile_obtain_lock_failed(&rw->lock_object,
&contested, &waittime);
#ifdef ADAPTIVE_RWLOCKS
@@ -622,8 +679,12 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
CTR3(KTR_LOCK, "%s: spinning on %p held by %p",
__func__, rw, owner);
while ((struct thread*)RW_OWNER(rw->rw_lock) == owner &&
- TD_IS_RUNNING(owner))
+ TD_IS_RUNNING(owner)) {
cpu_spinwait();
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
+ }
continue;
}
if ((v & RW_LOCK_READ) && RW_READERS(v) &&
@@ -641,6 +702,9 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
break;
cpu_spinwait();
}
+#ifdef KDTRACE_HOOKS
+ spin_cnt += rowner_loops - i;
+#endif
if (i != rowner_loops)
continue;
}
@@ -706,7 +770,14 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
if (LOCK_LOG_TEST(&rw->lock_object, 0))
CTR2(KTR_LOCK, "%s: %p blocking on turnstile", __func__,
rw);
+#ifdef KDTRACE_HOOKS
+ sleep_time -= lockstat_nsecs();
+#endif
turnstile_wait(ts, rw_owner(rw), TS_EXCLUSIVE_QUEUE);
+#ifdef KDTRACE_HOOKS
+ sleep_time += lockstat_nsecs();
+ sleep_cnt++;
+#endif
if (LOCK_LOG_TEST(&rw->lock_object, 0))
CTR2(KTR_LOCK, "%s: %p resuming from turnstile",
__func__, rw);
@@ -714,8 +785,18 @@ _rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file, int line)
spintries = 0;
#endif
}
- lock_profile_obtain_lock_success(&rw->lock_object, contested, waittime,
- file, line);
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_RW_WLOCK_ACQUIRE, rw, contested,
+ waittime, file, line);
+#ifdef KDTRACE_HOOKS
+ if (sleep_time)
+ LOCKSTAT_RECORD1(LS_RW_WLOCK_BLOCK, rw, sleep_time);
+
+ /*
+ * Record only the loops spinning and not sleeping.
+ */
+ if (spin_cnt > sleep_cnt)
+ LOCKSTAT_RECORD1(LS_RW_WLOCK_SPIN, rw, (spin_cnt - sleep_cnt));
+#endif
}
/*
@@ -847,6 +928,7 @@ _rw_try_upgrade(struct rwlock *rw, const char *file, int line)
curthread->td_rw_rlocks--;
WITNESS_UPGRADE(&rw->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
file, line);
+ LOCKSTAT_RECORD0(LS_RW_TRYUPGRADE_UPGRADE, rw);
}
return (success);
}
@@ -912,6 +994,7 @@ _rw_downgrade(struct rwlock *rw, const char *file, int line)
out:
curthread->td_rw_rlocks++;
LOCK_LOG_LOCK("WDOWNGRADE", &rw->lock_object, 0, 0, file, line);
+ LOCKSTAT_RECORD0(LS_RW_DOWNGRADE_DOWNGRADE, rw);
}
#ifdef INVARIANT_SUPPORT
diff --git a/sys/kern/kern_sx.c b/sys/kern/kern_sx.c
index 9a2c9a22d249..8c099ac12d47 100644
--- a/sys/kern/kern_sx.c
+++ b/sys/kern/kern_sx.c
@@ -38,6 +38,7 @@
#include "opt_adaptive_sx.h"
#include "opt_ddb.h"
+#include "opt_kdtrace.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -109,6 +110,9 @@ static void assert_sx(struct lock_object *lock, int what);
static void db_show_sx(struct lock_object *lock);
#endif
static void lock_sx(struct lock_object *lock, int how);
+#ifdef KDTRACE_HOOKS
+static int owner_sx(struct lock_object *lock, struct thread **owner);
+#endif
static int unlock_sx(struct lock_object *lock);
struct lock_class lock_class_sx = {
@@ -120,6 +124,9 @@ struct lock_class lock_class_sx = {
#endif
.lc_lock = lock_sx,
.lc_unlock = unlock_sx,
+#ifdef KDTRACE_HOOKS
+ .lc_owner = owner_sx,
+#endif
};
#ifndef INVARIANTS
@@ -161,6 +168,19 @@ unlock_sx(struct lock_object *lock)
}
}
+#ifdef KDTRACE_HOOKS
+int
+owner_sx(struct lock_object *lock, struct thread **owner)
+{
+ struct sx *sx = (struct sx *)lock;
+ uintptr_t x = sx->sx_lock;
+
+ *owner = (struct thread *)SX_OWNER(x);
+ return ((x & SX_LOCK_SHARED) != 0 ? (SX_SHARERS(x) != 0) :
+ (*owner != NULL));
+}
+#endif
+
void
sx_sysinit(void *arg)
{
@@ -304,7 +324,7 @@ _sx_sunlock(struct sx *sx, const char *file, int line)
WITNESS_UNLOCK(&sx->lock_object, 0, file, line);
LOCK_LOG_LOCK("SUNLOCK", &sx->lock_object, 0, 0, file, line);
__sx_sunlock(sx, file, line);
- lock_profile_release_lock(&sx->lock_object);
+ LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_SUNLOCK_RELEASE, sx);
}
void
@@ -320,7 +340,7 @@ _sx_xunlock(struct sx *sx, const char *file, int line)
LOCK_LOG_LOCK("XUNLOCK", &sx->lock_object, 0, sx->sx_recurse, file,
line);
if (!sx_recursed(sx))
- lock_profile_release_lock(&sx->lock_object);
+ LOCKSTAT_PROFILE_RELEASE_LOCK(LS_SX_XUNLOCK_RELEASE, sx);
__sx_xunlock(sx, curthread, file, line);
}
@@ -348,9 +368,11 @@ _sx_try_upgrade(struct sx *sx, const char *file, int line)
success = atomic_cmpset_ptr(&sx->sx_lock, SX_SHARERS_LOCK(1) | x,
(uintptr_t)curthread | x);
LOCK_LOG_TRY("XUPGRADE", &sx->lock_object, 0, success, file, line);
- if (success)
+ if (success) {
WITNESS_UPGRADE(&sx->lock_object, LOP_EXCLUSIVE | LOP_TRYLOCK,
file, line);
+ LOCKSTAT_RECORD0(LS_SX_TRYUPGRADE_UPGRADE, sx);
+ }
return (success);
}
@@ -412,6 +434,7 @@ _sx_downgrade(struct sx *sx, const char *file, int line)
sleepq_release(&sx->lock_object);
LOCK_LOG_LOCK("XDOWNGRADE", &sx->lock_object, 0, 0, file, line);
+ LOCKSTAT_RECORD0(LS_SX_DOWNGRADE_DOWNGRADE, sx);
if (wakeup_swapper)
kick_proc0();
@@ -437,6 +460,11 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
int contested = 0;
#endif
int error = 0;
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+ uint64_t sleep_cnt = 0;
+ int64_t sleep_time = 0;
+#endif
/* If we already hold an exclusive lock, then recurse. */
if (sx_xlocked(sx)) {
@@ -455,6 +483,9 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
sx->lock_object.lo_name, (void *)sx->sx_lock, file, line);
while (!atomic_cmpset_acq_ptr(&sx->sx_lock, SX_LOCK_UNLOCKED, tid)) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
lock_profile_obtain_lock_failed(&sx->lock_object, &contested,
&waittime);
#ifdef ADAPTIVE_SX
@@ -475,8 +506,12 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
__func__, sx, owner);
GIANT_SAVE();
while (SX_OWNER(sx->sx_lock) == x &&
- TD_IS_RUNNING(owner))
+ TD_IS_RUNNING(owner)) {
cpu_spinwait();
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
+ }
continue;
}
}
@@ -559,6 +594,9 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
__func__, sx);
+#ifdef KDTRACE_HOOKS
+ sleep_time -= lockstat_nsecs();
+#endif
GIANT_SAVE();
sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
@@ -567,7 +605,10 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
sleepq_wait(&sx->lock_object, 0);
else
error = sleepq_wait_sig(&sx->lock_object, 0);
-
+#ifdef KDTRACE_HOOKS
+ sleep_time += lockstat_nsecs();
+ sleep_cnt++;
+#endif
if (error) {
if (LOCK_LOG_TEST(&sx->lock_object, 0))
CTR2(KTR_LOCK,
@@ -582,8 +623,14 @@ _sx_xlock_hard(struct sx *sx, uintptr_t tid, int opts, const char *file,
GIANT_RESTORE();
if (!error)
- lock_profile_obtain_lock_success(&sx->lock_object, contested,
- waittime, file, line);
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_XLOCK_ACQUIRE, sx,
+ contested, waittime, file, line);
+#ifdef KDTRACE_HOOKS
+ if (sleep_time)
+ LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time);
+ if (spin_cnt > sleep_cnt)
+ LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt));
+#endif
return (error);
}
@@ -661,12 +708,20 @@ _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
#endif
uintptr_t x;
int error = 0;
+#ifdef KDTRACE_HOOKS
+ uint64_t spin_cnt = 0;
+ uint64_t sleep_cnt = 0;
+ int64_t sleep_time = 0;
+#endif
/*
* As with rwlocks, we don't make any attempt to try to block
* shared locks once there is an exclusive waiter.
*/
for (;;) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
x = sx->sx_lock;
/*
@@ -707,8 +762,12 @@ _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
__func__, sx, owner);
GIANT_SAVE();
while (SX_OWNER(sx->sx_lock) == x &&
- TD_IS_RUNNING(owner))
+ TD_IS_RUNNING(owner)) {
+#ifdef KDTRACE_HOOKS
+ spin_cnt++;
+#endif
cpu_spinwait();
+ }
continue;
}
}
@@ -770,6 +829,9 @@ _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
CTR2(KTR_LOCK, "%s: %p blocking on sleep queue",
__func__, sx);
+#ifdef KDTRACE_HOOKS
+ sleep_time -= lockstat_nsecs();
+#endif
GIANT_SAVE();
sleepq_add(&sx->lock_object, NULL, sx->lock_object.lo_name,
SLEEPQ_SX | ((opts & SX_INTERRUPTIBLE) ?
@@ -778,7 +840,10 @@ _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
sleepq_wait(&sx->lock_object, 0);
else
error = sleepq_wait_sig(&sx->lock_object, 0);
-
+#ifdef KDTRACE_HOOKS
+ sleep_time += lockstat_nsecs();
+ sleep_cnt++;
+#endif
if (error) {
if (LOCK_LOG_TEST(&sx->lock_object, 0))
CTR2(KTR_LOCK,
@@ -791,9 +856,14 @@ _sx_slock_hard(struct sx *sx, int opts, const char *file, int line)
__func__, sx);
}
if (error == 0)
- lock_profile_obtain_lock_success(&sx->lock_object, contested,
- waittime, file, line);
-
+ LOCKSTAT_PROFILE_OBTAIN_LOCK_SUCCESS(LS_SX_SLOCK_ACQUIRE, sx,
+ contested, waittime, file, line);
+#ifdef KDTRACE_HOOKS
+ if (sleep_time)
+ LOCKSTAT_RECORD1(LS_SX_XLOCK_BLOCK, sx, sleep_time);
+ if (spin_cnt > sleep_cnt)
+ LOCKSTAT_RECORD1(LS_SX_XLOCK_SPIN, sx, (spin_cnt - sleep_cnt));
+#endif
GIANT_RESTORE();
return (error);
}