• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Anton Protopopov
3 //
4 // Based on syscount(8) from BCC by Sasha Goldshtein
5 #include <vmlinux.h>
6 #include <bpf/bpf_helpers.h>
7 #include <bpf/bpf_tracing.h>
8 #include <bpf/bpf_core_read.h>
9 #include "syscount.h"
10 #include "maps.bpf.h"
11 
12 const volatile bool count_by_process = false;
13 const volatile bool measure_latency = false;
14 const volatile bool filter_failed = false;
15 const volatile int filter_errno = false;
16 const volatile pid_t filter_pid = 0;
17 
18 struct {
19 	__uint(type, BPF_MAP_TYPE_HASH);
20 	__uint(max_entries, MAX_ENTRIES);
21 	__type(key, u32);
22 	__type(value, u64);
23 	__uint(map_flags, BPF_F_NO_PREALLOC);
24 } start SEC(".maps");
25 
26 struct {
27 	__uint(type, BPF_MAP_TYPE_HASH);
28 	__uint(max_entries, MAX_ENTRIES);
29 	__type(key, u32);
30 	__type(value, struct data_t);
31 	__uint(map_flags, BPF_F_NO_PREALLOC);
32 } data SEC(".maps");
33 
34 static __always_inline
save_proc_name(struct data_t * val)35 void save_proc_name(struct data_t *val)
36 {
37 	struct task_struct *current = (void *)bpf_get_current_task();
38 
39 	/* We should save the process name every time because it can be
40 	 * changed (e.g., by exec).  This can be optimized later by managing
41 	 * this field with the help of tp/sched/sched_process_exec and
42 	 * raw_tp/task_rename. */
43 	BPF_CORE_READ_STR_INTO(&val->comm, current, group_leader, comm);
44 }
45 
46 SEC("tracepoint/raw_syscalls/sys_enter")
sys_enter(struct trace_event_raw_sys_enter * args)47 int sys_enter(struct trace_event_raw_sys_enter *args)
48 {
49 	u64 id = bpf_get_current_pid_tgid();
50 	pid_t pid = id >> 32;
51 	u32 tid = id;
52 	u64 ts;
53 
54 	if (filter_pid && pid != filter_pid)
55 		return 0;
56 
57 	ts = bpf_ktime_get_ns();
58 	bpf_map_update_elem(&start, &tid, &ts, 0);
59 	return 0;
60 }
61 
62 SEC("tracepoint/raw_syscalls/sys_exit")
sys_exit(struct trace_event_raw_sys_exit * args)63 int sys_exit(struct trace_event_raw_sys_exit *args)
64 {
65 	u64 id = bpf_get_current_pid_tgid();
66 	static const struct data_t zero;
67 	pid_t pid = id >> 32;
68 	struct data_t *val;
69 	u64 *start_ts;
70 	u32 tid = id;
71 	u32 key;
72 
73 	/* this happens when there is an interrupt */
74 	if (args->id == -1)
75 		return 0;
76 
77 	if (filter_pid && pid != filter_pid)
78 		return 0;
79 	if (filter_failed && args->ret >= 0)
80 		return 0;
81 	if (filter_errno && args->ret != -filter_errno)
82 		return 0;
83 
84 	if (measure_latency) {
85 		start_ts = bpf_map_lookup_elem(&start, &tid);
86 		if (!start_ts)
87 			return 0;
88 	}
89 
90 	key = (count_by_process) ? pid : args->id;
91 	val = bpf_map_lookup_or_try_init(&data, &key, &zero);
92 	if (val) {
93 		__sync_fetch_and_add(&val->count, 1);
94 		if (count_by_process)
95 			save_proc_name(val);
96 		if (measure_latency)
97 			__sync_fetch_and_add(&val->total_ns, bpf_ktime_get_ns() - *start_ts);
98 	}
99 	return 0;
100 }
101 
102 char LICENSE[] SEC("license") = "GPL";
103