diff options
-rw-r--r-- | Documentation/lockstat.txt | 50 | ||||
-rw-r--r-- | include/linux/lockdep.h | 13 | ||||
-rw-r--r-- | kernel/lockdep.c | 33 | ||||
-rw-r--r-- | kernel/lockdep_proc.c | 21 | ||||
-rw-r--r-- | kernel/mutex.c | 2 |
5 files changed, 82 insertions, 37 deletions
diff --git a/Documentation/lockstat.txt b/Documentation/lockstat.txt index 02f36f5c64fe..9cb9138f7a79 100644 --- a/Documentation/lockstat.txt +++ b/Documentation/lockstat.txt | |||
@@ -71,34 +71,48 @@ Look at the current lock statistics: | |||
71 | 71 | ||
72 | # less /proc/lock_stat | 72 | # less /proc/lock_stat |
73 | 73 | ||
74 | 01 lock_stat version 0.2 | 74 | 01 lock_stat version 0.3 |
75 | 02 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 75 | 02 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
76 | 03 class name con-bounces contentions waittime-min waittime-max waittime-total acq-bounces acquisitions holdtime-min holdtime-max holdtime-total | 76 | 03 class name con-bounces contentions waittime-min waittime-max waittime-total acq-bounces acquisitions holdtime-min holdtime-max holdtime-total |
77 | 04 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 77 | 04 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
78 | 05 | 78 | 05 |
79 | 06 &inode->i_data.tree_lock-W: 15 21657 0.18 1093295.30 11547131054.85 58 10415 0.16 87.51 6387.60 | 79 | 06 &mm->mmap_sem-W: 233 538 18446744073708 22924.27 607243.51 1342 45806 1.71 8595.89 1180582.34 |
80 | 07 &inode->i_data.tree_lock-R: 0 0 0.00 0.00 0.00 23302 231198 0.25 8.45 98023.38 | 80 | 07 &mm->mmap_sem-R: 205 587 18446744073708 28403.36 731975.00 1940 412426 0.58 187825.45 6307502.88 |
81 | 08 -------------------------- | 81 | 08 --------------- |
82 | 09 &inode->i_data.tree_lock 0 [<ffffffff8027c08f>] add_to_page_cache+0x5f/0x190 | 82 | 09 &mm->mmap_sem 487 [<ffffffff8053491f>] do_page_fault+0x466/0x928 |
83 | 10 | 83 | 10 &mm->mmap_sem 179 [<ffffffff802a6200>] sys_mprotect+0xcd/0x21d |
84 | 11 ............................................................................................................................................................................................... | 84 | 11 &mm->mmap_sem 279 [<ffffffff80210a57>] sys_mmap+0x75/0xce |
85 | 12 | 85 | 12 &mm->mmap_sem 76 [<ffffffff802a490b>] sys_munmap+0x32/0x59 |
86 | 13 dcache_lock: 1037 1161 0.38 45.32 774.51 6611 243371 0.15 306.48 77387.24 | 86 | 13 --------------- |
87 | 14 ----------- | 87 | 14 &mm->mmap_sem 270 [<ffffffff80210a57>] sys_mmap+0x75/0xce |
88 | 15 dcache_lock 180 [<ffffffff802c0d7e>] sys_getcwd+0x11e/0x230 | 88 | 15 &mm->mmap_sem 431 [<ffffffff8053491f>] do_page_fault+0x466/0x928 |
89 | 16 dcache_lock 165 [<ffffffff802c002a>] d_alloc+0x15a/0x210 | 89 | 16 &mm->mmap_sem 138 [<ffffffff802a490b>] sys_munmap+0x32/0x59 |
90 | 17 dcache_lock 33 [<ffffffff8035818d>] _atomic_dec_and_lock+0x4d/0x70 | 90 | 17 &mm->mmap_sem 145 [<ffffffff802a6200>] sys_mprotect+0xcd/0x21d |
91 | 18 dcache_lock 1 [<ffffffff802beef8>] shrink_dcache_parent+0x18/0x130 | 91 | 18 |
92 | 19 ............................................................................................................................................................................................... | ||
93 | 20 | ||
94 | 21 dcache_lock: 621 623 0.52 118.26 1053.02 6745 91930 0.29 316.29 118423.41 | ||
95 | 22 ----------- | ||
96 | 23 dcache_lock 179 [<ffffffff80378274>] _atomic_dec_and_lock+0x34/0x54 | ||
97 | 24 dcache_lock 113 [<ffffffff802cc17b>] d_alloc+0x19a/0x1eb | ||
98 | 25 dcache_lock 99 [<ffffffff802ca0dc>] d_rehash+0x1b/0x44 | ||
99 | 26 dcache_lock 104 [<ffffffff802cbca0>] d_instantiate+0x36/0x8a | ||
100 | 27 ----------- | ||
101 | 28 dcache_lock 192 [<ffffffff80378274>] _atomic_dec_and_lock+0x34/0x54 | ||
102 | 29 dcache_lock 98 [<ffffffff802ca0dc>] d_rehash+0x1b/0x44 | ||
103 | 30 dcache_lock 72 [<ffffffff802cc17b>] d_alloc+0x19a/0x1eb | ||
104 | 31 dcache_lock 112 [<ffffffff802cbca0>] d_instantiate+0x36/0x8a | ||
92 | 105 | ||
93 | This excerpt shows the first two lock class statistics. Line 01 shows the | 106 | This excerpt shows the first two lock class statistics. Line 01 shows the |
94 | output version - each time the format changes this will be updated. Line 02-04 | 107 | output version - each time the format changes this will be updated. Line 02-04 |
95 | show the header with column descriptions. Lines 05-10 and 13-18 show the actual | 108 | show the header with column descriptions. Lines 05-18 and 20-31 show the actual |
96 | statistics. These statistics come in two parts; the actual stats separated by a | 109 | statistics. These statistics come in two parts; the actual stats separated by a |
97 | short separator (line 08, 14) from the contention points. | 110 | short separator (line 08, 13) from the contention points. |
98 | 111 | ||
99 | The first lock (05-10) is a read/write lock, and shows two lines above the | 112 | The first lock (05-18) is a read/write lock, and shows two lines above the |
100 | short separator. The contention points don't match the column descriptors, | 113 | short separator. The contention points don't match the column descriptors, |
101 | they have two: contentions and [<IP>] symbol. | 114 | they have two: contentions and [<IP>] symbol. The second set of contention |
115 | points are the points we're contending with. | ||
102 | 116 | ||
103 | The integer part of the time values is in us. | 117 | The integer part of the time values is in us. |
104 | 118 | ||
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 0aa657aa8a1e..fc9f8e88123b 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -73,6 +73,8 @@ struct lock_class_key { | |||
73 | struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; | 73 | struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; |
74 | }; | 74 | }; |
75 | 75 | ||
76 | #define LOCKSTAT_POINTS 4 | ||
77 | |||
76 | /* | 78 | /* |
77 | * The lock-class itself: | 79 | * The lock-class itself: |
78 | */ | 80 | */ |
@@ -119,7 +121,8 @@ struct lock_class { | |||
119 | int name_version; | 121 | int name_version; |
120 | 122 | ||
121 | #ifdef CONFIG_LOCK_STAT | 123 | #ifdef CONFIG_LOCK_STAT |
122 | unsigned long contention_point[4]; | 124 | unsigned long contention_point[LOCKSTAT_POINTS]; |
125 | unsigned long contending_point[LOCKSTAT_POINTS]; | ||
123 | #endif | 126 | #endif |
124 | }; | 127 | }; |
125 | 128 | ||
@@ -144,6 +147,7 @@ enum bounce_type { | |||
144 | 147 | ||
145 | struct lock_class_stats { | 148 | struct lock_class_stats { |
146 | unsigned long contention_point[4]; | 149 | unsigned long contention_point[4]; |
150 | unsigned long contending_point[4]; | ||
147 | struct lock_time read_waittime; | 151 | struct lock_time read_waittime; |
148 | struct lock_time write_waittime; | 152 | struct lock_time write_waittime; |
149 | struct lock_time read_holdtime; | 153 | struct lock_time read_holdtime; |
@@ -165,6 +169,7 @@ struct lockdep_map { | |||
165 | const char *name; | 169 | const char *name; |
166 | #ifdef CONFIG_LOCK_STAT | 170 | #ifdef CONFIG_LOCK_STAT |
167 | int cpu; | 171 | int cpu; |
172 | unsigned long ip; | ||
168 | #endif | 173 | #endif |
169 | }; | 174 | }; |
170 | 175 | ||
@@ -355,7 +360,7 @@ struct lock_class_key { }; | |||
355 | #ifdef CONFIG_LOCK_STAT | 360 | #ifdef CONFIG_LOCK_STAT |
356 | 361 | ||
357 | extern void lock_contended(struct lockdep_map *lock, unsigned long ip); | 362 | extern void lock_contended(struct lockdep_map *lock, unsigned long ip); |
358 | extern void lock_acquired(struct lockdep_map *lock); | 363 | extern void lock_acquired(struct lockdep_map *lock, unsigned long ip); |
359 | 364 | ||
360 | #define LOCK_CONTENDED(_lock, try, lock) \ | 365 | #define LOCK_CONTENDED(_lock, try, lock) \ |
361 | do { \ | 366 | do { \ |
@@ -363,13 +368,13 @@ do { \ | |||
363 | lock_contended(&(_lock)->dep_map, _RET_IP_); \ | 368 | lock_contended(&(_lock)->dep_map, _RET_IP_); \ |
364 | lock(_lock); \ | 369 | lock(_lock); \ |
365 | } \ | 370 | } \ |
366 | lock_acquired(&(_lock)->dep_map); \ | 371 | lock_acquired(&(_lock)->dep_map, _RET_IP_); \ |
367 | } while (0) | 372 | } while (0) |
368 | 373 | ||
369 | #else /* CONFIG_LOCK_STAT */ | 374 | #else /* CONFIG_LOCK_STAT */ |
370 | 375 | ||
371 | #define lock_contended(lockdep_map, ip) do {} while (0) | 376 | #define lock_contended(lockdep_map, ip) do {} while (0) |
372 | #define lock_acquired(lockdep_map) do {} while (0) | 377 | #define lock_acquired(lockdep_map, ip) do {} while (0) |
373 | 378 | ||
374 | #define LOCK_CONTENDED(_lock, try, lock) \ | 379 | #define LOCK_CONTENDED(_lock, try, lock) \ |
375 | lock(_lock) | 380 | lock(_lock) |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index dbda475b13bd..234a9dccb4be 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -136,16 +136,16 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) | |||
136 | #ifdef CONFIG_LOCK_STAT | 136 | #ifdef CONFIG_LOCK_STAT |
137 | static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats); | 137 | static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats); |
138 | 138 | ||
139 | static int lock_contention_point(struct lock_class *class, unsigned long ip) | 139 | static int lock_point(unsigned long points[], unsigned long ip) |
140 | { | 140 | { |
141 | int i; | 141 | int i; |
142 | 142 | ||
143 | for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) { | 143 | for (i = 0; i < LOCKSTAT_POINTS; i++) { |
144 | if (class->contention_point[i] == 0) { | 144 | if (points[i] == 0) { |
145 | class->contention_point[i] = ip; | 145 | points[i] = ip; |
146 | break; | 146 | break; |
147 | } | 147 | } |
148 | if (class->contention_point[i] == ip) | 148 | if (points[i] == ip) |
149 | break; | 149 | break; |
150 | } | 150 | } |
151 | 151 | ||
@@ -185,6 +185,9 @@ struct lock_class_stats lock_stats(struct lock_class *class) | |||
185 | for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++) | 185 | for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++) |
186 | stats.contention_point[i] += pcs->contention_point[i]; | 186 | stats.contention_point[i] += pcs->contention_point[i]; |
187 | 187 | ||
188 | for (i = 0; i < ARRAY_SIZE(stats.contending_point); i++) | ||
189 | stats.contending_point[i] += pcs->contending_point[i]; | ||
190 | |||
188 | lock_time_add(&pcs->read_waittime, &stats.read_waittime); | 191 | lock_time_add(&pcs->read_waittime, &stats.read_waittime); |
189 | lock_time_add(&pcs->write_waittime, &stats.write_waittime); | 192 | lock_time_add(&pcs->write_waittime, &stats.write_waittime); |
190 | 193 | ||
@@ -209,6 +212,7 @@ void clear_lock_stats(struct lock_class *class) | |||
209 | memset(cpu_stats, 0, sizeof(struct lock_class_stats)); | 212 | memset(cpu_stats, 0, sizeof(struct lock_class_stats)); |
210 | } | 213 | } |
211 | memset(class->contention_point, 0, sizeof(class->contention_point)); | 214 | memset(class->contention_point, 0, sizeof(class->contention_point)); |
215 | memset(class->contending_point, 0, sizeof(class->contending_point)); | ||
212 | } | 216 | } |
213 | 217 | ||
214 | static struct lock_class_stats *get_lock_stats(struct lock_class *class) | 218 | static struct lock_class_stats *get_lock_stats(struct lock_class *class) |
@@ -3001,7 +3005,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) | |||
3001 | struct held_lock *hlock, *prev_hlock; | 3005 | struct held_lock *hlock, *prev_hlock; |
3002 | struct lock_class_stats *stats; | 3006 | struct lock_class_stats *stats; |
3003 | unsigned int depth; | 3007 | unsigned int depth; |
3004 | int i, point; | 3008 | int i, contention_point, contending_point; |
3005 | 3009 | ||
3006 | depth = curr->lockdep_depth; | 3010 | depth = curr->lockdep_depth; |
3007 | if (DEBUG_LOCKS_WARN_ON(!depth)) | 3011 | if (DEBUG_LOCKS_WARN_ON(!depth)) |
@@ -3025,18 +3029,22 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) | |||
3025 | found_it: | 3029 | found_it: |
3026 | hlock->waittime_stamp = sched_clock(); | 3030 | hlock->waittime_stamp = sched_clock(); |
3027 | 3031 | ||
3028 | point = lock_contention_point(hlock_class(hlock), ip); | 3032 | contention_point = lock_point(hlock_class(hlock)->contention_point, ip); |
3033 | contending_point = lock_point(hlock_class(hlock)->contending_point, | ||
3034 | lock->ip); | ||
3029 | 3035 | ||
3030 | stats = get_lock_stats(hlock_class(hlock)); | 3036 | stats = get_lock_stats(hlock_class(hlock)); |
3031 | if (point < ARRAY_SIZE(stats->contention_point)) | 3037 | if (contention_point < LOCKSTAT_POINTS) |
3032 | stats->contention_point[point]++; | 3038 | stats->contention_point[contention_point]++; |
3039 | if (contending_point < LOCKSTAT_POINTS) | ||
3040 | stats->contending_point[contending_point]++; | ||
3033 | if (lock->cpu != smp_processor_id()) | 3041 | if (lock->cpu != smp_processor_id()) |
3034 | stats->bounces[bounce_contended + !!hlock->read]++; | 3042 | stats->bounces[bounce_contended + !!hlock->read]++; |
3035 | put_lock_stats(stats); | 3043 | put_lock_stats(stats); |
3036 | } | 3044 | } |
3037 | 3045 | ||
3038 | static void | 3046 | static void |
3039 | __lock_acquired(struct lockdep_map *lock) | 3047 | __lock_acquired(struct lockdep_map *lock, unsigned long ip) |
3040 | { | 3048 | { |
3041 | struct task_struct *curr = current; | 3049 | struct task_struct *curr = current; |
3042 | struct held_lock *hlock, *prev_hlock; | 3050 | struct held_lock *hlock, *prev_hlock; |
@@ -3085,6 +3093,7 @@ found_it: | |||
3085 | put_lock_stats(stats); | 3093 | put_lock_stats(stats); |
3086 | 3094 | ||
3087 | lock->cpu = cpu; | 3095 | lock->cpu = cpu; |
3096 | lock->ip = ip; | ||
3088 | } | 3097 | } |
3089 | 3098 | ||
3090 | void lock_contended(struct lockdep_map *lock, unsigned long ip) | 3099 | void lock_contended(struct lockdep_map *lock, unsigned long ip) |
@@ -3106,7 +3115,7 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip) | |||
3106 | } | 3115 | } |
3107 | EXPORT_SYMBOL_GPL(lock_contended); | 3116 | EXPORT_SYMBOL_GPL(lock_contended); |
3108 | 3117 | ||
3109 | void lock_acquired(struct lockdep_map *lock) | 3118 | void lock_acquired(struct lockdep_map *lock, unsigned long ip) |
3110 | { | 3119 | { |
3111 | unsigned long flags; | 3120 | unsigned long flags; |
3112 | 3121 | ||
@@ -3119,7 +3128,7 @@ void lock_acquired(struct lockdep_map *lock) | |||
3119 | raw_local_irq_save(flags); | 3128 | raw_local_irq_save(flags); |
3120 | check_flags(flags); | 3129 | check_flags(flags); |
3121 | current->lockdep_recursion = 1; | 3130 | current->lockdep_recursion = 1; |
3122 | __lock_acquired(lock); | 3131 | __lock_acquired(lock, ip); |
3123 | current->lockdep_recursion = 0; | 3132 | current->lockdep_recursion = 0; |
3124 | raw_local_irq_restore(flags); | 3133 | raw_local_irq_restore(flags); |
3125 | } | 3134 | } |
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c index 8d3a6eba8d5a..13716b813896 100644 --- a/kernel/lockdep_proc.c +++ b/kernel/lockdep_proc.c | |||
@@ -557,7 +557,7 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | |||
557 | if (stats->read_holdtime.nr) | 557 | if (stats->read_holdtime.nr) |
558 | namelen += 2; | 558 | namelen += 2; |
559 | 559 | ||
560 | for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) { | 560 | for (i = 0; i < LOCKSTAT_POINTS; i++) { |
561 | char sym[KSYM_SYMBOL_LEN]; | 561 | char sym[KSYM_SYMBOL_LEN]; |
562 | char ip[32]; | 562 | char ip[32]; |
563 | 563 | ||
@@ -574,6 +574,23 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | |||
574 | stats->contention_point[i], | 574 | stats->contention_point[i], |
575 | ip, sym); | 575 | ip, sym); |
576 | } | 576 | } |
577 | for (i = 0; i < LOCKSTAT_POINTS; i++) { | ||
578 | char sym[KSYM_SYMBOL_LEN]; | ||
579 | char ip[32]; | ||
580 | |||
581 | if (class->contending_point[i] == 0) | ||
582 | break; | ||
583 | |||
584 | if (!i) | ||
585 | seq_line(m, '-', 40-namelen, namelen); | ||
586 | |||
587 | sprint_symbol(sym, class->contending_point[i]); | ||
588 | snprintf(ip, sizeof(ip), "[<%p>]", | ||
589 | (void *)class->contending_point[i]); | ||
590 | seq_printf(m, "%40s %14lu %29s %s\n", name, | ||
591 | stats->contending_point[i], | ||
592 | ip, sym); | ||
593 | } | ||
577 | if (i) { | 594 | if (i) { |
578 | seq_puts(m, "\n"); | 595 | seq_puts(m, "\n"); |
579 | seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1)); | 596 | seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1)); |
@@ -583,7 +600,7 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data) | |||
583 | 600 | ||
584 | static void seq_header(struct seq_file *m) | 601 | static void seq_header(struct seq_file *m) |
585 | { | 602 | { |
586 | seq_printf(m, "lock_stat version 0.2\n"); | 603 | seq_printf(m, "lock_stat version 0.3\n"); |
587 | seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); | 604 | seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1)); |
588 | seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s " | 605 | seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s " |
589 | "%14s %14s\n", | 606 | "%14s %14s\n", |
diff --git a/kernel/mutex.c b/kernel/mutex.c index 12c779dc65d4..39a3816b68d9 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c | |||
@@ -184,7 +184,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, | |||
184 | } | 184 | } |
185 | 185 | ||
186 | done: | 186 | done: |
187 | lock_acquired(&lock->dep_map); | 187 | lock_acquired(&lock->dep_map, ip); |
188 | /* got the lock - rejoice! */ | 188 | /* got the lock - rejoice! */ |
189 | mutex_remove_waiter(lock, &waiter, task_thread_info(task)); | 189 | mutex_remove_waiter(lock, &waiter, task_thread_info(task)); |
190 | debug_mutex_set_owner(lock, task_thread_info(task)); | 190 | debug_mutex_set_owner(lock, task_thread_info(task)); |