1 // SPDX-License-Identifier: GPL-2.0
7 #include "util/evlist.h" // for struct evsel_str_handler
8 #include "util/evsel.h"
9 #include "util/symbol.h"
10 #include "util/thread.h"
11 #include "util/header.h"
12 #include "util/target.h"
13 #include "util/callchain.h"
14 #include "util/lock-contention.h"
15 #include "util/bpf_skel/lock_data.h"
17 #include <subcmd/pager.h>
18 #include <subcmd/parse-options.h>
19 #include "util/trace-event.h"
20 #include "util/tracepoint.h"
22 #include "util/debug.h"
23 #include "util/session.h"
24 #include "util/tool.h"
25 #include "util/data.h"
26 #include "util/string2.h"
28 #include "util/util.h"
30 #include <sys/types.h>
31 #include <sys/prctl.h>
32 #include <semaphore.h>
37 #include <linux/list.h>
38 #include <linux/hash.h>
39 #include <linux/kernel.h>
40 #include <linux/zalloc.h>
41 #include <linux/err.h>
42 #include <linux/stringify.h>
44 static struct perf_session *session;
45 static struct target target;
47 /* based on kernel/lockdep.c */
48 #define LOCKHASH_BITS 12
49 #define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
51 static struct hlist_head lockhash_table[LOCKHASH_SIZE];
53 #define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
54 #define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
56 static struct rb_root thread_stats;
58 static bool combine_locks;
59 static bool show_thread_stats;
60 static bool show_lock_addrs;
62 static unsigned long bpf_map_entries = 10240;
63 static int max_stack_depth = CONTENTION_STACK_DEPTH;
64 static int stack_skip = CONTENTION_STACK_SKIP;
65 static int print_nr_entries = INT_MAX / 2;
66 static LIST_HEAD(callstack_filters);
68 struct callstack_filter {
69 struct list_head list;
73 static struct lock_filter filters;
75 static enum lock_aggr_mode aggr_mode = LOCK_AGGR_ADDR;
77 static bool needs_callstack(void)
79 return verbose > 0 || !list_empty(&callstack_filters);
82 static struct thread_stat *thread_stat_find(u32 tid)
85 struct thread_stat *st;
87 node = thread_stats.rb_node;
89 st = container_of(node, struct thread_stat, rb);
92 else if (tid < st->tid)
95 node = node->rb_right;
101 static void thread_stat_insert(struct thread_stat *new)
103 struct rb_node **rb = &thread_stats.rb_node;
104 struct rb_node *parent = NULL;
105 struct thread_stat *p;
108 p = container_of(*rb, struct thread_stat, rb);
111 if (new->tid < p->tid)
112 rb = &(*rb)->rb_left;
113 else if (new->tid > p->tid)
114 rb = &(*rb)->rb_right;
116 BUG_ON("inserting invalid thread_stat\n");
119 rb_link_node(&new->rb, parent, rb);
120 rb_insert_color(&new->rb, &thread_stats);
123 static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
125 struct thread_stat *st;
127 st = thread_stat_find(tid);
131 st = zalloc(sizeof(struct thread_stat));
133 pr_err("memory allocation failed\n");
138 INIT_LIST_HEAD(&st->seq_list);
140 thread_stat_insert(st);
145 static struct thread_stat *thread_stat_findnew_first(u32 tid);
146 static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
147 thread_stat_findnew_first;
149 static struct thread_stat *thread_stat_findnew_first(u32 tid)
151 struct thread_stat *st;
153 st = zalloc(sizeof(struct thread_stat));
155 pr_err("memory allocation failed\n");
159 INIT_LIST_HEAD(&st->seq_list);
161 rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
162 rb_insert_color(&st->rb, &thread_stats);
164 thread_stat_findnew = thread_stat_findnew_after_first;
168 /* build simple key function one is bigger than two */
169 #define SINGLE_KEY(member) \
170 static int lock_stat_key_ ## member(struct lock_stat *one, \
171 struct lock_stat *two) \
173 return one->member > two->member; \
176 SINGLE_KEY(nr_acquired)
177 SINGLE_KEY(nr_contended)
178 SINGLE_KEY(avg_wait_time)
179 SINGLE_KEY(wait_time_total)
180 SINGLE_KEY(wait_time_max)
182 static int lock_stat_key_wait_time_min(struct lock_stat *one,
183 struct lock_stat *two)
185 u64 s1 = one->wait_time_min;
186 u64 s2 = two->wait_time_min;
187 if (s1 == ULLONG_MAX)
189 if (s2 == ULLONG_MAX)
196 * name: the value for specify by user
197 * this should be simpler than raw name of member
198 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
201 /* header: the string printed on the header line */
203 /* len: the printing width of the field */
205 /* key: a pointer to function to compare two lock stats for sorting */
206 int (*key)(struct lock_stat*, struct lock_stat*);
207 /* print: a pointer to function to print a given lock stats */
208 void (*print)(struct lock_key*, struct lock_stat*);
209 /* list: list entry to link this */
210 struct list_head list;
213 static void lock_stat_key_print_time(unsigned long long nsec, int len)
215 static const struct {
219 { 1e9 * 3600, "h " },
227 for (int i = 0; table[i].unit; i++) {
228 if (nsec < table[i].base)
231 pr_info("%*.2f %s", len - 3, nsec / table[i].base, table[i].unit);
235 pr_info("%*llu %s", len - 3, nsec, "ns");
238 #define PRINT_KEY(member) \
239 static void lock_stat_key_print_ ## member(struct lock_key *key, \
240 struct lock_stat *ls) \
242 pr_info("%*llu", key->len, (unsigned long long)ls->member); \
245 #define PRINT_TIME(member) \
246 static void lock_stat_key_print_ ## member(struct lock_key *key, \
247 struct lock_stat *ls) \
249 lock_stat_key_print_time((unsigned long long)ls->member, key->len); \
252 PRINT_KEY(nr_acquired)
253 PRINT_KEY(nr_contended)
254 PRINT_TIME(avg_wait_time)
255 PRINT_TIME(wait_time_total)
256 PRINT_TIME(wait_time_max)
258 static void lock_stat_key_print_wait_time_min(struct lock_key *key,
259 struct lock_stat *ls)
261 u64 wait_time = ls->wait_time_min;
263 if (wait_time == ULLONG_MAX)
266 lock_stat_key_print_time(wait_time, key->len);
270 static const char *sort_key = "acquired";
272 static int (*compare)(struct lock_stat *, struct lock_stat *);
274 static struct rb_root sorted; /* place to store intermediate data */
275 static struct rb_root result; /* place to store sorted data */
277 static LIST_HEAD(lock_keys);
278 static const char *output_fields;
280 #define DEF_KEY_LOCK(name, header, fn_suffix, len) \
281 { #name, header, len, lock_stat_key_ ## fn_suffix, lock_stat_key_print_ ## fn_suffix, {} }
282 static struct lock_key report_keys[] = {
283 DEF_KEY_LOCK(acquired, "acquired", nr_acquired, 10),
284 DEF_KEY_LOCK(contended, "contended", nr_contended, 10),
285 DEF_KEY_LOCK(avg_wait, "avg wait", avg_wait_time, 12),
286 DEF_KEY_LOCK(wait_total, "total wait", wait_time_total, 12),
287 DEF_KEY_LOCK(wait_max, "max wait", wait_time_max, 12),
288 DEF_KEY_LOCK(wait_min, "min wait", wait_time_min, 12),
290 /* extra comparisons much complicated should be here */
294 static struct lock_key contention_keys[] = {
295 DEF_KEY_LOCK(contended, "contended", nr_contended, 10),
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),
299 DEF_KEY_LOCK(avg_wait, "avg wait", avg_wait_time, 12),
301 /* extra comparisons much complicated should be here */
305 static int select_key(bool contention)
308 struct lock_key *keys = report_keys;
311 keys = contention_keys;
313 for (i = 0; keys[i].name; i++) {
314 if (!strcmp(keys[i].name, sort_key)) {
315 compare = keys[i].key;
317 /* selected key should be in the output fields */
318 if (list_empty(&keys[i].list))
319 list_add_tail(&keys[i].list, &lock_keys);
325 pr_err("Unknown compare key: %s\n", sort_key);
329 static int add_output_field(bool contention, char *name)
332 struct lock_key *keys = report_keys;
335 keys = contention_keys;
337 for (i = 0; keys[i].name; i++) {
338 if (strcmp(keys[i].name, name))
341 /* prevent double link */
342 if (list_empty(&keys[i].list))
343 list_add_tail(&keys[i].list, &lock_keys);
348 pr_err("Unknown output field: %s\n", name);
352 static int setup_output_field(bool contention, const char *str)
354 char *tok, *tmp, *orig;
356 struct lock_key *keys = report_keys;
359 keys = contention_keys;
361 /* no output field given: use all of them */
363 for (i = 0; keys[i].name; i++)
364 list_add_tail(&keys[i].list, &lock_keys);
368 for (i = 0; keys[i].name; i++)
369 INIT_LIST_HEAD(&keys[i].list);
371 orig = tmp = strdup(str);
375 while ((tok = strsep(&tmp, ",")) != NULL){
376 ret = add_output_field(contention, tok);
385 static void combine_lock_stats(struct lock_stat *st)
387 struct rb_node **rb = &sorted.rb_node;
388 struct rb_node *parent = NULL;
393 p = container_of(*rb, struct lock_stat, rb);
396 if (st->name && p->name)
397 ret = strcmp(st->name, p->name);
399 ret = !!st->name - !!p->name;
402 p->nr_acquired += st->nr_acquired;
403 p->nr_contended += st->nr_contended;
404 p->wait_time_total += st->wait_time_total;
407 p->avg_wait_time = p->wait_time_total / p->nr_contended;
409 if (p->wait_time_min > st->wait_time_min)
410 p->wait_time_min = st->wait_time_min;
411 if (p->wait_time_max < st->wait_time_max)
412 p->wait_time_max = st->wait_time_max;
414 p->broken |= st->broken;
420 rb = &(*rb)->rb_left;
422 rb = &(*rb)->rb_right;
425 rb_link_node(&st->rb, parent, rb);
426 rb_insert_color(&st->rb, &sorted);
429 static void insert_to_result(struct lock_stat *st,
430 int (*bigger)(struct lock_stat *, struct lock_stat *))
432 struct rb_node **rb = &result.rb_node;
433 struct rb_node *parent = NULL;
436 if (combine_locks && st->combined)
440 p = container_of(*rb, struct lock_stat, rb);
444 rb = &(*rb)->rb_left;
446 rb = &(*rb)->rb_right;
449 rb_link_node(&st->rb, parent, rb);
450 rb_insert_color(&st->rb, &result);
453 /* returns left most element of result, and erase it */
454 static struct lock_stat *pop_from_result(void)
456 struct rb_node *node = result.rb_node;
461 while (node->rb_left)
462 node = node->rb_left;
464 rb_erase(node, &result);
465 return container_of(node, struct lock_stat, rb);
468 struct lock_stat *lock_stat_find(u64 addr)
470 struct hlist_head *entry = lockhashentry(addr);
471 struct lock_stat *ret;
473 hlist_for_each_entry(ret, entry, hash_entry) {
474 if (ret->addr == addr)
480 struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
482 struct hlist_head *entry = lockhashentry(addr);
483 struct lock_stat *ret, *new;
485 hlist_for_each_entry(ret, entry, hash_entry) {
486 if (ret->addr == addr)
490 new = zalloc(sizeof(struct lock_stat));
495 new->name = strdup(name);
502 new->wait_time_min = ULLONG_MAX;
504 hlist_add_head(&new->hash_entry, entry);
508 pr_err("memory allocation failed\n");
512 bool match_callstack_filter(struct machine *machine, u64 *callstack)
518 if (list_empty(&callstack_filters))
521 for (int i = 0; i < max_stack_depth; i++) {
522 struct callstack_filter *filter;
524 if (!callstack || !callstack[i])
528 sym = machine__find_kernel_symbol(machine, ip, &kmap);
532 list_for_each_entry(filter, &callstack_filters, list) {
533 if (strstr(sym->name, filter->name))
540 struct trace_lock_handler {
541 /* it's used on CONFIG_LOCKDEP */
542 int (*acquire_event)(struct evsel *evsel,
543 struct perf_sample *sample);
545 /* it's used on CONFIG_LOCKDEP && CONFIG_LOCK_STAT */
546 int (*acquired_event)(struct evsel *evsel,
547 struct perf_sample *sample);
549 /* it's used on CONFIG_LOCKDEP && CONFIG_LOCK_STAT */
550 int (*contended_event)(struct evsel *evsel,
551 struct perf_sample *sample);
553 /* it's used on CONFIG_LOCKDEP */
554 int (*release_event)(struct evsel *evsel,
555 struct perf_sample *sample);
557 /* it's used when CONFIG_LOCKDEP is off */
558 int (*contention_begin_event)(struct evsel *evsel,
559 struct perf_sample *sample);
561 /* it's used when CONFIG_LOCKDEP is off */
562 int (*contention_end_event)(struct evsel *evsel,
563 struct perf_sample *sample);
566 static struct lock_seq_stat *get_seq(struct thread_stat *ts, u64 addr)
568 struct lock_seq_stat *seq;
570 list_for_each_entry(seq, &ts->seq_list, list) {
571 if (seq->addr == addr)
575 seq = zalloc(sizeof(struct lock_seq_stat));
577 pr_err("memory allocation failed\n");
580 seq->state = SEQ_STATE_UNINITIALIZED;
583 list_add(&seq->list, &ts->seq_list);
595 static int bad_hist[BROKEN_MAX];
602 static int get_key_by_aggr_mode_simple(u64 *key, u64 addr, u32 tid)
611 case LOCK_AGGR_CALLER:
613 pr_err("Invalid aggregation mode: %d\n", aggr_mode);
619 static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample);
621 static int get_key_by_aggr_mode(u64 *key, u64 addr, struct evsel *evsel,
622 struct perf_sample *sample)
624 if (aggr_mode == LOCK_AGGR_CALLER) {
625 *key = callchain_id(evsel, sample);
628 return get_key_by_aggr_mode_simple(key, addr, sample->tid);
631 static int report_lock_acquire_event(struct evsel *evsel,
632 struct perf_sample *sample)
634 struct lock_stat *ls;
635 struct thread_stat *ts;
636 struct lock_seq_stat *seq;
637 const char *name = evsel__strval(evsel, sample, "name");
638 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
639 int flag = evsel__intval(evsel, sample, "flags");
643 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
647 ls = lock_stat_findnew(key, name, 0);
651 ts = thread_stat_findnew(sample->tid);
655 seq = get_seq(ts, addr);
659 switch (seq->state) {
660 case SEQ_STATE_UNINITIALIZED:
661 case SEQ_STATE_RELEASED:
663 seq->state = SEQ_STATE_ACQUIRING;
667 if (flag & READ_LOCK)
669 seq->state = SEQ_STATE_READ_ACQUIRED;
674 case SEQ_STATE_READ_ACQUIRED:
675 if (flag & READ_LOCK) {
683 case SEQ_STATE_ACQUIRED:
684 case SEQ_STATE_ACQUIRING:
685 case SEQ_STATE_CONTENDED:
687 /* broken lock sequence */
690 bad_hist[BROKEN_ACQUIRE]++;
692 list_del_init(&seq->list);
696 BUG_ON("Unknown state of lock sequence found!\n");
701 seq->prev_event_time = sample->time;
706 static int report_lock_acquired_event(struct evsel *evsel,
707 struct perf_sample *sample)
709 struct lock_stat *ls;
710 struct thread_stat *ts;
711 struct lock_seq_stat *seq;
713 const char *name = evsel__strval(evsel, sample, "name");
714 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
718 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
722 ls = lock_stat_findnew(key, name, 0);
726 ts = thread_stat_findnew(sample->tid);
730 seq = get_seq(ts, addr);
734 switch (seq->state) {
735 case SEQ_STATE_UNINITIALIZED:
736 /* orphan event, do nothing */
738 case SEQ_STATE_ACQUIRING:
740 case SEQ_STATE_CONTENDED:
741 contended_term = sample->time - seq->prev_event_time;
742 ls->wait_time_total += contended_term;
743 if (contended_term < ls->wait_time_min)
744 ls->wait_time_min = contended_term;
745 if (ls->wait_time_max < contended_term)
746 ls->wait_time_max = contended_term;
748 case SEQ_STATE_RELEASED:
749 case SEQ_STATE_ACQUIRED:
750 case SEQ_STATE_READ_ACQUIRED:
751 /* broken lock sequence */
754 bad_hist[BROKEN_ACQUIRED]++;
756 list_del_init(&seq->list);
760 BUG_ON("Unknown state of lock sequence found!\n");
764 seq->state = SEQ_STATE_ACQUIRED;
766 ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
767 seq->prev_event_time = sample->time;
772 static int report_lock_contended_event(struct evsel *evsel,
773 struct perf_sample *sample)
775 struct lock_stat *ls;
776 struct thread_stat *ts;
777 struct lock_seq_stat *seq;
778 const char *name = evsel__strval(evsel, sample, "name");
779 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
783 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
787 ls = lock_stat_findnew(key, name, 0);
791 ts = thread_stat_findnew(sample->tid);
795 seq = get_seq(ts, addr);
799 switch (seq->state) {
800 case SEQ_STATE_UNINITIALIZED:
801 /* orphan event, do nothing */
803 case SEQ_STATE_ACQUIRING:
805 case SEQ_STATE_RELEASED:
806 case SEQ_STATE_ACQUIRED:
807 case SEQ_STATE_READ_ACQUIRED:
808 case SEQ_STATE_CONTENDED:
809 /* broken lock sequence */
812 bad_hist[BROKEN_CONTENDED]++;
814 list_del_init(&seq->list);
818 BUG_ON("Unknown state of lock sequence found!\n");
822 seq->state = SEQ_STATE_CONTENDED;
824 ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
825 seq->prev_event_time = sample->time;
830 static int report_lock_release_event(struct evsel *evsel,
831 struct perf_sample *sample)
833 struct lock_stat *ls;
834 struct thread_stat *ts;
835 struct lock_seq_stat *seq;
836 const char *name = evsel__strval(evsel, sample, "name");
837 u64 addr = evsel__intval(evsel, sample, "lockdep_addr");
841 ret = get_key_by_aggr_mode_simple(&key, addr, sample->tid);
845 ls = lock_stat_findnew(key, name, 0);
849 ts = thread_stat_findnew(sample->tid);
853 seq = get_seq(ts, addr);
857 switch (seq->state) {
858 case SEQ_STATE_UNINITIALIZED:
860 case SEQ_STATE_ACQUIRED:
862 case SEQ_STATE_READ_ACQUIRED:
864 BUG_ON(seq->read_count < 0);
865 if (seq->read_count) {
870 case SEQ_STATE_ACQUIRING:
871 case SEQ_STATE_CONTENDED:
872 case SEQ_STATE_RELEASED:
873 /* broken lock sequence */
876 bad_hist[BROKEN_RELEASE]++;
880 BUG_ON("Unknown state of lock sequence found!\n");
886 list_del_init(&seq->list);
892 static int get_symbol_name_offset(struct map *map, struct symbol *sym, u64 ip,
897 if (map == NULL || sym == NULL) {
902 offset = map->map_ip(map, ip) - sym->start;
905 return scnprintf(buf, size, "%s+%#lx", sym->name, offset);
907 return strlcpy(buf, sym->name, size);
909 static int lock_contention_caller(struct evsel *evsel, struct perf_sample *sample,
912 struct thread *thread;
913 struct callchain_cursor *cursor = &callchain_cursor;
914 struct machine *machine = &session->machines.host;
919 /* lock names will be replaced to task name later */
920 if (show_thread_stats)
923 thread = machine__findnew_thread(machine, -1, sample->pid);
927 /* use caller function name from the callchain */
928 ret = thread__resolve_callchain(thread, cursor, evsel, sample,
929 NULL, NULL, max_stack_depth);
935 callchain_cursor_commit(cursor);
939 struct callchain_cursor_node *node;
941 node = callchain_cursor_current(cursor);
945 /* skip first few entries - for lock functions */
946 if (++skip <= stack_skip)
950 if (sym && !machine__is_lock_function(machine, node->ip)) {
951 get_symbol_name_offset(node->ms.map, sym, node->ip,
957 callchain_cursor_advance(cursor);
962 static u64 callchain_id(struct evsel *evsel, struct perf_sample *sample)
964 struct callchain_cursor *cursor = &callchain_cursor;
965 struct machine *machine = &session->machines.host;
966 struct thread *thread;
971 thread = machine__findnew_thread(machine, -1, sample->pid);
975 /* use caller function name from the callchain */
976 ret = thread__resolve_callchain(thread, cursor, evsel, sample,
977 NULL, NULL, max_stack_depth);
983 callchain_cursor_commit(cursor);
986 struct callchain_cursor_node *node;
988 node = callchain_cursor_current(cursor);
992 /* skip first few entries - for lock functions */
993 if (++skip <= stack_skip)
996 if (node->ms.sym && machine__is_lock_function(machine, node->ip))
999 hash ^= hash_long((unsigned long)node->ip, 64);
1002 callchain_cursor_advance(cursor);
1007 static u64 *get_callstack(struct perf_sample *sample, int max_stack)
1013 callstack = calloc(max_stack, sizeof(*callstack));
1014 if (callstack == NULL)
1017 for (i = 0, c = 0; i < sample->callchain->nr && c < max_stack; i++) {
1018 u64 ip = sample->callchain->ips[i];
1020 if (ip >= PERF_CONTEXT_MAX)
1023 callstack[c++] = ip;
1028 static int report_lock_contention_begin_event(struct evsel *evsel,
1029 struct perf_sample *sample)
1031 struct lock_stat *ls;
1032 struct thread_stat *ts;
1033 struct lock_seq_stat *seq;
1034 u64 addr = evsel__intval(evsel, sample, "lock_addr");
1035 unsigned int flags = evsel__intval(evsel, sample, "flags");
1038 static bool kmap_loaded;
1039 struct machine *machine = &session->machines.host;
1043 ret = get_key_by_aggr_mode(&key, addr, evsel, sample);
1048 unsigned long *addrs;
1050 /* make sure it loads the kernel map to find lock symbols */
1051 map__load(machine__kernel_map(machine));
1054 /* convert (kernel) symbols to addresses */
1055 for (i = 0; i < filters.nr_syms; i++) {
1056 sym = machine__find_kernel_symbol_by_name(machine,
1060 pr_warning("ignore unknown symbol: %s\n",
1065 addrs = realloc(filters.addrs,
1066 (filters.nr_addrs + 1) * sizeof(*addrs));
1067 if (addrs == NULL) {
1068 pr_warning("memory allocation failure\n");
1072 addrs[filters.nr_addrs++] = kmap->unmap_ip(kmap, sym->start);
1073 filters.addrs = addrs;
1077 ls = lock_stat_find(key);
1080 const char *name = "";
1082 switch (aggr_mode) {
1083 case LOCK_AGGR_ADDR:
1084 sym = machine__find_kernel_symbol(machine, key, &kmap);
1088 case LOCK_AGGR_CALLER:
1090 if (lock_contention_caller(evsel, sample, buf, sizeof(buf)) < 0)
1093 case LOCK_AGGR_TASK:
1098 ls = lock_stat_findnew(key, name, flags);
1103 if (filters.nr_types) {
1106 for (i = 0; i < filters.nr_types; i++) {
1107 if (flags == filters.types[i]) {
1117 if (filters.nr_addrs) {
1120 for (i = 0; i < filters.nr_addrs; i++) {
1121 if (addr == filters.addrs[i]) {
1131 if (needs_callstack()) {
1132 u64 *callstack = get_callstack(sample, max_stack_depth);
1133 if (callstack == NULL)
1136 if (!match_callstack_filter(machine, callstack)) {
1141 if (ls->callstack == NULL)
1142 ls->callstack = callstack;
1147 ts = thread_stat_findnew(sample->tid);
1151 seq = get_seq(ts, addr);
1155 switch (seq->state) {
1156 case SEQ_STATE_UNINITIALIZED:
1157 case SEQ_STATE_ACQUIRED:
1159 case SEQ_STATE_CONTENDED:
1161 * It can have nested contention begin with mutex spinning,
1162 * then we would use the original contention begin event and
1163 * ignore the second one.
1166 case SEQ_STATE_ACQUIRING:
1167 case SEQ_STATE_READ_ACQUIRED:
1168 case SEQ_STATE_RELEASED:
1169 /* broken lock sequence */
1172 bad_hist[BROKEN_CONTENDED]++;
1174 list_del_init(&seq->list);
1178 BUG_ON("Unknown state of lock sequence found!\n");
1182 if (seq->state != SEQ_STATE_CONTENDED) {
1183 seq->state = SEQ_STATE_CONTENDED;
1184 seq->prev_event_time = sample->time;
1191 static int report_lock_contention_end_event(struct evsel *evsel,
1192 struct perf_sample *sample)
1194 struct lock_stat *ls;
1195 struct thread_stat *ts;
1196 struct lock_seq_stat *seq;
1198 u64 addr = evsel__intval(evsel, sample, "lock_addr");
1202 ret = get_key_by_aggr_mode(&key, addr, evsel, sample);
1206 ls = lock_stat_find(key);
1210 ts = thread_stat_find(sample->tid);
1214 seq = get_seq(ts, addr);
1218 switch (seq->state) {
1219 case SEQ_STATE_UNINITIALIZED:
1221 case SEQ_STATE_CONTENDED:
1222 contended_term = sample->time - seq->prev_event_time;
1223 ls->wait_time_total += contended_term;
1224 if (contended_term < ls->wait_time_min)
1225 ls->wait_time_min = contended_term;
1226 if (ls->wait_time_max < contended_term)
1227 ls->wait_time_max = contended_term;
1229 case SEQ_STATE_ACQUIRING:
1230 case SEQ_STATE_ACQUIRED:
1231 case SEQ_STATE_READ_ACQUIRED:
1232 case SEQ_STATE_RELEASED:
1233 /* broken lock sequence */
1236 bad_hist[BROKEN_ACQUIRED]++;
1238 list_del_init(&seq->list);
1242 BUG_ON("Unknown state of lock sequence found!\n");
1246 seq->state = SEQ_STATE_ACQUIRED;
1248 ls->avg_wait_time = ls->wait_time_total/ls->nr_acquired;
1253 /* lock oriented handlers */
1254 /* TODO: handlers for CPU oriented, thread oriented */
1255 static struct trace_lock_handler report_lock_ops = {
1256 .acquire_event = report_lock_acquire_event,
1257 .acquired_event = report_lock_acquired_event,
1258 .contended_event = report_lock_contended_event,
1259 .release_event = report_lock_release_event,
1260 .contention_begin_event = report_lock_contention_begin_event,
1261 .contention_end_event = report_lock_contention_end_event,
1264 static struct trace_lock_handler contention_lock_ops = {
1265 .contention_begin_event = report_lock_contention_begin_event,
1266 .contention_end_event = report_lock_contention_end_event,
1270 static struct trace_lock_handler *trace_handler;
1272 static int evsel__process_lock_acquire(struct evsel *evsel, struct perf_sample *sample)
1274 if (trace_handler->acquire_event)
1275 return trace_handler->acquire_event(evsel, sample);
1279 static int evsel__process_lock_acquired(struct evsel *evsel, struct perf_sample *sample)
1281 if (trace_handler->acquired_event)
1282 return trace_handler->acquired_event(evsel, sample);
1286 static int evsel__process_lock_contended(struct evsel *evsel, struct perf_sample *sample)
1288 if (trace_handler->contended_event)
1289 return trace_handler->contended_event(evsel, sample);
1293 static int evsel__process_lock_release(struct evsel *evsel, struct perf_sample *sample)
1295 if (trace_handler->release_event)
1296 return trace_handler->release_event(evsel, sample);
1300 static int evsel__process_contention_begin(struct evsel *evsel, struct perf_sample *sample)
1302 if (trace_handler->contention_begin_event)
1303 return trace_handler->contention_begin_event(evsel, sample);
1307 static int evsel__process_contention_end(struct evsel *evsel, struct perf_sample *sample)
1309 if (trace_handler->contention_end_event)
1310 return trace_handler->contention_end_event(evsel, sample);
1314 static void print_bad_events(int bad, int total)
1316 /* Output for debug, this have to be removed */
1319 const char *name[4] =
1320 { "acquire", "acquired", "contended", "release" };
1322 for (i = 0; i < BROKEN_MAX; i++)
1323 broken += bad_hist[i];
1325 if (quiet || (broken == 0 && verbose <= 0))
1328 pr_info("\n=== output for debug===\n\n");
1329 pr_info("bad: %d, total: %d\n", bad, total);
1330 pr_info("bad rate: %.2f %%\n", (double)bad / (double)total * 100);
1331 pr_info("histogram of events caused bad sequence\n");
1332 for (i = 0; i < BROKEN_MAX; i++)
1333 pr_info(" %10s: %d\n", name[i], bad_hist[i]);
1336 /* TODO: various way to print, coloring, nano or milli sec */
1337 static void print_result(void)
1339 struct lock_stat *st;
1340 struct lock_key *key;
1342 int bad, total, printed;
1345 pr_info("%20s ", "Name");
1346 list_for_each_entry(key, &lock_keys, list)
1347 pr_info("%*s ", key->len, key->header);
1351 bad = total = printed = 0;
1352 while ((st = pop_from_result())) {
1356 if (!st->nr_acquired)
1359 bzero(cut_name, 20);
1361 if (strlen(st->name) < 20) {
1362 /* output raw name */
1363 const char *name = st->name;
1365 if (show_thread_stats) {
1368 /* st->addr contains tid of thread */
1369 t = perf_session__findnew(session, st->addr);
1370 name = thread__comm_str(t);
1373 pr_info("%20s ", name);
1375 strncpy(cut_name, st->name, 16);
1379 cut_name[19] = '\0';
1380 /* cut off name for saving output style */
1381 pr_info("%20s ", cut_name);
1384 list_for_each_entry(key, &lock_keys, list) {
1385 key->print(key, st);
1390 if (++printed >= print_nr_entries)
1394 print_bad_events(bad, total);
1397 static bool info_threads, info_map;
1399 static void dump_threads(void)
1401 struct thread_stat *st;
1402 struct rb_node *node;
1405 pr_info("%10s: comm\n", "Thread ID");
1407 node = rb_first(&thread_stats);
1409 st = container_of(node, struct thread_stat, rb);
1410 t = perf_session__findnew(session, st->tid);
1411 pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
1412 node = rb_next(node);
1417 static int compare_maps(struct lock_stat *a, struct lock_stat *b)
1421 if (a->name && b->name)
1422 ret = strcmp(a->name, b->name);
1424 ret = !!a->name - !!b->name;
1427 return a->addr < b->addr;
1432 static void dump_map(void)
1435 struct lock_stat *st;
1437 pr_info("Address of instance: name of class\n");
1438 for (i = 0; i < LOCKHASH_SIZE; i++) {
1439 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
1440 insert_to_result(st, compare_maps);
1444 while ((st = pop_from_result()))
1445 pr_info(" %#llx: %s\n", (unsigned long long)st->addr, st->name);
1448 static int dump_info(void)
1458 pr_err("Unknown type of information\n");
1464 static const struct evsel_str_handler lock_tracepoints[] = {
1465 { "lock:lock_acquire", evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
1466 { "lock:lock_acquired", evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
1467 { "lock:lock_contended", evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
1468 { "lock:lock_release", evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
1471 static const struct evsel_str_handler contention_tracepoints[] = {
1472 { "lock:contention_begin", evsel__process_contention_begin, },
1473 { "lock:contention_end", evsel__process_contention_end, },
1476 static int process_event_update(struct perf_tool *tool,
1477 union perf_event *event,
1478 struct evlist **pevlist)
1482 ret = perf_event__process_event_update(tool, event, pevlist);
1486 /* this can return -EEXIST since we call it for each evsel */
1487 perf_session__set_tracepoints_handlers(session, lock_tracepoints);
1488 perf_session__set_tracepoints_handlers(session, contention_tracepoints);
1492 typedef int (*tracepoint_handler)(struct evsel *evsel,
1493 struct perf_sample *sample);
1495 static int process_sample_event(struct perf_tool *tool __maybe_unused,
1496 union perf_event *event,
1497 struct perf_sample *sample,
1498 struct evsel *evsel,
1499 struct machine *machine)
1502 struct thread *thread = machine__findnew_thread(machine, sample->pid,
1505 if (thread == NULL) {
1506 pr_debug("problem processing %d event, skipping it.\n",
1507 event->header.type);
1511 if (evsel->handler != NULL) {
1512 tracepoint_handler f = evsel->handler;
1513 err = f(evsel, sample);
1516 thread__put(thread);
1521 static void combine_result(void)
1524 struct lock_stat *st;
1529 for (i = 0; i < LOCKHASH_SIZE; i++) {
1530 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
1531 combine_lock_stats(st);
1536 static void sort_result(void)
1539 struct lock_stat *st;
1541 for (i = 0; i < LOCKHASH_SIZE; i++) {
1542 hlist_for_each_entry(st, &lockhash_table[i], hash_entry) {
1543 insert_to_result(st, compare);
1548 static const struct {
1551 } lock_type_table[] = {
1553 { LCB_F_SPIN, "spinlock" },
1554 { LCB_F_SPIN | LCB_F_READ, "rwlock:R" },
1555 { LCB_F_SPIN | LCB_F_WRITE, "rwlock:W"},
1556 { LCB_F_READ, "rwsem:R" },
1557 { LCB_F_WRITE, "rwsem:W" },
1558 { LCB_F_RT, "rtmutex" },
1559 { LCB_F_RT | LCB_F_READ, "rwlock-rt:R" },
1560 { LCB_F_RT | LCB_F_WRITE, "rwlock-rt:W"},
1561 { LCB_F_PERCPU | LCB_F_READ, "pcpu-sem:R" },
1562 { LCB_F_PERCPU | LCB_F_WRITE, "pcpu-sem:W" },
1563 { LCB_F_MUTEX, "mutex" },
1564 { LCB_F_MUTEX | LCB_F_SPIN, "mutex" },
1565 /* alias for get_type_flag() */
1566 { LCB_F_MUTEX | LCB_F_SPIN, "mutex-spin" },
1569 static const char *get_type_str(unsigned int flags)
1571 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1572 if (lock_type_table[i].flags == flags)
1573 return lock_type_table[i].name;
1578 static unsigned int get_type_flag(const char *str)
1580 for (unsigned int i = 0; i < ARRAY_SIZE(lock_type_table); i++) {
1581 if (!strcmp(lock_type_table[i].name, str))
1582 return lock_type_table[i].flags;
1587 static void lock_filter_finish(void)
1589 zfree(&filters.types);
1590 filters.nr_types = 0;
1592 zfree(&filters.addrs);
1593 filters.nr_addrs = 0;
1595 for (int i = 0; i < filters.nr_syms; i++)
1596 free(filters.syms[i]);
1598 zfree(&filters.syms);
1599 filters.nr_syms = 0;
1602 static void sort_contention_result(void)
1607 static void print_contention_result(struct lock_contention *con)
1609 struct lock_stat *st;
1610 struct lock_key *key;
1611 int bad, total, printed;
1614 list_for_each_entry(key, &lock_keys, list)
1615 pr_info("%*s ", key->len, key->header);
1617 switch (aggr_mode) {
1618 case LOCK_AGGR_TASK:
1619 pr_info(" %10s %s\n\n", "pid", "comm");
1621 case LOCK_AGGR_CALLER:
1622 pr_info(" %10s %s\n\n", "type", "caller");
1624 case LOCK_AGGR_ADDR:
1625 pr_info(" %16s %s\n\n", "address", "symbol");
1632 bad = total = printed = 0;
1634 bad = bad_hist[BROKEN_CONTENDED];
1636 while ((st = pop_from_result())) {
1640 total += use_bpf ? st->nr_contended : 1;
1644 if (!st->wait_time_total)
1647 list_for_each_entry(key, &lock_keys, list) {
1648 key->print(key, st);
1652 switch (aggr_mode) {
1653 case LOCK_AGGR_CALLER:
1654 pr_info(" %10s %s\n", get_type_str(st->flags), st->name);
1656 case LOCK_AGGR_TASK:
1658 t = perf_session__findnew(session, pid);
1659 pr_info(" %10d %s\n", pid, thread__comm_str(t));
1661 case LOCK_AGGR_ADDR:
1662 pr_info(" %016llx %s\n", (unsigned long long)st->addr,
1669 if (aggr_mode == LOCK_AGGR_CALLER && verbose > 0) {
1675 for (int i = 0; i < max_stack_depth; i++) {
1676 if (!st->callstack || !st->callstack[i])
1679 ip = st->callstack[i];
1680 sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
1681 get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
1682 pr_info("\t\t\t%#lx %s\n", (unsigned long)ip, buf);
1686 if (++printed >= print_nr_entries)
1690 print_bad_events(bad, total);
1695 static int __cmd_report(bool display_info)
1698 struct perf_tool eops = {
1699 .attr = perf_event__process_attr,
1700 .event_update = process_event_update,
1701 .sample = process_sample_event,
1702 .comm = perf_event__process_comm,
1703 .mmap = perf_event__process_mmap,
1704 .namespaces = perf_event__process_namespaces,
1705 .tracing_data = perf_event__process_tracing_data,
1706 .ordered_events = true,
1708 struct perf_data data = {
1710 .mode = PERF_DATA_MODE_READ,
1714 session = perf_session__new(&data, &eops);
1715 if (IS_ERR(session)) {
1716 pr_err("Initializing perf session failed\n");
1717 return PTR_ERR(session);
1720 /* for lock function check */
1721 symbol_conf.sort_by_name = true;
1722 symbol_conf.allow_aliases = true;
1723 symbol__init(&session->header.env);
1725 if (!data.is_pipe) {
1726 if (!perf_session__has_traces(session, "lock record"))
1729 if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
1730 pr_err("Initializing perf session tracepoint handlers failed\n");
1734 if (perf_session__set_tracepoints_handlers(session, contention_tracepoints)) {
1735 pr_err("Initializing perf session tracepoint handlers failed\n");
1740 if (setup_output_field(false, output_fields))
1743 if (select_key(false))
1746 if (show_thread_stats)
1747 aggr_mode = LOCK_AGGR_TASK;
1749 err = perf_session__process_events(session);
1754 if (display_info) /* used for info subcommand */
1763 perf_session__delete(session);
1767 static void sighandler(int sig __maybe_unused)
1771 static int __cmd_contention(int argc, const char **argv)
1774 struct perf_tool eops = {
1775 .attr = perf_event__process_attr,
1776 .event_update = process_event_update,
1777 .sample = process_sample_event,
1778 .comm = perf_event__process_comm,
1779 .mmap = perf_event__process_mmap,
1780 .tracing_data = perf_event__process_tracing_data,
1781 .ordered_events = true,
1783 struct perf_data data = {
1785 .mode = PERF_DATA_MODE_READ,
1788 struct lock_contention con = {
1790 .result = &lockhash_table[0],
1791 .map_nr_entries = bpf_map_entries,
1792 .max_stack = max_stack_depth,
1793 .stack_skip = stack_skip,
1794 .filters = &filters,
1795 .save_callstack = needs_callstack(),
1798 session = perf_session__new(use_bpf ? NULL : &data, &eops);
1799 if (IS_ERR(session)) {
1800 pr_err("Initializing perf session failed\n");
1801 return PTR_ERR(session);
1804 con.machine = &session->machines.host;
1806 con.aggr_mode = aggr_mode = show_thread_stats ? LOCK_AGGR_TASK :
1807 show_lock_addrs ? LOCK_AGGR_ADDR : LOCK_AGGR_CALLER;
1809 if (con.aggr_mode == LOCK_AGGR_CALLER)
1810 con.save_callstack = true;
1812 /* for lock function check */
1813 symbol_conf.sort_by_name = true;
1814 symbol_conf.allow_aliases = true;
1815 symbol__init(&session->header.env);
1818 err = target__validate(&target);
1822 target__strerror(&target, err, errbuf, 512);
1823 pr_err("%s\n", errbuf);
1827 signal(SIGINT, sighandler);
1828 signal(SIGCHLD, sighandler);
1829 signal(SIGTERM, sighandler);
1831 con.evlist = evlist__new();
1832 if (con.evlist == NULL) {
1837 err = evlist__create_maps(con.evlist, &target);
1842 err = evlist__prepare_workload(con.evlist, &target,
1848 if (lock_contention_prepare(&con) < 0) {
1849 pr_err("lock contention BPF setup failed\n");
1852 } else if (!data.is_pipe) {
1853 if (!perf_session__has_traces(session, "lock record"))
1856 if (!evlist__find_evsel_by_str(session->evlist,
1857 "lock:contention_begin")) {
1858 pr_err("lock contention evsel not found\n");
1862 if (perf_session__set_tracepoints_handlers(session,
1863 contention_tracepoints)) {
1864 pr_err("Initializing perf session tracepoint handlers failed\n");
1869 if (setup_output_field(true, output_fields))
1872 if (select_key(true))
1876 lock_contention_start();
1878 evlist__start_workload(con.evlist);
1880 /* wait for signal */
1883 lock_contention_stop();
1884 lock_contention_read(&con);
1886 /* abuse bad hist stats for lost entries */
1887 bad_hist[BROKEN_CONTENDED] = con.lost;
1889 err = perf_session__process_events(session);
1896 sort_contention_result();
1897 print_contention_result(&con);
1900 lock_filter_finish();
1901 evlist__delete(con.evlist);
1902 lock_contention_finish();
1903 perf_session__delete(session);
1908 static int __cmd_record(int argc, const char **argv)
1910 const char *record_args[] = {
1911 "record", "-R", "-m", "1024", "-c", "1", "--synth", "task",
1913 const char *callgraph_args[] = {
1914 "--call-graph", "fp," __stringify(CONTENTION_STACK_DEPTH),
1916 unsigned int rec_argc, i, j, ret;
1917 unsigned int nr_tracepoints;
1918 unsigned int nr_callgraph_args = 0;
1919 const char **rec_argv;
1920 bool has_lock_stat = true;
1922 for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
1923 if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
1924 pr_debug("tracepoint %s is not enabled. "
1925 "Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
1926 lock_tracepoints[i].name);
1927 has_lock_stat = false;
1935 for (i = 0; i < ARRAY_SIZE(contention_tracepoints); i++) {
1936 if (!is_valid_tracepoint(contention_tracepoints[i].name)) {
1937 pr_err("tracepoint %s is not enabled.\n",
1938 contention_tracepoints[i].name);
1943 nr_callgraph_args = ARRAY_SIZE(callgraph_args);
1946 rec_argc = ARRAY_SIZE(record_args) + nr_callgraph_args + argc - 1;
1949 nr_tracepoints = ARRAY_SIZE(lock_tracepoints);
1951 nr_tracepoints = ARRAY_SIZE(contention_tracepoints);
1953 /* factor of 2 is for -e in front of each tracepoint */
1954 rec_argc += 2 * nr_tracepoints;
1956 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1960 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1961 rec_argv[i] = strdup(record_args[i]);
1963 for (j = 0; j < nr_tracepoints; j++) {
1964 const char *ev_name;
1967 ev_name = strdup(lock_tracepoints[j].name);
1969 ev_name = strdup(contention_tracepoints[j].name);
1974 rec_argv[i++] = "-e";
1975 rec_argv[i++] = ev_name;
1978 for (j = 0; j < nr_callgraph_args; j++, i++)
1979 rec_argv[i] = callgraph_args[j];
1981 for (j = 1; j < (unsigned int)argc; j++, i++)
1982 rec_argv[i] = argv[j];
1984 BUG_ON(i != rec_argc);
1986 ret = cmd_record(i, rec_argv);
1991 static int parse_map_entry(const struct option *opt, const char *str,
1992 int unset __maybe_unused)
1994 unsigned long *len = (unsigned long *)opt->value;
1999 val = strtoul(str, &endptr, 0);
2000 if (*endptr != '\0' || errno != 0) {
2001 pr_err("invalid BPF map length: %s\n", str);
2009 static int parse_max_stack(const struct option *opt, const char *str,
2010 int unset __maybe_unused)
2012 unsigned long *len = (unsigned long *)opt->value;
2017 val = strtol(str, &endptr, 0);
2018 if (*endptr != '\0' || errno != 0) {
2019 pr_err("invalid max stack depth: %s\n", str);
2023 if (val < 0 || val > sysctl__max_stack()) {
2024 pr_err("invalid max stack depth: %ld\n", val);
2032 static bool add_lock_type(unsigned int flags)
2036 tmp = realloc(filters.types, (filters.nr_types + 1) * sizeof(*filters.types));
2040 tmp[filters.nr_types++] = flags;
2041 filters.types = tmp;
2045 static int parse_lock_type(const struct option *opt __maybe_unused, const char *str,
2046 int unset __maybe_unused)
2048 char *s, *tmp, *tok;
2055 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2056 unsigned int flags = get_type_flag(tok);
2061 if (strchr(tok, ':'))
2064 /* try :R and :W suffixes for rwlock, rwsem, ... */
2065 scnprintf(buf, sizeof(buf), "%s:R", tok);
2066 flags = get_type_flag(buf);
2067 if (flags != UINT_MAX) {
2068 if (!add_lock_type(flags)) {
2074 scnprintf(buf, sizeof(buf), "%s:W", tok);
2075 flags = get_type_flag(buf);
2076 if (flags != UINT_MAX) {
2077 if (!add_lock_type(flags)) {
2085 if (!add_lock_type(flags)) {
2090 if (!strcmp(tok, "mutex")) {
2091 flags = get_type_flag("mutex-spin");
2092 if (flags != UINT_MAX) {
2093 if (!add_lock_type(flags)) {
2105 static bool add_lock_addr(unsigned long addr)
2109 tmp = realloc(filters.addrs, (filters.nr_addrs + 1) * sizeof(*filters.addrs));
2111 pr_err("Memory allocation failure\n");
2115 tmp[filters.nr_addrs++] = addr;
2116 filters.addrs = tmp;
2120 static bool add_lock_sym(char *name)
2123 char *sym = strdup(name);
2126 pr_err("Memory allocation failure\n");
2130 tmp = realloc(filters.syms, (filters.nr_syms + 1) * sizeof(*filters.syms));
2132 pr_err("Memory allocation failure\n");
2137 tmp[filters.nr_syms++] = sym;
2142 static int parse_lock_addr(const struct option *opt __maybe_unused, const char *str,
2143 int unset __maybe_unused)
2145 char *s, *tmp, *tok;
2153 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2156 addr = strtoul(tok, &end, 16);
2158 if (!add_lock_addr(addr)) {
2166 * At this moment, we don't have kernel symbols. Save the symbols
2167 * in a separate list and resolve them to addresses later.
2169 if (!add_lock_sym(tok)) {
2179 static int parse_call_stack(const struct option *opt __maybe_unused, const char *str,
2180 int unset __maybe_unused)
2182 char *s, *tmp, *tok;
2189 for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
2190 struct callstack_filter *entry;
2192 entry = malloc(sizeof(*entry) + strlen(tok) + 1);
2193 if (entry == NULL) {
2194 pr_err("Memory allocation failure\n");
2198 strcpy(entry->name, tok);
2199 list_add_tail(&entry->list, &callstack_filters);
2206 int cmd_lock(int argc, const char **argv)
2208 const struct option lock_options[] = {
2209 OPT_STRING('i', "input", &input_name, "file", "input file name"),
2210 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
2211 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
2212 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
2213 OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
2214 "file", "vmlinux pathname"),
2215 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
2216 "file", "kallsyms pathname"),
2217 OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any warnings or messages"),
2221 const struct option info_options[] = {
2222 OPT_BOOLEAN('t', "threads", &info_threads,
2223 "dump thread list in perf.data"),
2224 OPT_BOOLEAN('m', "map", &info_map,
2225 "map of lock instances (address:name table)"),
2226 OPT_PARENT(lock_options)
2229 const struct option report_options[] = {
2230 OPT_STRING('k', "key", &sort_key, "acquired",
2231 "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
2232 OPT_STRING('F', "field", &output_fields, NULL,
2233 "output fields (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
2235 OPT_BOOLEAN('c', "combine-locks", &combine_locks,
2236 "combine locks in the same class"),
2237 OPT_BOOLEAN('t', "threads", &show_thread_stats,
2238 "show per-thread lock stats"),
2239 OPT_INTEGER('E', "entries", &print_nr_entries, "display this many functions"),
2240 OPT_PARENT(lock_options)
2243 struct option contention_options[] = {
2244 OPT_STRING('k', "key", &sort_key, "wait_total",
2245 "key for sorting (contended / wait_total / wait_max / wait_min / avg_wait)"),
2246 OPT_STRING('F', "field", &output_fields, "contended,wait_total,wait_max,avg_wait",
2247 "output fields (contended / wait_total / wait_max / wait_min / avg_wait)"),
2248 OPT_BOOLEAN('t', "threads", &show_thread_stats,
2249 "show per-thread lock stats"),
2250 OPT_BOOLEAN('b', "use-bpf", &use_bpf, "use BPF program to collect lock contention stats"),
2251 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
2252 "System-wide collection from all CPUs"),
2253 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
2254 "List of cpus to monitor"),
2255 OPT_STRING('p', "pid", &target.pid, "pid",
2256 "Trace on existing process id"),
2257 OPT_STRING(0, "tid", &target.tid, "tid",
2258 "Trace on existing thread id (exclusive to --pid)"),
2259 OPT_CALLBACK(0, "map-nr-entries", &bpf_map_entries, "num",
2260 "Max number of BPF map entries", parse_map_entry),
2261 OPT_CALLBACK(0, "max-stack", &max_stack_depth, "num",
2262 "Set the maximum stack depth when collecting lopck contention, "
2263 "Default: " __stringify(CONTENTION_STACK_DEPTH), parse_max_stack),
2264 OPT_INTEGER(0, "stack-skip", &stack_skip,
2265 "Set the number of stack depth to skip when finding a lock caller, "
2266 "Default: " __stringify(CONTENTION_STACK_SKIP)),
2267 OPT_INTEGER('E', "entries", &print_nr_entries, "display this many functions"),
2268 OPT_BOOLEAN('l', "lock-addr", &show_lock_addrs, "show lock stats by address"),
2269 OPT_CALLBACK('Y', "type-filter", NULL, "FLAGS",
2270 "Filter specific type of locks", parse_lock_type),
2271 OPT_CALLBACK('L', "lock-filter", NULL, "ADDRS/NAMES",
2272 "Filter specific address/symbol of locks", parse_lock_addr),
2273 OPT_CALLBACK('S', "callstack-filter", NULL, "NAMES",
2274 "Filter specific function in the callstack", parse_call_stack),
2275 OPT_PARENT(lock_options)
2278 const char * const info_usage[] = {
2279 "perf lock info [<options>]",
2282 const char *const lock_subcommands[] = { "record", "report", "script",
2283 "info", "contention", NULL };
2284 const char *lock_usage[] = {
2288 const char * const report_usage[] = {
2289 "perf lock report [<options>]",
2292 const char * const contention_usage[] = {
2293 "perf lock contention [<options>]",
2299 for (i = 0; i < LOCKHASH_SIZE; i++)
2300 INIT_HLIST_HEAD(lockhash_table + i);
2302 argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
2303 lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
2305 usage_with_options(lock_usage, lock_options);
2307 if (strlen(argv[0]) > 2 && strstarts("record", argv[0])) {
2308 return __cmd_record(argc, argv);
2309 } else if (strlen(argv[0]) > 2 && strstarts("report", argv[0])) {
2310 trace_handler = &report_lock_ops;
2312 argc = parse_options(argc, argv,
2313 report_options, report_usage, 0);
2315 usage_with_options(report_usage, report_options);
2317 rc = __cmd_report(false);
2318 } else if (!strcmp(argv[0], "script")) {
2319 /* Aliased to 'perf script' */
2320 return cmd_script(argc, argv);
2321 } else if (!strcmp(argv[0], "info")) {
2323 argc = parse_options(argc, argv,
2324 info_options, info_usage, 0);
2326 usage_with_options(info_usage, info_options);
2328 /* recycling report_lock_ops */
2329 trace_handler = &report_lock_ops;
2330 rc = __cmd_report(true);
2331 } else if (strlen(argv[0]) > 2 && strstarts("contention", argv[0])) {
2332 trace_handler = &contention_lock_ops;
2333 sort_key = "wait_total";
2334 output_fields = "contended,wait_total,wait_max,avg_wait";
2336 #ifndef HAVE_BPF_SKEL
2337 set_option_nobuild(contention_options, 'b', "use-bpf",
2338 "no BUILD_BPF_SKEL=1", false);
2341 argc = parse_options(argc, argv, contention_options,
2342 contention_usage, 0);
2345 if (show_thread_stats && show_lock_addrs) {
2346 pr_err("Cannot use thread and addr mode together\n");
2347 parse_options_usage(contention_usage, contention_options,
2349 parse_options_usage(NULL, contention_options,
2354 rc = __cmd_contention(argc, argv);
2356 usage_with_options(lock_usage, lock_options);