diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2007-07-19 04:49:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:49 -0400 |
commit | 96645678cd726e87ce42a0664de71e047e32bca4 (patch) | |
tree | 116f568a090414777b481e8e5d9db55f420e4335 | |
parent | 443aef0eddfa44c158d1b94ebb431a70638fcab4 (diff) |
lockstat: measure lock bouncing
__acquire
|
lock _____
| \
| __contended
| |
| wait
| _______/
|/
|
__acquired
|
__release
|
unlock
We measure acquisition and contention bouncing.
This is done by recording a cpu stamp in each lock instance.
Contention bouncing requires the cpu stamp to be set on acquisition. Hence we
move __acquired into the generic path.
__acquired is then used to measure acquisition bouncing by comparing the
current cpu with the old stamp before replacing it.
__contended is used to measure contention bouncing (only useful for preemptable
locks)
[akpm@linux-foundation.org: cleanups]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/lockdep.h | 17 | ||||
-rw-r--r-- | kernel/lockdep.c | 38 | ||||
-rw-r--r-- | kernel/lockdep_proc.c | 19 | ||||
-rw-r--r-- | kernel/mutex.c | 2 |
4 files changed, 55 insertions, 21 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 3d3386b88b6a..0e843bf65877 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -130,12 +130,24 @@ struct lock_time { | |||
130 | unsigned long nr; | 130 | unsigned long nr; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | enum bounce_type { | ||
134 | bounce_acquired_write, | ||
135 | bounce_acquired_read, | ||
136 | bounce_contended_write, | ||
137 | bounce_contended_read, | ||
138 | nr_bounce_types, | ||
139 | |||
140 | bounce_acquired = bounce_acquired_write, | ||
141 | bounce_contended = bounce_contended_write, | ||
142 | }; | ||
143 | |||
133 | struct lock_class_stats { | 144 | struct lock_class_stats { |
134 | unsigned long contention_point[4]; | 145 | unsigned long contention_point[4]; |
135 | struct lock_time read_waittime; | 146 | struct lock_time read_waittime; |
136 | struct lock_time write_waittime; | 147 | struct lock_time write_waittime; |
137 | struct lock_time read_holdtime; | 148 | struct lock_time read_holdtime; |
138 | struct lock_time write_holdtime; | 149 | struct lock_time write_holdtime; |
150 | unsigned long bounces[nr_bounce_types]; | ||
139 | }; | 151 | }; |
140 | 152 | ||
141 | struct lock_class_stats lock_stats(struct lock_class *class); | 153 | struct lock_class_stats lock_stats(struct lock_class *class); |
@@ -150,6 +162,9 @@ struct lockdep_map { | |||
150 | struct lock_class_key *key; | 162 | struct lock_class_key *key; |
151 | struct lock_class *class_cache; | 163 | struct lock_class *class_cache; |
152 | const char *name; | 164 | const char *name; |
165 | #ifdef CONFIG_LOCK_STAT | ||
166 | int cpu; | ||
167 | #endif | ||
153 | }; | 168 | }; |
154 | 169 | ||
155 | /* | 170 | /* |
@@ -321,8 +336,8 @@ do { \ | |||
321 | if (!try(_lock)) { \ | 336 | if (!try(_lock)) { \ |
322 | lock_contended(&(_lock)->dep_map, _RET_IP_); \ | 337 | lock_contended(&(_lock)->dep_map, _RET_IP_); \ |
323 | lock(_lock); \ | 338 | lock(_lock); \ |
324 | lock_acquired(&(_lock)->dep_map); \ | ||
325 | } \ | 339 | } \ |
340 | lock_acquired(&(_lock)->dep_map); \ | ||
326 | } while (0) | 341 | } while (0) |
327 | 342 | ||
328 | #else /* CONFIG_LOCK_STAT */ | 343 | #else /* CONFIG_LOCK_STAT */ |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index cb64022851c8..156fce4960c3 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -177,6 +177,9 @@ struct lock_class_stats lock_stats(struct lock_class *class) | |||
177 | 177 | ||
178 | lock_time_add(&pcs->read_holdtime, &stats.read_holdtime); | 178 | lock_time_add(&pcs->read_holdtime, &stats.read_holdtime); |
179 | lock_time_add(&pcs->write_holdtime, &stats.write_holdtime); | 179 | lock_time_add(&pcs->write_holdtime, &stats.write_holdtime); |
180 | |||
181 | for (i = 0; i < ARRAY_SIZE(stats.bounces); i++) | ||
182 | stats.bounces[i] += pcs->bounces[i]; | ||
180 | } | 183 | } |
181 | 184 | ||
182 | return stats; | 185 | return stats; |
@@ -2325,6 +2328,9 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name, | |||
2325 | lock->name = name; | 2328 | lock->name = name; |
2326 | lock->key = key; | 2329 | lock->key = key; |
2327 | lock->class_cache = NULL; | 2330 | lock->class_cache = NULL; |
2331 | #ifdef CONFIG_LOCK_STAT | ||
2332 | lock->cpu = raw_smp_processor_id(); | ||
2333 | #endif | ||
2328 | if (subclass) | 2334 | if (subclass) |
2329 | register_lock_class(lock, subclass, 1); | 2335 | register_lock_class(lock, subclass, 1); |
2330 | } | 2336 | } |
@@ -2775,6 +2781,8 @@ found_it: | |||
2775 | stats = get_lock_stats(hlock->class); | 2781 | stats = get_lock_stats(hlock->class); |
2776 | if (point < ARRAY_SIZE(stats->contention_point)) | 2782 | if (point < ARRAY_SIZE(stats->contention_point)) |
2777 | stats->contention_point[i]++; | 2783 | stats->contention_point[i]++; |
2784 | if (lock->cpu != smp_processor_id()) | ||
2785 | stats->bounces[bounce_contended + !!hlock->read]++; | ||
2778 | put_lock_stats(stats); | 2786 | put_lock_stats(stats); |
2779 | } | 2787 | } |
2780 | 2788 | ||
@@ -2786,8 +2794,8 @@ __lock_acquired(struct lockdep_map *lock) | |||
2786 | struct lock_class_stats *stats; | 2794 | struct lock_class_stats *stats; |
2787 | unsigned int depth; | 2795 | unsigned int depth; |
2788 | u64 now; | 2796 | u64 now; |
2789 | s64 waittime; | 2797 | s64 waittime = 0; |
2790 | int i; | 2798 | int i, cpu; |
2791 | 2799 | ||
2792 | depth = curr->lockdep_depth; | 2800 | depth = curr->lockdep_depth; |
2793 | if (DEBUG_LOCKS_WARN_ON(!depth)) | 2801 | if (DEBUG_LOCKS_WARN_ON(!depth)) |
@@ -2809,19 +2817,25 @@ __lock_acquired(struct lockdep_map *lock) | |||
2809 | return; | 2817 | return; |
2810 | 2818 | ||
2811 | found_it: | 2819 | found_it: |
2812 | if (!hlock->waittime_stamp) | 2820 | cpu = smp_processor_id(); |
2813 | return; | 2821 | if (hlock->waittime_stamp) { |
2814 | 2822 | now = sched_clock(); | |
2815 | now = sched_clock(); | 2823 | waittime = now - hlock->waittime_stamp; |
2816 | waittime = now - hlock->waittime_stamp; | 2824 | hlock->holdtime_stamp = now; |
2817 | hlock->holdtime_stamp = now; | 2825 | } |
2818 | 2826 | ||
2819 | stats = get_lock_stats(hlock->class); | 2827 | stats = get_lock_stats(hlock->class); |
2820 | if (hlock->read) | 2828 | if (waittime) { |
2821 | lock_time_inc(&stats->read_waittime, waittime); | 2829 | if (hlock->read) |
2822 | else | 2830 | lock_time_inc(&stats->read_waittime, waittime); |
2823 | lock_time_inc(&stats->write_waittime, waittime); | 2831 | else |
2832 | lock_time_inc(&stats->write_waittime, waittime); | ||
2833 | } | ||
2834 | if (lock->cpu != cpu) | ||
2835 | stats->bounces[bounce_acquired + !!hlock->read]++; | ||
2824 | put_lock_stats(stats); | 2836 | put_lock_stats(stats); |
2837 | |||
2838 | lock->cpu = cpu; | ||
2825 | } | 2839 | } |
2826 | 2840 | ||
2827 | void lock_contended(struct lockdep_map *lock, unsigned long ip) | 2841 | void lock_contended(struct lockdep_map *lock, unsigned long ip) |
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 39163ed1bf0a..7ff80135cbeb 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c | |||
@@ -430,16 +430,18 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | |||
430 | else | 430 | else |
431 | seq_printf(m, "%40s:", name); | 431 | seq_printf(m, "%40s:", name); |
432 | 432 | ||
433 | seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]); | ||
433 | seq_lock_time(m, &stats->write_waittime); | 434 | seq_lock_time(m, &stats->write_waittime); |
434 | seq_puts(m, " "); | 435 | seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]); |
435 | seq_lock_time(m, &stats->write_holdtime); | 436 | seq_lock_time(m, &stats->write_holdtime); |
436 | seq_puts(m, "\n"); | 437 | seq_puts(m, "\n"); |
437 | } | 438 | } |
438 | 439 | ||
439 | if (stats->read_holdtime.nr) { | 440 | if (stats->read_holdtime.nr) { |
440 | seq_printf(m, "%38s-R:", name); | 441 | seq_printf(m, "%38s-R:", name); |
442 | seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]); | ||
441 | seq_lock_time(m, &stats->read_waittime); | 443 | seq_lock_time(m, &stats->read_waittime); |
442 | seq_puts(m, " "); | 444 | seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]); |
443 | seq_lock_time(m, &stats->read_holdtime); | 445 | seq_lock_time(m, &stats->read_holdtime); |
444 | seq_puts(m, "\n"); | 446 | seq_puts(m, "\n"); |
445 | } | 447 | } |
@@ -469,26 +471,29 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | |||
469 | } | 471 | } |
470 | if (i) { | 472 | if (i) { |
471 | seq_puts(m, "\n"); | 473 | seq_puts(m, "\n"); |
472 | seq_line(m, '.', 0, 40 + 1 + 8 * (14 + 1)); | 474 | seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1)); |
473 | seq_puts(m, "\n"); | 475 | seq_puts(m, "\n"); |
474 | } | 476 | } |
475 | } | 477 | } |
476 | 478 | ||
477 | static void seq_header(struct seq_file *m) | 479 | static void seq_header(struct seq_file *m) |
478 | { | 480 | { |
479 | seq_printf(m, "lock_stat version 0.1\n"); | 481 | seq_printf(m, "lock_stat version 0.2\n"); |
480 | seq_line(m, '-', 0, 40 + 1 + 8 * (14 + 1)); | 482 | seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); |
481 | seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s\n", | 483 | seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s " |
484 | "%14s %14s\n", | ||
482 | "class name", | 485 | "class name", |
486 | "con-bounces", | ||
483 | "contentions", | 487 | "contentions", |
484 | "waittime-min", | 488 | "waittime-min", |
485 | "waittime-max", | 489 | "waittime-max", |
486 | "waittime-total", | 490 | "waittime-total", |
491 | "acq-bounces", | ||
487 | "acquisitions", | 492 | "acquisitions", |
488 | "holdtime-min", | 493 | "holdtime-min", |
489 | "holdtime-max", | 494 | "holdtime-max", |
490 | "holdtime-total"); | 495 | "holdtime-total"); |
491 | seq_line(m, '-', 0, 40 + 1 + 8 * (14 + 1)); | 496 | seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); |
492 | seq_printf(m, "\n"); | 497 | seq_printf(m, "\n"); |
493 | } | 498 | } |
494 | 499 | ||
diff --git a/kernel/mutex.c b/kernel/mutex.c index 7a3f32761f26..691b86564dd9 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c | |||
@@ -180,8 +180,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass) | |||
180 | spin_lock_mutex(&lock->wait_lock, flags); | 180 | spin_lock_mutex(&lock->wait_lock, flags); |
181 | } | 181 | } |
182 | 182 | ||
183 | lock_acquired(&lock->dep_map); | ||
184 | done: | 183 | done: |
184 | lock_acquired(&lock->dep_map); | ||
185 | /* got the lock - rejoice! */ | 185 | /* got the lock - rejoice! */ |
186 | mutex_remove_waiter(lock, &waiter, task_thread_info(task)); | 186 | mutex_remove_waiter(lock, &waiter, task_thread_info(task)); |
187 | debug_mutex_set_owner(lock, task_thread_info(task)); | 187 | debug_mutex_set_owner(lock, task_thread_info(task)); |