diff options
Diffstat (limited to 'tools/perf/util/bpf_skel')
-rw-r--r-- | tools/perf/util/bpf_skel/lock_contention.bpf.c | 101 | ||||
-rw-r--r-- | tools/perf/util/bpf_skel/lock_data.h | 30 |
2 files changed, 100 insertions, 31 deletions
diff --git a/tools/perf/util/bpf_skel/lock_contention.bpf.c b/tools/perf/util/bpf_skel/lock_contention.bpf.c index 1bb8628e7c9f..11b0fc7ee53b 100644 --- a/tools/perf/util/bpf_skel/lock_contention.bpf.c +++ b/tools/perf/util/bpf_skel/lock_contention.bpf.c @@ -5,24 +5,11 @@ #include <bpf/bpf_tracing.h> #include <bpf/bpf_core_read.h> -/* maximum stack trace depth */ -#define MAX_STACKS 8 +#include "lock_data.h" /* default buffer size */ #define MAX_ENTRIES 10240 -struct contention_key { - __s32 stack_id; -}; - -struct contention_data { - __u64 total_time; - __u64 min_time; - __u64 max_time; - __u32 count; - __u32 flags; -}; - struct tstamp_data { __u64 timestamp; __u64 lock; @@ -34,16 +21,16 @@ struct tstamp_data { struct { __uint(type, BPF_MAP_TYPE_STACK_TRACE); __uint(key_size, sizeof(__u32)); - __uint(value_size, MAX_STACKS * sizeof(__u64)); + __uint(value_size, sizeof(__u64)); __uint(max_entries, MAX_ENTRIES); } stacks SEC(".maps"); /* maintain timestamp at the beginning of contention */ struct { - __uint(type, BPF_MAP_TYPE_TASK_STORAGE); - __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(type, BPF_MAP_TYPE_HASH); __type(key, int); __type(value, struct tstamp_data); + __uint(max_entries, MAX_ENTRIES); } tstamp SEC(".maps"); /* actual lock contention statistics */ @@ -57,6 +44,13 @@ struct { struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(struct contention_task_data)); + __uint(max_entries, MAX_ENTRIES); +} task_data SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); __uint(value_size, sizeof(__u8)); __uint(max_entries, 1); } cpu_filter SEC(".maps"); @@ -74,6 +68,9 @@ int has_cpu; int has_task; int stack_skip; +/* determine the key of lock stat */ +int aggr_mode; + /* error stat */ int lost; @@ -100,35 +97,62 @@ static inline int can_record(void) return 1; } +static inline void update_task_data(__u32 pid) +{ + struct contention_task_data *p; + + p = bpf_map_lookup_elem(&task_data, &pid); + if (p == NULL) { + struct contention_task_data data; + + bpf_get_current_comm(data.comm, sizeof(data.comm)); + bpf_map_update_elem(&task_data, &pid, &data, BPF_NOEXIST); + } +} + SEC("tp_btf/contention_begin") int contention_begin(u64 *ctx) { - struct task_struct *curr; + __u32 pid; struct tstamp_data *pelem; if (!enabled || !can_record()) return 0; - curr = bpf_get_current_task_btf(); - pelem = bpf_task_storage_get(&tstamp, curr, NULL, - BPF_LOCAL_STORAGE_GET_F_CREATE); - if (!pelem || pelem->lock) + pid = bpf_get_current_pid_tgid(); + pelem = bpf_map_lookup_elem(&tstamp, &pid); + if (pelem && pelem->lock) return 0; + if (pelem == NULL) { + struct tstamp_data zero = {}; + + bpf_map_update_elem(&tstamp, &pid, &zero, BPF_ANY); + pelem = bpf_map_lookup_elem(&tstamp, &pid); + if (pelem == NULL) { + lost++; + return 0; + } + } + pelem->timestamp = bpf_ktime_get_ns(); pelem->lock = (__u64)ctx[0]; pelem->flags = (__u32)ctx[1]; - pelem->stack_id = bpf_get_stackid(ctx, &stacks, BPF_F_FAST_STACK_CMP | stack_skip); - if (pelem->stack_id < 0) - lost++; + if (aggr_mode == LOCK_AGGR_CALLER) { + pelem->stack_id = bpf_get_stackid(ctx, &stacks, + BPF_F_FAST_STACK_CMP | stack_skip); + if (pelem->stack_id < 0) + lost++; + } + return 0; } SEC("tp_btf/contention_end") int contention_end(u64 *ctx) { - struct task_struct *curr; + __u32 pid; struct tstamp_data *pelem; struct contention_key key; struct contention_data *data; @@ -137,14 +161,29 @@ int contention_end(u64 *ctx) if (!enabled) return 0; - curr = bpf_get_current_task_btf(); - pelem = bpf_task_storage_get(&tstamp, curr, NULL, 0); + pid = bpf_get_current_pid_tgid(); + pelem = bpf_map_lookup_elem(&tstamp, &pid); if (!pelem || pelem->lock != ctx[0]) return 0; duration = bpf_ktime_get_ns() - pelem->timestamp; - key.stack_id = pelem->stack_id; + switch (aggr_mode) { + case LOCK_AGGR_CALLER: + key.aggr_key = pelem->stack_id; + break; + case LOCK_AGGR_TASK: + key.aggr_key = pid; + update_task_data(pid); + break; + case LOCK_AGGR_ADDR: + key.aggr_key = pelem->lock; + break; + default: + /* should not happen */ + return 0; + } + data = bpf_map_lookup_elem(&lock_stat, &key); if (!data) { struct contention_data first = { @@ -156,7 +195,7 @@ int contention_end(u64 *ctx) }; bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST); - pelem->lock = 0; + bpf_map_delete_elem(&tstamp, &pid); return 0; } @@ -169,7 +208,7 @@ int contention_end(u64 *ctx) if (data->min_time > duration) data->min_time = duration; - pelem->lock = 0; + bpf_map_delete_elem(&tstamp, &pid); return 0; } diff --git a/tools/perf/util/bpf_skel/lock_data.h b/tools/perf/util/bpf_skel/lock_data.h new file mode 100644 index 000000000000..ce71cf1a7e1e --- /dev/null +++ b/tools/perf/util/bpf_skel/lock_data.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Data structures shared between BPF and tools. */ +#ifndef UTIL_BPF_SKEL_LOCK_DATA_H +#define UTIL_BPF_SKEL_LOCK_DATA_H + +struct contention_key { + u64 aggr_key; /* can be stack_id, pid or lock addr */ +}; + +#define TASK_COMM_LEN 16 + +struct contention_task_data { + char comm[TASK_COMM_LEN]; +}; + +struct contention_data { + u64 total_time; + u64 min_time; + u64 max_time; + u32 count; + u32 flags; +}; + +enum lock_aggr_mode { + LOCK_AGGR_ADDR = 0, + LOCK_AGGR_TASK, + LOCK_AGGR_CALLER, +}; + +#endif /* UTIL_BPF_SKEL_LOCK_DATA_H */ |