aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking
diff options
context:
space:
mode:
authorWaiman Long <longman@redhat.com>2018-10-03 13:07:18 -0400
committerIngo Molnar <mingo@kernel.org>2018-10-09 03:56:33 -0400
commit8ca2b56cd7da98fc8f8d787bb706b9d6c8674a3b (patch)
treef73f5ff4065aab44ebc28dab5103393012a87c47 /kernel/locking
parentce52a18db45842f5b992851a552bd7f6acb2241b (diff)
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>
Diffstat (limited to 'kernel/locking')
-rw-r--r--kernel/locking/lockdep.c11
-rw-r--r--kernel/locking/lockdep_internals.h27
-rw-r--r--kernel/locking/lockdep_proc.c2
3 files changed, 36 insertions, 4 deletions
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 511d30f88bce..a0f83058d6aa 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -139,7 +139,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
139 * get freed - this significantly simplifies the debugging code. 139 * get freed - this significantly simplifies the debugging code.
140 */ 140 */
141unsigned long nr_lock_classes; 141unsigned long nr_lock_classes;
142static struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; 142struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
143 143
144static inline struct lock_class *hlock_class(struct held_lock *hlock) 144static inline struct lock_class *hlock_class(struct held_lock *hlock)
145{ 145{
@@ -436,6 +436,7 @@ unsigned int max_lockdep_depth;
436 * Various lockdep statistics: 436 * Various lockdep statistics:
437 */ 437 */
438DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats); 438DEFINE_PER_CPU(struct lockdep_stats, lockdep_stats);
439DEFINE_PER_CPU(unsigned long [MAX_LOCKDEP_KEYS], lock_class_ops);
439#endif 440#endif
440 441
441/* 442/*
@@ -1392,7 +1393,9 @@ static void print_lock_class_header(struct lock_class *class, int depth)
1392 1393
1393 printk("%*s->", depth, ""); 1394 printk("%*s->", depth, "");
1394 print_lock_name(class); 1395 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
1396 printk(KERN_CONT " {\n"); 1399 printk(KERN_CONT " {\n");
1397 1400
1398 for (bit = 0; bit < LOCK_USAGE_STATES; bit++) { 1401 for (bit = 0; bit < LOCK_USAGE_STATES; bit++) {
@@ -3227,7 +3230,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
3227 if (!class) 3230 if (!class)
3228 return 0; 3231 return 0;
3229 } 3232 }
3230 atomic_inc((atomic_t *)&class->ops); 3233
3234 debug_class_ops_inc(class);
3235
3231 if (very_verbose(class)) { 3236 if (very_verbose(class)) {
3232 printk("\nacquire class [%px] %s", class->key, class->name); 3237 printk("\nacquire class [%px] %s", class->key, class->name);
3233 if (class->name_version > 1) 3238 if (class->name_version > 1)
diff --git a/kernel/locking/lockdep_internals.h b/kernel/locking/lockdep_internals.h
index d459d624ba2a..88c847a41c8a 100644
--- a/kernel/locking/lockdep_internals.h
+++ b/kernel/locking/lockdep_internals.h
@@ -152,9 +152,15 @@ struct lockdep_stats {
152 int nr_find_usage_forwards_recursions; 152 int nr_find_usage_forwards_recursions;
153 int nr_find_usage_backwards_checks; 153 int nr_find_usage_backwards_checks;
154 int nr_find_usage_backwards_recursions; 154 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];
155}; 160};
156 161
157DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats); 162DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
163extern struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
158 164
159#define __debug_atomic_inc(ptr) \ 165#define __debug_atomic_inc(ptr) \
160 this_cpu_inc(lockdep_stats.ptr); 166 this_cpu_inc(lockdep_stats.ptr);
@@ -179,9 +185,30 @@ DECLARE_PER_CPU(struct lockdep_stats, lockdep_stats);
179 } \ 185 } \
180 __total; \ 186 __total; \
181}) 187})
188
189static 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
197static 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
182#else 208#else
183# define __debug_atomic_inc(ptr) do { } while (0) 209# define __debug_atomic_inc(ptr) do { } while (0)
184# define debug_atomic_inc(ptr) do { } while (0) 210# define debug_atomic_inc(ptr) do { } while (0)
185# define debug_atomic_dec(ptr) do { } while (0) 211# define debug_atomic_dec(ptr) do { } while (0)
186# define debug_atomic_read(ptr) 0 212# define debug_atomic_read(ptr) 0
213# define debug_class_ops_inc(ptr) do { } while (0)
187#endif 214#endif
diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c
index 3dd980dfba2d..3d31f9b0059e 100644
--- a/kernel/locking/lockdep_proc.c
+++ b/kernel/locking/lockdep_proc.c
@@ -68,7 +68,7 @@ static int l_show(struct seq_file *m, void *v)
68 68
69 seq_printf(m, "%p", class->key); 69 seq_printf(m, "%p", class->key);
70#ifdef CONFIG_DEBUG_LOCKDEP 70#ifdef CONFIG_DEBUG_LOCKDEP
71 seq_printf(m, " OPS:%8ld", class->ops); 71 seq_printf(m, " OPS:%8ld", debug_class_ops_read(class));
72#endif 72#endif
73#ifdef CONFIG_PROVE_LOCKING 73#ifdef CONFIG_PROVE_LOCKING
74 seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); 74 seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class));