diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2007-07-19 04:48:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:49 -0400 |
commit | f20786ff4da51e56b1956acf30be2552be266746 (patch) | |
tree | f6d0a9ed84ca476ca19fe7131d842699881756c4 /include/linux | |
parent | 8e18257d29238311e82085152741f0c3aa18b74d (diff) |
lockstat: core infrastructure
Introduce the core lock statistics code.
Lock statistics provides lock wait-time and hold-time (as well as the count
of corresponding contention and acquisitions events). Also, the first few
call-sites that encounter contention are tracked.
Lock wait-time is the time spent waiting on the lock. This provides insight
into the locking scheme, that is, a heavily contended lock is indicative of
a too coarse locking scheme.
Lock hold-time is the duration the lock was held, this provides a reference for
the wait-time numbers, so they can be put into perspective.
1)
lock
2)
... do stuff ..
unlock
3)
The time between 1 and 2 is the wait-time. The time between 2 and 3 is the
hold-time.
The lockdep held-lock tracking code is reused, because it already collects locks
into meaningful groups (classes), and because it is an existing infrastructure
for lock instrumentation.
Currently lockdep tracks lock acquisition with two hooks:
lock()
lock_acquire()
_lock()
... code protected by lock ...
unlock()
lock_release()
_unlock()
We need to extend this with two more hooks, in order to measure contention.
lock_contended() - used to measure contention events
lock_acquired() - completion of the contention
These are then placed the following way:
lock()
lock_acquire()
if (!_try_lock())
lock_contended()
_lock()
lock_acquired()
... do locked stuff ...
unlock()
lock_release()
_unlock()
(Note: the try_lock() 'trick' is used to avoid instrumenting all platform
dependent lock primitive implementations.)
It is also possible to toggle the two lockdep features at runtime using:
/proc/sys/kernel/prove_locking
/proc/sys/kernel/lock_stat
(esp. turning off the O(n^2) prove_locking functionaliy can help)
[akpm@linux-foundation.org: build fixes]
[akpm@linux-foundation.org: nuke unneeded ifdefs]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Ingo Molnar <mingo@elte.hu>
Acked-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/lockdep.h | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 14c937d345cb..8f946f614f8e 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #define __LINUX_LOCKDEP_H | 9 | #define __LINUX_LOCKDEP_H |
10 | 10 | ||
11 | struct task_struct; | 11 | struct task_struct; |
12 | struct lockdep_map; | ||
12 | 13 | ||
13 | #ifdef CONFIG_LOCKDEP | 14 | #ifdef CONFIG_LOCKDEP |
14 | 15 | ||
@@ -114,8 +115,32 @@ struct lock_class { | |||
114 | 115 | ||
115 | const char *name; | 116 | const char *name; |
116 | int name_version; | 117 | int name_version; |
118 | |||
119 | #ifdef CONFIG_LOCK_STAT | ||
120 | unsigned long contention_point[4]; | ||
121 | #endif | ||
122 | }; | ||
123 | |||
124 | #ifdef CONFIG_LOCK_STAT | ||
125 | struct lock_time { | ||
126 | s64 min; | ||
127 | s64 max; | ||
128 | s64 total; | ||
129 | unsigned long nr; | ||
117 | }; | 130 | }; |
118 | 131 | ||
132 | struct lock_class_stats { | ||
133 | unsigned long contention_point[4]; | ||
134 | struct lock_time read_waittime; | ||
135 | struct lock_time write_waittime; | ||
136 | struct lock_time read_holdtime; | ||
137 | struct lock_time write_holdtime; | ||
138 | }; | ||
139 | |||
140 | struct lock_class_stats lock_stats(struct lock_class *class); | ||
141 | void clear_lock_stats(struct lock_class *class); | ||
142 | #endif | ||
143 | |||
119 | /* | 144 | /* |
120 | * Map the lock object (the lock instance) to the lock-class object. | 145 | * Map the lock object (the lock instance) to the lock-class object. |
121 | * This is embedded into specific lock instances: | 146 | * This is embedded into specific lock instances: |
@@ -165,6 +190,10 @@ struct held_lock { | |||
165 | unsigned long acquire_ip; | 190 | unsigned long acquire_ip; |
166 | struct lockdep_map *instance; | 191 | struct lockdep_map *instance; |
167 | 192 | ||
193 | #ifdef CONFIG_LOCK_STAT | ||
194 | u64 waittime_stamp; | ||
195 | u64 holdtime_stamp; | ||
196 | #endif | ||
168 | /* | 197 | /* |
169 | * The lock-stack is unified in that the lock chains of interrupt | 198 | * The lock-stack is unified in that the lock chains of interrupt |
170 | * contexts nest ontop of process context chains, but we 'separate' | 199 | * contexts nest ontop of process context chains, but we 'separate' |
@@ -281,6 +310,30 @@ struct lock_class_key { }; | |||
281 | 310 | ||
282 | #endif /* !LOCKDEP */ | 311 | #endif /* !LOCKDEP */ |
283 | 312 | ||
313 | #ifdef CONFIG_LOCK_STAT | ||
314 | |||
315 | extern void lock_contended(struct lockdep_map *lock, unsigned long ip); | ||
316 | extern void lock_acquired(struct lockdep_map *lock); | ||
317 | |||
318 | #define LOCK_CONTENDED(_lock, try, lock) \ | ||
319 | do { \ | ||
320 | if (!try(_lock)) { \ | ||
321 | lock_contended(&(_lock)->dep_map, _RET_IP_); \ | ||
322 | lock(_lock); \ | ||
323 | lock_acquired(&(_lock)->dep_map); \ | ||
324 | } \ | ||
325 | } while (0) | ||
326 | |||
327 | #else /* CONFIG_LOCK_STAT */ | ||
328 | |||
329 | #define lock_contended(lockdep_map, ip) do {} while (0) | ||
330 | #define lock_acquired(lockdep_map) do {} while (0) | ||
331 | |||
332 | #define LOCK_CONTENDED(_lock, try, lock) \ | ||
333 | lock(_lock) | ||
334 | |||
335 | #endif /* CONFIG_LOCK_STAT */ | ||
336 | |||
284 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) | 337 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS) |
285 | extern void early_init_irq_lock_class(void); | 338 | extern void early_init_irq_lock_class(void); |
286 | #else | 339 | #else |