This adds two new lock contention tracepoints like below: * lock:contention_begin * lock:contention_end The lock:contention_begin takes a flags argument to classify locks. I found it useful to pass a task state it goes to and it can tell if the given lock is busy-waiting (spinlock) or sleeping (mutex or semaphore). Also it has info whether it's a reader-writer lock, real-time, and per-cpu. Move tracepoint definitions into a separate file so that we can use some of them without lockdep. Also lock_trace.h header was added to provide access to the tracepoints in the header file (like spinlock.h) which cannot include the tracepoint definition directly. Signed-off-by: Namhyung Kim <namhyung@xxxxxxxxxx> --- include/linux/lock_trace.h | 31 +++++++++++++++++++++++++++ include/trace/events/lock.h | 42 ++++++++++++++++++++++++++++++++++++- kernel/locking/Makefile | 2 +- kernel/locking/lockdep.c | 1 - kernel/locking/tracepoint.c | 21 +++++++++++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 include/linux/lock_trace.h create mode 100644 kernel/locking/tracepoint.c diff --git a/include/linux/lock_trace.h b/include/linux/lock_trace.h new file mode 100644 index 000000000000..d84bcc9570a4 --- /dev/null +++ b/include/linux/lock_trace.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __LINUX_LOCK_TRACE_H +#define __LINUX_LOCK_TRACE_H + +#include <linux/tracepoint-defs.h> + +DECLARE_TRACEPOINT(contention_begin); +DECLARE_TRACEPOINT(contention_end); + +#define LCB_F_READ (1U << 31) +#define LCB_F_WRITE (1U << 30) +#define LCB_F_RT (1U << 29) +#define LCB_F_PERCPU (1U << 28) + +extern void lock_contention_begin(void *lock, unsigned long ip, + unsigned int flags); +extern void lock_contention_end(void *lock); + +#define LOCK_CONTENTION_BEGIN(_lock, _flags) \ + do { \ + if (tracepoint_enabled(contention_begin)) \ + lock_contention_begin(_lock, _RET_IP_, _flags); \ + } while (0) + +#define LOCK_CONTENTION_END(_lock) \ + do { \ + if (tracepoint_enabled(contention_end)) \ + lock_contention_end(_lock); \ + } while (0) + +#endif /* __LINUX_LOCK_TRACE_H */ diff --git a/include/trace/events/lock.h b/include/trace/events/lock.h index d7512129a324..7bca0a537dbd 100644 --- a/include/trace/events/lock.h +++ b/include/trace/events/lock.h @@ -5,11 +5,12 @@ #if !defined(_TRACE_LOCK_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_LOCK_H -#include <linux/lockdep.h> #include <linux/tracepoint.h> #ifdef CONFIG_LOCKDEP +#include <linux/lockdep.h> + TRACE_EVENT(lock_acquire, TP_PROTO(struct lockdep_map *lock, unsigned int subclass, @@ -81,6 +82,45 @@ DEFINE_EVENT(lock, lock_acquired, #endif #endif +TRACE_EVENT(contention_begin, + + TP_PROTO(void *lock, unsigned long ip, unsigned int flags), + + TP_ARGS(lock, ip, flags), + + TP_STRUCT__entry( + __field(void *, lock_addr) + __field(unsigned long, ip) + __field(unsigned int, flags) + ), + + TP_fast_assign( + __entry->lock_addr = lock; + __entry->ip = ip; + __entry->flags = flags; + ), + + TP_printk("%p %pS (%x)", __entry->lock_addr, (void *) __entry->ip, + __entry->flags) +); + +TRACE_EVENT(contention_end, + + TP_PROTO(void *lock), + + TP_ARGS(lock), + + TP_STRUCT__entry( + __field(void *, lock_addr) + ), + + TP_fast_assign( + __entry->lock_addr = lock; + ), + + TP_printk("%p", __entry->lock_addr) +); + #endif /* _TRACE_LOCK_H */ /* This part must be outside protection */ diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile index d51cabf28f38..d212401adcdc 100644 --- a/kernel/locking/Makefile +++ b/kernel/locking/Makefile @@ -3,7 +3,7 @@ # and is generally not a function of system call inputs. KCOV_INSTRUMENT := n -obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o +obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o tracepoint.o # Avoid recursion lockdep -> KCSAN -> ... -> lockdep. KCSAN_SANITIZE_lockdep.o := n diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 50036c10b518..08f8fb6a2d1e 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -60,7 +60,6 @@ #include "lockdep_internals.h" -#define CREATE_TRACE_POINTS #include <trace/events/lock.h> #ifdef CONFIG_PROVE_LOCKING diff --git a/kernel/locking/tracepoint.c b/kernel/locking/tracepoint.c new file mode 100644 index 000000000000..d6f5c6c1d7bd --- /dev/null +++ b/kernel/locking/tracepoint.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#include <linux/lock_trace.h> + +#define CREATE_TRACE_POINTS +#include <trace/events/lock.h> + +/* these are exported via LOCK_CONTENTION_{BEGIN,END} macro */ +EXPORT_TRACEPOINT_SYMBOL_GPL(contention_begin); +EXPORT_TRACEPOINT_SYMBOL_GPL(contention_end); + +void lock_contention_begin(void *lock, unsigned long ip, unsigned int flags) +{ + trace_contention_begin(lock, ip, flags); +} +EXPORT_SYMBOL_GPL(lock_contention_begin); + +void lock_contention_end(void *lock) +{ + trace_contention_end(lock); +} +EXPORT_SYMBOL_GPL(lock_contention_end); -- 2.35.1.574.g5d30c73bfb-goog