diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-05-29 16:03:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-30 05:34:00 -0400 |
commit | c44613a4c1092e85841b78b7ab52a06654fcd321 (patch) | |
tree | 364605b0662b25f6a3abe3238489bdb5dfe001f5 | |
parent | b78c07d45a7e71be7b5c5d7486f922355ccf23a8 (diff) |
perf_counter tools: Add locking to perf top
perf_counter tools: Add locking to perf top
We need to protect the active_symbols list as two threads change it:
the main thread adding entries to the head and the display thread
decaying entries from any place in the list.
Also related: take a snapshot of syme->count[0] before using it to
calculate the weight and to show the same number used in this calc when
displaying the symbol usage.
Reported-by: Mike Galbraith <efault@gmx.de>
Tested-by: Mike Galbraith <efault@gmx.de>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20090529200307.GR4747@ghostprotocols.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | Documentation/perf_counter/builtin-top.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c index ebe8bec1a0e8..24a887907a7a 100644 --- a/Documentation/perf_counter/builtin-top.c +++ b/Documentation/perf_counter/builtin-top.c | |||
@@ -129,6 +129,8 @@ struct sym_entry { | |||
129 | struct rb_node rb_node; | 129 | struct rb_node rb_node; |
130 | struct list_head node; | 130 | struct list_head node; |
131 | unsigned long count[MAX_COUNTERS]; | 131 | unsigned long count[MAX_COUNTERS]; |
132 | unsigned long snap_count; | ||
133 | double weight; | ||
132 | int skip; | 134 | int skip; |
133 | }; | 135 | }; |
134 | 136 | ||
@@ -141,17 +143,16 @@ struct dso *kernel_dso; | |||
141 | * after decayed. | 143 | * after decayed. |
142 | */ | 144 | */ |
143 | static LIST_HEAD(active_symbols); | 145 | static LIST_HEAD(active_symbols); |
146 | static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; | ||
144 | 147 | ||
145 | /* | 148 | /* |
146 | * Ordering weight: count-1 * count-2 * ... / count-n | 149 | * Ordering weight: count-1 * count-2 * ... / count-n |
147 | */ | 150 | */ |
148 | static double sym_weight(const struct sym_entry *sym) | 151 | static double sym_weight(const struct sym_entry *sym) |
149 | { | 152 | { |
150 | double weight; | 153 | double weight = sym->snap_count; |
151 | int counter; | 154 | int counter; |
152 | 155 | ||
153 | weight = sym->count[0]; | ||
154 | |||
155 | for (counter = 1; counter < nr_counters-1; counter++) | 156 | for (counter = 1; counter < nr_counters-1; counter++) |
156 | weight *= sym->count[counter]; | 157 | weight *= sym->count[counter]; |
157 | 158 | ||
@@ -164,11 +165,18 @@ static long events; | |||
164 | static long userspace_events; | 165 | static long userspace_events; |
165 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 166 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
166 | 167 | ||
167 | static void list_insert_active_sym(struct sym_entry *syme) | 168 | static void __list_insert_active_sym(struct sym_entry *syme) |
168 | { | 169 | { |
169 | list_add(&syme->node, &active_symbols); | 170 | list_add(&syme->node, &active_symbols); |
170 | } | 171 | } |
171 | 172 | ||
173 | static void list_remove_active_sym(struct sym_entry *syme) | ||
174 | { | ||
175 | pthread_mutex_lock(&active_symbols_lock); | ||
176 | list_del_init(&syme->node); | ||
177 | pthread_mutex_unlock(&active_symbols_lock); | ||
178 | } | ||
179 | |||
172 | static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | 180 | static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) |
173 | { | 181 | { |
174 | struct rb_node **p = &tree->rb_node; | 182 | struct rb_node **p = &tree->rb_node; |
@@ -179,7 +187,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | |||
179 | parent = *p; | 187 | parent = *p; |
180 | iter = rb_entry(parent, struct sym_entry, rb_node); | 188 | iter = rb_entry(parent, struct sym_entry, rb_node); |
181 | 189 | ||
182 | if (sym_weight(se) > sym_weight(iter)) | 190 | if (se->weight > iter->weight) |
183 | p = &(*p)->rb_left; | 191 | p = &(*p)->rb_left; |
184 | else | 192 | else |
185 | p = &(*p)->rb_right; | 193 | p = &(*p)->rb_right; |
@@ -203,15 +211,21 @@ static void print_sym_table(void) | |||
203 | events = userspace_events = 0; | 211 | events = userspace_events = 0; |
204 | 212 | ||
205 | /* Sort the active symbols */ | 213 | /* Sort the active symbols */ |
206 | list_for_each_entry_safe(syme, n, &active_symbols, node) { | 214 | pthread_mutex_lock(&active_symbols_lock); |
207 | if (syme->count[0] != 0) { | 215 | syme = list_entry(active_symbols.next, struct sym_entry, node); |
216 | pthread_mutex_unlock(&active_symbols_lock); | ||
217 | |||
218 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | ||
219 | syme->snap_count = syme->count[0]; | ||
220 | if (syme->snap_count != 0) { | ||
221 | syme->weight = sym_weight(syme); | ||
208 | rb_insert_active_sym(&tmp, syme); | 222 | rb_insert_active_sym(&tmp, syme); |
209 | sum_kevents += syme->count[0]; | 223 | sum_kevents += syme->snap_count; |
210 | 224 | ||
211 | for (j = 0; j < nr_counters; j++) | 225 | for (j = 0; j < nr_counters; j++) |
212 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; | 226 | syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; |
213 | } else | 227 | } else |
214 | list_del_init(&syme->node); | 228 | list_remove_active_sym(syme); |
215 | } | 229 | } |
216 | 230 | ||
217 | write(1, CONSOLE_CLEAR, strlen(CONSOLE_CLEAR)); | 231 | write(1, CONSOLE_CLEAR, strlen(CONSOLE_CLEAR)); |
@@ -264,19 +278,18 @@ static void print_sym_table(void) | |||
264 | struct symbol *sym = (struct symbol *)(syme + 1); | 278 | struct symbol *sym = (struct symbol *)(syme + 1); |
265 | float pcnt; | 279 | float pcnt; |
266 | 280 | ||
267 | if (++printed > 18 || syme->count[0] < count_filter) | 281 | if (++printed > 18 || syme->snap_count < count_filter) |
268 | break; | 282 | continue; |
269 | 283 | ||
270 | pcnt = 100.0 - (100.0 * ((sum_kevents - syme->count[0]) / | 284 | pcnt = 100.0 - (100.0 * ((sum_kevents - syme->snap_count) / |
271 | sum_kevents)); | 285 | sum_kevents)); |
272 | 286 | ||
273 | if (nr_counters == 1) | 287 | if (nr_counters == 1) |
274 | printf("%19.2f - %4.1f%% - %016llx : %s\n", | 288 | printf("%19.2f - %4.1f%% - %016llx : %s\n", |
275 | sym_weight(syme), | 289 | syme->weight, pcnt, sym->start, sym->name); |
276 | pcnt, sym->start, sym->name); | ||
277 | else | 290 | else |
278 | printf("%8.1f %10ld - %4.1f%% - %016llx : %s\n", | 291 | printf("%8.1f %10ld - %4.1f%% - %016llx : %s\n", |
279 | sym_weight(syme), syme->count[0], | 292 | syme->weight, syme->snap_count, |
280 | pcnt, sym->start, sym->name); | 293 | pcnt, sym->start, sym->name); |
281 | } | 294 | } |
282 | 295 | ||
@@ -395,8 +408,10 @@ static void record_ip(uint64_t ip, int counter) | |||
395 | 408 | ||
396 | if (!syme->skip) { | 409 | if (!syme->skip) { |
397 | syme->count[counter]++; | 410 | syme->count[counter]++; |
411 | pthread_mutex_lock(&active_symbols_lock); | ||
398 | if (list_empty(&syme->node) || !syme->node.next) | 412 | if (list_empty(&syme->node) || !syme->node.next) |
399 | list_insert_active_sym(syme); | 413 | __list_insert_active_sym(syme); |
414 | pthread_mutex_unlock(&active_symbols_lock); | ||
400 | return; | 415 | return; |
401 | } | 416 | } |
402 | } | 417 | } |