Skip to content

Commit 688d2e8

Browse files
namhyungacmel
authored andcommitted
perf lock contention: Add -l/--lock-addr option
The -l/--lock-addr option is to implement per-lock-instance contention stat using LOCK_AGGR_ADDR. It displays lock address and optionally symbol name if exists. $ sudo ./perf lock con -abl sleep 1 contended total wait max wait avg wait address symbol 1 36.28 us 36.28 us 36.28 us ffff92615d6448b8 9 10.91 us 1.84 us 1.21 us ffffffffbaed50c0 rcu_state 1 10.49 us 10.49 us 10.49 us ffff9262ac4f0c80 8 4.68 us 1.67 us 585 ns ffffffffbae07a40 jiffies_lock 3 3.03 us 1.45 us 1.01 us ffff9262277861e0 1 924 ns 924 ns 924 ns ffff926095ba9d20 1 436 ns 436 ns 436 ns ffff9260bfda4f60 Signed-off-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Blake Jones <blakejones@google.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Song Liu <song@kernel.org> Cc: bpf@vger.kernel.org Link: https://lore.kernel.org/r/20221209190727.759804-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent eca949b commit 688d2e8

File tree

5 files changed

+102
-28
lines changed

5 files changed

+102
-28
lines changed

tools/perf/Documentation/perf-lock.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ CONTENTION OPTIONS
168168
--entries=<value>::
169169
Display this many entries.
170170

171+
-l::
172+
--lock-addr::
173+
Show lock contention stat by address
174+
171175

172176
SEE ALSO
173177
--------

tools/perf/builtin-lock.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static struct rb_root thread_stats;
5656

