perf lock contention: Prepare to handle cgroups
[linux-2.6-block.git] / tools / perf / builtin-lock.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
a43783ae 2#include <errno.h>
fd20e811 3#include <inttypes.h>
9b5e350c
HM
4#include "builtin.h"
5#include "perf.h"
6
7ae811b1 7#include "util/evlist.h" // for struct evsel_str_handler
fcf65bf1 8#include "util/evsel.h"
9b5e350c
HM
9#include "util/symbol.h"
10#include "util/thread.h"
11#include "util/header.h"
6fda2405 12#include "util/target.h"
0d2997f7 13#include "util/callchain.h"
407b36f6 14#include "util/lock-contention.h"
eca949b2 15#include "util/bpf_skel/lock_data.h"
9b5e350c 16
fa0d9846 17#include <subcmd/pager.h>
4b6ab94e 18#include <subcmd/parse-options.h>
9b5e350c 19#include "util/trace-event.h"
9b7c7728 20#include "util/tracepoint.h"
9b5e350c
HM
21
22#include "util/debug.h"
23#include "util/session.h"
45694aa7 24#include "util/tool.h"
f5fc1412 25#include "util/data.h"
ae0f4eb3 26#include "util/string2.h"
0d2997f7 27#include "util/map.h"
0a277b62 28#include "util/util.h"
9b5e350c 29
f6027053 30#include <stdio.h>
9b5e350c
HM
31#include <sys/types.h>
32#include <sys/prctl.h>
33#include <semaphore.h>
9b5e350c
HM
34#include <math.h>
35#include <limits.h>
511e19b9 36#include <ctype.h>
9b5e350c
HM
37
38#include <linux/list.h>
39#include <linux/hash.h>
877a7a11 40#include <linux/kernel.h>
7f7c536f 41#include <linux/zalloc.h>
6ef81c55 42#include <linux/err.h>
0d2997f7 43#include <linux/stringify.h>
9b5e350c 44
e4cef1f6 45static struct perf_session *session;
6fda2405 46static struct target target;
e4cef1f6 47
9b5e350c
HM
48/* based on kernel/lockdep.c */
49#define LOCKHASH_BITS 12
50#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
51
eef4fee5 52static struct hlist_head *lockhash_table;
9b5e350c
HM
53
54#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
55#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
56
e4cef1f6
HM
57static struct rb_root thread_stats;
58
0d435bf8 59static bool combine_locks;
7c3bcbdf 60static bool show_thread_stats;
688d2e8d 61static bool show_lock_addrs;
3477f079 62static bool show_lock_owner;
407b36f6 63static bool use_bpf;
2d8d0165 64static unsigned long bpf_map_entries = MAX_ENTRIES;
96532a83
NK
65static int max_stack_depth = CONTENTION_STACK_DEPTH;
66static int stack_skip = CONTENTION_STACK_SKIP;
6282a1f4 67static int print_nr_entries = INT_MAX / 2;
7b204399 68static LIST_HEAD(callstack_filters);
f6027053
NK
69static const char *output_name = NULL;
70static FILE *lock_output;
7b204399
NK
71
72struct callstack_filter {
73 struct list_head list;
74 char name[];
75};
0d435bf8 76
b4a7eff9
NK
77static struct lock_filter filters;
78
eca949b2 79static enum lock_aggr_mode aggr_mode = LOCK_AGGR_ADDR;
f9c695a2 80
7b204399
NK
81static bool needs_callstack(void)
82{
0fba2265 83 return !list_empty(&callstack_filters);
7b204399
NK
84}
85
e4cef1f6
HM
86static struct thread_stat *thread_stat_find(u32 tid)
87{
88 struct rb_node *node;
89 struct thread_stat *st;
90
91 node = thread_stats.rb_node;
92 while (node) {
93 st = container_of(node, struct thread_stat, rb);
94 if (st->tid == tid)
95 return st;
96 else if (tid < st->tid)
97 node = node->rb_left;
98 else
99 node = node->rb_right;
100 }
101
102 return NULL;
103}
104
105static void thread_stat_insert(struct thread_stat *new)
106{
107 struct rb_node **rb = &thread_stats.rb_node;
108 struct rb_node *parent = NULL;
109 struct thread_stat *p;
110
111 while (*rb) {
112 p = container_of(*rb, struct thread_stat, rb);
113 parent = *rb;
114
115 if (new->tid < p->tid)
116 rb = &(*rb)->rb_left;
117 else if (new->tid > p->tid)
118 rb = &(*rb)->rb_right;
119 else
120 BUG_ON("inserting invalid thread_stat\n");
121 }
122
123 rb_link_node(&new->rb, parent, rb);
124 rb_insert_color(&new->rb, &thread_stats);
125}
126
127static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
128{
129 struct thread_stat *st;
130
131 st = thread_stat_find(tid);
132 if (st)
133 return st;
134
135 st = zalloc(sizeof(struct thread_stat));
33d6aef5
DA
136 if (!st) {
137 pr_err("memory allocation failed\n");
138 return NULL;
139 }
e4cef1f6
HM
140
141 st->tid = tid;
142 INIT_LIST_HEAD(&st->seq_list);
143
144 thread_stat_insert(st);
145
146 return st;
147}
148
149static struct thread_stat *thread_stat_findnew_first(u32 tid);
150static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
151 thread_stat_findnew_first;
152
153static struct thread_stat *thread_stat_findnew_first(u32 tid)
154{
155 struct thread_stat *st;
156
157 st = zalloc(sizeof(struct thread_stat));
33d6aef5
DA
158 if (!st) {
159 pr_err("memory allocation failed\n");
160 return NULL;
161 }
e4cef1f6
HM
162 st->tid = tid;
163 INIT_LIST_HEAD(&st->seq_list);
164
165 rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
166 rb_insert_color(&st->rb, &thread_stats);
167
168 thread_stat_findnew = thread_stat_findnew_after_first;
169 return st;
170}
171
9b5e350c 172/* build simple key function one is bigger than two */
59f411b6 173#define SINGLE_KEY(member) \
9b5e350c
HM
174 static int lock_stat_key_ ## member(struct lock_stat *one, \
175 struct lock_stat *two) \
176 { \
177 return one->member > two->member; \
178 }
179
180SINGLE_KEY(nr_acquired)
181SINGLE_KEY(nr_contended)
f37376cd 182SINGLE_KEY(avg_wait_time)
9b5e350c 183SINGLE_KEY(wait_time_total)
9b5e350c
HM
184SINGLE_KEY(wait_time_max)
185
9df03abe
MS
186static int lock_stat_key_wait_time_min(struct lock_stat *one,
187 struct lock_stat *two)
188{
189 u64 s1 = one->wait_time_min;
190 u64 s2 = two->wait_time_min;
191 if (s1 == ULLONG_MAX)
192 s1 = 0;
193 if (s2 == ULLONG_MAX)
194 s2 = 0;
195 return s1 > s2;
196}
197
9b5e350c
HM
198struct lock_key {
199 /*
200 * name: the value for specify by user
201 * this should be simpler than raw name of member
202 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
203 */
59f411b6 204 const char *name;
64999e44
NK
205 /* header: the string printed on the header line */
206 const char *header;
207 /* len: the printing width of the field */
208 int len;
209 /* key: a pointer to function to compare two lock stats for sorting */
59f411b6 210 int (*key)(struct lock_stat*, struct lock_stat*);
64999e44
NK
211 /* print: a pointer to function to print a given lock stats */
212 void (*print)(struct lock_key*, struct lock_stat*);
213 /* list: list entry to link this */
214 struct list_head list;
9b5e350c
HM
215};
216
ab010176
NK
217static void lock_stat_key_print_time(unsigned long long nsec, int len)
218{
219 static const struct {
220 float base;
221 const char *unit;
222 } table[] = {
223 { 1e9 * 3600, "h " },
224 { 1e9 * 60, "m " },
225 { 1e9, "s " },
226 { 1e6, "ms" },
227 { 1e3, "us" },
228 { 0, NULL },
229 };
230
69c5c993
NK
231 /* for CSV output */
232 if (len == 0) {
f6027053 233 fprintf(lock_output, "%llu", nsec);
69c5c993
NK
234 return;
235 }
236
ab010176
NK
237 for (int i = 0; table[i].unit; i++) {
238 if (nsec < table[i].base)
239 continue;
240
f6027053 241 fprintf(lock_output, "%*.2f %s", len - 3, nsec / table[i].base, table[i].unit);
ab010176
NK
242 return;
243 }
244
f6027053 245 fprintf(lock_output, "%*llu %s", len - 3, nsec, "ns");
ab010176
NK
246}
247
64999e44
NK
248#define PRINT_KEY(member) \
249static void lock_stat_key_print_ ## member(struct lock_key *key, \
250 struct lock_stat *ls) \
251{ \
f6027053 252 fprintf(lock_output, "%*llu", key->len, (unsigned long long)ls->member);\
64999e44
NK
253}
254
ab010176
NK
255#define PRINT_TIME(member) \
256static void lock_stat_key_print_ ## member(struct lock_key *key, \
257 struct lock_stat *ls) \
258{ \
259 lock_stat_key_print_time((unsigned long long)ls->member, key->len); \
260}
261
64999e44
NK
262PRINT_KEY(nr_acquired)
263PRINT_KEY(nr_contended)
ab010176
NK
264PRINT_TIME(avg_wait_time)
265PRINT_TIME(wait_time_total)
266PRINT_TIME(wait_time_max)
64999e44
NK
267
268static void lock_stat_key_print_wait_time_min(struct lock_key *key,
269 struct lock_stat *ls)
270{
271 u64 wait_time = ls->wait_time_min;
272
273 if (wait_time == ULLONG_MAX)
274 wait_time = 0;
275
ab010176 276 lock_stat_key_print_time(wait_time, key->len);
64999e44
NK
277}
278
279
59f411b6
IM
280static const char *sort_key = "acquired";
281
282static int (*compare)(struct lock_stat *, struct lock_stat *);
283
0d435bf8 284static struct rb_root sorted; /* place to store intermediate data */
59f411b6 285static struct rb_root result; /* place to store sorted data */
9b5e350c 286
64999e44 287static LIST_HEAD(lock_keys);
4bd9cab5 288static const char *output_fields;
64999e44
NK
289
290#define DEF_KEY_LOCK(name, header, fn_suffix, len) \
291 { #name, header, len, lock_stat_key_ ## fn_suffix, lock_stat_key_print_ ## fn_suffix, {} }
79079f21 292static struct lock_key report_keys[] = {
64999e44
NK
293 DEF_KEY_LOCK(acquired, "acquired", nr_acquired, 10),
294 DEF_KEY_LOCK(contended, "contended", nr_contended, 10),
ab010176
NK
295 DEF_KEY_LOCK(avg_wait, "avg wait", avg_wait_time, 12),
296 DEF_KEY_LOCK(wait_total, "total wait", wait_time_total, 12),
297 DEF_KEY_LOCK(wait_max, "max wait", wait_time_max, 12),
298 DEF_KEY_LOCK(wait_min, "min wait", wait_time_min, 12),
9b5e350c
HM
299
300 /* extra comparisons much complicated should be here */
64999e44 301 { }
9b5e350c
HM
302};
303
79079f21
NK
304static struct lock_key contention_keys[] = {
305 DEF_KEY_LOCK(contended, "contended", nr_contended, 10),
306 DEF_KEY_LOCK(wait_total, "total wait", wait_time_total, 12),
307 DEF_KEY_LOCK(wait_max, "max wait", wait_time_max, 12),
308 DEF_KEY_LOCK(wait_min, "min wait", wait_time_min, 12),
309 DEF_KEY_LOCK(avg_wait, "avg wait", avg_wait_time, 12),
310
311 /* extra comparisons much complicated should be here */
312 { }
313};
314
315static int select_key(bool contention)
9b5e350c
HM
316{
317 int i;
79079f21
NK
318 struct lock_key *keys = report_keys;
319
320 if (contention)
321 keys = contention_keys;
9b5e350c
HM
322
323 for (i = 0; keys[i].name; i++) {
324 if (!strcmp(keys[i].name, sort_key)) {
325 compare = keys[i].key;
4bd9cab5
NK
326
327 /* selected key should be in the output fields */
328 if (list_empty(&keys[i].list))
329 list_add_tail(&keys[i].list, &lock_keys);
330
33d6aef5 331 return 0;
9b5e350c
HM
332 }
333 }
334
33d6aef5 335 pr_err("Unknown compare key: %s\n", sort_key);
33d6aef5 336 return -1;
9b5e350c
HM
337}
338
79079f21 339static int add_output_field(bool contention, char *name)
64999e44
NK
340{
341 int i;
79079f21
NK
342 struct lock_key *keys = report_keys;
343
344 if (contention)
345 keys = contention_keys;
64999e44 346
4bd9cab5
NK
347 for (i = 0; keys[i].name; i++) {
348 if (strcmp(keys[i].name, name))
349 continue;
350
351 /* prevent double link */
352 if (list_empty(&keys[i].list))
79079f21 353 list_add_tail(&keys[i].list, &lock_keys);
4bd9cab5
NK
354
355 return 0;
356 }
357
358 pr_err("Unknown output field: %s\n", name);
359 return -1;
360}
361
79079f21 362static int setup_output_field(bool contention, const char *str)
4bd9cab5
NK
363{
364 char *tok, *tmp, *orig;
365 int i, ret = 0;
79079f21
NK
366 struct lock_key *keys = report_keys;
367
368 if (contention)
369 keys = contention_keys;
4bd9cab5
NK
370
371 /* no output field given: use all of them */
372 if (str == NULL) {
373 for (i = 0; keys[i].name; i++)
374 list_add_tail(&keys[i].list, &lock_keys);
375 return 0;
376 }
377
64999e44 378 for (i = 0; keys[i].name; i++)
4bd9cab5 379 INIT_LIST_HEAD(&keys[i].list);
64999e44 380
4bd9cab5
NK
381 orig = tmp = strdup(str);
382 if (orig == NULL)
383 return -ENOMEM;
384
385 while ((tok = strsep(&tmp, ",")) != NULL){
79079f21 386 ret = add_output_field(contention, tok);
4bd9cab5
NK
387 if (ret < 0)
388 break;
389 }
390 free(orig);
391
392 return ret;
64999e44
NK
393}
394
0d435bf8
NK
395static void combine_lock_stats(struct lock_stat *st)
396{
397 struct rb_node **rb = &sorted.rb_node;
398 struct rb_node *parent = NULL;
399 struct lock_stat *p;
400 int ret;
401
402 while (*rb) {
403 p = container_of(*rb, struct lock_stat, rb);
404 parent = *rb;
405
406 if (st->name && p->name)
407 ret = strcmp(st->name, p->name);
408 else
409 ret = !!st->name - !!p->name;
410
411 if (ret == 0) {
412 p->nr_acquired += st->nr_acquired;
413 p->nr_contended += st->nr_contended;
414 p->wait_time_total += st->wait_time_total;
415
416 if (p->nr_contended)
417 p->avg_wait_time = p->wait_time_total / p->nr_contended;
418
419 if (p->wait_time_min > st->wait_time_min)
420 p->wait_time_min = st->wait_time_min;
421 if (p->wait_time_max < st->wait_time_max)
422 p->wait_time_max = st->wait_time_max;
423
79d9333b 424 p->broken |= st->broken;
0d435bf8
NK
425 st->combined = 1;
426 return;
427 }
428
429 if (ret < 0)
430 rb = &(*rb)->rb_left;
431 else
432 rb = &(*rb)->rb_right;
433 }
434
435 rb_link_node(&st->rb, parent, rb);
436 rb_insert_color(&st->rb, &sorted);
437}
438
9b5e350c 439static void insert_to_result(struct lock_stat *st,
59f411b6 440 int (*bigger)(struct lock_stat *, struct lock_stat *))
9b5e350c
HM
441{
442 struct rb_node **rb = &result.rb_node;
443 struct rb_node *parent = NULL;
444 struct lock_stat *p;
445
0d435bf8
NK
446 if (combine_locks && st->combined)
447 return;
448
9b5e350c
HM
449 while (*rb) {
450 p = container_of(*rb, struct lock_stat, rb);
451 parent = *rb;
452
453 if (bigger(st, p))
454 rb = &(*rb)->rb_left;
455 else
456 rb = &(*rb)->rb_right;
457 }
458
459 rb_link_node(&st->rb, parent, rb);
460 rb_insert_color(&st->rb, &result);
461}
462
463/* returns left most element of result, and erase it */
464static struct lock_stat *pop_from_result(void)
465{
466 struct rb_node *node = result.rb_node;
467
468 if (!node)
469 return NULL;
470
471 while (node->rb_left)
472 node = node->rb_left;
473
474 rb_erase(node, &result);
475 return container_of(node, struct lock_stat, rb);
476}
477
16cad1d3 478struct lock_stat *lock_stat_find(u64 addr)
3ae03f26
NK
479{
480 struct hlist_head *entry = lockhashentry(addr);
481 struct lock_stat *ret;
482
483 hlist_for_each_entry(ret, entry, hash_entry) {
484 if (ret->addr == addr)
485 return ret;
486 }
487 return NULL;
488}
489
16cad1d3 490struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
9b5e350c 491{
7672d00a 492 struct hlist_head *entry = lockhashentry(addr);
9b5e350c
HM
493 struct lock_stat *ret, *new;
494
7672d00a 495 hlist_for_each_entry(ret, entry, hash_entry) {
9b5e350c
HM
496 if (ret->addr == addr)
497 return ret;
498 }
499
500 new = zalloc(sizeof(struct lock_stat));
501 if (!new)
502 goto alloc_failed;
503
504 new->addr = addr;
fb87158b 505 new->name = strdup(name);
0a98c7fe
DB
506 if (!new->name) {
507 free(new);
9b5e350c 508 goto alloc_failed;
0a98c7fe 509 }
9b5e350c 510
fb87158b 511 new->flags = flags;
9b5e350c
HM
512 new->wait_time_min = ULLONG_MAX;
513
7672d00a 514 hlist_add_head(&new->hash_entry, entry);
9b5e350c
HM
515 return new;
516
517alloc_failed:
33d6aef5
DA
518 pr_err("memory allocation failed\n");
519 return NULL;
9b5e350c
HM
520}
521
ebab2916
NK
522bool match_callstack_filter(struct machine *machine, u64 *callstack)
523{
524 struct map *kmap;
525 struct symbol *sym;
526 u64 ip;
527
528 if (list_empty(&callstack_filters))
529 return true;
530
531 for (int i = 0; i < max_stack_depth; i++) {
532 struct callstack_filter *filter;
533
534 if (!callstack || !callstack[i])
535 break;
536
537 ip = callstack[i];
538 sym = machine__find_kernel_symbol(machine, ip, &kmap);
539 if (sym == NULL)
540 continue;
541
542 list_for_each_entry(filter, &callstack_filters, list) {
543 if (strstr(sym->name, filter->name))
544 return true;
545 }
546 }
547 return false;
548}
549
9b5e350c 550struct trace_lock_handler {
166a9764 551 /* it's used on CONFIG_LOCKDEP */
32dcd021 552 int (*acquire_event)(struct evsel *evsel,
746f16ec 553 struct perf_sample *sample);
9b5e350c 554
166a9764 555 /* it's used on CONFIG_LOCKDEP && CONFIG_LOCK_STAT */
32dcd021 556 int (*acquired_event)(struct evsel *evsel,
746f16ec 557 struct perf_sample *sample);
9b5e350c 558
166a9764 559 /* it's used on CONFIG_LOCKDEP && CONFIG_LOCK_STAT */
32dcd021 560 int (*contended_event)(struct evsel *evsel,
746f16ec 561 struct perf_sample *sample);
9b5e350c 562
166a9764 563 /* it's used on CONFIG_LOCKDEP */
32dcd021 564 int (*release_event)(struct evsel *evsel,
746f16ec 565 struct perf_sample *sample);
166a9764
NK
566
567 /* it's used when CONFIG_LOCKDEP is off */
568 int (*contention_begin_event)(struct evsel *evsel,
569 struct perf_sample *sample);
570
571 /* it's used when CONFIG_LOCKDEP is off */
572 int (*contention_end_event)(struct evsel *evsel,
573 struct perf_sample *sample);
9b5e350c
HM
574};
575
e1c3177b 576static struct lock_seq_stat *get_seq(struct thread_stat *ts, u64 addr)
e4cef1f6
HM
577{
578 struct lock_seq_stat *seq;
579
580 list_for_each_entry(seq, &ts->seq_list, list) {
581 if (seq->addr == addr)
582 return seq;
583 }
584
585 seq = zalloc(sizeof(struct lock_seq_stat));
33d6aef5
DA
586 if (!seq) {
587 pr_err("memory allocation failed\n");
588 return NULL;
589 }
e4cef1f6
HM
590 seq->state = SEQ_STATE_UNINITIALIZED;
591 seq->addr = addr;
592
593 list_add(&seq->list, &ts->seq_list);
594 return seq;
595}
596
10350ec3
FW
597enum broken_state {
598 BROKEN_ACQUIRE,
599 BROKEN_ACQUIRED,
600 BROKEN_CONTENDED,
601 BROKEN_RELEASE,
602 BROKEN_MAX,
603};
604
605static int bad_hist[BROKEN_MAX];
e4cef1f6 606
84c7a217
FW
607enum acquire_flags {
608 TRY_LOCK = 1,
609 READ_LOCK = 2,
610};
611
0f405f87 612static int get_key_by_aggr_mode_simple(u64 *key, u64 addr, u32 tid)
9b5e350c 613{
f9c695a2
NK
614 switch (aggr_mode) {
615 case LOCK_AGGR_ADDR:
0f405f87 616 *key = addr;
f9c695a2
NK
617 break;
618 case LOCK_AGGR_TASK:
0f405f87 619 *key = tid;
f9c695a2
NK
620 break;
621 case LOCK_AGGR_CALLER:
622 default:
623 pr_err("Invalid aggregation mode: %d\n", aggr_mode);
624 return -EINVAL;
625 }
0f405f87
SX
626 return 0;
627}
628
629static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample);
630
631static int get_key_by_aggr_mode(u64 *key, u64 addr, struct evsel *evsel,
632 struct perf_sample *sample)
633{
634 if (aggr_mode == LOCK_AGGR_CALLER) {
635 *key = callchain_id(evsel, sample);
636 return 0;
637 }
638 return get_key_by_aggr_mode_simple(key, addr, sample->tid);
639}
640
641static int report_lock_acquire_event(struct evsel *evsel,
642 struct perf_sample *sample)
643{
644 struct lock_stat *ls;
645 struct thread_stat *ts;
646 struct lock_seq_stat *seq;
647 const char *name = evsel__strval(evsel, sample, "name");
648 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
649 int flag = evsel__intval(evsel, sample, "flags");
650 u64 key;
651 int ret;
652
653 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
654 if (ret < 0)
655 return ret;
7c3bcbdf 656
f9c695a2 657 ls = lock_stat_findnew(key, name, 0);
33d6aef5 658 if (!ls)
b33492ad 659 return -ENOMEM;
9b5e350c 660
01d95524 661 ts = thread_stat_findnew(sample->tid);
33d6aef5 662 if (!ts)
b33492ad 663 return -ENOMEM;
33d6aef5 664
746f16ec 665 seq = get_seq(ts, addr);
33d6aef5 666 if (!seq)
b33492ad 667 return -ENOMEM;
9b5e350c 668
e4cef1f6
HM
669 switch (seq->state) {
670 case SEQ_STATE_UNINITIALIZED:
671 case SEQ_STATE_RELEASED:
746f16ec 672 if (!flag) {
e4cef1f6
HM
673 seq->state = SEQ_STATE_ACQUIRING;
674 } else {
746f16ec 675 if (flag & TRY_LOCK)
e4cef1f6 676 ls->nr_trylock++;
746f16ec 677 if (flag & READ_LOCK)
e4cef1f6
HM
678 ls->nr_readlock++;
679 seq->state = SEQ_STATE_READ_ACQUIRED;
680 seq->read_count = 1;
681 ls->nr_acquired++;
682 }
683 break;
684 case SEQ_STATE_READ_ACQUIRED:
746f16ec 685 if (flag & READ_LOCK) {
e4cef1f6
HM
686 seq->read_count++;
687 ls->nr_acquired++;
688 goto end;
689 } else {
690 goto broken;
691 }
9b5e350c 692 break;
e4cef1f6
HM
693 case SEQ_STATE_ACQUIRED:
694 case SEQ_STATE_ACQUIRING:
695 case SEQ_STATE_CONTENDED:
696broken:
79d9333b
NK
697 /* broken lock sequence */
698 if (!ls->broken) {
699 ls->broken = 1;
700 bad_hist[BROKEN_ACQUIRE]++;
701 }
e56fbc9d 702 list_del_init(&seq->list);
e4cef1f6
HM
703 free(seq);
704 goto end;
9b5e350c 705 default:
e4cef1f6 706 BUG_ON("Unknown state of lock sequence found!\n");
9b5e350c
HM
707 break;
708 }
709
e4cef1f6 710 ls->nr_acquire++;
01d95524 711 seq->prev_event_time = sample->time;
e4cef1f6 712end:
33d6aef5 713 return 0;
9b5e350c
HM
714}
715
32dcd021 716static int report_lock_acquired_event(struct evsel *evsel,
746f16ec 717 struct perf_sample *sample)
9b5e350c 718{
e4cef1f6
HM
719 struct lock_stat *ls;
720 struct thread_stat *ts;
721 struct lock_seq_stat *seq;
722 u64 contended_term;
efc0cdc9 723 const char *name = evsel__strval(evsel, sample, "name");
e1c3177b 724 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
f9c695a2 725 u64 key;
0f405f87 726 int ret;
9b5e350c 727
0f405f87
SX
728 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
729 if (ret < 0)
730 return ret;
7c3bcbdf 731
f9c695a2 732 ls = lock_stat_findnew(key, name, 0);
33d6aef5 733 if (!ls)
b33492ad 734 return -ENOMEM;
e4cef1f6 735
01d95524 736 ts = thread_stat_findnew(sample->tid);
33d6aef5 737 if (!ts)
b33492ad 738 return -ENOMEM;
33d6aef5 739
746f16ec 740 seq = get_seq(ts, addr);
33d6aef5 741 if (!seq)
b33492ad 742 return -ENOMEM;
9b5e350c 743
e4cef1f6
HM
744 switch (seq->state) {
745 case SEQ_STATE_UNINITIALIZED:
746 /* orphan event, do nothing */
33d6aef5 747 return 0;
e4cef1f6 748 case SEQ_STATE_ACQUIRING:
9b5e350c 749 break;
e4cef1f6 750 case SEQ_STATE_CONTENDED:
746f16ec 751 contended_term = sample->time - seq->prev_event_time;
e4cef1f6 752 ls->wait_time_total += contended_term;
e4cef1f6
HM
753 if (contended_term < ls->wait_time_min)
754 ls->wait_time_min = contended_term;
90c0e5fc 755 if (ls->wait_time_max < contended_term)
e4cef1f6 756 ls->wait_time_max = contended_term;
9b5e350c 757 break;
e4cef1f6
HM
758 case SEQ_STATE_RELEASED:
759 case SEQ_STATE_ACQUIRED:
760 case SEQ_STATE_READ_ACQUIRED:
79d9333b
NK
761 /* broken lock sequence */
762 if (!ls->broken) {
763 ls->broken = 1;
764 bad_hist[BROKEN_ACQUIRED]++;
765 }
e56fbc9d 766 list_del_init(&seq->list);
e4cef1f6
HM
767 free(seq);
768 goto end;
9b5e350c 769 default:
e4cef1f6 770 BUG_ON("Unknown state of lock sequence found!\n");
9b5e350c
HM
771 break;
772 }
773
e4cef1f6
HM
774 seq->state = SEQ_STATE_ACQUIRED;
775 ls->nr_acquired++;
f37376cd 776 ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
746f16ec 777 seq->prev_event_time = sample->time;
e4cef1f6 778end:
33d6aef5 779 return 0;
9b5e350c
HM
780}
781
32dcd021 782static int report_lock_contended_event(struct evsel *evsel,
746f16ec 783 struct perf_sample *sample)
9b5e350c 784{
e4cef1f6
HM
785 struct lock_stat *ls;
786 struct thread_stat *ts;
787 struct lock_seq_stat *seq;
efc0cdc9 788 const char *name = evsel__strval(evsel, sample, "name");
e1c3177b 789 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
f9c695a2 790 u64 key;
0f405f87 791 int ret;
e4cef1f6 792
0f405f87
SX
793 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
794 if (ret < 0)
795 return ret;
7c3bcbdf 796
f9c695a2 797 ls = lock_stat_findnew(key, name, 0);
33d6aef5 798 if (!ls)
b33492ad 799 return -ENOMEM;
9b5e350c 800
01d95524 801 ts = thread_stat_findnew(sample->tid);
33d6aef5 802 if (!ts)
b33492ad 803 return -ENOMEM;
33d6aef5 804
746f16ec 805 seq = get_seq(ts, addr);
33d6aef5 806 if (!seq)
b33492ad 807 return -ENOMEM;
9b5e350c 808
e4cef1f6
HM
809 switch (seq->state) {
810 case SEQ_STATE_UNINITIALIZED:
811 /* orphan event, do nothing */
33d6aef5 812 return 0;
e4cef1f6 813 case SEQ_STATE_ACQUIRING:
9b5e350c 814 break;
e4cef1f6
HM
815 case SEQ_STATE_RELEASED:
816 case SEQ_STATE_ACQUIRED:
817 case SEQ_STATE_READ_ACQUIRED:
818 case SEQ_STATE_CONTENDED:
79d9333b
NK
819 /* broken lock sequence */
820 if (!ls->broken) {
821 ls->broken = 1;
822 bad_hist[BROKEN_CONTENDED]++;
823 }
e56fbc9d 824 list_del_init(&seq->list);
e4cef1f6
HM
825 free(seq);
826 goto end;
9b5e350c 827 default:
e4cef1f6 828 BUG_ON("Unknown state of lock sequence found!\n");
9b5e350c
HM
829 break;
830 }
831
e4cef1f6
HM
832 seq->state = SEQ_STATE_CONTENDED;
833 ls->nr_contended++;
f37376cd 834 ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
01d95524 835 seq->prev_event_time = sample->time;
e4cef1f6 836end:
33d6aef5 837 return 0;
9b5e350c
HM
838}
839
32dcd021 840static int report_lock_release_event(struct evsel *evsel,
746f16ec 841 struct perf_sample *sample)
9b5e350c 842{
e4cef1f6
HM
843 struct lock_stat *ls;
844 struct thread_stat *ts;
845 struct lock_seq_stat *seq;
efc0cdc9 846 const char *name = evsel__strval(evsel, sample, "name");
e1c3177b 847 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
f9c695a2 848 u64 key;
0f405f87 849 int ret;
746f16ec 850
0f405f87
SX
851 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
852 if (ret < 0)
853 return ret;
7c3bcbdf 854
f9c695a2 855 ls = lock_stat_findnew(key, name, 0);
33d6aef5 856 if (!ls)
b33492ad 857 return -ENOMEM;
9b5e350c 858
01d95524 859 ts = thread_stat_findnew(sample->tid);
33d6aef5 860 if (!ts)
b33492ad 861 return -ENOMEM;
33d6aef5 862
746f16ec 863 seq = get_seq(ts, addr);
33d6aef5 864 if (!seq)
b33492ad 865 return -ENOMEM;
9b5e350c 866
e4cef1f6
HM
867 switch (seq->state) {
868 case SEQ_STATE_UNINITIALIZED:
869 goto end;
e4cef1f6
HM
870 case SEQ_STATE_ACQUIRED:
871 break;
872 case SEQ_STATE_READ_ACQUIRED:
873 seq->read_count--;
874 BUG_ON(seq->read_count < 0);
b0e5a05c 875 if (seq->read_count) {
e4cef1f6 876 ls->nr_release++;
9b5e350c
HM
877 goto end;
878 }
e4cef1f6
HM
879 break;
880 case SEQ_STATE_ACQUIRING:
881 case SEQ_STATE_CONTENDED:
882 case SEQ_STATE_RELEASED:
79d9333b
NK
883 /* broken lock sequence */
884 if (!ls->broken) {
885 ls->broken = 1;
886 bad_hist[BROKEN_RELEASE]++;
887 }
e4cef1f6 888 goto free_seq;
9b5e350c 889 default:
e4cef1f6 890 BUG_ON("Unknown state of lock sequence found!\n");
9b5e350c
HM
891 break;
892 }
893
e4cef1f6
HM
894 ls->nr_release++;
895free_seq:
e56fbc9d 896 list_del_init(&seq->list);
e4cef1f6 897 free(seq);
9b5e350c 898end:
33d6aef5 899 return 0;
9b5e350c
HM
900}
901
637522ce
NK
902static int get_symbol_name_offset(struct map *map, struct symbol *sym, u64 ip,
903 char *buf, int size)
904{
905 u64 offset;
906
907 if (map == NULL || sym == NULL) {
908 buf[0] = '\0';
909 return 0;
910 }
911
78a1f7cd 912 offset = map__map_ip(map, ip) - sym->start;
637522ce
NK
913
914 if (offset)
915 return scnprintf(buf, size, "%s+%#lx", sym->name, offset);
916 else
917 return strlcpy(buf, sym->name, size);
918}
0d2997f7
NK
919static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sample,
920 char *buf, int size)
921{
922 struct thread *thread;
8ab12a20 923 struct callchain_cursor *cursor;
77d54a2c 924 struct machine *machine = &session->machines.host;
0d2997f7
NK
925 struct symbol *sym;
926 int skip = 0;
927 int ret;
928
929 /* lock names will be replaced to task name later */
930 if (show_thread_stats)
931 return -1;
932
77d54a2c 933 thread = machine__findnew_thread(machine, -1, sample->pid);
0d2997f7
NK
934 if (thread == NULL)
935 return -1;
936
8ab12a20
IR
937 cursor = get_tls_callchain_cursor();
938
0d2997f7
NK
939 /* use caller function name from the callchain */
940 ret = thread__resolve_callchain(thread, cursor, evsel, sample,
96532a83 941 NULL, NULL, max_stack_depth);
0d2997f7
NK
942 if (ret != 0) {
943 thread__put(thread);
944 return -1;
945 }
946
947 callchain_cursor_commit(cursor);
948 thread__put(thread);
949
950 while (true) {
951 struct callchain_cursor_node *node;
952
953 node = callchain_cursor_current(cursor);
954 if (node == NULL)
955 break;
956
957 /* skip first few entries - for lock functions */
96532a83 958 if (++skip <= stack_skip)
0d2997f7
NK
959 goto next;
960
961 sym = node->ms.sym;
cc2367ee 962 if (sym && !machine__is_lock_function(machine, node->ip)) {
637522ce
NK
963 get_symbol_name_offset(node->ms.map, sym, node->ip,
964 buf, size);
0d2997f7
NK
965 return 0;
966 }
967
968next:
969 callchain_cursor_advance(cursor);
970 }
971 return -1;
972}
973
528b9cab
NK
974static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
975{
8ab12a20 976 struct callchain_cursor *cursor;
77d54a2c 977 struct machine *machine = &session->machines.host;
528b9cab
NK
978 struct thread *thread;
979 u64 hash = 0;
980 int skip = 0;
981 int ret;
982
77d54a2c 983 thread = machine__findnew_thread(machine, -1, sample->pid);
528b9cab
NK
984 if (thread == NULL)
985 return -1;
986
8ab12a20 987 cursor = get_tls_callchain_cursor();
528b9cab
NK
988 /* use caller function name from the callchain */
989 ret = thread__resolve_callchain(thread, cursor, evsel, sample,
96532a83 990 NULL, NULL, max_stack_depth);
528b9cab
NK
991 thread__put(thread);
992
993 if (ret != 0)
994 return -1;
995
996 callchain_cursor_commit(cursor);
997
998 while (true) {
999 struct callchain_cursor_node *node;
1000
1001 node = callchain_cursor_current(cursor);
1002 if (node == NULL)
1003 break;
1004
1005 /* skip first few entries - for lock functions */
96532a83 1006 if (++skip <= stack_skip)
528b9cab
NK
1007 goto next;
1008
cc2367ee 1009 if (node->ms.sym && machine__is_lock_function(machine, node->ip))
528b9cab
NK
1010 goto next;
1011
1012 hash ^= hash_long((unsigned long)node->ip, 64);
1013
1014next:
1015 callchain_cursor_advance(cursor);
1016 }
1017 return hash;
1018}
1019
a6eaf966
NK
1020static u64 *get_callstack(struct perf_sample *sample, int max_stack)
1021{
1022 u64 *callstack;
1023 u64 i;
1024 int c;
1025
1026 callstack = calloc(max_stack, sizeof(*callstack));
1027 if (callstack == NULL)
1028 return NULL;
1029
1030 for (i = 0, c = 0; i < sample->callchain->nr && c < max_stack; i++) {
1031 u64 ip = sample->callchain->ips[i];
1032
1033 if (ip >= PERF_CONTEXT_MAX)
1034 continue;
1035
1036 callstack[c++] = ip;
1037 }
1038 return callstack;
1039}
1040
3ae03f26
NK
1041static int report_lock_contention_begin_event(struct evsel *evsel,
1042 struct perf_sample *sample)
1043{
1044 struct lock_stat *ls;
1045 struct thread_stat *ts;
1046 struct lock_seq_stat *seq;
1047 u64 addr = evsel__intval(evsel, sample, "lock_addr");
b4a7eff9 1048 unsigned int flags = evsel__intval(evsel, sample, "flags");
f9c695a2 1049 u64 key;
b4a7eff9 1050 int i, ret;
511e19b9
NK
1051 static bool kmap_loaded;
1052 struct machine *machine = &session->machines.host;
1053 struct map *kmap;
1054 struct symbol *sym;
3ae03f26 1055
0f405f87
SX
1056 ret = get_key_by_aggr_mode(&key, addr, evsel, sample);
1057 if (ret < 0)
1058 return ret;
3ae03f26 1059
511e19b9
NK
1060 if (!kmap_loaded) {
1061 unsigned long *addrs;
1062
1063 /* make sure it loads the kernel map to find lock symbols */
1064 map__load(machine__kernel_map(machine));
1065 kmap_loaded = true;
1066
1067 /* convert (kernel) symbols to addresses */
1068 for (i = 0; i < filters.nr_syms; i++) {
1069 sym = machine__find_kernel_symbol_by_name(machine,
1070 filters.syms[i],
1071 &kmap);
1072 if (sym == NULL) {
1073 pr_warning("ignore unknown symbol: %s\n",
1074 filters.syms[i]);
1075 continue;
1076 }
1077
1078 addrs = realloc(filters.addrs,
1079 (filters.nr_addrs + 1) * sizeof(*addrs));
1080 if (addrs == NULL) {
1081 pr_warning("memory allocation failure\n");
1082 return -ENOMEM;
1083 }
1084
78a1f7cd 1085 addrs[filters.nr_addrs++] = map__unmap_ip(kmap, sym->start);
511e19b9
NK
1086 filters.addrs = addrs;
1087 }
1088 }
1089
f9c695a2 1090 ls = lock_stat_find(key);
0d2997f7
NK
1091 if (!ls) {
1092 char buf[128];
688d2e8d 1093 const char *name = "";
688d2e8d
NK
1094
1095 switch (aggr_mode) {
1096 case LOCK_AGGR_ADDR:
688d2e8d
NK
1097 sym = machine__find_kernel_symbol(machine, key, &kmap);
1098 if (sym)
1099 name = sym->name;
1100 break;
1101 case LOCK_AGGR_CALLER:
1102 name = buf;
1103 if (lock_contention_caller(evsel, sample, buf, sizeof(buf)) < 0)
1104 name = "Unknown";
1105 break;
1106 case LOCK_AGGR_TASK:
1107 default:
1108 break;
1109 }
0d2997f7 1110
688d2e8d 1111 ls = lock_stat_findnew(key, name, flags);
0d2997f7
NK
1112 if (!ls)
1113 return -ENOMEM;
1114 }
3ae03f26 1115
b4a7eff9
NK
1116 if (filters.nr_types) {
1117 bool found = false;
1118
1119 for (i = 0; i < filters.nr_types; i++) {
1120 if (flags == filters.types[i]) {
1121 found = true;
1122 break;
1123 }
1124 }
1125
1126 if (!found)
1127 return 0;
1128 }
1129
511e19b9
NK
1130 if (filters.nr_addrs) {
1131 bool found = false;
1132
1133 for (i = 0; i < filters.nr_addrs; i++) {
1134 if (addr == filters.addrs[i]) {
1135 found = true;
1136 break;
1137 }
1138 }
1139
1140 if (!found)
1141 return 0;
1142 }
1143
ebab2916
NK
1144 if (needs_callstack()) {
1145 u64 *callstack = get_callstack(sample, max_stack_depth);
1146 if (callstack == NULL)
1147 return -ENOMEM;
1148
1149 if (!match_callstack_filter(machine, callstack)) {
1150 free(callstack);
1151 return 0;
1152 }
1153
1154 if (ls->callstack == NULL)
1155 ls->callstack = callstack;
1156 else
1157 free(callstack);
1158 }
1159
3ae03f26
NK
1160 ts = thread_stat_findnew(sample->tid);
1161 if (!ts)
1162 return -ENOMEM;
1163
1164 seq = get_seq(ts, addr);
1165 if (!seq)
1166 return -ENOMEM;
1167
1168 switch (seq->state) {
1169 case SEQ_STATE_UNINITIALIZED:
1170 case SEQ_STATE_ACQUIRED:
1171 break;
1172 case SEQ_STATE_CONTENDED:
1173 /*
1174 * It can have nested contention begin with mutex spinning,
1175 * then we would use the original contention begin event and
1176 * ignore the second one.
1177 */
1178 goto end;
1179 case SEQ_STATE_ACQUIRING:
1180 case SEQ_STATE_READ_ACQUIRED:
1181 case SEQ_STATE_RELEASED:
1182 /* broken lock sequence */
1183 if (!ls->broken) {
1184 ls->broken = 1;
1185 bad_hist[BROKEN_CONTENDED]++;
1186 }
1187 list_del_init(&seq->list);
1188 free(seq);
1189 goto end;
1190 default:
1191 BUG_ON("Unknown state of lock sequence found!\n");
1192 break;
1193 }
1194
1195 if (seq->state != SEQ_STATE_CONTENDED) {
1196 seq->state = SEQ_STATE_CONTENDED;
1197 seq->prev_event_time = sample->time;
1198 ls->nr_contended++;
1199 }
1200end:
1201 return 0;
1202}
1203
1204static int report_lock_contention_end_event(struct evsel *evsel,
1205 struct perf_sample *sample)
1206{
1207 struct lock_stat *ls;
1208 struct thread_stat *ts;
1209 struct lock_seq_stat *seq;
1210 u64 contended_term;
1211 u64 addr = evsel__intval(evsel, sample, "lock_addr");
f9c695a2 1212 u64 key;
0f405f87 1213 int ret;
3ae03f26 1214
0f405f87
SX
1215 ret = get_key_by_aggr_mode(&key, addr, evsel, sample);
1216 if (ret < 0)
1217 return ret;
3ae03f26 1218
f9c695a2 1219 ls = lock_stat_find(key);
3ae03f26
NK
1220 if (!ls)
1221 return 0;
1222
1223 ts = thread_stat_find(sample->tid);
1224 if (!ts)
1225 return 0;
1226
1227 seq = get_seq(ts, addr);
1228 if (!seq)
1229 return -ENOMEM;
1230
1231 switch (seq->state) {
1232 case SEQ_STATE_UNINITIALIZED:
1233 goto end;
1234 case SEQ_STATE_CONTENDED:
1235 contended_term = sample->time - seq->prev_event_time;
1236 ls->wait_time_total += contended_term;
1237 if (contended_term < ls->wait_time_min)
1238 ls->wait_time_min = contended_term;
1239 if (ls->wait_time_max < contended_term)
1240 ls->wait_time_max = contended_term;
1241 break;
1242 case SEQ_STATE_ACQUIRING:
1243 case SEQ_STATE_ACQUIRED:
1244 case SEQ_STATE_READ_ACQUIRED:
1245 case SEQ_STATE_RELEASED:
1246 /* broken lock sequence */
1247 if (!ls->broken) {
1248 ls->broken = 1;
1249 bad_hist[BROKEN_ACQUIRED]++;
1250 }
1251 list_del_init(&seq->list);
1252 free(seq);
1253 goto end;
1254 default:
1255 BUG_ON("Unknown state of lock sequence found!\n");
1256 break;
1257 }
1258
1259 seq->state = SEQ_STATE_ACQUIRED;
1260 ls->nr_acquired++;
1261 ls->avg_wait_time = ls->wait_time_total/ls->nr_acquired;
1262end:
1263 return 0;
1264}
1265
9b5e350c
HM
1266/* lock oriented handlers */
1267/* TODO: handlers for CPU oriented, thread oriented */
59f411b6
IM
1268static struct trace_lock_handler report_lock_ops = {
1269 .acquire_event = report_lock_acquire_event,
1270 .acquired_event = report_lock_acquired_event,
1271 .contended_event = report_lock_contended_event,
1272 .release_event = report_lock_release_event,
3ae03f26
NK
1273 .contention_begin_event = report_lock_contention_begin_event,
1274 .contention_end_event = report_lock_contention_end_event,
9b5e350c
HM
1275};
1276
528b9cab
NK
1277static struct trace_lock_handler contention_lock_ops = {
1278 .contention_begin_event = report_lock_contention_begin_event,
1279 .contention_end_event = report_lock_contention_end_event,
1280};
1281
1282
9b5e350c
HM
1283static struct trace_lock_handler *trace_handler;
1284
3d655813 1285static int evsel__process_lock_acquire(struct evsel *evsel, struct perf_sample *sample)
9b5e350c 1286{
59f411b6 1287 if (trace_handler->acquire_event)
746f16ec
ACM
1288 return trace_handler->acquire_event(evsel, sample);
1289 return 0;
9b5e350c
HM
1290}
1291
3d655813 1292static int evsel__process_lock_acquired(struct evsel *evsel, struct perf_sample *sample)
9b5e350c 1293{
33d6aef5 1294 if (trace_handler->acquired_event)
746f16ec
ACM
1295 return trace_handler->acquired_event(evsel, sample);
1296 return 0;
9b5e350c
HM
1297}
1298
3d655813 1299static int evsel__process_lock_contended(struct evsel *evsel, struct perf_sample *sample)
9b5e350c 1300{
33d6aef5 1301 if (trace_handler->contended_event)
746f16ec
ACM
1302 return trace_handler->contended_event(evsel, sample);
1303 return 0;
9b5e350c
HM
1304}
1305
3d655813 1306static int evsel__process_lock_release(struct evsel *evsel, struct perf_sample *sample)
9b5e350c 1307{
33d6aef5 1308 if (trace_handler->release_event)
746f16ec
ACM
1309 return trace_handler->release_event(evsel, sample);
1310 return 0;
9b5e350c
HM
1311}
1312
166a9764
NK
1313static int evsel__process_contention_begin(struct evsel *evsel, struct perf_sample *sample)
1314{
1315 if (trace_handler->contention_begin_event)
1316 return trace_handler->contention_begin_event(evsel, sample);
1317 return 0;
1318}
1319
1320static int evsel__process_contention_end(struct evsel *evsel, struct perf_sample *sample)
1321{
1322 if (trace_handler->contention_end_event)
1323 return trace_handler->contention_end_event(evsel, sample);
1324 return 0;
1325}
1326
10350ec3
FW
1327static void print_bad_events(int bad, int total)
1328{
1329 /* Output for debug, this have to be removed */
1330 int i;
9565c918 1331 int broken = 0;
10350ec3
FW
1332 const char *name[4] =
1333 { "acquire", "acquired", "contended", "release" };
1334
9565c918
NK
1335 for (i = 0; i < BROKEN_MAX; i++)
1336 broken += bad_hist[i];
1337
35bf007e 1338 if (quiet || total == 0 || (broken == 0 && verbose <= 0))
9565c918
NK
1339 return;
1340
f6027053
NK
1341 fprintf(lock_output, "\n=== output for debug ===\n\n");
1342 fprintf(lock_output, "bad: %d, total: %d\n", bad, total);
1343 fprintf(lock_output, "bad rate: %.2f %%\n", (double)bad / (double)total * 100);
1344 fprintf(lock_output, "histogram of events caused bad sequence\n");
10350ec3 1345 for (i = 0; i < BROKEN_MAX; i++)
f6027053 1346 fprintf(lock_output, " %10s: %d\n", name[i], bad_hist[i]);
10350ec3
FW
1347}
1348
9b5e350c
HM
1349/* TODO: various way to print, coloring, nano or milli sec */
1350static void print_result(void)
1351{
1352 struct lock_stat *st;
64999e44 1353 struct lock_key *key;
9b5e350c 1354 char cut_name[20];
6282a1f4 1355 int bad, total, printed;
9b5e350c 1356
6bbc4820 1357 if (!quiet) {
f6027053 1358 fprintf(lock_output, "%20s ", "Name");
6bbc4820 1359 list_for_each_entry(key, &lock_keys, list)
f6027053
NK
1360 fprintf(lock_output, "%*s ", key->len, key->header);
1361 fprintf(lock_output, "\n\n");
6bbc4820 1362 }
9b5e350c 1363
6282a1f4 1364 bad = total = printed = 0;
9b5e350c 1365 while ((st = pop_from_result())) {
e4cef1f6 1366 total++;
79d9333b 1367 if (st->broken)
e4cef1f6 1368 bad++;
79d9333b 1369 if (!st->nr_acquired)
e4cef1f6 1370 continue;
79d9333b 1371
9b5e350c
HM
1372 bzero(cut_name, 20);
1373
ba8a56c7 1374 if (strlen(st->name) < 20) {
9b5e350c 1375 /* output raw name */
7c3bcbdf
NK
1376 const char *name = st->name;
1377
1378 if (show_thread_stats) {
1379 struct thread *t;
1380
1381 /* st->addr contains tid of thread */
1382 t = perf_session__findnew(session, st->addr);
1383 name = thread__comm_str(t);
1384 }
1385
f6027053 1386 fprintf(lock_output, "%20s ", name);
9b5e350c
HM
1387 } else {
1388 strncpy(cut_name, st->name, 16);
1389 cut_name[16] = '.';
1390 cut_name[17] = '.';
1391 cut_name[18] = '.';
1392 cut_name[19] = '\0';
1393 /* cut off name for saving output style */
f6027053 1394 fprintf(lock_output, "%20s ", cut_name);
9b5e350c
HM
1395 }
1396
64999e44
NK
1397 list_for_each_entry(key, &lock_keys, list) {
1398 key->print(key, st);
f6027053 1399 fprintf(lock_output, " ");
64999e44 1400 }
f6027053 1401 fprintf(lock_output, "\n");
6282a1f4
NK
1402
1403 if (++printed >= print_nr_entries)
1404 break;
9b5e350c 1405 }
e4cef1f6 1406
10350ec3 1407 print_bad_events(bad, total);
9b5e350c
HM
1408}
1409
8035458f 1410static bool info_threads, info_map;
26242d85
HM
1411
1412static void dump_threads(void)
1413{
1414 struct thread_stat *st;
1415 struct rb_node *node;
1416 struct thread *t;
1417
f6027053 1418 fprintf(lock_output, "%10s: comm\n", "Thread ID");
26242d85
HM
1419
1420 node = rb_first(&thread_stats);
1421 while (node) {
1422 st = container_of(node, struct thread_stat, rb);
1423 t = perf_session__findnew(session, st->tid);
f6027053 1424 fprintf(lock_output, "%10d: %s\n", st->tid, thread__comm_str(t));
26242d85 1425 node = rb_next(node);
b91fc39f 1426 thread__put(t);
8284bbea 1427 }
26242d85
HM
1428}
1429
f4cf2d75
NK
1430static int compare_maps(struct lock_stat *a, struct lock_stat *b)
1431{
1432 int ret;
1433
1434 if (a->name && b->name)
1435 ret = strcmp(a->name, b->name);
1436 else
1437 ret = !!a->name - !!b->name;
1438
1439 if (!ret)
1440 return a->addr < b->addr;
1441 else
1442 return ret < 0;
1443}
1444
9b5e350c
HM
1445static void dump_map(void)
1446{
1447 unsigned int i;
1448 struct lock_stat *st;
1449
f6027053 1450 fprintf(lock_output, "Address of instance: name of class\n");
9b5e350c 1451 for (i = 0; i < LOCKHASH_SIZE; i++) {
7672d00a 1452 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
f4cf2d75 1453 insert_to_result(st, compare_maps);
9b5e350c
HM
1454 }
1455 }
f4cf2d75
NK
1456
1457 while ((st = pop_from_result()))
f6027053 1458 fprintf(lock_output, " %#llx: %s\n", (unsigned long long)st->addr, st->name);
9b5e350c
HM
1459}
1460
33d6aef5 1461static int dump_info(void)
26242d85 1462{
33d6aef5
DA
1463 int rc = 0;
1464
26242d85
HM
1465 if (info_threads)
1466 dump_threads();
1467 else if (info_map)
1468 dump_map();
33d6aef5
DA
1469 else {
1470 rc = -1;
1471 pr_err("Unknown type of information\n");
1472 }
1473
1474 return rc;
26242d85
HM
1475}
1476
30b331d2
NK
1477static const struct evsel_str_handler lock_tracepoints[] = {
1478 { "lock:lock_acquire", evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
1479 { "lock:lock_acquired", evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
1480 { "lock:lock_contended", evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
1481 { "lock:lock_release", evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
1482};
1483
1484static const struct evsel_str_handler contention_tracepoints[] = {
1485 { "lock:contention_begin", evsel__process_contention_begin, },
1486 { "lock:contention_end", evsel__process_contention_end, },
1487};
1488
1489static int process_event_update(struct perf_tool *tool,
1490 union perf_event *event,
1491 struct evlist **pevlist)
1492{
1493 int ret;
1494
1495 ret = perf_event__process_event_update(tool, event, pevlist);
1496 if (ret < 0)
1497 return ret;
1498
1499 /* this can return -EEXIST since we call it for each evsel */
1500 perf_session__set_tracepoints_handlers(session, lock_tracepoints);
1501 perf_session__set_tracepoints_handlers(session, contention_tracepoints);
1502 return 0;
1503}
1504
32dcd021 1505typedef int (*tracepoint_handler)(struct evsel *evsel,
746f16ec
ACM
1506 struct perf_sample *sample);
1507
1d037ca1 1508static int process_sample_event(struct perf_tool *tool __maybe_unused,
d20deb64 1509 union perf_event *event,
9e69c210 1510 struct perf_sample *sample,
32dcd021 1511 struct evsel *evsel,
743eb868 1512 struct machine *machine)
c61e52ee 1513{
b91fc39f 1514 int err = 0;
314add6b
AH
1515 struct thread *thread = machine__findnew_thread(machine, sample->pid,
1516 sample->tid);
c61e52ee 1517
c61e52ee
FW
1518 if (thread == NULL) {
1519 pr_debug("problem processing %d event, skipping it.\n",
8115d60c 1520 event->header.type);
c61e52ee
FW
1521 return -1;
1522 }
1523
744a9719
ACM
1524 if (evsel->handler != NULL) {
1525 tracepoint_handler f = evsel->handler;
b91fc39f 1526 err = f(evsel, sample);
746f16ec
ACM
1527 }
1528
b91fc39f
ACM
1529 thread__put(thread);
1530
1531 return err;
c61e52ee
FW
1532}
1533
0d435bf8
NK
1534static void combine_result(void)
1535{
1536 unsigned int i;
1537 struct lock_stat *st;
1538
1539 if (!combine_locks)
1540 return;
1541
1542 for (i = 0; i < LOCKHASH_SIZE; i++) {
1543 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
1544 combine_lock_stats(st);
1545 }
1546 }
1547}
1548
375eb2be
DB
1549static void sort_result(void)
1550{
1551 unsigned int i;
1552 struct lock_stat *st;
1553
1554 for (i = 0; i < LOCKHASH_SIZE; i++) {
7672d00a 1555 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
375eb2be
DB
1556 insert_to_result(st, compare);
1557 }
1558 }
1559}
1560
59119c09
NK
1561static const struct {
1562 unsigned int flags;
4f701063 1563 const char *str;
59119c09
NK
1564 const char *name;
1565} lock_type_table[] = {
4f701063
NK
1566 { 0, "semaphore", "semaphore" },
1567 { LCB_F_SPIN, "spinlock", "spinlock" },
1568 { LCB_F_SPIN | LCB_F_READ, "rwlock:R", "rwlock" },
1569 { LCB_F_SPIN | LCB_F_WRITE, "rwlock:W", "rwlock" },
1570 { LCB_F_READ, "rwsem:R", "rwsem" },
1571 { LCB_F_WRITE, "rwsem:W", "rwsem" },
d783ea8f 1572 { LCB_F_RT, "rt-mutex", "rt-mutex" },
4f701063
NK
1573 { LCB_F_RT | LCB_F_READ, "rwlock-rt:R", "rwlock-rt" },
1574 { LCB_F_RT | LCB_F_WRITE, "rwlock-rt:W", "rwlock-rt" },
1575 { LCB_F_PERCPU | LCB_F_READ, "pcpu-sem:R", "percpu-rwsem" },
1576 { LCB_F_PERCPU | LCB_F_WRITE, "pcpu-sem:W", "percpu-rwsem" },
1577 { LCB_F_MUTEX, "mutex", "mutex" },
1578 { LCB_F_MUTEX | LCB_F_SPIN, "mutex", "mutex" },
b4a7eff9 1579 /* alias for get_type_flag() */
4f701063 1580 { LCB_F_MUTEX | LCB_F_SPIN, "mutex-spin", "mutex" },
59119c09 1581};
528b9cab 1582
59119c09
NK
1583static const char *get_type_str(unsigned int flags)
1584{
4f701063
NK
1585 flags &= LCB_F_MAX_FLAGS - 1;
1586
1587 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1588 if (lock_type_table[i].flags == flags)
1589 return lock_type_table[i].str;
1590 }
1591 return "unknown";
1592}
1593
1594static const char *get_type_name(unsigned int flags)
1595{
1596 flags &= LCB_F_MAX_FLAGS - 1;
1597
59119c09
NK
1598 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1599 if (lock_type_table[i].flags == flags)
1600 return lock_type_table[i].name;
528b9cab
NK
1601 }
1602 return "unknown";
1603}
1604
b4a7eff9
NK
1605static unsigned int get_type_flag(const char *str)
1606{
1607 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1608 if (!strcmp(lock_type_table[i].name, str))
1609 return lock_type_table[i].flags;
1610 }
d783ea8f
NK
1611 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1612 if (!strcmp(lock_type_table[i].str, str))
1613 return lock_type_table[i].flags;
1614 }
b4a7eff9
NK
1615 return UINT_MAX;
1616}
1617
1618static void lock_filter_finish(void)
1619{
1620 zfree(&filters.types);
1621 filters.nr_types = 0;
511e19b9
NK
1622
1623 zfree(&filters.addrs);
1624 filters.nr_addrs = 0;
1625
1626 for (int i = 0; i < filters.nr_syms; i++)
1627 free(filters.syms[i]);
1628
1629 zfree(&filters.syms);
1630 filters.nr_syms = 0;
b4a7eff9
NK
1631}
1632
528b9cab
NK
1633static void sort_contention_result(void)
1634{
1635 sort_result();
1636}
1637
69c5c993
NK
1638static void print_header_stdio(void)
1639{
1640 struct lock_key *key;
1641
1642 list_for_each_entry(key, &lock_keys, list)
f6027053 1643 fprintf(lock_output, "%*s ", key->len, key->header);
69c5c993
NK
1644
1645 switch (aggr_mode) {
1646 case LOCK_AGGR_TASK:
f6027053 1647 fprintf(lock_output, " %10s %s\n\n", "pid",
69c5c993
NK
1648 show_lock_owner ? "owner" : "comm");
1649 break;
1650 case LOCK_AGGR_CALLER:
f6027053 1651 fprintf(lock_output, " %10s %s\n\n", "type", "caller");
69c5c993
NK
1652 break;
1653 case LOCK_AGGR_ADDR:
f6027053 1654 fprintf(lock_output, " %16s %s\n\n", "address", "symbol");
69c5c993
NK
1655 break;
1656 default:
1657 break;
1658 }
1659}
1660
1661static void print_header_csv(const char *sep)
1662{
1663 struct lock_key *key;
1664
f6027053 1665 fprintf(lock_output, "# output: ");
69c5c993 1666 list_for_each_entry(key, &lock_keys, list)
f6027053 1667 fprintf(lock_output, "%s%s ", key->header, sep);
69c5c993
NK
1668
1669 switch (aggr_mode) {
1670 case LOCK_AGGR_TASK:
f6027053 1671 fprintf(lock_output, "%s%s %s\n", "pid", sep,
69c5c993
NK
1672 show_lock_owner ? "owner" : "comm");
1673 break;
1674 case LOCK_AGGR_CALLER:
f6027053 1675 fprintf(lock_output, "%s%s %s", "type", sep, "caller");
69c5c993 1676 if (verbose > 0)
f6027053
NK
1677 fprintf(lock_output, "%s %s", sep, "stacktrace");
1678 fprintf(lock_output, "\n");
69c5c993
NK
1679 break;
1680 case LOCK_AGGR_ADDR:
f6027053 1681 fprintf(lock_output, "%s%s %s%s %s\n", "address", sep, "symbol", sep, "type");
69c5c993
NK
1682 break;
1683 default:
1684 break;
1685 }
1686}
1687
1688static void print_header(void)
1689{
1690 if (!quiet) {
1691 if (symbol_conf.field_sep)
1692 print_header_csv(symbol_conf.field_sep);
1693 else
1694 print_header_stdio();
1695 }
1696}
1697
1698static void print_lock_stat_stdio(struct lock_contention *con, struct lock_stat *st)
1699{
1700 struct lock_key *key;
1701 struct thread *t;
1702 int pid;
1703
1704 list_for_each_entry(key, &lock_keys, list) {
1705 key->print(key, st);
f6027053 1706 fprintf(lock_output, " ");
69c5c993
NK
1707 }
1708
1709 switch (aggr_mode) {
1710 case LOCK_AGGR_CALLER:
f6027053 1711 fprintf(lock_output, " %10s %s\n", get_type_str(st->flags), st->name);
69c5c993
NK
1712 break;
1713 case LOCK_AGGR_TASK:
1714 pid = st->addr;
1715 t = perf_session__findnew(session, pid);
f6027053 1716 fprintf(lock_output, " %10d %s\n",
69c5c993
NK
1717 pid, pid == -1 ? "Unknown" : thread__comm_str(t));
1718 break;
1719 case LOCK_AGGR_ADDR:
f6027053 1720 fprintf(lock_output, " %016llx %s (%s)\n", (unsigned long long)st->addr,
69c5c993
NK
1721 st->name, get_type_name(st->flags));
1722 break;
1723 default:
1724 break;
1725 }
1726
1727 if (aggr_mode == LOCK_AGGR_CALLER && verbose > 0) {
1728 struct map *kmap;
1729 struct symbol *sym;
1730 char buf[128];
1731 u64 ip;
1732
1733 for (int i = 0; i < max_stack_depth; i++) {
1734 if (!st->callstack || !st->callstack[i])
1735 break;
1736
1737 ip = st->callstack[i];
1738 sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
1739 get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
f6027053 1740 fprintf(lock_output, "\t\t\t%#lx %s\n", (unsigned long)ip, buf);
69c5c993
NK
1741 }
1742 }
1743}
1744
1745static void print_lock_stat_csv(struct lock_contention *con, struct lock_stat *st,
1746 const char *sep)
1747{
1748 struct lock_key *key;
1749 struct thread *t;
1750 int pid;
1751
1752 list_for_each_entry(key, &lock_keys, list) {
1753 key->print(key, st);
f6027053 1754 fprintf(lock_output, "%s ", sep);
69c5c993
NK
1755 }
1756
1757 switch (aggr_mode) {
1758 case LOCK_AGGR_CALLER:
f6027053 1759 fprintf(lock_output, "%s%s %s", get_type_str(st->flags), sep, st->name);
69c5c993 1760 if (verbose <= 0)
f6027053 1761 fprintf(lock_output, "\n");
69c5c993
NK
1762 break;
1763 case LOCK_AGGR_TASK:
1764 pid = st->addr;
1765 t = perf_session__findnew(session, pid);
f6027053
NK
1766 fprintf(lock_output, "%d%s %s\n", pid, sep,
1767 pid == -1 ? "Unknown" : thread__comm_str(t));
69c5c993
NK
1768 break;
1769 case LOCK_AGGR_ADDR:
f6027053 1770 fprintf(lock_output, "%llx%s %s%s %s\n", (unsigned long long)st->addr, sep,
69c5c993
NK
1771 st->name, sep, get_type_name(st->flags));
1772 break;
1773 default:
1774 break;
1775 }
1776
1777 if (aggr_mode == LOCK_AGGR_CALLER && verbose > 0) {
1778 struct map *kmap;
1779 struct symbol *sym;
1780 char buf[128];
1781 u64 ip;
1782
1783 for (int i = 0; i < max_stack_depth; i++) {
1784 if (!st->callstack || !st->callstack[i])
1785 break;
1786
1787 ip = st->callstack[i];
1788 sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
1789 get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
f6027053 1790 fprintf(lock_output, "%s %#lx %s", i ? ":" : sep, (unsigned long) ip, buf);
69c5c993 1791 }
f6027053 1792 fprintf(lock_output, "\n");
69c5c993
NK
1793 }
1794}
1795
1796static void print_lock_stat(struct lock_contention *con, struct lock_stat *st)
1797{
1798 if (symbol_conf.field_sep)
1799 print_lock_stat_csv(con, st, symbol_conf.field_sep);
1800 else
1801 print_lock_stat_stdio(con, st);
1802}
1803
1804static void print_footer_stdio(int total, int bad, struct lock_contention_fails *fails)
84c3a2bb
NK
1805{
1806 /* Output for debug, this have to be removed */
954cdac7 1807 int broken = fails->task + fails->stack + fails->time + fails->data;
84c3a2bb 1808
69c5c993
NK
1809 if (!use_bpf)
1810 print_bad_events(bad, total);
1811
84c3a2bb
NK
1812 if (quiet || total == 0 || (broken == 0 && verbose <= 0))
1813 return;
1814
1815 total += broken;
f6027053
NK
1816 fprintf(lock_output, "\n=== output for debug ===\n\n");
1817 fprintf(lock_output, "bad: %d, total: %d\n", broken, total);
1818 fprintf(lock_output, "bad rate: %.2f %%\n", 100.0 * broken / total);
84c3a2bb 1819
f6027053
NK
1820 fprintf(lock_output, "histogram of failure reasons\n");
1821 fprintf(lock_output, " %10s: %d\n", "task", fails->task);
1822 fprintf(lock_output, " %10s: %d\n", "stack", fails->stack);
1823 fprintf(lock_output, " %10s: %d\n", "time", fails->time);
1824 fprintf(lock_output, " %10s: %d\n", "data", fails->data);
84c3a2bb 1825}
954cdac7 1826
69c5c993
NK
1827static void print_footer_csv(int total, int bad, struct lock_contention_fails *fails,
1828 const char *sep)
1829{
1830 /* Output for debug, this have to be removed */
1831 if (use_bpf)
1832 bad = fails->task + fails->stack + fails->time + fails->data;
1833
1834 if (quiet || total == 0 || (bad == 0 && verbose <= 0))
1835 return;
1836
1837 total += bad;
f6027053 1838 fprintf(lock_output, "# debug: total=%d%s bad=%d", total, sep, bad);
69c5c993
NK
1839
1840 if (use_bpf) {
f6027053
NK
1841 fprintf(lock_output, "%s bad_%s=%d", sep, "task", fails->task);
1842 fprintf(lock_output, "%s bad_%s=%d", sep, "stack", fails->stack);
1843 fprintf(lock_output, "%s bad_%s=%d", sep, "time", fails->time);
1844 fprintf(lock_output, "%s bad_%s=%d", sep, "data", fails->data);
69c5c993
NK
1845 } else {
1846 int i;
1847 const char *name[4] = { "acquire", "acquired", "contended", "release" };
1848
1849 for (i = 0; i < BROKEN_MAX; i++)
f6027053 1850 fprintf(lock_output, "%s bad_%s=%d", sep, name[i], bad_hist[i]);
69c5c993 1851 }
f6027053 1852 fprintf(lock_output, "\n");
69c5c993
NK
1853}
1854
1855static void print_footer(int total, int bad, struct lock_contention_fails *fails)
1856{
1857 if (symbol_conf.field_sep)
1858 print_footer_csv(total, bad, fails, symbol_conf.field_sep);
1859 else
1860 print_footer_stdio(total, bad, fails);
1861}
1862
a6eaf966 1863static void print_contention_result(struct lock_contention *con)
528b9cab
NK
1864{
1865 struct lock_stat *st;
6282a1f4 1866 int bad, total, printed;
528b9cab 1867
69c5c993
NK
1868 if (!quiet)
1869 print_header();
528b9cab 1870
6282a1f4 1871 bad = total = printed = 0;
6d499a6b 1872
528b9cab 1873 while ((st = pop_from_result())) {
6d499a6b 1874 total += use_bpf ? st->nr_contended : 1;
528b9cab
NK
1875 if (st->broken)
1876 bad++;
1877
b4a7eff9
NK
1878 if (!st->wait_time_total)
1879 continue;
1880
69c5c993 1881 print_lock_stat(con, st);
6282a1f4 1882
6282a1f4
NK
1883 if (++printed >= print_nr_entries)
1884 break;
528b9cab
NK
1885 }
1886
aae7e453
NK
1887 if (print_nr_entries) {
1888 /* update the total/bad stats */
1889 while ((st = pop_from_result())) {
1890 total += use_bpf ? st->nr_contended : 1;
1891 if (st->broken)
1892 bad++;
1893 }
1894 }
1895 /* some entries are collected but hidden by the callstack filter */
1896 total += con->nr_filtered;
1897
69c5c993 1898 print_footer(total, bad, &con->fails);
528b9cab
NK
1899}
1900
c4ac732a
YS
1901static bool force;
1902
375eb2be 1903static int __cmd_report(bool display_info)
9b5e350c 1904{
375eb2be 1905 int err = -EINVAL;
c75d98af 1906 struct perf_tool eops = {
30b331d2
NK
1907 .attr = perf_event__process_attr,
1908 .event_update = process_event_update,
c75d98af
ACM
1909 .sample = process_sample_event,
1910 .comm = perf_event__process_comm,
0d2997f7 1911 .mmap = perf_event__process_mmap,
f3b3614a 1912 .namespaces = perf_event__process_namespaces,
30b331d2 1913 .tracing_data = perf_event__process_tracing_data,
0a8cb85c 1914 .ordered_events = true,
c75d98af 1915 };
8ceb41d7 1916 struct perf_data data = {
2d4f2799
JO
1917 .path = input_name,
1918 .mode = PERF_DATA_MODE_READ,
1919 .force = force,
f5fc1412 1920 };
375eb2be 1921
2681bd85 1922 session = perf_session__new(&data, &eops);
6ef81c55 1923 if (IS_ERR(session)) {
33d6aef5 1924 pr_err("Initializing perf session failed\n");
6ef81c55 1925 return PTR_ERR(session);
33d6aef5 1926 }
9b5e350c 1927
d8d85ce8 1928 symbol_conf.allow_aliases = true;
0a7e6d1b 1929 symbol__init(&session->header.env);
6fd6c6b4 1930
30b331d2
NK
1931 if (!data.is_pipe) {
1932 if (!perf_session__has_traces(session, "lock record"))
1933 goto out_delete;
375eb2be 1934
30b331d2
NK
1935 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
1936 pr_err("Initializing perf session tracepoint handlers failed\n");
1937 goto out_delete;
1938 }
746f16ec 1939
30b331d2
NK
1940 if (perf_session__set_tracepoints_handlers(session, contention_tracepoints)) {
1941 pr_err("Initializing perf session tracepoint handlers failed\n");
1942 goto out_delete;
1943 }
3ae03f26
NK
1944 }
1945
79079f21 1946 if (setup_output_field(false, output_fields))
64999e44
NK
1947 goto out_delete;
1948
79079f21 1949 if (select_key(false))
375eb2be 1950 goto out_delete;
9b5e350c 1951
f9c695a2
NK
1952 if (show_thread_stats)
1953 aggr_mode = LOCK_AGGR_TASK;
1954
b7b61cbe 1955 err = perf_session__process_events(session);
375eb2be
DB
1956 if (err)
1957 goto out_delete;
9b5e350c 1958
9b5e350c 1959 setup_pager();
375eb2be
DB
1960 if (display_info) /* used for info subcommand */
1961 err = dump_info();
1962 else {
0d435bf8 1963 combine_result();
375eb2be
DB
1964 sort_result();
1965 print_result();
1966 }
33d6aef5 1967
375eb2be
DB
1968out_delete:
1969 perf_session__delete(session);
1970 return err;
9b5e350c
HM
1971}
1972
407b36f6
NK
1973static void sighandler(int sig __maybe_unused)
1974{
1975}
1976
3477f079
NK
1977static int check_lock_contention_options(const struct option *options,
1978 const char * const *usage)
1979
1980{
1981 if (show_thread_stats && show_lock_addrs) {
1982 pr_err("Cannot use thread and addr mode together\n");
1983 parse_options_usage(usage, options, "threads", 0);
1984 parse_options_usage(NULL, options, "lock-addr", 0);
1985 return -1;
1986 }
1987
1988 if (show_lock_owner && !use_bpf) {
1989 pr_err("Lock owners are available only with BPF\n");
1990 parse_options_usage(usage, options, "lock-owner", 0);
1991 parse_options_usage(NULL, options, "use-bpf", 0);
1992 return -1;
1993 }
1994
1995 if (show_lock_owner && show_lock_addrs) {
1996 pr_err("Cannot use owner and addr mode together\n");
1997 parse_options_usage(usage, options, "lock-owner", 0);
1998 parse_options_usage(NULL, options, "lock-addr", 0);
1999 return -1;
2000 }
2001
69c5c993
NK
2002 if (symbol_conf.field_sep) {
2003 if (strstr(symbol_conf.field_sep, ":") || /* part of type flags */
2004 strstr(symbol_conf.field_sep, "+") || /* part of caller offset */
2005 strstr(symbol_conf.field_sep, ".")) { /* can be in a symbol name */
2006 pr_err("Cannot use the separator that is already used\n");
2007 parse_options_usage(usage, options, "x", 1);
2008 return -1;
2009 }
2010 }
2011
3477f079
NK
2012 if (show_lock_owner)
2013 show_thread_stats = true;
2014
2015 return 0;
2016}
2017
6fda2405 2018static int __cmd_contention(int argc, const char **argv)
528b9cab
NK
2019{
2020 int err = -EINVAL;
2021 struct perf_tool eops = {
30b331d2
NK
2022 .attr = perf_event__process_attr,
2023 .event_update = process_event_update,
528b9cab
NK
2024 .sample = process_sample_event,
2025 .comm = perf_event__process_comm,
2026 .mmap = perf_event__process_mmap,
30b331d2 2027 .tracing_data = perf_event__process_tracing_data,
528b9cab
NK
2028 .ordered_events = true,
2029 };
2030 struct perf_data data = {
2031 .path = input_name,
2032 .mode = PERF_DATA_MODE_READ,
2033 .force = force,
2034 };
447ec4e5
NK
2035 struct lock_contention con = {
2036 .target = &target,
ceb13bfc 2037 .map_nr_entries = bpf_map_entries,
96532a83
NK
2038 .max_stack = max_stack_depth,
2039 .stack_skip = stack_skip,
529772c4 2040 .filters = &filters,
7b204399 2041 .save_callstack = needs_callstack(),
3477f079 2042 .owner = show_lock_owner,
d0c502e4 2043 .cgroups = RB_ROOT,
447ec4e5 2044 };
528b9cab 2045
eef4fee5
IR
2046 lockhash_table = calloc(LOCKHASH_SIZE, sizeof(*lockhash_table));
2047 if (!lockhash_table)
2048 return -ENOMEM;
2049
2050 con.result = &lockhash_table[0];
2051
407b36f6 2052 session = perf_session__new(use_bpf ? NULL : &data, &eops);
528b9cab
NK
2053 if (IS_ERR(session)) {
2054 pr_err("Initializing perf session failed\n");
eef4fee5 2055 err = PTR_ERR(session);
abaf1e03 2056 session = NULL;
eef4fee5 2057 goto out_delete;
528b9cab
NK
2058 }
2059
a6eaf966
NK
2060 con.machine = &session->machines.host;
2061
688d2e8d
NK
2062 con.aggr_mode = aggr_mode = show_thread_stats ? LOCK_AGGR_TASK :
2063 show_lock_addrs ? LOCK_AGGR_ADDR : LOCK_AGGR_CALLER;
2064
55e39185
NK
2065 if (con.aggr_mode == LOCK_AGGR_CALLER)
2066 con.save_callstack = true;
2067
d8d85ce8 2068 symbol_conf.allow_aliases = true;
528b9cab
NK
2069 symbol__init(&session->header.env);
2070
407b36f6 2071 if (use_bpf) {
6fda2405
NK
2072 err = target__validate(&target);
2073 if (err) {
2074 char errbuf[512];
2075
2076 target__strerror(&target, err, errbuf, 512);
2077 pr_err("%s\n", errbuf);
2078 goto out_delete;
407b36f6 2079 }
528b9cab 2080
407b36f6
NK
2081 signal(SIGINT, sighandler);
2082 signal(SIGCHLD, sighandler);
2083 signal(SIGTERM, sighandler);
6fda2405 2084
447ec4e5
NK
2085 con.evlist = evlist__new();
2086 if (con.evlist == NULL) {
6fda2405
NK
2087 err = -ENOMEM;
2088 goto out_delete;
2089 }
2090
447ec4e5 2091 err = evlist__create_maps(con.evlist, &target);
6fda2405
NK
2092 if (err < 0)
2093 goto out_delete;
2094
2095 if (argc) {
447ec4e5 2096 err = evlist__prepare_workload(con.evlist, &target,
6fda2405
NK
2097 argv, false, NULL);
2098 if (err < 0)
2099 goto out_delete;
2100 }
2101
447ec4e5 2102 if (lock_contention_prepare(&con) < 0) {
6fda2405
NK
2103 pr_err("lock contention BPF setup failed\n");
2104 goto out_delete;
2105 }
30b331d2 2106 } else if (!data.is_pipe) {
407b36f6
NK
2107 if (!perf_session__has_traces(session, "lock record"))
2108 goto out_delete;
528b9cab 2109
407b36f6
NK
2110 if (!evlist__find_evsel_by_str(session->evlist,
2111 "lock:contention_begin")) {
2112 pr_err("lock contention evsel not found\n");
2113 goto out_delete;
2114 }
2115
2116 if (perf_session__set_tracepoints_handlers(session,
2117 contention_tracepoints)) {
2118 pr_err("Initializing perf session tracepoint handlers failed\n");
2119 goto out_delete;
2120 }
528b9cab
NK
2121 }
2122
79079f21 2123 if (setup_output_field(true, output_fields))
528b9cab
NK
2124 goto out_delete;
2125
79079f21 2126 if (select_key(true))
528b9cab
NK
2127 goto out_delete;
2128
69c5c993
NK
2129 if (symbol_conf.field_sep) {
2130 int i;
2131 struct lock_key *keys = contention_keys;
2132
2133 /* do not align output in CSV format */
2134 for (i = 0; keys[i].name; i++)
2135 keys[i].len = 0;
2136 }
2137
407b36f6
NK
2138 if (use_bpf) {
2139 lock_contention_start();
6fda2405 2140 if (argc)
447ec4e5 2141 evlist__start_workload(con.evlist);
407b36f6
NK
2142
2143 /* wait for signal */
2144 pause();
2145
2146 lock_contention_stop();
447ec4e5 2147 lock_contention_read(&con);
407b36f6
NK
2148 } else {
2149 err = perf_session__process_events(session);
2150 if (err)
2151 goto out_delete;
2152 }
528b9cab
NK
2153
2154 setup_pager();
2155
2156 sort_contention_result();
a6eaf966 2157 print_contention_result(&con);
528b9cab
NK
2158
2159out_delete:
b4a7eff9 2160 lock_filter_finish();
447ec4e5 2161 evlist__delete(con.evlist);
d0c502e4 2162 lock_contention_finish(&con);
528b9cab 2163 perf_session__delete(session);
eef4fee5 2164 zfree(&lockhash_table);
528b9cab
NK
2165 return err;
2166}
2167
2168
9b5e350c
HM
2169static int __cmd_record(int argc, const char **argv)
2170{
c75d98af 2171 const char *record_args[] = {
2762c488 2172 "record", "-R", "-m", "1024", "-c", "1", "--synth", "task",
c75d98af 2173 };
0d2997f7
NK
2174 const char *callgraph_args[] = {
2175 "--call-graph", "fp," __stringify(CONTENTION_STACK_DEPTH),
2176 };
0a98c7fe 2177 unsigned int rec_argc, i, j, ret;
166a9764 2178 unsigned int nr_tracepoints;
0d2997f7 2179 unsigned int nr_callgraph_args = 0;
9b5e350c 2180 const char **rec_argv;
166a9764 2181 bool has_lock_stat = true;
9b5e350c 2182
d25dcba8 2183 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
746f16ec 2184 if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
166a9764
NK
2185 pr_debug("tracepoint %s is not enabled. "
2186 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
2187 lock_tracepoints[i].name);
2188 has_lock_stat = false;
2189 break;
2190 }
2191 }
2192
2193 if (has_lock_stat)
2194 goto setup_args;
2195
2196 for (i = 0; i < ARRAY_SIZE(contention_tracepoints); i++) {
2197 if (!is_valid_tracepoint(contention_tracepoints[i].name)) {
2198 pr_err("tracepoint %s is not enabled.\n",
2199 contention_tracepoints[i].name);
2200 return 1;
d25dcba8
DA
2201 }
2202 }
2203
0d2997f7
NK
2204 nr_callgraph_args = ARRAY_SIZE(callgraph_args);
2205
166a9764 2206setup_args:
0d2997f7 2207 rec_argc = ARRAY_SIZE(record_args) + nr_callgraph_args + argc - 1;
166a9764
NK
2208
2209 if (has_lock_stat)
2210 nr_tracepoints = ARRAY_SIZE(lock_tracepoints);
2211 else
2212 nr_tracepoints = ARRAY_SIZE(contention_tracepoints);
2213
d25dcba8 2214 /* factor of 2 is for -e in front of each tracepoint */
166a9764 2215 rec_argc += 2 * nr_tracepoints;
9b5e350c 2216
d25dcba8 2217 rec_argv = calloc(rec_argc + 1, sizeof(char *));
0a98c7fe 2218 if (!rec_argv)
ce47dc56
CS
2219 return -ENOMEM;
2220
9b5e350c
HM
2221 for (i = 0; i < ARRAY_SIZE(record_args); i++)
2222 rec_argv[i] = strdup(record_args[i]);
2223
166a9764
NK
2224 for (j = 0; j < nr_tracepoints; j++) {
2225 const char *ev_name;
2226
2227 if (has_lock_stat)
2228 ev_name = strdup(lock_tracepoints[j].name);
2229 else
2230 ev_name = strdup(contention_tracepoints[j].name);
2231
2232 if (!ev_name)
2233 return -ENOMEM;
2234
d25dcba8 2235 rec_argv[i++] = "-e";
166a9764 2236 rec_argv[i++] = ev_name;
d25dcba8
DA
2237 }
2238
0d2997f7
NK
2239 for (j = 0; j < nr_callgraph_args; j++, i++)
2240 rec_argv[i] = callgraph_args[j];
2241
9b5e350c
HM
2242 for (j = 1; j < (unsigned int)argc; j++, i++)
2243 rec_argv[i] = argv[j];
2244
2245 BUG_ON(i != rec_argc);
2246
b0ad8ea6 2247 ret = cmd_record(i, rec_argv);
0a98c7fe
DB
2248 free(rec_argv);
2249 return ret;
9b5e350c
HM
2250}
2251
ceb13bfc
NK
2252static int parse_map_entry(const struct option *opt, const char *str,
2253 int unset __maybe_unused)
2254{
2255 unsigned long *len = (unsigned long *)opt->value;
2256 unsigned long val;
2257 char *endptr;
2258
2259 errno = 0;
2260 val = strtoul(str, &endptr, 0);
2261 if (*endptr != '\0' || errno != 0) {
2262 pr_err("invalid BPF map length: %s\n", str);
2263 return -1;
2264 }
2265
2266 *len = val;
2267 return 0;
2268}
2269
0a277b62
NK
2270static int parse_max_stack(const struct option *opt, const char *str,
2271 int unset __maybe_unused)
2272{
2273 unsigned long *len = (unsigned long *)opt->value;
2274 long val;
2275 char *endptr;
2276
2277 errno = 0;
2278 val = strtol(str, &endptr, 0);
2279 if (*endptr != '\0' || errno != 0) {
2280 pr_err("invalid max stack depth: %s\n", str);
2281 return -1;
2282 }
2283
2284 if (val < 0 || val > sysctl__max_stack()) {
2285 pr_err("invalid max stack depth: %ld\n", val);
2286 return -1;
2287 }
2288
2289 *len = val;
2290 return 0;
2291}
2292
b4a7eff9
NK
2293static bool add_lock_type(unsigned int flags)
2294{
2295 unsigned int *tmp;
2296
2297 tmp = realloc(filters.types, (filters.nr_types + 1) * sizeof(*filters.types));
2298 if (tmp == NULL)
2299 return false;
2300
2301 tmp[filters.nr_types++] = flags;
2302 filters.types = tmp;
2303 return true;
2304}
2305
2306static int parse_lock_type(const struct option *opt __maybe_unused, const char *str,
2307 int unset __maybe_unused)
2308{
2309 char *s, *tmp, *tok;
2310 int ret = 0;
2311
2312 s = strdup(str);
2313 if (s == NULL)
2314 return -1;
2315
2316 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2317 unsigned int flags = get_type_flag(tok);
2318
2319 if (flags == -1U) {
d783ea8f
NK
2320 pr_err("Unknown lock flags: %s\n", tok);
2321 ret = -1;
2322 break;
b4a7eff9
NK
2323 }
2324
2325 if (!add_lock_type(flags)) {
2326 ret = -1;
2327 break;
2328 }
b4a7eff9
NK
2329 }
2330
2331 free(s);
2332 return ret;
2333}
2334
511e19b9
NK
2335static bool add_lock_addr(unsigned long addr)
2336{
2337 unsigned long *tmp;
2338
2339 tmp = realloc(filters.addrs, (filters.nr_addrs + 1) * sizeof(*filters.addrs));
2340 if (tmp == NULL) {
2341 pr_err("Memory allocation failure\n");
2342 return false;
2343 }
2344
2345 tmp[filters.nr_addrs++] = addr;
2346 filters.addrs = tmp;
2347 return true;
2348}
2349
2350static bool add_lock_sym(char *name)
2351{
2352 char **tmp;
2353 char *sym = strdup(name);
2354
2355 if (sym == NULL) {
2356 pr_err("Memory allocation failure\n");
2357 return false;
2358 }
2359
2360 tmp = realloc(filters.syms, (filters.nr_syms + 1) * sizeof(*filters.syms));
2361 if (tmp == NULL) {
2362 pr_err("Memory allocation failure\n");
2363 free(sym);
2364 return false;
2365 }
2366
2367 tmp[filters.nr_syms++] = sym;
2368 filters.syms = tmp;
2369 return true;
2370}
2371
2372static int parse_lock_addr(const struct option *opt __maybe_unused, const char *str,
2373 int unset __maybe_unused)
2374{
2375 char *s, *tmp, *tok;
2376 int ret = 0;
2377 u64 addr;
2378
2379 s = strdup(str);
2380 if (s == NULL)
2381 return -1;
2382
2383 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2384 char *end;
2385
2386 addr = strtoul(tok, &end, 16);
2387 if (*end == '\0') {
2388 if (!add_lock_addr(addr)) {
2389 ret = -1;
2390 break;
2391 }
2392 continue;
2393 }
2394
2395 /*
2396 * At this moment, we don't have kernel symbols. Save the symbols
2397 * in a separate list and resolve them to addresses later.
2398 */
2399 if (!add_lock_sym(tok)) {
2400 ret = -1;
2401 break;
2402 }
2403 }
2404
2405 free(s);
2406 return ret;
2407}
2408
7b204399
NK
2409static int parse_call_stack(const struct option *opt __maybe_unused, const char *str,
2410 int unset __maybe_unused)
2411{
2412 char *s, *tmp, *tok;
2413 int ret = 0;
2414
2415 s = strdup(str);
2416 if (s == NULL)
2417 return -1;
2418
2419 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2420 struct callstack_filter *entry;
2421
2422 entry = malloc(sizeof(*entry) + strlen(tok) + 1);
2423 if (entry == NULL) {
2424 pr_err("Memory allocation failure\n");
2425 return -1;
2426 }
2427
2428 strcpy(entry->name, tok);
2429 list_add_tail(&entry->list, &callstack_filters);
2430 }
2431
2432 free(s);
2433 return ret;
2434}
2435
f6027053
NK
2436static int parse_output(const struct option *opt __maybe_unused, const char *str,
2437 int unset __maybe_unused)
2438{
2439 const char **name = (const char **)opt->value;
2440
2441 if (str == NULL)
2442 return -1;
2443
2444 lock_output = fopen(str, "w");
2445 if (lock_output == NULL) {
2446 pr_err("Cannot open %s\n", str);
2447 return -1;
2448 }
2449
2450 *name = str;
2451 return 0;
2452}
2453
b0ad8ea6 2454int cmd_lock(int argc, const char **argv)
9b5e350c 2455{
249eed53
CD
2456 const struct option lock_options[] = {
2457 OPT_STRING('i', "input", &input_name, "file", "input file name"),
f6027053 2458 OPT_CALLBACK(0, "output", &output_name, "file", "output file name", parse_output),
249eed53
CD
2459 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
2460 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
b40e3612 2461 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
309e133d
NK
2462 OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
2463 "file", "vmlinux pathname"),
2464 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
2465 "file", "kallsyms pathname"),
a527c2c1 2466 OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any warnings or messages"),
249eed53
CD
2467 OPT_END()
2468 };
2469
c75d98af
ACM
2470 const struct option info_options[] = {
2471 OPT_BOOLEAN('t', "threads", &info_threads,
2472 "dump thread list in perf.data"),
2473 OPT_BOOLEAN('m', "map", &info_map,
2474 "map of lock instances (address:name table)"),
249eed53 2475 OPT_PARENT(lock_options)
c75d98af 2476 };
249eed53 2477
c75d98af
ACM
2478 const struct option report_options[] = {
2479 OPT_STRING('k', "key", &sort_key, "acquired",
f37376cd 2480 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
4bd9cab5
NK
2481 OPT_STRING('F', "field", &output_fields, NULL,
2482 "output fields (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
c75d98af 2483 /* TODO: type */
0d435bf8
NK
2484 OPT_BOOLEAN('c', "combine-locks", &combine_locks,
2485 "combine locks in the same class"),
7c3bcbdf
NK
2486 OPT_BOOLEAN('t', "threads", &show_thread_stats,
2487 "show per-thread lock stats"),
6282a1f4 2488 OPT_INTEGER('E', "entries", &print_nr_entries, "display this many functions"),
249eed53 2489 OPT_PARENT(lock_options)
c75d98af 2490 };
249eed53 2491
407b36f6 2492 struct option contention_options[] = {
79079f21
NK
2493 OPT_STRING('k', "key", &sort_key, "wait_total",
2494 "key for sorting (contended / wait_total / wait_max / wait_min / avg_wait)"),
2495 OPT_STRING('F', "field", &output_fields, "contended,wait_total,wait_max,avg_wait",
2496 "output fields (contended / wait_total / wait_max / wait_min / avg_wait)"),
1ab55323
NK
2497 OPT_BOOLEAN('t', "threads", &show_thread_stats,
2498 "show per-thread lock stats"),
407b36f6 2499 OPT_BOOLEAN('b', "use-bpf", &use_bpf, "use BPF program to collect lock contention stats"),
6fda2405
NK
2500 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
2501 "System-wide collection from all CPUs"),
2502 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
2503 "List of cpus to monitor"),
2504 OPT_STRING('p', "pid", &target.pid, "pid",
2505 "Trace on existing process id"),
6fda2405
NK
2506 OPT_STRING(0, "tid", &target.tid, "tid",
2507 "Trace on existing thread id (exclusive to --pid)"),
84b91920 2508 OPT_CALLBACK('M', "map-nr-entries", &bpf_map_entries, "num",
ceb13bfc 2509 "Max number of BPF map entries", parse_map_entry),
0a277b62 2510 OPT_CALLBACK(0, "max-stack", &max_stack_depth, "num",
0f2418fd 2511 "Set the maximum stack depth when collecting lock contention, "
0a277b62 2512 "Default: " __stringify(CONTENTION_STACK_DEPTH), parse_max_stack),
96532a83
NK
2513 OPT_INTEGER(0, "stack-skip", &stack_skip,
2514 "Set the number of stack depth to skip when finding a lock caller, "
2515 "Default: " __stringify(CONTENTION_STACK_SKIP)),
6282a1f4 2516 OPT_INTEGER('E', "entries", &print_nr_entries, "display this many functions"),
688d2e8d 2517 OPT_BOOLEAN('l', "lock-addr", &show_lock_addrs, "show lock stats by address"),
b4a7eff9
NK
2518 OPT_CALLBACK('Y', "type-filter", NULL, "FLAGS",
2519 "Filter specific type of locks", parse_lock_type),
511e19b9
NK
2520 OPT_CALLBACK('L', "lock-filter", NULL, "ADDRS/NAMES",
2521 "Filter specific address/symbol of locks", parse_lock_addr),
7b204399
NK
2522 OPT_CALLBACK('S', "callstack-filter", NULL, "NAMES",
2523 "Filter specific function in the callstack", parse_call_stack),
3477f079 2524 OPT_BOOLEAN('o', "lock-owner", &show_lock_owner, "show lock owners instead of waiters"),
69c5c993
NK
2525 OPT_STRING_NOEMPTY('x', "field-separator", &symbol_conf.field_sep, "separator",
2526 "print result in CSV format with custom separator"),
528b9cab
NK
2527 OPT_PARENT(lock_options)
2528 };
2529
c75d98af
ACM
2530 const char * const info_usage[] = {
2531 "perf lock info [<options>]",
2532 NULL
2533 };
a2368c31 2534 const char *const lock_subcommands[] = { "record", "report", "script",
3705a6ef 2535 "info", "contention", NULL };
a2368c31
RR
2536 const char *lock_usage[] = {
2537 NULL,
c75d98af
ACM
2538 NULL
2539 };
2540 const char * const report_usage[] = {
2541 "perf lock report [<options>]",
2542 NULL
2543 };
528b9cab
NK
2544 const char * const contention_usage[] = {
2545 "perf lock contention [<options>]",
2546 NULL
2547 };
9b5e350c 2548 unsigned int i;
33d6aef5 2549 int rc = 0;
9b5e350c 2550
eef4fee5
IR
2551 lockhash_table = calloc(LOCKHASH_SIZE, sizeof(*lockhash_table));
2552 if (!lockhash_table)
2553 return -ENOMEM;
2554
9b5e350c 2555 for (i = 0; i < LOCKHASH_SIZE; i++)
7672d00a 2556 INIT_HLIST_HEAD(lockhash_table + i);
9b5e350c 2557
f6027053 2558 lock_output = stderr;
a2368c31
RR
2559 argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
2560 lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
9b5e350c
HM
2561 if (!argc)
2562 usage_with_options(lock_usage, lock_options);
2563
ae0f4eb3 2564 if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
9b5e350c 2565 return __cmd_record(argc, argv);
ae0f4eb3 2566 } else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) {
59f411b6 2567 trace_handler = &report_lock_ops;
9b5e350c
HM
2568 if (argc) {
2569 argc = parse_options(argc, argv,
59f411b6 2570 report_options, report_usage, 0);
9b5e350c 2571 if (argc)
59f411b6 2572 usage_with_options(report_usage, report_options);
9b5e350c 2573 }
375eb2be 2574 rc = __cmd_report(false);
133dc4c3
IM
2575 } else if (!strcmp(argv[0], "script")) {
2576 /* Aliased to 'perf script' */
eef4fee5 2577 rc = cmd_script(argc, argv);
26242d85
HM
2578 } else if (!strcmp(argv[0], "info")) {
2579 if (argc) {
2580 argc = parse_options(argc, argv,
2581 info_options, info_usage, 0);
2582 if (argc)
2583 usage_with_options(info_usage, info_options);
2584 }
59f411b6
IM
2585 /* recycling report_lock_ops */
2586 trace_handler = &report_lock_ops;
375eb2be 2587 rc = __cmd_report(true);
528b9cab
NK
2588 } else if (strlen(argv[0]) > 2 && strstarts("contention", argv[0])) {
2589 trace_handler = &contention_lock_ops;
79079f21
NK
2590 sort_key = "wait_total";
2591 output_fields = "contended,wait_total,wait_max,avg_wait";
2592
407b36f6
NK
2593#ifndef HAVE_BPF_SKEL
2594 set_option_nobuild(contention_options, 'b', "use-bpf",
9a2d5178 2595 "no BUILD_BPF_SKEL=1", false);
407b36f6 2596#endif
528b9cab
NK
2597 if (argc) {
2598 argc = parse_options(argc, argv, contention_options,
2599 contention_usage, 0);
528b9cab 2600 }
688d2e8d 2601
3477f079
NK
2602 if (check_lock_contention_options(contention_options,
2603 contention_usage) < 0)
688d2e8d 2604 return -1;
688d2e8d 2605
6fda2405 2606 rc = __cmd_contention(argc, argv);
9b5e350c
HM
2607 } else {
2608 usage_with_options(lock_usage, lock_options);
2609 }
2610
eef4fee5 2611 zfree(&lockhash_table);
33d6aef5 2612 return rc;
9b5e350c 2613}