Skip to content

Commit

Permalink
locking/lockdep: Make class->ops a percpu counter and move it under C…
Browse files Browse the repository at this point in the history
…ONFIG_DEBUG_LOCKDEP=y

A sizable portion of the CPU cycles spent on the __lock_acquire() is used
up by the atomic increment of the class->ops stat counter. By taking it out
from the lock_class structure and changing it to a per-cpu per-lock-class
counter, we can reduce the amount of cacheline contention on the class
structure when multiple CPUs are trying to acquire locks of the same
class simultaneously.

To limit the increase in memory consumption because of the percpu nature
of that counter, it is now put back under the CONFIG_DEBUG_LOCKDEP
config option. So the memory consumption increase will only occur if
CONFIG_DEBUG_LOCKDEP is defined. The lock_class structure, however,
is reduced in size by 16 bytes on 64-bit archs after ops removal and
a minor restructuring of the fields.

This patch also fixes a bug in the increment code as the counter is of
the 'unsigned long' type, but atomic_inc() was used to increment it.

Signed-off-by: Waiman Long <[email protected]>
Acked-by: Peter Zijlstra <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Will Deacon <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
Waiman-Long authored and Ingo Molnar committed Oct 9, 2018
1 parent ce52a18 commit 8ca2b56
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 10 deletions.
7 changes: 1 addition & 6 deletions include/linux/lockdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,8 @@ struct lock_class {
*/
unsigned int version;

/*
* Statistics counter:
*/
unsigned long ops;

const char *name;
int name_version;
const char *name;

#ifdef CONFIG_LOCK_STAT
unsigned long contention_point[LOCKSTAT_POINTS];
Expand Down
11 changes: 8 additions & 3 deletions kernel/locking/lockdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
* get freed - this significantly simplifies the debugging code.
*/
unsigned long nr_lock_classes;
static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
struct lock_class lock_classes[MAX_LOCKDEP_KEYS];

static inline struct lock_class *hlock_class(struct held_lock *hlock)
{
Expand Down Expand Up @@ -436,6 +436,7 @@ unsigned int max_lockdep_depth;
* Various lockdep statistics:
*/
DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats);
DEFINE_PER_CPU(unsigned long [MAX_LOCKDEP_KEYS], lock_class_ops);
#endif

/*
Expand Down Expand Up @@ -1392,7 +1393,9 @@ static void print_lock_class_header(struct lock_class *class, int depth)

printk("%*s->", depth, "");
print_lock_name(class);
printk(KERN_CONT " ops: %lu", class->ops);
#ifdef CONFIG_DEBUG_LOCKDEP
printk(KERN_CONT " ops: %lu", debug_class_ops_read(class));
#endif
printk(KERN_CONT " {\n");

for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
Expand Down Expand Up @@ -3227,7 +3230,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (!class)
return 0;
}
atomic_inc((atomic_t *)&class->ops);

debug_class_ops_inc(class);

if (very_verbose(class)) {
printk("\nacquire class [%px] %s", class->key, class->name);
if (class->name_version > 1)
Expand Down
27 changes: 27 additions & 0 deletions kernel/locking/lockdep_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,15 @@ struct lockdep_stats {
int nr_find_usage_forwards_recursions;
int nr_find_usage_backwards_checks;
int nr_find_usage_backwards_recursions;

/*
* Per lock class locking operation stat counts
*/
unsigned long lock_class_ops[MAX_LOCKDEP_KEYS];
};

DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS];

#define __debug_atomic_inc(ptr) \
this_cpu_inc(lockdep_stats.ptr);
Expand All @@ -179,9 +185,30 @@ DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
} \
__total; \
})

static inline void debug_class_ops_inc(struct lock_class *class)
{
int idx;

idx = class - lock_classes;
__debug_atomic_inc(lock_class_ops[idx]);
}

static inline unsigned long debug_class_ops_read(struct lock_class *class)
{
int idx, cpu;
unsigned long ops = 0;

idx = class - lock_classes;
for_each_possible_cpu(cpu)
ops += per_cpu(lockdep_stats.lock_class_ops[idx], cpu);
return ops;
}

#else
# define __debug_atomic_inc(ptr) do { } while (0)
# define debug_atomic_inc(ptr) do { } while (0)
# define debug_atomic_dec(ptr) do { } while (0)
# define debug_atomic_read(ptr) 0
# define debug_class_ops_inc(ptr) do { } while (0)
#endif
2 changes: 1 addition & 1 deletion kernel/locking/lockdep_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ static int l_show(struct seq_file *m, void *v)

seq_printf(m, "%p", class->key);
#ifdef CONFIG_DEBUG_LOCKDEP
seq_printf(m, " OPS:%8ld", class->ops);
seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));
#endif
#ifdef CONFIG_PROVE_LOCKING
seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class));
Expand Down

0 comments on commit 8ca2b56

Please sign in to comment.