5757
static bool combine_locks;
5858
static bool show_thread_stats;
59+
static bool show_lock_addrs;
5960
static bool use_bpf;
6061
static unsigned long bpf_map_entries = 10240;
6162
static int max_stack_depth = CONTENTION_STACK_DEPTH;
@@ -999,13 +1000,32 @@ static int report_lock_contention_begin_event(struct evsel *evsel,
9991000
ls = lock_stat_find(key);
10001001
if (!ls) {
10011002
char buf[128];
1002-
const char *caller = buf;
1003+
const char *name = "";
10031004
unsigned int flags = evsel__intval(evsel, sample, "flags");
1005+
struct machine *machine = &session->machines.host;
1006+
struct map *kmap;
1007+
struct symbol *sym;
1008+
1009+
switch (aggr_mode) {
1010+
case LOCK_AGGR_ADDR:
1011+
/* make sure it loads the kernel map to find lock symbols */
1012+
map__load(machine__kernel_map(machine));
1013+
1014+
sym = machine__find_kernel_symbol(machine, key, &kmap);
1015+
if (sym)
1016+
name = sym->name;
1017+
break;
1018+
case LOCK_AGGR_CALLER:
1019+
name = buf;
1020+
if (lock_contention_caller(evsel, sample, buf, sizeof(buf)) < 0)
1021+
name = "Unknown";
1022+
break;
1023+
case LOCK_AGGR_TASK:
1024+
default:
1025+
break;
1026+
}
10041027

1005-
if (lock_contention_caller(evsel, sample, buf, sizeof(buf)) < 0)
1006-
caller = "Unknown";
1007-
1008-
ls = lock_stat_findnew(key, caller, flags);
1028+
ls = lock_stat_findnew(key, name, flags);
10091029
if (!ls)
10101030
return -ENOMEM;
10111031

@@ -1460,17 +1480,29 @@ static void print_contention_result(struct lock_contention *con)
14601480
list_for_each_entry(key, &lock_keys, list)
14611481
pr_info("%*s ", key->len, key->header);
14621482

1463-
if (show_thread_stats)
1483+
switch (aggr_mode) {
1484+
case LOCK_AGGR_TASK:
14641485
pr_info(" %10s %s\n\n", "pid", "comm");
1465-
else
1486+
break;
1487+
case LOCK_AGGR_CALLER:
14661488
pr_info(" %10s %s\n\n", "type", "caller");
1489+
break;
1490+
case LOCK_AGGR_ADDR:
1491+
pr_info(" %16s %s\n\n", "address", "symbol");
1492+
break;
1493+
default:
1494+
break;
1495+
}
14671496
}
14681497

14691498
bad = total = printed = 0;
14701499
if (use_bpf)
14711500
bad = bad_hist[BROKEN_CONTENDED];
14721501

14731502
while ((st = pop_from_result())) {
1503+
struct thread *t;
1504+
int pid;
1505+
14741506
total += use_bpf ? st->nr_contended : 1;
14751507
if (st->broken)
14761508
bad++;
@@ -1480,18 +1512,24 @@ static void print_contention_result(struct lock_contention *con)
14801512
pr_info(" ");
14811513
}
14821514

1483-
if (show_thread_stats) {
1484-
struct thread *t;
1485-
int pid = st->addr;
1486-
1487-
/* st->addr contains tid of thread */
1515+
switch (aggr_mode) {
1516+
case LOCK_AGGR_CALLER:
1517+
pr_info(" %10s %s\n", get_type_str(st), st->name);
1518+
break;
1519+
case LOCK_AGGR_TASK:
1520+
pid = st->addr;
14881521
t = perf_session__findnew(session, pid);
14891522
pr_info(" %10d %s\n", pid, thread__comm_str(t));
1490-
goto next;
1523+
break;
1524+
case LOCK_AGGR_ADDR:
1525+
pr_info(" %016llx %s\n", (unsigned long long)st->addr,
1526+
st->name ? : "");
1527+
break;
1528+
default:
1529+
break;
14911530
}
14921531

1493-
pr_info(" %10s %s\n", get_type_str(st), st->name);
1494-
if (verbose) {
1532+
if (aggr_mode == LOCK_AGGR_CALLER && verbose) {
14951533
struct map *kmap;
14961534
struct symbol *sym;
14971535
char buf[128];
@@ -1508,7 +1546,6 @@ static void print_contention_result(struct lock_contention *con)
15081546
}
15091547
}
15101548

1511-
next:
15121549
if (++printed >= print_nr_entries)
15131550
break;
15141551
}
@@ -1616,7 +1653,6 @@ static int __cmd_contention(int argc, const char **argv)
16161653
.map_nr_entries = bpf_map_entries,
16171654
.max_stack = max_stack_depth,
16181655
.stack_skip = stack_skip,
1619-
.aggr_mode = show_thread_stats ? LOCK_AGGR_TASK : LOCK_AGGR_CALLER,
16201656
};
16211657

16221658
session = perf_session__new(use_bpf ? NULL : &data, &eops);
@@ -1627,6 +1663,9 @@ static int __cmd_contention(int argc, const char **argv)
16271663

16281664
con.machine = &session->machines.host;
16291665

1666+
con.aggr_mode = aggr_mode = show_thread_stats ? LOCK_AGGR_TASK :
1667+
show_lock_addrs ? LOCK_AGGR_ADDR : LOCK_AGGR_CALLER;
1668+
16301669
/* for lock function check */
16311670
symbol_conf.sort_by_name = true;
16321671
symbol__init(&session->header.env);
@@ -1907,6 +1946,7 @@ int cmd_lock(int argc, const char **argv)
19071946
"Set the number of stack depth to skip when finding a lock caller, "
19081947
"Default: " __stringify(CONTENTION_STACK_SKIP)),
19091948
OPT_INTEGER('E', "entries", &print_nr_entries, "display this many functions"),
1949+
OPT_BOOLEAN('l', "lock-addr", &show_lock_addrs, "show lock stats by address"),
19101950
OPT_PARENT(lock_options)
19111951
};
19121952

