Linux Kernel Lock Statistics: Debugging Lock Contention with /proc/lock_stat-Free Linux Device Driver Course Online

Linux Kernel Lock Statistics: Debugging Lock Contention with /proc/lock_stat
A free, hands-on lesson from the Linux Kernel Development Course on EmbeddedPathashala — learn how the kernel tracks spinlock and mutex contention on modern 6.x kernels.
Level
Intermediate
Kernel
6.12+ (LTS)
Reading Time
12 min

If you’ve ever wondered why a driver or subsystem feels sluggish under heavy load, the answer is very often lock contention. This lesson is part of our free linux kernel development course and walks through the kernel’s built-in lock statistics facility, exposed at /proc/lock_stat, so you can measure exactly which lock is slowing your system down and for how long. We’ll also point out where the tooling landscape has moved on since older texts were written, so the workflow you learn here matches what you’ll actually see on a current 6.12+ kernel.

In this lesson you’ll work with:
CONFIG_LOCK_STAT lockdep /proc/lock_stat bpftrace contended locks

What You Will Learn

  • What lock contention is and why it matters for embedded and systems performance
  • How to enable the kernel’s lock statistics subsystem safely
  • How to read and interpret every column of the /proc/lock_stat report
  • How to reset counters and isolate contention during a specific test window
  • Modern alternatives — bpftrace and perf lock — for kernels where lock_stat is disabled
  • Common mistakes engineers make when profiling locks, and how to avoid them

Prerequisites

  • Basic familiarity with spinlocks and mutexes in the Linux kernel
  • A kernel you can rebuild, or root access to a distro kernel with debug symbols
  • Comfort working at the shell as root (all commands below need sudo)

Why Lock Contention Matters

Every time two CPU cores race to grab the same spinlock or mutex, one of them has to wait. Occasional waiting is normal and harmless. But when a lock is grabbed thousands of times a second from multiple cores, that waiting adds up into real, measurable latency — the kind that shows up as dropped audio frames, missed real-time deadlines, or a network stack that can’t keep up with line rate. The kernel’s lock statistics engine exists precisely to make this invisible cost visible.

How Two Cores Contend for One Lock
CPU 0
holds lock
doing work
→
Lock
owned by CPU 0
←
CPU 1
blocked, waiting
(this is contention)

Enabling Lock Statistics

Lock statistics ride on top of the kernel’s lock validator (lockdep), so both need to be enabled in your kernel configuration before you can collect anything.

CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKDEP=y
CONFIG_LOCK_STAT=y
CONFIG_DEBUG_LOCK_ALLOC=y

Once you boot a kernel built with these options, a control file appears that lets you turn tracking on and off without rebooting:

echo 1 | sudo tee /proc/sys/kernel/lock_stat

Reading the /proc/lock_stat Report

With statistics enabled, run your workload for a few seconds and then dump the report:

sudo cat /proc/lock_stat | head -40

Each row describes one lock class — not one lock instance, but the type of lock (for example, every instance of a particular spinlock in a driver is grouped together). The table below explains the columns you’ll see, in plain language rather than kernel jargon:

Column What it tells you
class nameThe symbolic name of the lock (usually the struct field it protects)
con-bounces / contentionsHow many times a thread had to wait because another core already held the lock
waittime-min/max/total/avgHow long waiters sat blocked, in microseconds — the number to watch for latency-sensitive code
acquisitionsTotal number of times the lock was successfully taken — tells you how “hot” the lock is
holdtime-min/max/total/avgHow long the lock was held once acquired — a large average hold time is often the real root cause of contention

Rule of thumb: a lock with high acquisitions but low waittime is simply busy, not a problem. A lock with even a modest acquisition count but a high average waittime or holdtime is the one worth investigating first.

Resetting Counters Before a Test

Lock statistics accumulate from the moment they’re enabled, so stale numbers from boot-time activity can hide the pattern you actually care about. Clear the table immediately before running your test:

sudo sh -c 'echo 0 > /proc/lock_stat'
# ... run your workload here ...
sudo cat /proc/lock_stat

Modern Alternative: Tracing Lock Contention with bpftrace

On distro kernels shipped without CONFIG_LOCK_STAT — which is common in production 6.12+ builds because lockdep instrumentation carries a measurable performance cost — you can still observe contention using eBPF-based tracing instead of rebuilding your kernel:

sudo bpftrace -e '
kprobe:queued_spin_lock_slowpath
{
    @contended[comm] = count();
}
interval:s:5 { print(@contended); exit(); }
'

This one-liner hooks the slow-path entry point that spinlocks fall into only when contended, so every hit it records is genuine contention — a good first sanity check before you commit to a full lockdep rebuild.

Common Mistakes

  • Leaving lockdep enabled in production — lock_stat is a debugging aid; disable it before shipping, as the tracking overhead affects real-world latency.
  • Comparing raw acquisition counts across different workloads — always normalize by test duration.
  • Ignoring holdtime — engineers often stare only at waittime and miss that a lock held too long is the actual cause.
  • Forgetting to reset counters — old boot-time noise skews short test runs.

Best Practices

  • Always reset the lock_stat table right before a controlled test run.
  • Cross-check suspicious locks with bpftrace or perf lock record to confirm the finding on a production-like kernel.
  • Fix contention by shrinking critical sections first — reducing holdtime is usually cheaper than redesigning the locking scheme.

Performance and Security Considerations

Lockdep-based tracking adds real overhead to every lock acquisition on the system, so treat it strictly as a development/debug-kernel feature. From a security standpoint, /proc/lock_stat reveals internal kernel structure names and timing behavior, so it’s gated behind root access by default — keep it that way on any shared or production system.

Summary / Key Takeaways

  • Lock contention is invisible until you measure it — /proc/lock_stat makes it visible on debug kernels.
  • Watch waittime for latency impact and holdtime for root cause.
  • On production kernels without lockdep, bpftrace gives you a lightweight second option.

Conclusion

Lock statistics turn a vague feeling that “something feels slow” into a concrete, per-lock number you can act on. Whether you reach for the kernel’s built-in lockdep-based reporting or a quick bpftrace probe on a production system, the goal is the same: find the lock, find whether it’s contention or hold-time driven, and fix the smallest possible critical section. This kind of measurement-first debugging is exactly the mindset we build throughout this free linux kernel development course.

Frequently Asked Questions

Q1. Does /proc/lock_stat work on all Linux kernels?

No — it only appears when the kernel is built with CONFIG_LOCK_STAT and CONFIG_LOCKDEP enabled. Most production distro kernels ship without it due to overhead.

Q2. What’s the difference between con-bounces and contentions?

They’re closely related counters both tracking how often a waiter had to block; contentions is the general count while con-bounces specifically tracks cross-CPU cacheline bouncing on the lock.

Q3. Why is lock debugging sometimes reported as disabled even though I enabled it?

The kernel automatically disables lock debugging after it detects a lockdep warning, to avoid flooding output. A reboot is usually required to restore tracking.

Q4. Can I use lock statistics on an embedded ARM board?

Yes, as long as your kernel config enables the same lockdep and lock_stat options — the interface behaves identically across architectures.

Q5. Is there a GUI for /proc/lock_stat output?

Not built-in, but several perf-based and bpftrace-based front ends can visualize contention over time; the raw file remains the ground truth.

Q6. How much overhead does CONFIG_LOCK_STAT add?

Enough that it should never be used in production — expect a measurable slowdown on lock-heavy workloads, which is exactly why it’s a debug-only kernel config.

Q7. What’s a “good” waittime-avg value?

There’s no universal number — it depends entirely on your latency budget. What matters is comparing it before and after a fix.

Continue the Free Linux Kernel Development Course

Explore more lessons on kernel synchronization, scheduling, and device drivers — all free, all hands-on.

Browse the Course

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *