Skip to content

Commit 8ca2b56

Browse files
Waiman-LongIngo Molnar
authored andcommitted
locking/lockdep: Make class->ops a percpu counter and move it under CONFIG_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 <longman@redhat.com> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Will Deacon <will.deacon@arm.com> Link: http://lkml.kernel.org/r/d66681f3-8781-9793-1dcf-2436a284550b@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent ce52a18 commit 8ca2b56

File tree

4 files changed

+37
-10
lines changed

4 files changed

+37
-10
lines changed

include/linux/lockdep.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,8 @@ struct lock_class {
9999
*/
100100
unsigned int version;
101101

102-
/*
103-
* Statistics counter:
104-
*/
105-
unsigned long ops;
106-
107-
const char *name;
108102
int name_version;
103+
const char *name;
109104

110105
#ifdef CONFIG_LOCK_STAT
111106
unsigned long contention_point[LOCKSTAT_POINTS];

kernel/locking/lockdep.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
139139
* get freed - this significantly simplifies the debugging code.
140140
*/
141141
unsigned long nr_lock_classes;
142-
static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
142+
struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
143143

144144
static inline struct lock_class *hlock_class(struct held_lock *hlock)
145145
{
@@ -436,6 +436,7 @@ unsigned int max_lockdep_depth;
436436
* Various lockdep statistics:
437437
*/
438438
DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats);
439+
DEFINE_PER_CPU(unsigned long [MAX_LOCKDEP_KEYS], lock_class_ops);
439440
#endif
440441

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

13931394
printk("%*s->", depth, "");
13941395
print_lock_name(class);
1395-
printk(KERN_CONT " ops: %lu", class->ops);
1396+
#ifdef CONFIG_DEBUG_LOCKDEP
1397+
printk(KERN_CONT " ops: %lu", debug_class_ops_read(class));
1398+
#endif
13961399
printk(KERN_CONT " {\n");
13971400

13981401
for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
@@ -3227,7 +3230,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
32273230
if (!class)
32283231
return 0;
32293232
}
3230-
atomic_inc((atomic_t *)&class->ops);
3233+
3234+
debug_class_ops_inc(class);
3235+
32313236
if (very_verbose(class)) {
32323237
printk("\nacquire class [%px] %s", class->key, class->name);
32333238
if (class->name_version > 1)

kernel/locking/lockdep_internals.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,15 @@ struct lockdep_stats {
152152
int nr_find_usage_forwards_recursions;
153153
int nr_find_usage_backwards_checks;
154154
int nr_find_usage_backwards_recursions;
155+
156+
/*
157+
* Per lock class locking operation stat counts
158+
*/
159+
unsigned long lock_class_ops[MAX_LOCKDEP_KEYS];
155160
};
156161

157162
DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
163+
extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
158164

159165
#define __debug_atomic_inc(ptr) \
160166
this_cpu_inc(lockdep_stats.ptr);
@@ -179,9 +185,30 @@ DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
179185
} \
180186
__total; \
181187
})
188+
189+
static inline void debug_class_ops_inc(struct lock_class *class)
190+
{
191+
int idx;
192+
193+
idx = class - lock_classes;
194+
__debug_atomic_inc(lock_class_ops[idx]);
195+
}
196+
197+
static inline unsigned long debug_class_ops_read(struct lock_class *class)
198+
{
199+
int idx, cpu;
200+
unsigned long ops = 0;
201+
202+
idx = class - lock_classes;
203+
for_each_possible_cpu(cpu)
204+
ops += per_cpu(lockdep_stats.lock_class_ops[idx], cpu);
205+
return ops;
206+
}
207+
182208
#else
183209
# define __debug_atomic_inc(ptr) do { } while (0)
184210
# define debug_atomic_inc(ptr) do { } while (0)
185211
# define debug_atomic_dec(ptr) do { } while (0)
186212
# define debug_atomic_read(ptr) 0
213+
# define debug_class_ops_inc(ptr) do { } while (0)
187214
#endif

kernel/locking/lockdep_proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static int l_show(struct seq_file *m, void *v)
6868

6969
seq_printf(m, "%p", class->key);
7070
#ifdef CONFIG_DEBUG_LOCKDEP
71-
seq_printf(m, " OPS:%8ld", class->ops);
71+
seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));
7272
#endif
7373
#ifdef CONFIG_PROVE_LOCKING
7474
seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class));

0 commit comments

Comments
 (0)