@@ -1976,6 +2016,16 @@ int cmd_lock(int argc, const char **argv)
19762016
argc = parse_options(argc, argv, contention_options,
19772017
contention_usage, 0);
19782018
}
2019+
2020+
if (show_thread_stats && show_lock_addrs) {
2021+
pr_err("Cannot use thread and addr mode together\n");
2022+
parse_options_usage(contention_usage, contention_options,
2023+
"threads", 0);
2024+
parse_options_usage(NULL, contention_options,
2025+
"lock-addr", 0);
2026+
return -1;
2027+
}
2028+
19792029
rc = __cmd_contention(argc, argv);
19802030
} else {
19812031
usage_with_options(lock_usage, lock_options);

tools/perf/util/bpf_lock_contention.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,15 @@ int lock_contention_read(struct lock_contention *con)
137137
thread__set_comm(idle, "swapper", /*timestamp=*/0);
138138
}
139139

140+
/* make sure it loads the kernel map */
141+
map__load(maps__first(machine->kmaps));
142+
140143
prev_key = NULL;
141144
while (!bpf_map_get_next_key(fd, prev_key, &key)) {
142145
struct map *kmap;
143146
struct symbol *sym;
144147
int idx = 0;
148+
s32 stack_id;
145149

146150
/* to handle errors in the loop body */
147151
err = -1;
@@ -160,24 +164,31 @@ int lock_contention_read(struct lock_contention *con)
160164
st->avg_wait_time = data.total_time / data.count;
161165

162166
st->flags = data.flags;
167+
st->addr = key.aggr_key;
163168

164169
if (con->aggr_mode == LOCK_AGGR_TASK) {
165170
struct contention_task_data task;
166171
struct thread *t;
167-
168-
st->addr = key.stack_or_task_id;
172+
int pid = key.aggr_key;
169173

170174
/* do not update idle comm which contains CPU number */
171175
if (st->addr) {
172-
bpf_map_lookup_elem(task_fd, &key, &task);
173-
t = __machine__findnew_thread(machine, /*pid=*/-1,
174-
key.stack_or_task_id);
176+
bpf_map_lookup_elem(task_fd, &pid, &task);
177+
t = __machine__findnew_thread(machine, /*pid=*/-1, pid);
175178
thread__set_comm(t, task.comm, /*timestamp=*/0);
176179
}
177180
goto next;
178181
}
179182

180-
bpf_map_lookup_elem(stack, &key, stack_trace);
183+
if (con->aggr_mode == LOCK_AGGR_ADDR) {
184+
sym = machine__find_kernel_symbol(machine, st->addr, &kmap);
185+
if (sym)
186+
st->name = strdup(sym->name);
187+
goto next;
188+
}
189+
190+
stack_id = key.aggr_key;
191+
bpf_map_lookup_elem(stack, &stack_id, stack_trace);
181192

182193
/* skip lock internal functions */
183194
while (machine__is_lock_function(machine, stack_trace[idx]) &&

tools/perf/util/bpf_skel/lock_contention.bpf.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,20 @@ int contention_end(u64 *ctx)
168168

169169
duration = bpf_ktime_get_ns() - pelem->timestamp;
170170

171-
if (aggr_mode == LOCK_AGGR_CALLER) {
172-
key.stack_or_task_id = pelem->stack_id;
173-
} else {
174-
key.stack_or_task_id = pid;
171+
switch (aggr_mode) {
172+
case LOCK_AGGR_CALLER:
173+
key.aggr_key = pelem->stack_id;
174+
break;
175+
case LOCK_AGGR_TASK:
176+
key.aggr_key = pid;
175177
update_task_data(pid);
178+
break;
179+
case LOCK_AGGR_ADDR:
180+
key.aggr_key = pelem->lock;
181+
break;
182+
default:
183+
/* should not happen */
184+
return 0;
176185
}
177186

178187
data = bpf_map_lookup_elem(&lock_stat, &key);

tools/perf/util/bpf_skel/lock_data.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#define UTIL_BPF_SKEL_LOCK_DATA_H
55

66
struct contention_key {
7-
s32 stack_or_task_id;
7+
u64 aggr_key; /* can be stack_id, pid or lock addr */
88
};
99

1010
#define TASK_COMM_LEN 16

0 commit comments

Comments
 (0)