diff options
| author | Stacey Son <sson@FreeBSD.org> | 2009-05-26 20:28:22 +0000 |
|---|---|---|
| committer | Stacey Son <sson@FreeBSD.org> | 2009-05-26 20:28:22 +0000 |
| commit | a5aedd68b4eb5bb0cafdc51eb8f325c32543ad9a (patch) | |
| tree | b7873baadff878509f8c7b930ddeeaa84074e546 /sys/kern | |
| parent | e8cdb7739f0b50ae5650edc6207d6617770442f7 (diff) | |
Notes
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/kern_lock.c | 18 | ||||
| -rw-r--r-- | sys/kern/kern_lockstat.c | 64 | ||||
| -rw-r--r-- | sys/kern/kern_mutex.c | 79 | ||||
| -rw-r--r-- | sys/kern/kern_rmlock.c | 16 | ||||
| -rw-r--r-- | sys/kern/kern_rwlock.c | 97 | ||||
| -rw-r--r-- | sys/kern/kern_sx.c | 94 |
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); } |
