xref: /openbmc/linux/tools/perf/util/bpf_skel/lock_contention.bpf.c (revision c845428b7a9157523103100806bc8130d64769c8)
1407b36f6SNamhyung Kim // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2407b36f6SNamhyung Kim // Copyright (c) 2022 Google
3407b36f6SNamhyung Kim #include "vmlinux.h"
4407b36f6SNamhyung Kim #include <bpf/bpf_helpers.h>
5407b36f6SNamhyung Kim #include <bpf/bpf_tracing.h>
6407b36f6SNamhyung Kim #include <bpf/bpf_core_read.h>
7222de5e5SNamhyung Kim #include <asm-generic/errno-base.h>
8407b36f6SNamhyung Kim 
9fd507d3eSNamhyung Kim #include "lock_data.h"
10407b36f6SNamhyung Kim 
11d24c0144SNamhyung Kim /* for collect_lock_syms().  4096 was rejected by the verifier */
12d24c0144SNamhyung Kim #define MAX_CPUS  1024
13d24c0144SNamhyung Kim 
143477f079SNamhyung Kim /* lock contention flags from include/trace/events/lock.h */
153477f079SNamhyung Kim #define LCB_F_SPIN	(1U << 0)
163477f079SNamhyung Kim #define LCB_F_READ	(1U << 1)
173477f079SNamhyung Kim #define LCB_F_WRITE	(1U << 2)
183477f079SNamhyung Kim #define LCB_F_RT	(1U << 3)
193477f079SNamhyung Kim #define LCB_F_PERCPU	(1U << 4)
203477f079SNamhyung Kim #define LCB_F_MUTEX	(1U << 5)
213477f079SNamhyung Kim 
22407b36f6SNamhyung Kim struct tstamp_data {
23407b36f6SNamhyung Kim 	__u64 timestamp;
24407b36f6SNamhyung Kim 	__u64 lock;
25407b36f6SNamhyung Kim 	__u32 flags;
266d499a6bSNamhyung Kim 	__s32 stack_id;
27407b36f6SNamhyung Kim };
28407b36f6SNamhyung Kim 
29407b36f6SNamhyung Kim /* callstack storage  */
30407b36f6SNamhyung Kim struct {
31407b36f6SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_STACK_TRACE);
32407b36f6SNamhyung Kim 	__uint(key_size, sizeof(__u32));
33fd507d3eSNamhyung Kim 	__uint(value_size, sizeof(__u64));
34407b36f6SNamhyung Kim 	__uint(max_entries, MAX_ENTRIES);
35407b36f6SNamhyung Kim } stacks SEC(".maps");
36407b36f6SNamhyung Kim 
37407b36f6SNamhyung Kim /* maintain timestamp at the beginning of contention */
38407b36f6SNamhyung Kim struct {
39c66a36afSNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
40407b36f6SNamhyung Kim 	__type(key, int);
41407b36f6SNamhyung Kim 	__type(value, struct tstamp_data);
42c66a36afSNamhyung Kim 	__uint(max_entries, MAX_ENTRIES);
43407b36f6SNamhyung Kim } tstamp SEC(".maps");
44407b36f6SNamhyung Kim 
45407b36f6SNamhyung Kim /* actual lock contention statistics */
46407b36f6SNamhyung Kim struct {
47407b36f6SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
48407b36f6SNamhyung Kim 	__uint(key_size, sizeof(struct contention_key));
49407b36f6SNamhyung Kim 	__uint(value_size, sizeof(struct contention_data));
50407b36f6SNamhyung Kim 	__uint(max_entries, MAX_ENTRIES);
51407b36f6SNamhyung Kim } lock_stat SEC(".maps");
52407b36f6SNamhyung Kim 
536fda2405SNamhyung Kim struct {
546fda2405SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
556fda2405SNamhyung Kim 	__uint(key_size, sizeof(__u32));
56eca949b2SNamhyung Kim 	__uint(value_size, sizeof(struct contention_task_data));
57eca949b2SNamhyung Kim 	__uint(max_entries, MAX_ENTRIES);
58eca949b2SNamhyung Kim } task_data SEC(".maps");
59eca949b2SNamhyung Kim 
60eca949b2SNamhyung Kim struct {
61eca949b2SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
62d24c0144SNamhyung Kim 	__uint(key_size, sizeof(__u64));
63d24c0144SNamhyung Kim 	__uint(value_size, sizeof(__u32));
642d8d0165SNamhyung Kim 	__uint(max_entries, MAX_ENTRIES);
65d24c0144SNamhyung Kim } lock_syms SEC(".maps");
66d24c0144SNamhyung Kim 
67d24c0144SNamhyung Kim struct {
68d24c0144SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
69eca949b2SNamhyung Kim 	__uint(key_size, sizeof(__u32));
706fda2405SNamhyung Kim 	__uint(value_size, sizeof(__u8));
716fda2405SNamhyung Kim 	__uint(max_entries, 1);
726fda2405SNamhyung Kim } cpu_filter SEC(".maps");
736fda2405SNamhyung Kim 
746fda2405SNamhyung Kim struct {
756fda2405SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
766fda2405SNamhyung Kim 	__uint(key_size, sizeof(__u32));
776fda2405SNamhyung Kim 	__uint(value_size, sizeof(__u8));
786fda2405SNamhyung Kim 	__uint(max_entries, 1);
796fda2405SNamhyung Kim } task_filter SEC(".maps");
806fda2405SNamhyung Kim 
81529772c4SNamhyung Kim struct {
82529772c4SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
83529772c4SNamhyung Kim 	__uint(key_size, sizeof(__u32));
84529772c4SNamhyung Kim 	__uint(value_size, sizeof(__u8));
85529772c4SNamhyung Kim 	__uint(max_entries, 1);
86529772c4SNamhyung Kim } type_filter SEC(".maps");
87529772c4SNamhyung Kim 
885e3febe7SNamhyung Kim struct {
895e3febe7SNamhyung Kim 	__uint(type, BPF_MAP_TYPE_HASH);
905e3febe7SNamhyung Kim 	__uint(key_size, sizeof(__u64));
915e3febe7SNamhyung Kim 	__uint(value_size, sizeof(__u8));
925e3febe7SNamhyung Kim 	__uint(max_entries, 1);
935e3febe7SNamhyung Kim } addr_filter SEC(".maps");
945e3febe7SNamhyung Kim 
951bece135SNamhyung Kim struct rw_semaphore___old {
961bece135SNamhyung Kim 	struct task_struct *owner;
971bece135SNamhyung Kim } __attribute__((preserve_access_index));
981bece135SNamhyung Kim 
991bece135SNamhyung Kim struct rw_semaphore___new {
1001bece135SNamhyung Kim 	atomic_long_t owner;
1011bece135SNamhyung Kim } __attribute__((preserve_access_index));
1021bece135SNamhyung Kim 
1033ace2435SNamhyung Kim struct mm_struct___old {
1043ace2435SNamhyung Kim 	struct rw_semaphore mmap_sem;
1053ace2435SNamhyung Kim } __attribute__((preserve_access_index));
1063ace2435SNamhyung Kim 
1073ace2435SNamhyung Kim struct mm_struct___new {
1083ace2435SNamhyung Kim 	struct rw_semaphore mmap_lock;
1093ace2435SNamhyung Kim } __attribute__((preserve_access_index));
1103ace2435SNamhyung Kim 
111407b36f6SNamhyung Kim /* control flags */
112407b36f6SNamhyung Kim int enabled;
1136fda2405SNamhyung Kim int has_cpu;
1146fda2405SNamhyung Kim int has_task;
115529772c4SNamhyung Kim int has_type;
1165e3febe7SNamhyung Kim int has_addr;
117ebab2916SNamhyung Kim int needs_callstack;
118c1da8dd5SNamhyung Kim int stack_skip;
1193477f079SNamhyung Kim int lock_owner;
1206fda2405SNamhyung Kim 
121eca949b2SNamhyung Kim /* determine the key of lock stat */
122eca949b2SNamhyung Kim int aggr_mode;
123eca949b2SNamhyung Kim 
1246d499a6bSNamhyung Kim /* error stat */
12584c3a2bbSNamhyung Kim int task_fail;
12684c3a2bbSNamhyung Kim int stack_fail;
12784c3a2bbSNamhyung Kim int time_fail;
128954cdac7SNamhyung Kim int data_fail;
1296d499a6bSNamhyung Kim 
130222de5e5SNamhyung Kim int task_map_full;
131222de5e5SNamhyung Kim int data_map_full;
132222de5e5SNamhyung Kim 
can_record(u64 * ctx)133529772c4SNamhyung Kim static inline int can_record(u64 *ctx)
1346fda2405SNamhyung Kim {
1356fda2405SNamhyung Kim 	if (has_cpu) {
1366fda2405SNamhyung Kim 		__u32 cpu = bpf_get_smp_processor_id();
1376fda2405SNamhyung Kim 		__u8 *ok;
1386fda2405SNamhyung Kim 
1396fda2405SNamhyung Kim 		ok = bpf_map_lookup_elem(&cpu_filter, &cpu);
1406fda2405SNamhyung Kim 		if (!ok)
1416fda2405SNamhyung Kim 			return 0;
1426fda2405SNamhyung Kim 	}
1436fda2405SNamhyung Kim 
1446fda2405SNamhyung Kim 	if (has_task) {
1456fda2405SNamhyung Kim 		__u8 *ok;
1466fda2405SNamhyung Kim 		__u32 pid = bpf_get_current_pid_tgid();
1476fda2405SNamhyung Kim 
1486fda2405SNamhyung Kim 		ok = bpf_map_lookup_elem(&task_filter, &pid);
1496fda2405SNamhyung Kim 		if (!ok)
1506fda2405SNamhyung Kim 			return 0;
1516fda2405SNamhyung Kim 	}
1526fda2405SNamhyung Kim 
153529772c4SNamhyung Kim 	if (has_type) {
154529772c4SNamhyung Kim 		__u8 *ok;
155529772c4SNamhyung Kim 		__u32 flags = (__u32)ctx[1];
156529772c4SNamhyung Kim 
157529772c4SNamhyung Kim 		ok = bpf_map_lookup_elem(&type_filter, &flags);
158529772c4SNamhyung Kim 		if (!ok)
159529772c4SNamhyung Kim 			return 0;
160529772c4SNamhyung Kim 	}
161529772c4SNamhyung Kim 
1625e3febe7SNamhyung Kim 	if (has_addr) {
1635e3febe7SNamhyung Kim 		__u8 *ok;
1645e3febe7SNamhyung Kim 		__u64 addr = ctx[0];
1655e3febe7SNamhyung Kim 
1665e3febe7SNamhyung Kim 		ok = bpf_map_lookup_elem(&addr_filter, &addr);
1675e3febe7SNamhyung Kim 		if (!ok)
1685e3febe7SNamhyung Kim 			return 0;
1695e3febe7SNamhyung Kim 	}
1705e3febe7SNamhyung Kim 
1716fda2405SNamhyung Kim 	return 1;
1726fda2405SNamhyung Kim }
173407b36f6SNamhyung Kim 
update_task_data(struct task_struct * task)1743477f079SNamhyung Kim static inline int update_task_data(struct task_struct *task)
175eca949b2SNamhyung Kim {
176eca949b2SNamhyung Kim 	struct contention_task_data *p;
1773477f079SNamhyung Kim 	int pid, err;
1783477f079SNamhyung Kim 
1793477f079SNamhyung Kim 	err = bpf_core_read(&pid, sizeof(pid), &task->pid);
1803477f079SNamhyung Kim 	if (err)
1813477f079SNamhyung Kim 		return -1;
182eca949b2SNamhyung Kim 
183eca949b2SNamhyung Kim 	p = bpf_map_lookup_elem(&task_data, &pid);
184222de5e5SNamhyung Kim 	if (p == NULL && !task_map_full) {
1853477f079SNamhyung Kim 		struct contention_task_data data = {};
186eca949b2SNamhyung Kim 
1873477f079SNamhyung Kim 		BPF_CORE_READ_STR_INTO(&data.comm, task, comm);
188222de5e5SNamhyung Kim 		if (bpf_map_update_elem(&task_data, &pid, &data, BPF_NOEXIST) == -E2BIG)
189222de5e5SNamhyung Kim 			task_map_full = 1;
190eca949b2SNamhyung Kim 	}
1913477f079SNamhyung Kim 
1923477f079SNamhyung Kim 	return 0;
193eca949b2SNamhyung Kim }
194eca949b2SNamhyung Kim 
1951bece135SNamhyung Kim #ifndef __has_builtin
1961bece135SNamhyung Kim # define __has_builtin(x) 0
1971bece135SNamhyung Kim #endif
1981bece135SNamhyung Kim 
get_lock_owner(__u64 lock,__u32 flags)1991bece135SNamhyung Kim static inline struct task_struct *get_lock_owner(__u64 lock, __u32 flags)
2001bece135SNamhyung Kim {
2011bece135SNamhyung Kim 	struct task_struct *task;
2021bece135SNamhyung Kim 	__u64 owner = 0;
2031bece135SNamhyung Kim 
2041bece135SNamhyung Kim 	if (flags & LCB_F_MUTEX) {
2051bece135SNamhyung Kim 		struct mutex *mutex = (void *)lock;
2061bece135SNamhyung Kim 		owner = BPF_CORE_READ(mutex, owner.counter);
2071bece135SNamhyung Kim 	} else if (flags == LCB_F_READ || flags == LCB_F_WRITE) {
20817535a33SIan Rogers 	/*
20917535a33SIan Rogers 	 * Support for the BPF_TYPE_MATCHES argument to the
21017535a33SIan Rogers 	 * __builtin_preserve_type_info builtin was added at some point during
21117535a33SIan Rogers 	 * development of clang 15 and it's what is needed for
21217535a33SIan Rogers 	 * bpf_core_type_matches.
21317535a33SIan Rogers 	 */
21417535a33SIan Rogers #if __has_builtin(__builtin_preserve_type_info) && __clang_major__ >= 15
2151bece135SNamhyung Kim 		if (bpf_core_type_matches(struct rw_semaphore___old)) {
2161bece135SNamhyung Kim 			struct rw_semaphore___old *rwsem = (void *)lock;
2171bece135SNamhyung Kim 			owner = (unsigned long)BPF_CORE_READ(rwsem, owner);
2181bece135SNamhyung Kim 		} else if (bpf_core_type_matches(struct rw_semaphore___new)) {
2191bece135SNamhyung Kim 			struct rw_semaphore___new *rwsem = (void *)lock;
2201bece135SNamhyung Kim 			owner = BPF_CORE_READ(rwsem, owner.counter);
2211bece135SNamhyung Kim 		}
2221bece135SNamhyung Kim #else
2231bece135SNamhyung Kim 		/* assume new struct */
2241bece135SNamhyung Kim 		struct rw_semaphore *rwsem = (void *)lock;
2251bece135SNamhyung Kim 		owner = BPF_CORE_READ(rwsem, owner.counter);
2261bece135SNamhyung Kim #endif
2271bece135SNamhyung Kim 	}
2281bece135SNamhyung Kim 
2291bece135SNamhyung Kim 	if (!owner)
2301bece135SNamhyung Kim 		return NULL;
2311bece135SNamhyung Kim 
2321bece135SNamhyung Kim 	task = (void *)(owner & ~7UL);
2331bece135SNamhyung Kim 	return task;
2341bece135SNamhyung Kim }
2351bece135SNamhyung Kim 
check_lock_type(__u64 lock,__u32 flags)2363ace2435SNamhyung Kim static inline __u32 check_lock_type(__u64 lock, __u32 flags)
2373ace2435SNamhyung Kim {
2383ace2435SNamhyung Kim 	struct task_struct *curr;
2393ace2435SNamhyung Kim 	struct mm_struct___old *mm_old;
2403ace2435SNamhyung Kim 	struct mm_struct___new *mm_new;
241*c418d7a6SNamhyung Kim 	struct sighand_struct *sighand;
2423ace2435SNamhyung Kim 
2433ace2435SNamhyung Kim 	switch (flags) {
2443ace2435SNamhyung Kim 	case LCB_F_READ:  /* rwsem */
2453ace2435SNamhyung Kim 	case LCB_F_WRITE:
2463ace2435SNamhyung Kim 		curr = bpf_get_current_task_btf();
2473ace2435SNamhyung Kim 		if (curr->mm == NULL)
2483ace2435SNamhyung Kim 			break;
2493ace2435SNamhyung Kim 		mm_new = (void *)curr->mm;
2503ace2435SNamhyung Kim 		if (bpf_core_field_exists(mm_new->mmap_lock)) {
2513ace2435SNamhyung Kim 			if (&mm_new->mmap_lock == (void *)lock)
2523ace2435SNamhyung Kim 				return LCD_F_MMAP_LOCK;
2533ace2435SNamhyung Kim 			break;
2543ace2435SNamhyung Kim 		}
2553ace2435SNamhyung Kim 		mm_old = (void *)curr->mm;
2563ace2435SNamhyung Kim 		if (bpf_core_field_exists(mm_old->mmap_sem)) {
2573ace2435SNamhyung Kim 			if (&mm_old->mmap_sem == (void *)lock)
2583ace2435SNamhyung Kim 				return LCD_F_MMAP_LOCK;
2593ace2435SNamhyung Kim 		}
2603ace2435SNamhyung Kim 		break;
2611811e827SNamhyung Kim 	case LCB_F_SPIN:  /* spinlock */
2621811e827SNamhyung Kim 		curr = bpf_get_current_task_btf();
263*c418d7a6SNamhyung Kim 		sighand = curr->sighand;
264*c418d7a6SNamhyung Kim 
265*c418d7a6SNamhyung Kim 		if (sighand && &sighand->siglock == (void *)lock)
2661811e827SNamhyung Kim 			return LCD_F_SIGHAND_LOCK;
2671811e827SNamhyung Kim 		break;
2683ace2435SNamhyung Kim 	default:
2693ace2435SNamhyung Kim 		break;
2703ace2435SNamhyung Kim 	}
2713ace2435SNamhyung Kim 	return 0;
2723ace2435SNamhyung Kim }
2733ace2435SNamhyung Kim 
274407b36f6SNamhyung Kim SEC("tp_btf/contention_begin")
contention_begin(u64 * ctx)275407b36f6SNamhyung Kim int contention_begin(u64 *ctx)
276407b36f6SNamhyung Kim {
277c66a36afSNamhyung Kim 	__u32 pid;
278407b36f6SNamhyung Kim 	struct tstamp_data *pelem;
279407b36f6SNamhyung Kim 
280529772c4SNamhyung Kim 	if (!enabled || !can_record(ctx))
281407b36f6SNamhyung Kim 		return 0;
282407b36f6SNamhyung Kim 
283c66a36afSNamhyung Kim 	pid = bpf_get_current_pid_tgid();
284c66a36afSNamhyung Kim 	pelem = bpf_map_lookup_elem(&tstamp, &pid);
285c66a36afSNamhyung Kim 	if (pelem && pelem->lock)
286407b36f6SNamhyung Kim 		return 0;
287407b36f6SNamhyung Kim 
288c66a36afSNamhyung Kim 	if (pelem == NULL) {
289c66a36afSNamhyung Kim 		struct tstamp_data zero = {};
290c66a36afSNamhyung Kim 
291c66a36afSNamhyung Kim 		bpf_map_update_elem(&tstamp, &pid, &zero, BPF_ANY);
292c66a36afSNamhyung Kim 		pelem = bpf_map_lookup_elem(&tstamp, &pid);
293c66a36afSNamhyung Kim 		if (pelem == NULL) {
29484c3a2bbSNamhyung Kim 			__sync_fetch_and_add(&task_fail, 1);
295c66a36afSNamhyung Kim 			return 0;
296c66a36afSNamhyung Kim 		}
297c66a36afSNamhyung Kim 	}
298c66a36afSNamhyung Kim 
299407b36f6SNamhyung Kim 	pelem->timestamp = bpf_ktime_get_ns();
300407b36f6SNamhyung Kim 	pelem->lock = (__u64)ctx[0];
301407b36f6SNamhyung Kim 	pelem->flags = (__u32)ctx[1];
302407b36f6SNamhyung Kim 
303ebab2916SNamhyung Kim 	if (needs_callstack) {
304eca949b2SNamhyung Kim 		pelem->stack_id = bpf_get_stackid(ctx, &stacks,
305eca949b2SNamhyung Kim 						  BPF_F_FAST_STACK_CMP | stack_skip);
3066d499a6bSNamhyung Kim 		if (pelem->stack_id < 0)
30784c3a2bbSNamhyung Kim 			__sync_fetch_and_add(&stack_fail, 1);
3083477f079SNamhyung Kim 	} else if (aggr_mode == LOCK_AGGR_TASK) {
3093477f079SNamhyung Kim 		struct task_struct *task;
3103477f079SNamhyung Kim 
3113477f079SNamhyung Kim 		if (lock_owner) {
3121bece135SNamhyung Kim 			task = get_lock_owner(pelem->lock, pelem->flags);
3133477f079SNamhyung Kim 
3143477f079SNamhyung Kim 			/* The flags is not used anymore.  Pass the owner pid. */
3153477f079SNamhyung Kim 			if (task)
3163477f079SNamhyung Kim 				pelem->flags = BPF_CORE_READ(task, pid);
3173477f079SNamhyung Kim 			else
3183477f079SNamhyung Kim 				pelem->flags = -1U;
3193477f079SNamhyung Kim 
3203477f079SNamhyung Kim 		} else {
3213477f079SNamhyung Kim 			task = bpf_get_current_task_btf();
3223477f079SNamhyung Kim 		}
3233477f079SNamhyung Kim 
3243477f079SNamhyung Kim 		if (task) {
3253477f079SNamhyung Kim 			if (update_task_data(task) < 0 && lock_owner)
3263477f079SNamhyung Kim 				pelem->flags = -1U;
3273477f079SNamhyung Kim 		}
328eca949b2SNamhyung Kim 	}
329eca949b2SNamhyung Kim 
330407b36f6SNamhyung Kim 	return 0;
331407b36f6SNamhyung Kim }
332407b36f6SNamhyung Kim 
333407b36f6SNamhyung Kim SEC("tp_btf/contention_end")
contention_end(u64 * ctx)334407b36f6SNamhyung Kim int contention_end(u64 *ctx)
335407b36f6SNamhyung Kim {
336c66a36afSNamhyung Kim 	__u32 pid;
337407b36f6SNamhyung Kim 	struct tstamp_data *pelem;
338ebab2916SNamhyung Kim 	struct contention_key key = {};
339407b36f6SNamhyung Kim 	struct contention_data *data;
340407b36f6SNamhyung Kim 	__u64 duration;
341407b36f6SNamhyung Kim 
342407b36f6SNamhyung Kim 	if (!enabled)
343407b36f6SNamhyung Kim 		return 0;
344407b36f6SNamhyung Kim 
345c66a36afSNamhyung Kim 	pid = bpf_get_current_pid_tgid();
346c66a36afSNamhyung Kim 	pelem = bpf_map_lookup_elem(&tstamp, &pid);
347407b36f6SNamhyung Kim 	if (!pelem || pelem->lock != ctx[0])
348407b36f6SNamhyung Kim 		return 0;
349407b36f6SNamhyung Kim 
350407b36f6SNamhyung Kim 	duration = bpf_ktime_get_ns() - pelem->timestamp;
35184c3a2bbSNamhyung Kim 	if ((__s64)duration < 0) {
35284c3a2bbSNamhyung Kim 		bpf_map_delete_elem(&tstamp, &pid);
35384c3a2bbSNamhyung Kim 		__sync_fetch_and_add(&time_fail, 1);
35484c3a2bbSNamhyung Kim 		return 0;
35584c3a2bbSNamhyung Kim 	}
356407b36f6SNamhyung Kim 
357688d2e8dSNamhyung Kim 	switch (aggr_mode) {
358688d2e8dSNamhyung Kim 	case LOCK_AGGR_CALLER:
359ebab2916SNamhyung Kim 		key.stack_id = pelem->stack_id;
360688d2e8dSNamhyung Kim 		break;
361688d2e8dSNamhyung Kim 	case LOCK_AGGR_TASK:
3623477f079SNamhyung Kim 		if (lock_owner)
3633477f079SNamhyung Kim 			key.pid = pelem->flags;
3643477f079SNamhyung Kim 		else
365ebab2916SNamhyung Kim 			key.pid = pid;
366ebab2916SNamhyung Kim 		if (needs_callstack)
367ebab2916SNamhyung Kim 			key.stack_id = pelem->stack_id;
368688d2e8dSNamhyung Kim 		break;
369688d2e8dSNamhyung Kim 	case LOCK_AGGR_ADDR:
370ebab2916SNamhyung Kim 		key.lock_addr = pelem->lock;
371ebab2916SNamhyung Kim 		if (needs_callstack)
372ebab2916SNamhyung Kim 			key.stack_id = pelem->stack_id;
373688d2e8dSNamhyung Kim 		break;
374688d2e8dSNamhyung Kim 	default:
375688d2e8dSNamhyung Kim 		/* should not happen */
376688d2e8dSNamhyung Kim 		return 0;
377eca949b2SNamhyung Kim 	}
378eca949b2SNamhyung Kim 
379407b36f6SNamhyung Kim 	data = bpf_map_lookup_elem(&lock_stat, &key);
380407b36f6SNamhyung Kim 	if (!data) {
381222de5e5SNamhyung Kim 		if (data_map_full) {
382222de5e5SNamhyung Kim 			bpf_map_delete_elem(&tstamp, &pid);
383222de5e5SNamhyung Kim 			__sync_fetch_and_add(&data_fail, 1);
384222de5e5SNamhyung Kim 			return 0;
385222de5e5SNamhyung Kim 		}
386222de5e5SNamhyung Kim 
387407b36f6SNamhyung Kim 		struct contention_data first = {
388407b36f6SNamhyung Kim 			.total_time = duration,
389407b36f6SNamhyung Kim 			.max_time = duration,
390407b36f6SNamhyung Kim 			.min_time = duration,
391407b36f6SNamhyung Kim 			.count = 1,
392407b36f6SNamhyung Kim 			.flags = pelem->flags,
393407b36f6SNamhyung Kim 		};
394222de5e5SNamhyung Kim 		int err;
395407b36f6SNamhyung Kim 
3963ace2435SNamhyung Kim 		if (aggr_mode == LOCK_AGGR_ADDR)
3973ace2435SNamhyung Kim 			first.flags |= check_lock_type(pelem->lock, pelem->flags);
3983ace2435SNamhyung Kim 
399222de5e5SNamhyung Kim 		err = bpf_map_update_elem(&lock_stat, &key, &first, BPF_NOEXIST);
400222de5e5SNamhyung Kim 		if (err < 0) {
401222de5e5SNamhyung Kim 			if (err == -E2BIG)
402222de5e5SNamhyung Kim 				data_map_full = 1;
403954cdac7SNamhyung Kim 			__sync_fetch_and_add(&data_fail, 1);
404222de5e5SNamhyung Kim 		}
405c66a36afSNamhyung Kim 		bpf_map_delete_elem(&tstamp, &pid);
406407b36f6SNamhyung Kim 		return 0;
407407b36f6SNamhyung Kim 	}
408407b36f6SNamhyung Kim 
409407b36f6SNamhyung Kim 	__sync_fetch_and_add(&data->total_time, duration);
410407b36f6SNamhyung Kim 	__sync_fetch_and_add(&data->count, 1);
411407b36f6SNamhyung Kim 
412407b36f6SNamhyung Kim 	/* FIXME: need atomic operations */
413407b36f6SNamhyung Kim 	if (data->max_time < duration)
414407b36f6SNamhyung Kim 		data->max_time = duration;
415407b36f6SNamhyung Kim 	if (data->min_time > duration)
416407b36f6SNamhyung Kim 		data->min_time = duration;
417407b36f6SNamhyung Kim 
418c66a36afSNamhyung Kim 	bpf_map_delete_elem(&tstamp, &pid);
419407b36f6SNamhyung Kim 	return 0;
420407b36f6SNamhyung Kim }
421407b36f6SNamhyung Kim 
422d24c0144SNamhyung Kim extern struct rq runqueues __ksym;
423d24c0144SNamhyung Kim 
424e53de7b6SNamhyung Kim struct rq___old {
4250c122848SIan Rogers 	raw_spinlock_t lock;
4260c122848SIan Rogers } __attribute__((preserve_access_index));
4270c122848SIan Rogers 
428e53de7b6SNamhyung Kim struct rq___new {
4290c122848SIan Rogers 	raw_spinlock_t __lock;
4300c122848SIan Rogers } __attribute__((preserve_access_index));
4310c122848SIan Rogers 
432d24c0144SNamhyung Kim SEC("raw_tp/bpf_test_finish")
BPF_PROG(collect_lock_syms)433d24c0144SNamhyung Kim int BPF_PROG(collect_lock_syms)
434d24c0144SNamhyung Kim {
435b9f82b5cSNamhyung Kim 	__u64 lock_addr, lock_off;
436d24c0144SNamhyung Kim 	__u32 lock_flag;
437d24c0144SNamhyung Kim 
438b9f82b5cSNamhyung Kim 	if (bpf_core_field_exists(struct rq___new, __lock))
439b9f82b5cSNamhyung Kim 		lock_off = offsetof(struct rq___new, __lock);
440b9f82b5cSNamhyung Kim 	else
441b9f82b5cSNamhyung Kim 		lock_off = offsetof(struct rq___old, lock);
442b9f82b5cSNamhyung Kim 
443d24c0144SNamhyung Kim 	for (int i = 0; i < MAX_CPUS; i++) {
444d24c0144SNamhyung Kim 		struct rq *rq = bpf_per_cpu_ptr(&runqueues, i);
445d24c0144SNamhyung Kim 
446d24c0144SNamhyung Kim 		if (rq == NULL)
447d24c0144SNamhyung Kim 			break;
448d24c0144SNamhyung Kim 
449b9f82b5cSNamhyung Kim 		lock_addr = (__u64)(void *)rq + lock_off;
450d24c0144SNamhyung Kim 		lock_flag = LOCK_CLASS_RQLOCK;
451d24c0144SNamhyung Kim 		bpf_map_update_elem(&lock_syms, &lock_addr, &lock_flag, BPF_ANY);
452d24c0144SNamhyung Kim 	}
453d24c0144SNamhyung Kim 	return 0;
454d24c0144SNamhyung Kim }
455d24c0144SNamhyung Kim 
456407b36f6SNamhyung Kim char LICENSE[] SEC("license") = "Dual BSD/GPL";
457