summaryrefslogtreecommitdiff
path: root/kern/mutex
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-08-30 23:27:31 +0200
committerRichard Braun <rbraun@sceen.net>2017-08-31 00:43:37 +0200
commit5daf8db5209b0849a7bf43d9d823c67be9a52bcf (patch)
tree1481da1f05f7ef7ee7202f300adf7a1b7d46f01b /kern/mutex
parenta9719450e83c2c64eecd097d82beb624948e9de9 (diff)
Add debugging code to the mutex modules
Diffstat (limited to 'kern/mutex')
-rw-r--r--kern/mutex/mutex_adaptive.c99
-rw-r--r--kern/mutex/mutex_adaptive_i.h5
-rw-r--r--kern/mutex/mutex_pi_i.h2
-rw-r--r--kern/mutex/mutex_plain.c68
-rw-r--r--kern/mutex/mutex_plain_i.h5
5 files changed, 179 insertions, 0 deletions
diff --git a/kern/mutex/mutex_adaptive.c b/kern/mutex/mutex_adaptive.c
index 34fdd22..ceec8f1 100644
--- a/kern/mutex/mutex_adaptive.c
+++ b/kern/mutex/mutex_adaptive.c
@@ -23,12 +23,83 @@
#include <kern/atomic.h>
#include <kern/clock.h>
#include <kern/error.h>
+#include <kern/init.h>
#include <kern/mutex.h>
#include <kern/mutex_types.h>
#include <kern/sleepq.h>
+#include <kern/syscnt.h>
#include <kern/thread.h>
#include <machine/cpu.h>
+/* Set to 1 to enable debugging */
+#define MUTEX_ADAPTIVE_DEBUG 0
+
+#if MUTEX_ADAPTIVE_DEBUG
+
+enum {
+ MUTEX_ADAPTIVE_SC_SPINS,
+ MUTEX_ADAPTIVE_SC_WAIT_SUCCESSES,
+ MUTEX_ADAPTIVE_SC_WAIT_ERRORS,
+ MUTEX_ADAPTIVE_SC_DOWNGRADES,
+ MUTEX_ADAPTIVE_SC_ERROR_DOWNGRADES,
+ MUTEX_ADAPTIVE_SC_ERROR_CLEARBITS,
+ MUTEX_ADAPTIVE_SC_ERROR_CLEARCONT,
+ MUTEX_ADAPTIVE_SC_FAST_UNLOCKS,
+ MUTEX_ADAPTIVE_SC_SLOW_UNLOCKS,
+ MUTEX_ADAPTIVE_SC_EXTERNAL_UNLOCKS,
+ MUTEX_ADAPTIVE_SC_SIGNALS,
+ MUTEX_ADAPTIVE_NR_SCS
+};
+
+static struct syscnt mutex_adaptive_sc_array[MUTEX_ADAPTIVE_NR_SCS];
+
+static void
+mutex_adaptive_register_sc(unsigned int index, const char *name)
+{
+ assert(index < ARRAY_SIZE(mutex_adaptive_sc_array));
+ syscnt_register(&mutex_adaptive_sc_array[index], name);
+}
+
+static void
+mutex_adaptive_setup_debug(void)
+{
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_SPINS,
+ "mutex_adaptive_spins");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_WAIT_SUCCESSES,
+ "mutex_adaptive_wait_successes");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_WAIT_ERRORS,
+ "mutex_adaptive_wait_errors");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_DOWNGRADES,
+ "mutex_adaptive_downgrades");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_ERROR_DOWNGRADES,
+ "mutex_adaptive_error_downgrades");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_ERROR_CLEARBITS,
+ "mutex_adaptive_error_clearbits");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_ERROR_CLEARCONT,
+ "mutex_adaptive_error_clearcont");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_FAST_UNLOCKS,
+ "mutex_adaptive_fast_unlocks");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_SLOW_UNLOCKS,
+ "mutex_adaptive_slow_unlocks");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_EXTERNAL_UNLOCKS,
+ "mutex_adaptive_external_unlocks");
+ mutex_adaptive_register_sc(MUTEX_ADAPTIVE_SC_SIGNALS,
+ "mutex_adaptive_signals");
+}
+
+static void
+mutex_adaptive_inc_sc(unsigned int index)
+{
+ assert(index < ARRAY_SIZE(mutex_adaptive_sc_array));
+ syscnt_inc(&mutex_adaptive_sc_array[index]);
+}
+
+#else /* MUTEX_ADAPTIVE_DEBUG */
+#define mutex_adaptive_setup_debug()
+#define mutex_adaptive_inc_sc(x)
+#endif /* MUTEX_ADAPTIVE_DEBUG */
+
+
static struct thread *
mutex_adaptive_get_thread(uintptr_t owner)
{
@@ -81,6 +152,8 @@ mutex_adaptive_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
*/
while (mutex_adaptive_is_owner(mutex, owner)) {
if (thread_is_running(mutex_adaptive_get_thread(owner))) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_SPINS);
+
if (timed && clock_time_occurred(ticks, clock_get_time())) {
error = ERROR_TIMEDOUT;
break;
@@ -113,13 +186,17 @@ mutex_adaptive_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
*/
if (error) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_WAIT_ERRORS);
+
if (sleepq_empty(sleepq)) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_ERROR_DOWNGRADES);
owner = atomic_load(&mutex->owner, ATOMIC_RELAXED);
assert(owner & MUTEX_ADAPTIVE_CONTENDED);
thread = mutex_adaptive_get_thread(owner);
/* If there is an owner, try to clear the contended bit */
if (thread != NULL) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_ERROR_CLEARBITS);
owner = atomic_cas(&mutex->owner, owner,
(uintptr_t)thread, ATOMIC_RELAXED);
assert(owner & MUTEX_ADAPTIVE_CONTENDED);
@@ -132,6 +209,7 @@ mutex_adaptive_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
* value of the mutex to become different from the contended bit.
*/
if (thread == NULL) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_ERROR_CLEARCONT);
owner = atomic_cas(&mutex->owner, owner, 0, ATOMIC_RELAXED);
assert(owner == MUTEX_ADAPTIVE_CONTENDED);
}
@@ -140,7 +218,10 @@ mutex_adaptive_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
goto out;
}
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_WAIT_SUCCESSES);
+
if (sleepq_empty(sleepq)) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_DOWNGRADES);
atomic_store(&mutex->owner, self, ATOMIC_RELAXED);
}
@@ -193,10 +274,13 @@ mutex_adaptive_unlock_slow(struct mutex *mutex)
continue;
}
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_FAST_UNLOCKS);
return;
}
}
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_SLOW_UNLOCKS);
+
for (;;) {
owner = atomic_load(&mutex->owner, ATOMIC_RELAXED);
@@ -208,6 +292,7 @@ mutex_adaptive_unlock_slow(struct mutex *mutex)
* 2/ A timeout cleared the contended bit.
*/
if (owner != MUTEX_ADAPTIVE_CONTENDED) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_EXTERNAL_UNLOCKS);
break;
}
@@ -222,6 +307,7 @@ mutex_adaptive_unlock_slow(struct mutex *mutex)
sleepq = sleepq_tryacquire(mutex, false, &flags);
if (sleepq != NULL) {
+ mutex_adaptive_inc_sc(MUTEX_ADAPTIVE_SC_SIGNALS);
sleepq_signal(sleepq);
sleepq_release(sleepq, flags);
break;
@@ -233,3 +319,16 @@ mutex_adaptive_unlock_slow(struct mutex *mutex)
*/
}
}
+
+static int
+mutex_adaptive_setup(void)
+{
+ mutex_adaptive_setup_debug();
+ return 0;
+}
+
+INIT_OP_DEFINE(mutex_adaptive_setup,
+#if MUTEX_ADAPTIVE_DEBUG
+ INIT_OP_DEP(syscnt_setup, true),
+#endif /* MUTEX_ADAPTIVE_DEBUG */
+);
diff --git a/kern/mutex/mutex_adaptive_i.h b/kern/mutex/mutex_adaptive_i.h
index be822c2..a8598e6 100644
--- a/kern/mutex/mutex_adaptive_i.h
+++ b/kern/mutex/mutex_adaptive_i.h
@@ -28,6 +28,7 @@
#include <kern/atomic.h>
#include <kern/error.h>
+#include <kern/init.h>
#include <kern/macros.h>
#include <kern/mutex_types.h>
#include <kern/thread.h>
@@ -132,4 +133,8 @@ mutex_impl_unlock(struct mutex *mutex)
}
}
+#define mutex_impl_setup mutex_adaptive_setup
+
+INIT_OP_DECLARE(mutex_adaptive_setup);
+
#endif /* _KERN_MUTEX_ADAPTIVE_I_H */
diff --git a/kern/mutex/mutex_pi_i.h b/kern/mutex/mutex_pi_i.h
index 616f09b..2d5a2b6 100644
--- a/kern/mutex/mutex_pi_i.h
+++ b/kern/mutex/mutex_pi_i.h
@@ -65,4 +65,6 @@ mutex_impl_unlock(struct mutex *mutex)
rtmutex_unlock(&mutex->rtmutex);
}
+#define mutex_impl_setup rtmutex_setup
+
#endif /* _KERN_MUTEX_PI_I_H */
diff --git a/kern/mutex/mutex_plain.c b/kern/mutex/mutex_plain.c
index 58fc487..6a7cbdc 100644
--- a/kern/mutex/mutex_plain.c
+++ b/kern/mutex/mutex_plain.c
@@ -21,9 +21,58 @@
#include <stdint.h>
#include <kern/atomic.h>
+#include <kern/init.h>
#include <kern/mutex.h>
#include <kern/mutex_types.h>
#include <kern/sleepq.h>
+#include <kern/syscnt.h>
+
+/* Set to 1 to enable debugging */
+#define MUTEX_PLAIN_DEBUG 0
+
+#if MUTEX_PLAIN_DEBUG
+
+enum {
+ MUTEX_PLAIN_SC_WAIT_SUCCESSES,
+ MUTEX_PLAIN_SC_WAIT_ERRORS,
+ MUTEX_PLAIN_SC_DOWNGRADES,
+ MUTEX_PLAIN_SC_ERROR_DOWNGRADES,
+ MUTEX_PLAIN_NR_SCS
+};
+
+static struct syscnt mutex_plain_sc_array[MUTEX_PLAIN_NR_SCS];
+
+static void
+mutex_plain_register_sc(unsigned int index, const char *name)
+{
+ assert(index < ARRAY_SIZE(mutex_plain_sc_array));
+ syscnt_register(&mutex_plain_sc_array[index], name);
+}
+
+static void
+mutex_plain_setup_debug(void)
+{
+ mutex_plain_register_sc(MUTEX_PLAIN_SC_WAIT_SUCCESSES,
+ "mutex_plain_wait_successes");
+ mutex_plain_register_sc(MUTEX_PLAIN_SC_WAIT_ERRORS,
+ "mutex_plain_wait_errors");
+ mutex_plain_register_sc(MUTEX_PLAIN_SC_DOWNGRADES,
+ "mutex_plain_downgrades");
+ mutex_plain_register_sc(MUTEX_PLAIN_SC_ERROR_DOWNGRADES,
+ "mutex_plain_error_downgrades");
+}
+
+static void
+mutex_plain_inc_sc(unsigned int index)
+{
+ assert(index < ARRAY_SIZE(mutex_plain_sc_array));
+ syscnt_inc(&mutex_plain_sc_array[index]);
+}
+
+#else /* MUTEX_PLAIN_DEBUG */
+#define mutex_plain_setup_debug()
+#define mutex_plain_inc_sc(x)
+#endif /* MUTEX_PLAIN_DEBUG */
static int
mutex_plain_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
@@ -56,7 +105,10 @@ mutex_plain_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
}
if (error) {
+ mutex_plain_inc_sc(MUTEX_PLAIN_SC_WAIT_ERRORS);
+
if (sleepq_empty(sleepq)) {
+ mutex_plain_inc_sc(MUTEX_PLAIN_SC_ERROR_DOWNGRADES);
atomic_cas(&mutex->state, MUTEX_CONTENDED,
MUTEX_LOCKED, ATOMIC_RELAXED);
}
@@ -64,7 +116,10 @@ mutex_plain_lock_slow_common(struct mutex *mutex, bool timed, uint64_t ticks)
goto out;
}
+ mutex_plain_inc_sc(MUTEX_PLAIN_SC_WAIT_SUCCESSES);
+
if (sleepq_empty(sleepq)) {
+ mutex_plain_inc_sc(MUTEX_PLAIN_SC_DOWNGRADES);
atomic_store(&mutex->state, MUTEX_LOCKED, ATOMIC_RELAXED);
}
@@ -105,3 +160,16 @@ mutex_plain_unlock_slow(struct mutex *mutex)
sleepq_release(sleepq, flags);
}
+
+static int
+mutex_plain_setup(void)
+{
+ mutex_plain_setup_debug();
+ return 0;
+}
+
+INIT_OP_DEFINE(mutex_plain_setup,
+#if MUTEX_PLAIN_DEBUG
+ INIT_OP_DEP(syscnt_setup, true),
+#endif /* MUTEX_PLAIN_DEBUG */
+);
diff --git a/kern/mutex/mutex_plain_i.h b/kern/mutex/mutex_plain_i.h
index 58e565e..fe97308 100644
--- a/kern/mutex/mutex_plain_i.h
+++ b/kern/mutex/mutex_plain_i.h
@@ -28,6 +28,7 @@
#include <kern/atomic.h>
#include <kern/error.h>
+#include <kern/init.h>
#include <kern/mutex_types.h>
#define MUTEX_UNLOCKED 0
@@ -126,4 +127,8 @@ mutex_impl_unlock(struct mutex *mutex)
}
}
+#define mutex_impl_setup mutex_plain_setup
+
+INIT_OP_DECLARE(mutex_plain_setup);
+
#endif /* _KERN_MUTEX_PLAIN_I_H */