xref: /aosp_15_r20/external/bcc/libbpf-tools/klockstat.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*387f9dfdSAndroid Build Coastguard Worker /* Copyright (c) 2021 Google LLC.
3*387f9dfdSAndroid Build Coastguard Worker  *
4*387f9dfdSAndroid Build Coastguard Worker  * Based on klockstat from BCC by Jiri Olsa and others
5*387f9dfdSAndroid Build Coastguard Worker  * 2021-10-26   Barret Rhoden   Created this.
6*387f9dfdSAndroid Build Coastguard Worker  */
7*387f9dfdSAndroid Build Coastguard Worker /* Differences from BCC python tool:
8*387f9dfdSAndroid Build Coastguard Worker  * - can specify a lock by ksym name, using '-L'
9*387f9dfdSAndroid Build Coastguard Worker  * - tracks whichever task had the max time for acquire and hold, outputted
10*387f9dfdSAndroid Build Coastguard Worker  *     when '-s' > 1 (otherwise it's cluttered).
11*387f9dfdSAndroid Build Coastguard Worker  * - does not reset stats each interval by default. Can request with -R.
12*387f9dfdSAndroid Build Coastguard Worker  */
13*387f9dfdSAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
14*387f9dfdSAndroid Build Coastguard Worker #define _GNU_SOURCE
15*387f9dfdSAndroid Build Coastguard Worker #endif
16*387f9dfdSAndroid Build Coastguard Worker #include <argp.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <signal.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
22*387f9dfdSAndroid Build Coastguard Worker #include <time.h>
23*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
24*387f9dfdSAndroid Build Coastguard Worker #include <sys/param.h>
25*387f9dfdSAndroid Build Coastguard Worker 
26*387f9dfdSAndroid Build Coastguard Worker #include <bpf/libbpf.h>
27*387f9dfdSAndroid Build Coastguard Worker #include <bpf/bpf.h>
28*387f9dfdSAndroid Build Coastguard Worker #include "klockstat.h"
29*387f9dfdSAndroid Build Coastguard Worker #include "klockstat.skel.h"
30*387f9dfdSAndroid Build Coastguard Worker #include "compat.h"
31*387f9dfdSAndroid Build Coastguard Worker #include "trace_helpers.h"
32*387f9dfdSAndroid Build Coastguard Worker 
33*387f9dfdSAndroid Build Coastguard Worker #define warn(...) fprintf(stderr, __VA_ARGS__)
34*387f9dfdSAndroid Build Coastguard Worker 
35*387f9dfdSAndroid Build Coastguard Worker enum {
36*387f9dfdSAndroid Build Coastguard Worker 	SORT_ACQ_MAX,
37*387f9dfdSAndroid Build Coastguard Worker 	SORT_ACQ_COUNT,
38*387f9dfdSAndroid Build Coastguard Worker 	SORT_ACQ_TOTAL,
39*387f9dfdSAndroid Build Coastguard Worker 	SORT_HLD_MAX,
40*387f9dfdSAndroid Build Coastguard Worker 	SORT_HLD_COUNT,
41*387f9dfdSAndroid Build Coastguard Worker 	SORT_HLD_TOTAL,
42*387f9dfdSAndroid Build Coastguard Worker };
43*387f9dfdSAndroid Build Coastguard Worker 
44*387f9dfdSAndroid Build Coastguard Worker static struct prog_env {
45*387f9dfdSAndroid Build Coastguard Worker 	pid_t pid;
46*387f9dfdSAndroid Build Coastguard Worker 	pid_t tid;
47*387f9dfdSAndroid Build Coastguard Worker 	char *caller;
48*387f9dfdSAndroid Build Coastguard Worker 	char *lock_name;
49*387f9dfdSAndroid Build Coastguard Worker 	unsigned int nr_locks;
50*387f9dfdSAndroid Build Coastguard Worker 	unsigned int nr_stack_entries;
51*387f9dfdSAndroid Build Coastguard Worker 	unsigned int sort_acq;
52*387f9dfdSAndroid Build Coastguard Worker 	unsigned int sort_hld;
53*387f9dfdSAndroid Build Coastguard Worker 	unsigned int duration;
54*387f9dfdSAndroid Build Coastguard Worker 	unsigned int interval;
55*387f9dfdSAndroid Build Coastguard Worker 	unsigned int iterations;
56*387f9dfdSAndroid Build Coastguard Worker 	bool reset;
57*387f9dfdSAndroid Build Coastguard Worker 	bool timestamp;
58*387f9dfdSAndroid Build Coastguard Worker 	bool verbose;
59*387f9dfdSAndroid Build Coastguard Worker 	bool per_thread;
60*387f9dfdSAndroid Build Coastguard Worker } env = {
61*387f9dfdSAndroid Build Coastguard Worker 	.nr_locks = 99999999,
62*387f9dfdSAndroid Build Coastguard Worker 	.nr_stack_entries = 1,
63*387f9dfdSAndroid Build Coastguard Worker 	.sort_acq = SORT_ACQ_MAX,
64*387f9dfdSAndroid Build Coastguard Worker 	.sort_hld = SORT_HLD_MAX,
65*387f9dfdSAndroid Build Coastguard Worker 	.interval = 99999999,
66*387f9dfdSAndroid Build Coastguard Worker 	.iterations = 99999999,
67*387f9dfdSAndroid Build Coastguard Worker };
68*387f9dfdSAndroid Build Coastguard Worker 
69*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_version = "klockstat 0.2";
70*387f9dfdSAndroid Build Coastguard Worker const char *argp_program_bug_address =
71*387f9dfdSAndroid Build Coastguard Worker 	"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
72*387f9dfdSAndroid Build Coastguard Worker static const char args_doc[] = "FUNCTION";
73*387f9dfdSAndroid Build Coastguard Worker static const char program_doc[] =
74*387f9dfdSAndroid Build Coastguard Worker "Trace mutex/sem lock acquisition and hold times, in nsec\n"
75*387f9dfdSAndroid Build Coastguard Worker "\n"
76*387f9dfdSAndroid Build Coastguard Worker "Usage: klockstat [-hPRTv] [-p PID] [-t TID] [-c FUNC] [-L LOCK] [-n NR_LOCKS]\n"
77*387f9dfdSAndroid Build Coastguard Worker "                 [-s NR_STACKS] [-S SORT] [-d DURATION] [-i INTERVAL]\n"
78*387f9dfdSAndroid Build Coastguard Worker "\v"
79*387f9dfdSAndroid Build Coastguard Worker "Examples:\n"
80*387f9dfdSAndroid Build Coastguard Worker "  klockstat                     # trace system wide until ctrl-c\n"
81*387f9dfdSAndroid Build Coastguard Worker "  klockstat -d 5                # trace for 5 seconds\n"
82*387f9dfdSAndroid Build Coastguard Worker "  klockstat -i 5                # print stats every 5 seconds\n"
83*387f9dfdSAndroid Build Coastguard Worker "  klockstat -p 181              # trace process 181 only\n"
84*387f9dfdSAndroid Build Coastguard Worker "  klockstat -t 181              # trace thread 181 only\n"
85*387f9dfdSAndroid Build Coastguard Worker "  klockstat -c pipe_            # print only for lock callers with 'pipe_'\n"
86*387f9dfdSAndroid Build Coastguard Worker "                                # prefix\n"
87*387f9dfdSAndroid Build Coastguard Worker "  klockstat -L cgroup_mutex     # trace the cgroup_mutex lock only (accepts addr too)\n"
88*387f9dfdSAndroid Build Coastguard Worker "  klockstat -S acq_count        # sort lock acquired results by acquire count\n"
89*387f9dfdSAndroid Build Coastguard Worker "  klockstat -S hld_total        # sort lock held results by total held time\n"
90*387f9dfdSAndroid Build Coastguard Worker "  klockstat -S acq_count,hld_total  # combination of above\n"
91*387f9dfdSAndroid Build Coastguard Worker "  klockstat -n 3                # display top 3 locks/threads\n"
92*387f9dfdSAndroid Build Coastguard Worker "  klockstat -s 6                # display 6 stack entries per lock\n"
93*387f9dfdSAndroid Build Coastguard Worker "  klockstat -P                  # print stats per thread\n"
94*387f9dfdSAndroid Build Coastguard Worker ;
95*387f9dfdSAndroid Build Coastguard Worker 
96*387f9dfdSAndroid Build Coastguard Worker static const struct argp_option opts[] = {
97*387f9dfdSAndroid Build Coastguard Worker 	{ "pid", 'p', "PID", 0, "Filter by process ID" },
98*387f9dfdSAndroid Build Coastguard Worker 	{ "tid", 't', "TID", 0, "Filter by thread ID" },
99*387f9dfdSAndroid Build Coastguard Worker 	{ 0, 0, 0, 0, "" },
100*387f9dfdSAndroid Build Coastguard Worker 	{ "caller", 'c', "FUNC", 0, "Filter by caller string prefix" },
101*387f9dfdSAndroid Build Coastguard Worker 	{ "lock", 'L', "LOCK", 0, "Filter by specific ksym lock name" },
102*387f9dfdSAndroid Build Coastguard Worker 	{ 0, 0, 0, 0, "" },
103*387f9dfdSAndroid Build Coastguard Worker 	{ "locks", 'n', "NR_LOCKS", 0, "Number of locks or threads to print" },
104*387f9dfdSAndroid Build Coastguard Worker 	{ "stacks", 's', "NR_STACKS", 0, "Number of stack entries to print per lock" },
105*387f9dfdSAndroid Build Coastguard Worker 	{ "sort", 'S', "SORT", 0, "Sort by field:\n  acq_[max|total|count]\n  hld_[max|total|count]" },
106*387f9dfdSAndroid Build Coastguard Worker 	{ 0, 0, 0, 0, "" },
107*387f9dfdSAndroid Build Coastguard Worker 	{ "duration", 'd', "SECONDS", 0, "Duration to trace" },
108*387f9dfdSAndroid Build Coastguard Worker 	{ "interval", 'i', "SECONDS", 0, "Print interval" },
109*387f9dfdSAndroid Build Coastguard Worker 	{ "reset", 'R', NULL, 0, "Reset stats each interval" },
110*387f9dfdSAndroid Build Coastguard Worker 	{ "timestamp", 'T', NULL, 0, "Print timestamp" },
111*387f9dfdSAndroid Build Coastguard Worker 	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
112*387f9dfdSAndroid Build Coastguard Worker 	{ "per-thread", 'P', NULL, 0, "Print per-thread stats" },
113*387f9dfdSAndroid Build Coastguard Worker 
114*387f9dfdSAndroid Build Coastguard Worker 	{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
115*387f9dfdSAndroid Build Coastguard Worker 	{},
116*387f9dfdSAndroid Build Coastguard Worker };
117*387f9dfdSAndroid Build Coastguard Worker 
parse_lock_addr(const char * lock_name)118*387f9dfdSAndroid Build Coastguard Worker static void *parse_lock_addr(const char *lock_name)
119*387f9dfdSAndroid Build Coastguard Worker {
120*387f9dfdSAndroid Build Coastguard Worker 	unsigned long lock_addr;
121*387f9dfdSAndroid Build Coastguard Worker 
122*387f9dfdSAndroid Build Coastguard Worker 	return sscanf(lock_name, "0x%lx", &lock_addr) ? (void*)lock_addr : NULL;
123*387f9dfdSAndroid Build Coastguard Worker }
124*387f9dfdSAndroid Build Coastguard Worker 
get_lock_addr(struct ksyms * ksyms,const char * lock_name)125*387f9dfdSAndroid Build Coastguard Worker static void *get_lock_addr(struct ksyms *ksyms, const char *lock_name)
126*387f9dfdSAndroid Build Coastguard Worker {
127*387f9dfdSAndroid Build Coastguard Worker 	const struct ksym *ksym = ksyms__get_symbol(ksyms, lock_name);
128*387f9dfdSAndroid Build Coastguard Worker 
129*387f9dfdSAndroid Build Coastguard Worker 	return ksym ? (void*)ksym->addr : parse_lock_addr(lock_name);
130*387f9dfdSAndroid Build Coastguard Worker }
131*387f9dfdSAndroid Build Coastguard Worker 
get_lock_name(struct ksyms * ksyms,unsigned long addr)132*387f9dfdSAndroid Build Coastguard Worker static const char *get_lock_name(struct ksyms *ksyms, unsigned long addr)
133*387f9dfdSAndroid Build Coastguard Worker {
134*387f9dfdSAndroid Build Coastguard Worker 	const struct ksym *ksym = ksyms__map_addr(ksyms, addr);
135*387f9dfdSAndroid Build Coastguard Worker 
136*387f9dfdSAndroid Build Coastguard Worker 	return (ksym && ksym->addr == addr) ? ksym->name : "no-ksym";
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker 
parse_one_sort(struct prog_env * env,const char * sort)139*387f9dfdSAndroid Build Coastguard Worker static bool parse_one_sort(struct prog_env *env, const char *sort)
140*387f9dfdSAndroid Build Coastguard Worker {
141*387f9dfdSAndroid Build Coastguard Worker 	const char *field = sort + 4;
142*387f9dfdSAndroid Build Coastguard Worker 
143*387f9dfdSAndroid Build Coastguard Worker 	if (!strncmp(sort, "acq_", 4)) {
144*387f9dfdSAndroid Build Coastguard Worker 		if (!strcmp(field, "max")) {
145*387f9dfdSAndroid Build Coastguard Worker 			env->sort_acq = SORT_ACQ_MAX;
146*387f9dfdSAndroid Build Coastguard Worker 			return true;
147*387f9dfdSAndroid Build Coastguard Worker 		} else if (!strcmp(field, "total")) {
148*387f9dfdSAndroid Build Coastguard Worker 			env->sort_acq = SORT_ACQ_TOTAL;
149*387f9dfdSAndroid Build Coastguard Worker 			return true;
150*387f9dfdSAndroid Build Coastguard Worker 		} else if (!strcmp(field, "count")) {
151*387f9dfdSAndroid Build Coastguard Worker 			env->sort_acq = SORT_ACQ_COUNT;
152*387f9dfdSAndroid Build Coastguard Worker 			return true;
153*387f9dfdSAndroid Build Coastguard Worker 		}
154*387f9dfdSAndroid Build Coastguard Worker 	} else if (!strncmp(sort, "hld_", 4)) {
155*387f9dfdSAndroid Build Coastguard Worker 		if (!strcmp(field, "max")) {
156*387f9dfdSAndroid Build Coastguard Worker 			env->sort_hld = SORT_HLD_MAX;
157*387f9dfdSAndroid Build Coastguard Worker 			return true;
158*387f9dfdSAndroid Build Coastguard Worker 		} else if (!strcmp(field, "total")) {
159*387f9dfdSAndroid Build Coastguard Worker 			env->sort_hld = SORT_HLD_TOTAL;
160*387f9dfdSAndroid Build Coastguard Worker 			return true;
161*387f9dfdSAndroid Build Coastguard Worker 		} else if (!strcmp(field, "count")) {
162*387f9dfdSAndroid Build Coastguard Worker 			env->sort_hld = SORT_HLD_COUNT;
163*387f9dfdSAndroid Build Coastguard Worker 			return true;
164*387f9dfdSAndroid Build Coastguard Worker 		}
165*387f9dfdSAndroid Build Coastguard Worker 	}
166*387f9dfdSAndroid Build Coastguard Worker 
167*387f9dfdSAndroid Build Coastguard Worker 	return false;
168*387f9dfdSAndroid Build Coastguard Worker }
169*387f9dfdSAndroid Build Coastguard Worker 
parse_sorts(struct prog_env * env,char * arg)170*387f9dfdSAndroid Build Coastguard Worker static bool parse_sorts(struct prog_env *env, char *arg)
171*387f9dfdSAndroid Build Coastguard Worker {
172*387f9dfdSAndroid Build Coastguard Worker 	char *comma = strchr(arg, ',');
173*387f9dfdSAndroid Build Coastguard Worker 
174*387f9dfdSAndroid Build Coastguard Worker 	if (comma) {
175*387f9dfdSAndroid Build Coastguard Worker 		*comma = '\0';
176*387f9dfdSAndroid Build Coastguard Worker 		comma++;
177*387f9dfdSAndroid Build Coastguard Worker 		if (!parse_one_sort(env, comma))
178*387f9dfdSAndroid Build Coastguard Worker 			return false;
179*387f9dfdSAndroid Build Coastguard Worker 	}
180*387f9dfdSAndroid Build Coastguard Worker 	return parse_one_sort(env, arg);
181*387f9dfdSAndroid Build Coastguard Worker }
182*387f9dfdSAndroid Build Coastguard Worker 
parse_arg(int key,char * arg,struct argp_state * state)183*387f9dfdSAndroid Build Coastguard Worker static error_t parse_arg(int key, char *arg, struct argp_state *state)
184*387f9dfdSAndroid Build Coastguard Worker {
185*387f9dfdSAndroid Build Coastguard Worker 	struct prog_env *env = state->input;
186*387f9dfdSAndroid Build Coastguard Worker 	long duration, interval;
187*387f9dfdSAndroid Build Coastguard Worker 
188*387f9dfdSAndroid Build Coastguard Worker 	switch (key) {
189*387f9dfdSAndroid Build Coastguard Worker 	case 'p':
190*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
191*387f9dfdSAndroid Build Coastguard Worker 		env->pid = strtol(arg, NULL, 10);
192*387f9dfdSAndroid Build Coastguard Worker 		if (errno || env->pid <= 0) {
193*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid PID: %s\n", arg);
194*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
195*387f9dfdSAndroid Build Coastguard Worker 		}
196*387f9dfdSAndroid Build Coastguard Worker 		break;
197*387f9dfdSAndroid Build Coastguard Worker 	case 't':
198*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
199*387f9dfdSAndroid Build Coastguard Worker 		env->tid = strtol(arg, NULL, 10);
200*387f9dfdSAndroid Build Coastguard Worker 		if (errno || env->tid <= 0) {
201*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid TID: %s\n", arg);
202*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
203*387f9dfdSAndroid Build Coastguard Worker 		}
204*387f9dfdSAndroid Build Coastguard Worker 		break;
205*387f9dfdSAndroid Build Coastguard Worker 	case 'c':
206*387f9dfdSAndroid Build Coastguard Worker 		env->caller = arg;
207*387f9dfdSAndroid Build Coastguard Worker 		break;
208*387f9dfdSAndroid Build Coastguard Worker 	case 'L':
209*387f9dfdSAndroid Build Coastguard Worker 		env->lock_name = arg;
210*387f9dfdSAndroid Build Coastguard Worker 		break;
211*387f9dfdSAndroid Build Coastguard Worker 	case 'n':
212*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
213*387f9dfdSAndroid Build Coastguard Worker 		env->nr_locks = strtol(arg, NULL, 10);
214*387f9dfdSAndroid Build Coastguard Worker 		if (errno || env->nr_locks <= 0) {
215*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid NR_LOCKS: %s\n", arg);
216*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
217*387f9dfdSAndroid Build Coastguard Worker 		}
218*387f9dfdSAndroid Build Coastguard Worker 		break;
219*387f9dfdSAndroid Build Coastguard Worker 	case 's':
220*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
221*387f9dfdSAndroid Build Coastguard Worker 		env->nr_stack_entries = strtol(arg, NULL, 10);
222*387f9dfdSAndroid Build Coastguard Worker 		if (errno || env->nr_stack_entries <= 0) {
223*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid NR_STACKS: %s\n", arg);
224*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
225*387f9dfdSAndroid Build Coastguard Worker 		}
226*387f9dfdSAndroid Build Coastguard Worker 		break;
227*387f9dfdSAndroid Build Coastguard Worker 	case 'S':
228*387f9dfdSAndroid Build Coastguard Worker 		if (!parse_sorts(env, arg)) {
229*387f9dfdSAndroid Build Coastguard Worker 			warn("Bad sort string: %s\n", arg);
230*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
231*387f9dfdSAndroid Build Coastguard Worker 		}
232*387f9dfdSAndroid Build Coastguard Worker 		break;
233*387f9dfdSAndroid Build Coastguard Worker 	case 'd':
234*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
235*387f9dfdSAndroid Build Coastguard Worker 		duration = strtol(arg, NULL, 10);
236*387f9dfdSAndroid Build Coastguard Worker 		if (errno || duration <= 0) {
237*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid duration: %s\n", arg);
238*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
239*387f9dfdSAndroid Build Coastguard Worker 		}
240*387f9dfdSAndroid Build Coastguard Worker 		env->duration = duration;
241*387f9dfdSAndroid Build Coastguard Worker 		break;
242*387f9dfdSAndroid Build Coastguard Worker 	case 'i':
243*387f9dfdSAndroid Build Coastguard Worker 		errno = 0;
244*387f9dfdSAndroid Build Coastguard Worker 		interval = strtol(arg, NULL, 10);
245*387f9dfdSAndroid Build Coastguard Worker 		if (errno || interval <= 0) {
246*387f9dfdSAndroid Build Coastguard Worker 			warn("Invalid interval: %s\n", arg);
247*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
248*387f9dfdSAndroid Build Coastguard Worker 		}
249*387f9dfdSAndroid Build Coastguard Worker 		env->interval = interval;
250*387f9dfdSAndroid Build Coastguard Worker 		break;
251*387f9dfdSAndroid Build Coastguard Worker 	case 'R':
252*387f9dfdSAndroid Build Coastguard Worker 		env->reset = true;
253*387f9dfdSAndroid Build Coastguard Worker 		break;
254*387f9dfdSAndroid Build Coastguard Worker 	case 'T':
255*387f9dfdSAndroid Build Coastguard Worker 		env->timestamp = true;
256*387f9dfdSAndroid Build Coastguard Worker 		break;
257*387f9dfdSAndroid Build Coastguard Worker 	case 'P':
258*387f9dfdSAndroid Build Coastguard Worker 		env->per_thread = true;
259*387f9dfdSAndroid Build Coastguard Worker 		break;
260*387f9dfdSAndroid Build Coastguard Worker 	case 'h':
261*387f9dfdSAndroid Build Coastguard Worker 		argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
262*387f9dfdSAndroid Build Coastguard Worker 		break;
263*387f9dfdSAndroid Build Coastguard Worker 	case 'v':
264*387f9dfdSAndroid Build Coastguard Worker 		env->verbose = true;
265*387f9dfdSAndroid Build Coastguard Worker 		break;
266*387f9dfdSAndroid Build Coastguard Worker 	case ARGP_KEY_END:
267*387f9dfdSAndroid Build Coastguard Worker 		if (env->duration) {
268*387f9dfdSAndroid Build Coastguard Worker 			if (env->interval > env->duration)
269*387f9dfdSAndroid Build Coastguard Worker 				env->interval = env->duration;
270*387f9dfdSAndroid Build Coastguard Worker 			env->iterations = env->duration / env->interval;
271*387f9dfdSAndroid Build Coastguard Worker 		}
272*387f9dfdSAndroid Build Coastguard Worker 		if (env->per_thread && env->nr_stack_entries != 1) {
273*387f9dfdSAndroid Build Coastguard Worker 			warn("--per-thread and --stacks cannot be used together\n");
274*387f9dfdSAndroid Build Coastguard Worker 			argp_usage(state);
275*387f9dfdSAndroid Build Coastguard Worker 		}
276*387f9dfdSAndroid Build Coastguard Worker 		break;
277*387f9dfdSAndroid Build Coastguard Worker 	default:
278*387f9dfdSAndroid Build Coastguard Worker 		return ARGP_ERR_UNKNOWN;
279*387f9dfdSAndroid Build Coastguard Worker 	}
280*387f9dfdSAndroid Build Coastguard Worker 	return 0;
281*387f9dfdSAndroid Build Coastguard Worker }
282*387f9dfdSAndroid Build Coastguard Worker 
283*387f9dfdSAndroid Build Coastguard Worker struct stack_stat {
284*387f9dfdSAndroid Build Coastguard Worker 	uint32_t stack_id;
285*387f9dfdSAndroid Build Coastguard Worker 	struct lock_stat ls;
286*387f9dfdSAndroid Build Coastguard Worker 	uint64_t bt[PERF_MAX_STACK_DEPTH];
287*387f9dfdSAndroid Build Coastguard Worker };
288*387f9dfdSAndroid Build Coastguard Worker 
caller_is_traced(struct ksyms * ksyms,uint64_t caller_pc)289*387f9dfdSAndroid Build Coastguard Worker static bool caller_is_traced(struct ksyms *ksyms, uint64_t caller_pc)
290*387f9dfdSAndroid Build Coastguard Worker {
291*387f9dfdSAndroid Build Coastguard Worker 	const struct ksym *ksym;
292*387f9dfdSAndroid Build Coastguard Worker 
293*387f9dfdSAndroid Build Coastguard Worker 	if (!env.caller)
294*387f9dfdSAndroid Build Coastguard Worker 		return true;
295*387f9dfdSAndroid Build Coastguard Worker 	ksym = ksyms__map_addr(ksyms, caller_pc);
296*387f9dfdSAndroid Build Coastguard Worker 	if (!ksym)
297*387f9dfdSAndroid Build Coastguard Worker 		return true;
298*387f9dfdSAndroid Build Coastguard Worker 	return strncmp(env.caller, ksym->name, strlen(env.caller)) == 0;
299*387f9dfdSAndroid Build Coastguard Worker }
300*387f9dfdSAndroid Build Coastguard Worker 
larger_first(uint64_t x,uint64_t y)301*387f9dfdSAndroid Build Coastguard Worker static int larger_first(uint64_t x, uint64_t y)
302*387f9dfdSAndroid Build Coastguard Worker {
303*387f9dfdSAndroid Build Coastguard Worker 	if (x > y)
304*387f9dfdSAndroid Build Coastguard Worker 		return -1;
305*387f9dfdSAndroid Build Coastguard Worker 	if (x == y)
306*387f9dfdSAndroid Build Coastguard Worker 		return 0;
307*387f9dfdSAndroid Build Coastguard Worker 	return 1;
308*387f9dfdSAndroid Build Coastguard Worker }
309*387f9dfdSAndroid Build Coastguard Worker 
sort_by_acq(const void * x,const void * y)310*387f9dfdSAndroid Build Coastguard Worker static int sort_by_acq(const void *x, const void *y)
311*387f9dfdSAndroid Build Coastguard Worker {
312*387f9dfdSAndroid Build Coastguard Worker 	struct stack_stat *ss_x = *(struct stack_stat**)x;
313*387f9dfdSAndroid Build Coastguard Worker 	struct stack_stat *ss_y = *(struct stack_stat**)y;
314*387f9dfdSAndroid Build Coastguard Worker 
315*387f9dfdSAndroid Build Coastguard Worker 	switch (env.sort_acq) {
316*387f9dfdSAndroid Build Coastguard Worker 	case SORT_ACQ_MAX:
317*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.acq_max_time,
318*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.acq_max_time);
319*387f9dfdSAndroid Build Coastguard Worker 	case SORT_ACQ_COUNT:
320*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.acq_count,
321*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.acq_count);
322*387f9dfdSAndroid Build Coastguard Worker 	case SORT_ACQ_TOTAL:
323*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.acq_total_time,
324*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.acq_total_time);
325*387f9dfdSAndroid Build Coastguard Worker 	}
326*387f9dfdSAndroid Build Coastguard Worker 
327*387f9dfdSAndroid Build Coastguard Worker 	warn("bad sort_acq %d\n", env.sort_acq);
328*387f9dfdSAndroid Build Coastguard Worker 	return -1;
329*387f9dfdSAndroid Build Coastguard Worker }
330*387f9dfdSAndroid Build Coastguard Worker 
sort_by_hld(const void * x,const void * y)331*387f9dfdSAndroid Build Coastguard Worker static int sort_by_hld(const void *x, const void *y)
332*387f9dfdSAndroid Build Coastguard Worker {
333*387f9dfdSAndroid Build Coastguard Worker 	struct stack_stat *ss_x = *(struct stack_stat**)x;
334*387f9dfdSAndroid Build Coastguard Worker 	struct stack_stat *ss_y = *(struct stack_stat**)y;
335*387f9dfdSAndroid Build Coastguard Worker 
336*387f9dfdSAndroid Build Coastguard Worker 	switch (env.sort_hld) {
337*387f9dfdSAndroid Build Coastguard Worker 	case SORT_HLD_MAX:
338*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.hld_max_time,
339*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.hld_max_time);
340*387f9dfdSAndroid Build Coastguard Worker 	case SORT_HLD_COUNT:
341*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.hld_count,
342*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.hld_count);
343*387f9dfdSAndroid Build Coastguard Worker 	case SORT_HLD_TOTAL:
344*387f9dfdSAndroid Build Coastguard Worker 		return larger_first(ss_x->ls.hld_total_time,
345*387f9dfdSAndroid Build Coastguard Worker 				    ss_y->ls.hld_total_time);
346*387f9dfdSAndroid Build Coastguard Worker 	}
347*387f9dfdSAndroid Build Coastguard Worker 
348*387f9dfdSAndroid Build Coastguard Worker 	warn("bad sort_hld %d\n", env.sort_hld);
349*387f9dfdSAndroid Build Coastguard Worker 	return -1;
350*387f9dfdSAndroid Build Coastguard Worker }
351*387f9dfdSAndroid Build Coastguard Worker 
symname(struct ksyms * ksyms,uint64_t pc,char * buf,size_t n)352*387f9dfdSAndroid Build Coastguard Worker static char *symname(struct ksyms *ksyms, uint64_t pc, char *buf, size_t n)
353*387f9dfdSAndroid Build Coastguard Worker {
354*387f9dfdSAndroid Build Coastguard Worker 	const struct ksym *ksym = ksyms__map_addr(ksyms, pc);
355*387f9dfdSAndroid Build Coastguard Worker 
356*387f9dfdSAndroid Build Coastguard Worker 	if (!ksym)
357*387f9dfdSAndroid Build Coastguard Worker 		return "Unknown";
358*387f9dfdSAndroid Build Coastguard Worker 	snprintf(buf, n, "%s+0x%lx", ksym->name, pc - ksym->addr);
359*387f9dfdSAndroid Build Coastguard Worker 	return buf;
360*387f9dfdSAndroid Build Coastguard Worker }
361*387f9dfdSAndroid Build Coastguard Worker 
print_caller(char * buf,int size,struct stack_stat * ss)362*387f9dfdSAndroid Build Coastguard Worker static char *print_caller(char *buf, int size, struct stack_stat *ss)
363*387f9dfdSAndroid Build Coastguard Worker {
364*387f9dfdSAndroid Build Coastguard Worker 	snprintf(buf, size, "%u  %16s", ss->stack_id, ss->ls.acq_max_comm);
365*387f9dfdSAndroid Build Coastguard Worker 	return buf;
366*387f9dfdSAndroid Build Coastguard Worker }
367*387f9dfdSAndroid Build Coastguard Worker 
print_time(char * buf,int size,uint64_t nsec)368*387f9dfdSAndroid Build Coastguard Worker static char *print_time(char *buf, int size, uint64_t nsec)
369*387f9dfdSAndroid Build Coastguard Worker {
370*387f9dfdSAndroid Build Coastguard Worker 	struct {
371*387f9dfdSAndroid Build Coastguard Worker 		float base;
372*387f9dfdSAndroid Build Coastguard Worker 		char *unit;
373*387f9dfdSAndroid Build Coastguard Worker 	} table[] = {
374*387f9dfdSAndroid Build Coastguard Worker 		{ 1e9 * 3600, "h " },
375*387f9dfdSAndroid Build Coastguard Worker 		{ 1e9 * 60, "m " },
376*387f9dfdSAndroid Build Coastguard Worker 		{ 1e9, "s " },
377*387f9dfdSAndroid Build Coastguard Worker 		{ 1e6, "ms" },
378*387f9dfdSAndroid Build Coastguard Worker 		{ 1e3, "us" },
379*387f9dfdSAndroid Build Coastguard Worker 		{ 0, NULL },
380*387f9dfdSAndroid Build Coastguard Worker 	};
381*387f9dfdSAndroid Build Coastguard Worker 
382*387f9dfdSAndroid Build Coastguard Worker 	for (int i = 0; table[i].base; i++) {
383*387f9dfdSAndroid Build Coastguard Worker 		if (nsec < table[i].base)
384*387f9dfdSAndroid Build Coastguard Worker 			continue;
385*387f9dfdSAndroid Build Coastguard Worker 
386*387f9dfdSAndroid Build Coastguard Worker 		snprintf(buf, size, "%.1f %s", nsec / table[i].base, table[i].unit);
387*387f9dfdSAndroid Build Coastguard Worker 		return buf;
388*387f9dfdSAndroid Build Coastguard Worker 	}
389*387f9dfdSAndroid Build Coastguard Worker 
390*387f9dfdSAndroid Build Coastguard Worker 	snprintf(buf, size, "%u ns", (unsigned)nsec);
391*387f9dfdSAndroid Build Coastguard Worker 	return buf;
392*387f9dfdSAndroid Build Coastguard Worker }
393*387f9dfdSAndroid Build Coastguard Worker 
print_acq_header(void)394*387f9dfdSAndroid Build Coastguard Worker static void print_acq_header(void)
395*387f9dfdSAndroid Build Coastguard Worker {
396*387f9dfdSAndroid Build Coastguard Worker 	if (env.per_thread)
397*387f9dfdSAndroid Build Coastguard Worker 		printf("\n                Tid              Comm");
398*387f9dfdSAndroid Build Coastguard Worker 	else
399*387f9dfdSAndroid Build Coastguard Worker 		printf("\n                               Caller");
400*387f9dfdSAndroid Build Coastguard Worker 
401*387f9dfdSAndroid Build Coastguard Worker 	printf("  Avg Wait    Count   Max Wait   Total Wait\n");
402*387f9dfdSAndroid Build Coastguard Worker }
403*387f9dfdSAndroid Build Coastguard Worker 
print_acq_stat(struct ksyms * ksyms,struct stack_stat * ss,int nr_stack_entries)404*387f9dfdSAndroid Build Coastguard Worker static void print_acq_stat(struct ksyms *ksyms, struct stack_stat *ss,
405*387f9dfdSAndroid Build Coastguard Worker 			   int nr_stack_entries)
406*387f9dfdSAndroid Build Coastguard Worker {
407*387f9dfdSAndroid Build Coastguard Worker 	char buf[40];
408*387f9dfdSAndroid Build Coastguard Worker 	char avg[40];
409*387f9dfdSAndroid Build Coastguard Worker 	char max[40];
410*387f9dfdSAndroid Build Coastguard Worker 	char tot[40];
411*387f9dfdSAndroid Build Coastguard Worker 	int i;
412*387f9dfdSAndroid Build Coastguard Worker 
413*387f9dfdSAndroid Build Coastguard Worker 	printf("%37s %9s %8llu %10s %12s\n",
414*387f9dfdSAndroid Build Coastguard Worker 	       symname(ksyms, ss->bt[0], buf, sizeof(buf)),
415*387f9dfdSAndroid Build Coastguard Worker 	       print_time(avg, sizeof(avg), ss->ls.acq_total_time / ss->ls.acq_count),
416*387f9dfdSAndroid Build Coastguard Worker 	       ss->ls.acq_count,
417*387f9dfdSAndroid Build Coastguard Worker 	       print_time(max, sizeof(max), ss->ls.acq_max_time),
418*387f9dfdSAndroid Build Coastguard Worker 	       print_time(tot, sizeof(tot), ss->ls.acq_total_time));
419*387f9dfdSAndroid Build Coastguard Worker 	for (i = 1; i < nr_stack_entries; i++) {
420*387f9dfdSAndroid Build Coastguard Worker 		if (!ss->bt[i] || env.per_thread)
421*387f9dfdSAndroid Build Coastguard Worker 			break;
422*387f9dfdSAndroid Build Coastguard Worker 		printf("%37s\n", symname(ksyms, ss->bt[i], buf, sizeof(buf)));
423*387f9dfdSAndroid Build Coastguard Worker 	}
424*387f9dfdSAndroid Build Coastguard Worker 	if (nr_stack_entries > 1 && !env.per_thread)
425*387f9dfdSAndroid Build Coastguard Worker 		printf("                              Max PID %llu, COMM %s, Lock %s (0x%llx)\n",
426*387f9dfdSAndroid Build Coastguard Worker 		       ss->ls.acq_max_id >> 32,
427*387f9dfdSAndroid Build Coastguard Worker 		       ss->ls.acq_max_comm,
428*387f9dfdSAndroid Build Coastguard Worker 			   get_lock_name(ksyms, ss->ls.acq_max_lock_ptr),
429*387f9dfdSAndroid Build Coastguard Worker 			   ss->ls.acq_max_lock_ptr);
430*387f9dfdSAndroid Build Coastguard Worker }
431*387f9dfdSAndroid Build Coastguard Worker 
print_acq_task(struct stack_stat * ss)432*387f9dfdSAndroid Build Coastguard Worker static void print_acq_task(struct stack_stat *ss)
433*387f9dfdSAndroid Build Coastguard Worker {
434*387f9dfdSAndroid Build Coastguard Worker 	char buf[40];
435*387f9dfdSAndroid Build Coastguard Worker 	char avg[40];
436*387f9dfdSAndroid Build Coastguard Worker 	char max[40];
437*387f9dfdSAndroid Build Coastguard Worker 	char tot[40];
438*387f9dfdSAndroid Build Coastguard Worker 
439*387f9dfdSAndroid Build Coastguard Worker 	printf("%37s %9s %8llu %10s %12s\n",
440*387f9dfdSAndroid Build Coastguard Worker 	       print_caller(buf, sizeof(buf), ss),
441*387f9dfdSAndroid Build Coastguard Worker 	       print_time(avg, sizeof(avg), ss->ls.acq_total_time / ss->ls.acq_count),
442*387f9dfdSAndroid Build Coastguard Worker 	       ss->ls.acq_count,
443*387f9dfdSAndroid Build Coastguard Worker 	       print_time(max, sizeof(max), ss->ls.acq_max_time),
444*387f9dfdSAndroid Build Coastguard Worker 	       print_time(tot, sizeof(tot), ss->ls.acq_total_time));
445*387f9dfdSAndroid Build Coastguard Worker }
446*387f9dfdSAndroid Build Coastguard Worker 
print_hld_header(void)447*387f9dfdSAndroid Build Coastguard Worker static void print_hld_header(void)
448*387f9dfdSAndroid Build Coastguard Worker {
449*387f9dfdSAndroid Build Coastguard Worker 	if (env.per_thread)
450*387f9dfdSAndroid Build Coastguard Worker 		printf("\n                Tid              Comm");
451*387f9dfdSAndroid Build Coastguard Worker 	else
452*387f9dfdSAndroid Build Coastguard Worker 		printf("\n                               Caller");
453*387f9dfdSAndroid Build Coastguard Worker 
454*387f9dfdSAndroid Build Coastguard Worker 	printf("  Avg Hold    Count   Max Hold   Total Hold\n");
455*387f9dfdSAndroid Build Coastguard Worker }
456*387f9dfdSAndroid Build Coastguard Worker 
print_hld_stat(struct ksyms * ksyms,struct stack_stat * ss,int nr_stack_entries)457*387f9dfdSAndroid Build Coastguard Worker static void print_hld_stat(struct ksyms *ksyms, struct stack_stat *ss,
458*387f9dfdSAndroid Build Coastguard Worker 			   int nr_stack_entries)
459*387f9dfdSAndroid Build Coastguard Worker {
460*387f9dfdSAndroid Build Coastguard Worker 	char buf[40];
461*387f9dfdSAndroid Build Coastguard Worker 	char avg[40];
462*387f9dfdSAndroid Build Coastguard Worker 	char max[40];
463*387f9dfdSAndroid Build Coastguard Worker 	char tot[40];
464*387f9dfdSAndroid Build Coastguard Worker 	int i;
465*387f9dfdSAndroid Build Coastguard Worker 
466*387f9dfdSAndroid Build Coastguard Worker 	printf("%37s %9s %8llu %10s %12s\n",
467*387f9dfdSAndroid Build Coastguard Worker 	       symname(ksyms, ss->bt[0], buf, sizeof(buf)),
468*387f9dfdSAndroid Build Coastguard Worker 	       print_time(avg, sizeof(avg), ss->ls.hld_total_time / ss->ls.hld_count),
469*387f9dfdSAndroid Build Coastguard Worker 	       ss->ls.hld_count,
470*387f9dfdSAndroid Build Coastguard Worker 	       print_time(max, sizeof(max), ss->ls.hld_max_time),
471*387f9dfdSAndroid Build Coastguard Worker 	       print_time(tot, sizeof(tot), ss->ls.hld_total_time));
472*387f9dfdSAndroid Build Coastguard Worker 	for (i = 1; i < nr_stack_entries; i++) {
473*387f9dfdSAndroid Build Coastguard Worker 		if (!ss->bt[i] || env.per_thread)
474*387f9dfdSAndroid Build Coastguard Worker 			break;
475*387f9dfdSAndroid Build Coastguard Worker 		printf("%37s\n", symname(ksyms, ss->bt[i], buf, sizeof(buf)));
476*387f9dfdSAndroid Build Coastguard Worker 	}
477*387f9dfdSAndroid Build Coastguard Worker 	if (nr_stack_entries > 1 && !env.per_thread)
478*387f9dfdSAndroid Build Coastguard Worker 		printf("                              Max PID %llu, COMM %s, Lock %s (0x%llx)\n",
479*387f9dfdSAndroid Build Coastguard Worker 		       ss->ls.hld_max_id >> 32,
480*387f9dfdSAndroid Build Coastguard Worker 		       ss->ls.hld_max_comm,
481*387f9dfdSAndroid Build Coastguard Worker 			   get_lock_name(ksyms, ss->ls.hld_max_lock_ptr),
482*387f9dfdSAndroid Build Coastguard Worker 			   ss->ls.hld_max_lock_ptr);
483*387f9dfdSAndroid Build Coastguard Worker }
484*387f9dfdSAndroid Build Coastguard Worker 
print_hld_task(struct stack_stat * ss)485*387f9dfdSAndroid Build Coastguard Worker static void print_hld_task(struct stack_stat *ss)
486*387f9dfdSAndroid Build Coastguard Worker {
487*387f9dfdSAndroid Build Coastguard Worker 	char buf[40];
488*387f9dfdSAndroid Build Coastguard Worker 	char avg[40];
489*387f9dfdSAndroid Build Coastguard Worker 	char max[40];
490*387f9dfdSAndroid Build Coastguard Worker 	char tot[40];
491*387f9dfdSAndroid Build Coastguard Worker 
492*387f9dfdSAndroid Build Coastguard Worker 	printf("%37s %9s %8llu %10s %12s\n",
493*387f9dfdSAndroid Build Coastguard Worker 	       print_caller(buf, sizeof(buf), ss),
494*387f9dfdSAndroid Build Coastguard Worker 	       print_time(avg, sizeof(avg), ss->ls.hld_total_time / ss->ls.hld_count),
495*387f9dfdSAndroid Build Coastguard Worker 	       ss->ls.hld_count,
496*387f9dfdSAndroid Build Coastguard Worker 	       print_time(max, sizeof(max), ss->ls.hld_max_time),
497*387f9dfdSAndroid Build Coastguard Worker 	       print_time(tot, sizeof(tot), ss->ls.hld_total_time));
498*387f9dfdSAndroid Build Coastguard Worker }
499*387f9dfdSAndroid Build Coastguard Worker 
print_stats(struct ksyms * ksyms,int stack_map,int stat_map)500*387f9dfdSAndroid Build Coastguard Worker static int print_stats(struct ksyms *ksyms, int stack_map, int stat_map)
501*387f9dfdSAndroid Build Coastguard Worker {
502*387f9dfdSAndroid Build Coastguard Worker 	struct stack_stat **stats, *ss;
503*387f9dfdSAndroid Build Coastguard Worker 	size_t stat_idx = 0;
504*387f9dfdSAndroid Build Coastguard Worker 	size_t stats_sz = 1;
505*387f9dfdSAndroid Build Coastguard Worker 	uint32_t lookup_key = 0;
506*387f9dfdSAndroid Build Coastguard Worker 	uint32_t stack_id;
507*387f9dfdSAndroid Build Coastguard Worker 	int ret, i;
508*387f9dfdSAndroid Build Coastguard Worker 	int nr_stack_entries;
509*387f9dfdSAndroid Build Coastguard Worker 
510*387f9dfdSAndroid Build Coastguard Worker 	stats = calloc(stats_sz, sizeof(void *));
511*387f9dfdSAndroid Build Coastguard Worker 	if (!stats) {
512*387f9dfdSAndroid Build Coastguard Worker 		warn("Out of memory\n");
513*387f9dfdSAndroid Build Coastguard Worker 		return -1;
514*387f9dfdSAndroid Build Coastguard Worker 	}
515*387f9dfdSAndroid Build Coastguard Worker 
516*387f9dfdSAndroid Build Coastguard Worker 	while (bpf_map_get_next_key(stat_map, &lookup_key, &stack_id) == 0) {
517*387f9dfdSAndroid Build Coastguard Worker 		if (stat_idx == stats_sz) {
518*387f9dfdSAndroid Build Coastguard Worker 			stats_sz *= 2;
519*387f9dfdSAndroid Build Coastguard Worker 			stats = libbpf_reallocarray(stats, stats_sz, sizeof(void *));
520*387f9dfdSAndroid Build Coastguard Worker 			if (!stats) {
521*387f9dfdSAndroid Build Coastguard Worker 				warn("Out of memory\n");
522*387f9dfdSAndroid Build Coastguard Worker 				return -1;
523*387f9dfdSAndroid Build Coastguard Worker 			}
524*387f9dfdSAndroid Build Coastguard Worker 		}
525*387f9dfdSAndroid Build Coastguard Worker 		ss = malloc(sizeof(struct stack_stat));
526*387f9dfdSAndroid Build Coastguard Worker 		if (!ss) {
527*387f9dfdSAndroid Build Coastguard Worker 			warn("Out of memory\n");
528*387f9dfdSAndroid Build Coastguard Worker 			return -1;
529*387f9dfdSAndroid Build Coastguard Worker 		}
530*387f9dfdSAndroid Build Coastguard Worker 
531*387f9dfdSAndroid Build Coastguard Worker 		lookup_key = ss->stack_id = stack_id;
532*387f9dfdSAndroid Build Coastguard Worker 		ret = bpf_map_lookup_elem(stat_map, &stack_id, &ss->ls);
533*387f9dfdSAndroid Build Coastguard Worker 		if (ret) {
534*387f9dfdSAndroid Build Coastguard Worker 			free(ss);
535*387f9dfdSAndroid Build Coastguard Worker 			continue;
536*387f9dfdSAndroid Build Coastguard Worker 		}
537*387f9dfdSAndroid Build Coastguard Worker 		if (!env.per_thread && bpf_map_lookup_elem(stack_map, &stack_id, &ss->bt)) {
538*387f9dfdSAndroid Build Coastguard Worker 			/* Can still report the results without a backtrace. */
539*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to lookup stack_id %u\n", stack_id);
540*387f9dfdSAndroid Build Coastguard Worker 		}
541*387f9dfdSAndroid Build Coastguard Worker 		if (!env.per_thread && !caller_is_traced(ksyms, ss->bt[0])) {
542*387f9dfdSAndroid Build Coastguard Worker 			free(ss);
543*387f9dfdSAndroid Build Coastguard Worker 			continue;
544*387f9dfdSAndroid Build Coastguard Worker 		}
545*387f9dfdSAndroid Build Coastguard Worker 		stats[stat_idx++] = ss;
546*387f9dfdSAndroid Build Coastguard Worker 	}
547*387f9dfdSAndroid Build Coastguard Worker 
548*387f9dfdSAndroid Build Coastguard Worker 	nr_stack_entries = MIN(env.nr_stack_entries, PERF_MAX_STACK_DEPTH);
549*387f9dfdSAndroid Build Coastguard Worker 
550*387f9dfdSAndroid Build Coastguard Worker 	qsort(stats, stat_idx, sizeof(void*), sort_by_acq);
551*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < MIN(env.nr_locks, stat_idx); i++) {
552*387f9dfdSAndroid Build Coastguard Worker 		if (i == 0 || env.nr_stack_entries > 1)
553*387f9dfdSAndroid Build Coastguard Worker 			print_acq_header();
554*387f9dfdSAndroid Build Coastguard Worker 
555*387f9dfdSAndroid Build Coastguard Worker 		if (env.per_thread)
556*387f9dfdSAndroid Build Coastguard Worker 			print_acq_task(stats[i]);
557*387f9dfdSAndroid Build Coastguard Worker 		else
558*387f9dfdSAndroid Build Coastguard Worker 			print_acq_stat(ksyms, stats[i], nr_stack_entries);
559*387f9dfdSAndroid Build Coastguard Worker 	}
560*387f9dfdSAndroid Build Coastguard Worker 
561*387f9dfdSAndroid Build Coastguard Worker 	qsort(stats, stat_idx, sizeof(void*), sort_by_hld);
562*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < MIN(env.nr_locks, stat_idx); i++) {
563*387f9dfdSAndroid Build Coastguard Worker 		if (i == 0 || env.nr_stack_entries > 1)
564*387f9dfdSAndroid Build Coastguard Worker 			print_hld_header();
565*387f9dfdSAndroid Build Coastguard Worker 
566*387f9dfdSAndroid Build Coastguard Worker 		if (env.per_thread)
567*387f9dfdSAndroid Build Coastguard Worker 			print_hld_task(stats[i]);
568*387f9dfdSAndroid Build Coastguard Worker 		else
569*387f9dfdSAndroid Build Coastguard Worker 			print_hld_stat(ksyms, stats[i], nr_stack_entries);
570*387f9dfdSAndroid Build Coastguard Worker 	}
571*387f9dfdSAndroid Build Coastguard Worker 
572*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < stat_idx; i++) {
573*387f9dfdSAndroid Build Coastguard Worker 		if (env.reset)
574*387f9dfdSAndroid Build Coastguard Worker 			bpf_map_delete_elem(stat_map, &ss->stack_id);
575*387f9dfdSAndroid Build Coastguard Worker 		free(stats[i]);
576*387f9dfdSAndroid Build Coastguard Worker         }
577*387f9dfdSAndroid Build Coastguard Worker 	free(stats);
578*387f9dfdSAndroid Build Coastguard Worker 
579*387f9dfdSAndroid Build Coastguard Worker 	return 0;
580*387f9dfdSAndroid Build Coastguard Worker }
581*387f9dfdSAndroid Build Coastguard Worker 
582*387f9dfdSAndroid Build Coastguard Worker static volatile bool exiting;
583*387f9dfdSAndroid Build Coastguard Worker 
sig_hand(int signr)584*387f9dfdSAndroid Build Coastguard Worker static void sig_hand(int signr)
585*387f9dfdSAndroid Build Coastguard Worker {
586*387f9dfdSAndroid Build Coastguard Worker 	exiting = true;
587*387f9dfdSAndroid Build Coastguard Worker }
588*387f9dfdSAndroid Build Coastguard Worker 
589*387f9dfdSAndroid Build Coastguard Worker static struct sigaction sigact = {.sa_handler = sig_hand};
590*387f9dfdSAndroid Build Coastguard Worker 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)591*387f9dfdSAndroid Build Coastguard Worker static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
592*387f9dfdSAndroid Build Coastguard Worker {
593*387f9dfdSAndroid Build Coastguard Worker 	if (level == LIBBPF_DEBUG && !env.verbose)
594*387f9dfdSAndroid Build Coastguard Worker 		return 0;
595*387f9dfdSAndroid Build Coastguard Worker 	return vfprintf(stderr, format, args);
596*387f9dfdSAndroid Build Coastguard Worker }
597*387f9dfdSAndroid Build Coastguard Worker 
enable_fentry(struct klockstat_bpf * obj)598*387f9dfdSAndroid Build Coastguard Worker static void enable_fentry(struct klockstat_bpf *obj)
599*387f9dfdSAndroid Build Coastguard Worker {
600*387f9dfdSAndroid Build Coastguard Worker 	bool debug_lock;
601*387f9dfdSAndroid Build Coastguard Worker 
602*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock, false);
603*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_exit, false);
604*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_trylock, false);
605*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_trylock_exit, false);
606*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible, false);
607*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_interruptible_exit, false);
608*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable, false);
609*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_lock_killable_exit, false);
610*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_mutex_unlock, false);
611*387f9dfdSAndroid Build Coastguard Worker 
612*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read, false);
613*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_exit, false);
614*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_trylock, false);
615*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_trylock_exit, false);
616*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_interruptible, false);
617*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_interruptible_exit, false);
618*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_killable, false);
619*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_read_killable_exit, false);
620*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_up_read, false);
621*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write, false);
622*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write_exit, false);
623*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write_trylock, false);
624*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write_trylock_exit, false);
625*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write_killable, false);
626*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_down_write_killable_exit, false);
627*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.kprobe_up_write, false);
628*387f9dfdSAndroid Build Coastguard Worker 
629*387f9dfdSAndroid Build Coastguard Worker 	/* CONFIG_DEBUG_LOCK_ALLOC is on */
630*387f9dfdSAndroid Build Coastguard Worker 	debug_lock = fentry_can_attach("mutex_lock_nested", NULL);
631*387f9dfdSAndroid Build Coastguard Worker 	if (!debug_lock)
632*387f9dfdSAndroid Build Coastguard Worker 		return;
633*387f9dfdSAndroid Build Coastguard Worker 
634*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock, 0,
635*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_nested");
636*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock_exit, 0,
637*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_nested");
638*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock_interruptible, 0,
639*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_interruptible_nested");
640*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock_interruptible_exit, 0,
641*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_interruptible_nested");
642*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock_killable, 0,
643*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_killable_nested");
644*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.mutex_lock_killable_exit, 0,
645*387f9dfdSAndroid Build Coastguard Worker 				       "mutex_lock_killable_nested");
646*387f9dfdSAndroid Build Coastguard Worker 
647*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_read, 0,
648*387f9dfdSAndroid Build Coastguard Worker 				       "down_read_nested");
649*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_read_exit, 0,
650*387f9dfdSAndroid Build Coastguard Worker 				       "down_read_nested");
651*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_read_killable, 0,
652*387f9dfdSAndroid Build Coastguard Worker 				       "down_read_killable_nested");
653*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_read_killable_exit, 0,
654*387f9dfdSAndroid Build Coastguard Worker 				       "down_read_killable_nested");
655*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_write, 0,
656*387f9dfdSAndroid Build Coastguard Worker 				       "down_write_nested");
657*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_write_exit, 0,
658*387f9dfdSAndroid Build Coastguard Worker 				       "down_write_nested");
659*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_write_killable, 0,
660*387f9dfdSAndroid Build Coastguard Worker 				       "down_write_killable_nested");
661*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_attach_target(obj->progs.down_write_killable_exit, 0,
662*387f9dfdSAndroid Build Coastguard Worker 				       "down_write_killable_nested");
663*387f9dfdSAndroid Build Coastguard Worker }
664*387f9dfdSAndroid Build Coastguard Worker 
enable_kprobes(struct klockstat_bpf * obj)665*387f9dfdSAndroid Build Coastguard Worker static void enable_kprobes(struct klockstat_bpf *obj)
666*387f9dfdSAndroid Build Coastguard Worker {
667*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock, false);
668*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock_exit, false);
669*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_trylock_exit, false);
670*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock_interruptible, false);
671*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock_interruptible_exit, false);
672*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock_killable, false);
673*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_lock_killable_exit, false);
674*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.mutex_unlock, false);
675*387f9dfdSAndroid Build Coastguard Worker 
676*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read, false);
677*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_exit, false);
678*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_trylock_exit, false);
679*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_interruptible, false);
680*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_interruptible_exit, false);
681*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_killable, false);
682*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_read_killable_exit, false);
683*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.up_read, false);
684*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_write, false);
685*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_write_exit, false);
686*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_write_trylock_exit, false);
687*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_write_killable, false);
688*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.down_write_killable_exit, false);
689*387f9dfdSAndroid Build Coastguard Worker 	bpf_program__set_autoload(obj->progs.up_write, false);
690*387f9dfdSAndroid Build Coastguard Worker }
691*387f9dfdSAndroid Build Coastguard Worker 
main(int argc,char ** argv)692*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char **argv)
693*387f9dfdSAndroid Build Coastguard Worker {
694*387f9dfdSAndroid Build Coastguard Worker 	static const struct argp argp = {
695*387f9dfdSAndroid Build Coastguard Worker 		.options = opts,
696*387f9dfdSAndroid Build Coastguard Worker 		.parser = parse_arg,
697*387f9dfdSAndroid Build Coastguard Worker 		.args_doc = args_doc,
698*387f9dfdSAndroid Build Coastguard Worker 		.doc = program_doc,
699*387f9dfdSAndroid Build Coastguard Worker 	};
700*387f9dfdSAndroid Build Coastguard Worker 	struct klockstat_bpf *obj = NULL;
701*387f9dfdSAndroid Build Coastguard Worker 	struct ksyms *ksyms = NULL;
702*387f9dfdSAndroid Build Coastguard Worker 	int i, err;
703*387f9dfdSAndroid Build Coastguard Worker 	struct tm *tm;
704*387f9dfdSAndroid Build Coastguard Worker 	char ts[32];
705*387f9dfdSAndroid Build Coastguard Worker 	time_t t;
706*387f9dfdSAndroid Build Coastguard Worker 	void *lock_addr = NULL;
707*387f9dfdSAndroid Build Coastguard Worker 
708*387f9dfdSAndroid Build Coastguard Worker 	err = argp_parse(&argp, argc, argv, 0, NULL, &env);
709*387f9dfdSAndroid Build Coastguard Worker 	if (err)
710*387f9dfdSAndroid Build Coastguard Worker 		return err;
711*387f9dfdSAndroid Build Coastguard Worker 
712*387f9dfdSAndroid Build Coastguard Worker 	sigaction(SIGINT, &sigact, 0);
713*387f9dfdSAndroid Build Coastguard Worker 
714*387f9dfdSAndroid Build Coastguard Worker 	libbpf_set_print(libbpf_print_fn);
715*387f9dfdSAndroid Build Coastguard Worker 
716*387f9dfdSAndroid Build Coastguard Worker 	ksyms = ksyms__load();
717*387f9dfdSAndroid Build Coastguard Worker 	if (!ksyms) {
718*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to load kallsyms\n");
719*387f9dfdSAndroid Build Coastguard Worker 		err = 1;
720*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
721*387f9dfdSAndroid Build Coastguard Worker 	}
722*387f9dfdSAndroid Build Coastguard Worker 	if (env.lock_name) {
723*387f9dfdSAndroid Build Coastguard Worker 		lock_addr = get_lock_addr(ksyms, env.lock_name);
724*387f9dfdSAndroid Build Coastguard Worker 		if (!lock_addr) {
725*387f9dfdSAndroid Build Coastguard Worker 			warn("failed to find lock %s\n", env.lock_name);
726*387f9dfdSAndroid Build Coastguard Worker 			err = 1;
727*387f9dfdSAndroid Build Coastguard Worker 			goto cleanup;
728*387f9dfdSAndroid Build Coastguard Worker 		}
729*387f9dfdSAndroid Build Coastguard Worker 	}
730*387f9dfdSAndroid Build Coastguard Worker 
731*387f9dfdSAndroid Build Coastguard Worker 	obj = klockstat_bpf__open();
732*387f9dfdSAndroid Build Coastguard Worker 	if (!obj) {
733*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to open BPF object\n");
734*387f9dfdSAndroid Build Coastguard Worker 		err = 1;
735*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
736*387f9dfdSAndroid Build Coastguard Worker 	}
737*387f9dfdSAndroid Build Coastguard Worker 
738*387f9dfdSAndroid Build Coastguard Worker 	obj->rodata->targ_tgid = env.pid;
739*387f9dfdSAndroid Build Coastguard Worker 	obj->rodata->targ_pid = env.tid;
740*387f9dfdSAndroid Build Coastguard Worker 	obj->rodata->targ_lock = lock_addr;
741*387f9dfdSAndroid Build Coastguard Worker 	obj->rodata->per_thread = env.per_thread;
742*387f9dfdSAndroid Build Coastguard Worker 
743*387f9dfdSAndroid Build Coastguard Worker 	if (fentry_can_attach("mutex_lock", NULL) ||
744*387f9dfdSAndroid Build Coastguard Worker 	    fentry_can_attach("mutex_lock_nested", NULL))
745*387f9dfdSAndroid Build Coastguard Worker 		enable_fentry(obj);
746*387f9dfdSAndroid Build Coastguard Worker 	else
747*387f9dfdSAndroid Build Coastguard Worker 		enable_kprobes(obj);
748*387f9dfdSAndroid Build Coastguard Worker 
749*387f9dfdSAndroid Build Coastguard Worker 	err = klockstat_bpf__load(obj);
750*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
751*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to load BPF object\n");
752*387f9dfdSAndroid Build Coastguard Worker 		return 1;
753*387f9dfdSAndroid Build Coastguard Worker 	}
754*387f9dfdSAndroid Build Coastguard Worker 	err = klockstat_bpf__attach(obj);
755*387f9dfdSAndroid Build Coastguard Worker 	if (err) {
756*387f9dfdSAndroid Build Coastguard Worker 		warn("failed to attach BPF object\n");
757*387f9dfdSAndroid Build Coastguard Worker 		goto cleanup;
758*387f9dfdSAndroid Build Coastguard Worker 	}
759*387f9dfdSAndroid Build Coastguard Worker 
760*387f9dfdSAndroid Build Coastguard Worker 	printf("Tracing mutex/sem lock events...  Hit Ctrl-C to end\n");
761*387f9dfdSAndroid Build Coastguard Worker 
762*387f9dfdSAndroid Build Coastguard Worker 	for (i = 0; i < env.iterations && !exiting; i++) {
763*387f9dfdSAndroid Build Coastguard Worker 		sleep(env.interval);
764*387f9dfdSAndroid Build Coastguard Worker 
765*387f9dfdSAndroid Build Coastguard Worker 		printf("\n");
766*387f9dfdSAndroid Build Coastguard Worker 		if (env.timestamp) {
767*387f9dfdSAndroid Build Coastguard Worker 			time(&t);
768*387f9dfdSAndroid Build Coastguard Worker 			tm = localtime(&t);
769*387f9dfdSAndroid Build Coastguard Worker 			strftime(ts, sizeof(ts), "%H:%M:%S", tm);
770*387f9dfdSAndroid Build Coastguard Worker 			printf("%-8s\n", ts);
771*387f9dfdSAndroid Build Coastguard Worker 		}
772*387f9dfdSAndroid Build Coastguard Worker 
773*387f9dfdSAndroid Build Coastguard Worker 		if (print_stats(ksyms, bpf_map__fd(obj->maps.stack_map),
774*387f9dfdSAndroid Build Coastguard Worker 				bpf_map__fd(obj->maps.stat_map))) {
775*387f9dfdSAndroid Build Coastguard Worker 			warn("print_stats error, aborting.\n");
776*387f9dfdSAndroid Build Coastguard Worker 			break;
777*387f9dfdSAndroid Build Coastguard Worker 		}
778*387f9dfdSAndroid Build Coastguard Worker 		fflush(stdout);
779*387f9dfdSAndroid Build Coastguard Worker 	}
780*387f9dfdSAndroid Build Coastguard Worker 
781*387f9dfdSAndroid Build Coastguard Worker 	printf("Exiting trace of mutex/sem locks\n");
782*387f9dfdSAndroid Build Coastguard Worker 
783*387f9dfdSAndroid Build Coastguard Worker cleanup:
784*387f9dfdSAndroid Build Coastguard Worker 	klockstat_bpf__destroy(obj);
785*387f9dfdSAndroid Build Coastguard Worker 	ksyms__free(ksyms);
786*387f9dfdSAndroid Build Coastguard Worker 
787*387f9dfdSAndroid Build Coastguard Worker 	return err != 0;
788*387f9dfdSAndroid Build Coastguard Worker }
789