xref: /aosp_15_r20/external/bcc/tools/klockstat.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# klockstat traces lock events and display locks statistics.
4*387f9dfdSAndroid Build Coastguard Worker#
5*387f9dfdSAndroid Build Coastguard Worker# USAGE: klockstat
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker
8*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
9*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT
10*387f9dfdSAndroid Build Coastguard Workerimport argparse
11*387f9dfdSAndroid Build Coastguard Workerimport subprocess
12*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct
13*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
14*387f9dfdSAndroid Build Coastguard Workerfrom datetime import datetime, timedelta
15*387f9dfdSAndroid Build Coastguard Workerimport errno
16*387f9dfdSAndroid Build Coastguard Workerfrom sys import stderr
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Workerexamples = """
19*387f9dfdSAndroid Build Coastguard Worker    klockstat                           # trace system wide
20*387f9dfdSAndroid Build Coastguard Worker    klockstat -d 5                      # trace for 5 seconds only
21*387f9dfdSAndroid Build Coastguard Worker    klockstat -i 5                      # display stats every 5 seconds
22*387f9dfdSAndroid Build Coastguard Worker    klockstat -p 123                    # trace locks for PID 123
23*387f9dfdSAndroid Build Coastguard Worker    klockstat -t 321                    # trace locks for TID 321
24*387f9dfdSAndroid Build Coastguard Worker    klockstat -c pipe_                  # display stats only for lock callers with 'pipe_' substring
25*387f9dfdSAndroid Build Coastguard Worker    klockstat -S acq_count              # sort lock acquired results on acquired count
26*387f9dfdSAndroid Build Coastguard Worker    klockstat -S hld_total              # sort lock held results on total held time
27*387f9dfdSAndroid Build Coastguard Worker    klockstat -S acq_count,hld_total    # combination of above
28*387f9dfdSAndroid Build Coastguard Worker    klockstat -n 3                      # display 3 locks
29*387f9dfdSAndroid Build Coastguard Worker    klockstat -s 3                      # display 3 levels of stack
30*387f9dfdSAndroid Build Coastguard Worker"""
31*387f9dfdSAndroid Build Coastguard Worker
32*387f9dfdSAndroid Build Coastguard Worker# arg validation
33*387f9dfdSAndroid Build Coastguard Workerdef positive_int(val):
34*387f9dfdSAndroid Build Coastguard Worker    try:
35*387f9dfdSAndroid Build Coastguard Worker        ival = int(val)
36*387f9dfdSAndroid Build Coastguard Worker    except ValueError:
37*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be an integer")
38*387f9dfdSAndroid Build Coastguard Worker
39*387f9dfdSAndroid Build Coastguard Worker    if ival < 0:
40*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be positive")
41*387f9dfdSAndroid Build Coastguard Worker    return ival
42*387f9dfdSAndroid Build Coastguard Worker
43*387f9dfdSAndroid Build Coastguard Workerdef positive_nonzero_int(val):
44*387f9dfdSAndroid Build Coastguard Worker    ival = positive_int(val)
45*387f9dfdSAndroid Build Coastguard Worker    if ival == 0:
46*387f9dfdSAndroid Build Coastguard Worker        raise argparse.ArgumentTypeError("must be nonzero")
47*387f9dfdSAndroid Build Coastguard Worker    return ival
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard Workerdef stack_id_err(stack_id):
50*387f9dfdSAndroid Build Coastguard Worker    # -EFAULT in get_stackid normally means the stack-trace is not available,
51*387f9dfdSAndroid Build Coastguard Worker    # Such as getting kernel stack trace in userspace code
52*387f9dfdSAndroid Build Coastguard Worker    return (stack_id < 0) and (stack_id != -errno.EFAULT)
53*387f9dfdSAndroid Build Coastguard Worker
54*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
55*387f9dfdSAndroid Build Coastguard Worker    description="",
56*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
57*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Workertime_group = parser.add_mutually_exclusive_group()
60*387f9dfdSAndroid Build Coastguard Workertime_group.add_argument("-d", "--duration", type=int,
61*387f9dfdSAndroid Build Coastguard Worker    help="total duration of trace in seconds")
62*387f9dfdSAndroid Build Coastguard Workertime_group.add_argument("-i", "--interval", type=int,
63*387f9dfdSAndroid Build Coastguard Worker    help="print summary at this interval (seconds)")
64*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-n", "--locks", type=int, default=99999999,
65*387f9dfdSAndroid Build Coastguard Worker    help="print given number of locks")
66*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--stacks", type=int, default=1,
67*387f9dfdSAndroid Build Coastguard Worker    help="print given number of stack entries")
68*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-c", "--caller",
69*387f9dfdSAndroid Build Coastguard Worker    help="print locks taken by given caller")
70*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-S", "--sort",
71*387f9dfdSAndroid Build Coastguard Worker    help="sort data on <aq_field,hd_field>, fields: acq_[max|total|count] hld_[max|total|count]")
72*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
73*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
74*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--tid",
75*387f9dfdSAndroid Build Coastguard Worker    help="trace this TID only")
76*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--stack-storage-size", default=16384,
77*387f9dfdSAndroid Build Coastguard Worker    type=positive_nonzero_int,
78*387f9dfdSAndroid Build Coastguard Worker    help="the number of unique stack traces that can be stored and "
79*387f9dfdSAndroid Build Coastguard Worker         "displayed (default 16384)")
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Workerprogram = """
84*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
85*387f9dfdSAndroid Build Coastguard Worker
86*387f9dfdSAndroid Build Coastguard Workerstruct depth_id {
87*387f9dfdSAndroid Build Coastguard Worker  u64 id;
88*387f9dfdSAndroid Build Coastguard Worker  u64 depth;
89*387f9dfdSAndroid Build Coastguard Worker};
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard WorkerBPF_ARRAY(enabled,   u64, 1);
92*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(track,      u64, u64);
93*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(time_aq,    u64, u64);
94*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(lock_depth, u64, u64);
95*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(time_held,  struct depth_id, u64);
96*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(stack,      struct depth_id, int);
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(aq_report_count, int, u64);
99*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(aq_report_max,   int, u64);
100*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(aq_report_total, int, u64);
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(hl_report_count, int, u64);
103*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(hl_report_max,   int, u64);
104*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(hl_report_total, int, u64);
105*387f9dfdSAndroid Build Coastguard Worker
106*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, STACK_STORAGE_SIZE);
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Workerstatic bool is_enabled(void)
109*387f9dfdSAndroid Build Coastguard Worker{
110*387f9dfdSAndroid Build Coastguard Worker    int key = 0;
111*387f9dfdSAndroid Build Coastguard Worker    u64 *ret;
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker    ret = enabled.lookup(&key);
114*387f9dfdSAndroid Build Coastguard Worker    return ret && *ret == 1;
115*387f9dfdSAndroid Build Coastguard Worker}
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Workerstatic bool allow_pid(u64 id)
118*387f9dfdSAndroid Build Coastguard Worker{
119*387f9dfdSAndroid Build Coastguard Worker    u32 pid = id >> 32; // PID is higher part
120*387f9dfdSAndroid Build Coastguard Worker    u32 tid = id;       // Cast and get the lower part
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker    FILTER
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Worker    return 1;
125*387f9dfdSAndroid Build Coastguard Worker}
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Workerstatic int do_mutex_lock_enter(void *ctx, int skip)
128*387f9dfdSAndroid Build Coastguard Worker{
129*387f9dfdSAndroid Build Coastguard Worker    if (!is_enabled())
130*387f9dfdSAndroid Build Coastguard Worker        return 0;
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
133*387f9dfdSAndroid Build Coastguard Worker
134*387f9dfdSAndroid Build Coastguard Worker    if (!allow_pid(id))
135*387f9dfdSAndroid Build Coastguard Worker        return 0;
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker    u64 one = 1, zero = 0;
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Worker    track.update(&id, &one);
140*387f9dfdSAndroid Build Coastguard Worker
141*387f9dfdSAndroid Build Coastguard Worker    u64 *depth = lock_depth.lookup(&id);
142*387f9dfdSAndroid Build Coastguard Worker
143*387f9dfdSAndroid Build Coastguard Worker    if (!depth) {
144*387f9dfdSAndroid Build Coastguard Worker        lock_depth.update(&id, &zero);
145*387f9dfdSAndroid Build Coastguard Worker
146*387f9dfdSAndroid Build Coastguard Worker        depth = lock_depth.lookup(&id);
147*387f9dfdSAndroid Build Coastguard Worker        /* something is wrong.. */
148*387f9dfdSAndroid Build Coastguard Worker        if (!depth)
149*387f9dfdSAndroid Build Coastguard Worker            return 0;
150*387f9dfdSAndroid Build Coastguard Worker    }
151*387f9dfdSAndroid Build Coastguard Worker
152*387f9dfdSAndroid Build Coastguard Worker    int stackid = stack_traces.get_stackid(ctx, skip);
153*387f9dfdSAndroid Build Coastguard Worker    struct depth_id did = {
154*387f9dfdSAndroid Build Coastguard Worker      .id    = id,
155*387f9dfdSAndroid Build Coastguard Worker      .depth = *depth,
156*387f9dfdSAndroid Build Coastguard Worker    };
157*387f9dfdSAndroid Build Coastguard Worker    stack.update(&did, &stackid);
158*387f9dfdSAndroid Build Coastguard Worker
159*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
160*387f9dfdSAndroid Build Coastguard Worker    time_aq.update(&id, &ts);
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker    *depth += 1;
163*387f9dfdSAndroid Build Coastguard Worker    return 0;
164*387f9dfdSAndroid Build Coastguard Worker}
165*387f9dfdSAndroid Build Coastguard Worker
166*387f9dfdSAndroid Build Coastguard Workerstatic void update_aq_report_count(int *stackid)
167*387f9dfdSAndroid Build Coastguard Worker{
168*387f9dfdSAndroid Build Coastguard Worker    u64 *count, one = 1;
169*387f9dfdSAndroid Build Coastguard Worker
170*387f9dfdSAndroid Build Coastguard Worker    count = aq_report_count.lookup(stackid);
171*387f9dfdSAndroid Build Coastguard Worker    if (!count) {
172*387f9dfdSAndroid Build Coastguard Worker        aq_report_count.update(stackid, &one);
173*387f9dfdSAndroid Build Coastguard Worker    } else {
174*387f9dfdSAndroid Build Coastguard Worker        *count += 1;
175*387f9dfdSAndroid Build Coastguard Worker    }
176*387f9dfdSAndroid Build Coastguard Worker}
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Workerstatic void update_hl_report_count(int *stackid)
179*387f9dfdSAndroid Build Coastguard Worker{
180*387f9dfdSAndroid Build Coastguard Worker    u64 *count, one = 1;
181*387f9dfdSAndroid Build Coastguard Worker
182*387f9dfdSAndroid Build Coastguard Worker    count = hl_report_count.lookup(stackid);
183*387f9dfdSAndroid Build Coastguard Worker    if (!count) {
184*387f9dfdSAndroid Build Coastguard Worker        hl_report_count.update(stackid, &one);
185*387f9dfdSAndroid Build Coastguard Worker    } else {
186*387f9dfdSAndroid Build Coastguard Worker        *count += 1;
187*387f9dfdSAndroid Build Coastguard Worker    }
188*387f9dfdSAndroid Build Coastguard Worker}
189*387f9dfdSAndroid Build Coastguard Worker
190*387f9dfdSAndroid Build Coastguard Workerstatic void update_aq_report_max(int *stackid, u64 time)
191*387f9dfdSAndroid Build Coastguard Worker{
192*387f9dfdSAndroid Build Coastguard Worker    u64 *max;
193*387f9dfdSAndroid Build Coastguard Worker
194*387f9dfdSAndroid Build Coastguard Worker    max = aq_report_max.lookup(stackid);
195*387f9dfdSAndroid Build Coastguard Worker    if (!max || *max < time)
196*387f9dfdSAndroid Build Coastguard Worker        aq_report_max.update(stackid, &time);
197*387f9dfdSAndroid Build Coastguard Worker}
198*387f9dfdSAndroid Build Coastguard Worker
199*387f9dfdSAndroid Build Coastguard Workerstatic void update_hl_report_max(int *stackid, u64 time)
200*387f9dfdSAndroid Build Coastguard Worker{
201*387f9dfdSAndroid Build Coastguard Worker    u64 *max;
202*387f9dfdSAndroid Build Coastguard Worker
203*387f9dfdSAndroid Build Coastguard Worker    max = hl_report_max.lookup(stackid);
204*387f9dfdSAndroid Build Coastguard Worker    if (!max || *max < time)
205*387f9dfdSAndroid Build Coastguard Worker        hl_report_max.update(stackid, &time);
206*387f9dfdSAndroid Build Coastguard Worker}
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Workerstatic void update_aq_report_total(int *stackid, u64 delta)
209*387f9dfdSAndroid Build Coastguard Worker{
210*387f9dfdSAndroid Build Coastguard Worker    u64 *count, *time;
211*387f9dfdSAndroid Build Coastguard Worker
212*387f9dfdSAndroid Build Coastguard Worker    count = aq_report_count.lookup(stackid);
213*387f9dfdSAndroid Build Coastguard Worker    if (!count)
214*387f9dfdSAndroid Build Coastguard Worker        return;
215*387f9dfdSAndroid Build Coastguard Worker
216*387f9dfdSAndroid Build Coastguard Worker    time = aq_report_total.lookup(stackid);
217*387f9dfdSAndroid Build Coastguard Worker    if (!time) {
218*387f9dfdSAndroid Build Coastguard Worker        aq_report_total.update(stackid, &delta);
219*387f9dfdSAndroid Build Coastguard Worker    } else {
220*387f9dfdSAndroid Build Coastguard Worker        *time = *time + delta;
221*387f9dfdSAndroid Build Coastguard Worker    }
222*387f9dfdSAndroid Build Coastguard Worker}
223*387f9dfdSAndroid Build Coastguard Worker
224*387f9dfdSAndroid Build Coastguard Workerstatic void update_hl_report_total(int *stackid, u64 delta)
225*387f9dfdSAndroid Build Coastguard Worker{
226*387f9dfdSAndroid Build Coastguard Worker    u64 *count, *time;
227*387f9dfdSAndroid Build Coastguard Worker
228*387f9dfdSAndroid Build Coastguard Worker    count = hl_report_count.lookup(stackid);
229*387f9dfdSAndroid Build Coastguard Worker    if (!count)
230*387f9dfdSAndroid Build Coastguard Worker        return;
231*387f9dfdSAndroid Build Coastguard Worker
232*387f9dfdSAndroid Build Coastguard Worker    time = hl_report_total.lookup(stackid);
233*387f9dfdSAndroid Build Coastguard Worker    if (!time) {
234*387f9dfdSAndroid Build Coastguard Worker        hl_report_total.update(stackid, &delta);
235*387f9dfdSAndroid Build Coastguard Worker    } else {
236*387f9dfdSAndroid Build Coastguard Worker        *time = *time + delta;
237*387f9dfdSAndroid Build Coastguard Worker    }
238*387f9dfdSAndroid Build Coastguard Worker}
239*387f9dfdSAndroid Build Coastguard Worker
240*387f9dfdSAndroid Build Coastguard Workerstatic int do_mutex_lock_return(void)
241*387f9dfdSAndroid Build Coastguard Worker{
242*387f9dfdSAndroid Build Coastguard Worker    if (!is_enabled())
243*387f9dfdSAndroid Build Coastguard Worker        return 0;
244*387f9dfdSAndroid Build Coastguard Worker
245*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
246*387f9dfdSAndroid Build Coastguard Worker
247*387f9dfdSAndroid Build Coastguard Worker    if (!allow_pid(id))
248*387f9dfdSAndroid Build Coastguard Worker        return 0;
249*387f9dfdSAndroid Build Coastguard Worker
250*387f9dfdSAndroid Build Coastguard Worker    u64 *one = track.lookup(&id);
251*387f9dfdSAndroid Build Coastguard Worker
252*387f9dfdSAndroid Build Coastguard Worker    if (!one)
253*387f9dfdSAndroid Build Coastguard Worker        return 0;
254*387f9dfdSAndroid Build Coastguard Worker
255*387f9dfdSAndroid Build Coastguard Worker    track.delete(&id);
256*387f9dfdSAndroid Build Coastguard Worker
257*387f9dfdSAndroid Build Coastguard Worker    u64 *depth = lock_depth.lookup(&id);
258*387f9dfdSAndroid Build Coastguard Worker    if (!depth)
259*387f9dfdSAndroid Build Coastguard Worker        return 0;
260*387f9dfdSAndroid Build Coastguard Worker
261*387f9dfdSAndroid Build Coastguard Worker    struct depth_id did = {
262*387f9dfdSAndroid Build Coastguard Worker      .id    = id,
263*387f9dfdSAndroid Build Coastguard Worker      .depth = *depth - 1,
264*387f9dfdSAndroid Build Coastguard Worker    };
265*387f9dfdSAndroid Build Coastguard Worker
266*387f9dfdSAndroid Build Coastguard Worker    u64 *aq = time_aq.lookup(&id);
267*387f9dfdSAndroid Build Coastguard Worker    if (!aq)
268*387f9dfdSAndroid Build Coastguard Worker        return 0;
269*387f9dfdSAndroid Build Coastguard Worker
270*387f9dfdSAndroid Build Coastguard Worker    int *stackid = stack.lookup(&did);
271*387f9dfdSAndroid Build Coastguard Worker    if (!stackid)
272*387f9dfdSAndroid Build Coastguard Worker        return 0;
273*387f9dfdSAndroid Build Coastguard Worker
274*387f9dfdSAndroid Build Coastguard Worker    int stackid_ = *stackid;
275*387f9dfdSAndroid Build Coastguard Worker    u64 cur = bpf_ktime_get_ns();
276*387f9dfdSAndroid Build Coastguard Worker
277*387f9dfdSAndroid Build Coastguard Worker    if (cur > *aq) {
278*387f9dfdSAndroid Build Coastguard Worker        int val = cur - *aq;
279*387f9dfdSAndroid Build Coastguard Worker        update_aq_report_count(&stackid_);
280*387f9dfdSAndroid Build Coastguard Worker        update_aq_report_max(&stackid_, val);
281*387f9dfdSAndroid Build Coastguard Worker        update_aq_report_total(&stackid_, val);
282*387f9dfdSAndroid Build Coastguard Worker    }
283*387f9dfdSAndroid Build Coastguard Worker
284*387f9dfdSAndroid Build Coastguard Worker    time_held.update(&did, &cur);
285*387f9dfdSAndroid Build Coastguard Worker    return 0;
286*387f9dfdSAndroid Build Coastguard Worker}
287*387f9dfdSAndroid Build Coastguard Worker
288*387f9dfdSAndroid Build Coastguard Workerstatic int do_mutex_unlock_enter(void)
289*387f9dfdSAndroid Build Coastguard Worker{
290*387f9dfdSAndroid Build Coastguard Worker    if (!is_enabled())
291*387f9dfdSAndroid Build Coastguard Worker        return 0;
292*387f9dfdSAndroid Build Coastguard Worker
293*387f9dfdSAndroid Build Coastguard Worker    u64 id = bpf_get_current_pid_tgid();
294*387f9dfdSAndroid Build Coastguard Worker
295*387f9dfdSAndroid Build Coastguard Worker    if (!allow_pid(id))
296*387f9dfdSAndroid Build Coastguard Worker        return 0;
297*387f9dfdSAndroid Build Coastguard Worker
298*387f9dfdSAndroid Build Coastguard Worker    u64 *depth = lock_depth.lookup(&id);
299*387f9dfdSAndroid Build Coastguard Worker
300*387f9dfdSAndroid Build Coastguard Worker    if (!depth || *depth == 0)
301*387f9dfdSAndroid Build Coastguard Worker        return 0;
302*387f9dfdSAndroid Build Coastguard Worker
303*387f9dfdSAndroid Build Coastguard Worker    *depth -= 1;
304*387f9dfdSAndroid Build Coastguard Worker
305*387f9dfdSAndroid Build Coastguard Worker    struct depth_id did = {
306*387f9dfdSAndroid Build Coastguard Worker      .id    = id,
307*387f9dfdSAndroid Build Coastguard Worker      .depth = *depth,
308*387f9dfdSAndroid Build Coastguard Worker    };
309*387f9dfdSAndroid Build Coastguard Worker
310*387f9dfdSAndroid Build Coastguard Worker    u64 *held = time_held.lookup(&did);
311*387f9dfdSAndroid Build Coastguard Worker    if (!held)
312*387f9dfdSAndroid Build Coastguard Worker        return 0;
313*387f9dfdSAndroid Build Coastguard Worker
314*387f9dfdSAndroid Build Coastguard Worker    int *stackid = stack.lookup(&did);
315*387f9dfdSAndroid Build Coastguard Worker    if (!stackid)
316*387f9dfdSAndroid Build Coastguard Worker        return 0;
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Worker
319*387f9dfdSAndroid Build Coastguard Worker    int stackid_ = *stackid;
320*387f9dfdSAndroid Build Coastguard Worker    u64 cur = bpf_ktime_get_ns();
321*387f9dfdSAndroid Build Coastguard Worker
322*387f9dfdSAndroid Build Coastguard Worker    if (cur > *held) {
323*387f9dfdSAndroid Build Coastguard Worker        u64 val = cur - *held;
324*387f9dfdSAndroid Build Coastguard Worker        update_hl_report_count(&stackid_);
325*387f9dfdSAndroid Build Coastguard Worker        update_hl_report_max(&stackid_, val);
326*387f9dfdSAndroid Build Coastguard Worker        update_hl_report_total(&stackid_, val);
327*387f9dfdSAndroid Build Coastguard Worker    }
328*387f9dfdSAndroid Build Coastguard Worker
329*387f9dfdSAndroid Build Coastguard Worker    stack.delete(&did);
330*387f9dfdSAndroid Build Coastguard Worker    time_held.delete(&did);
331*387f9dfdSAndroid Build Coastguard Worker    return 0;
332*387f9dfdSAndroid Build Coastguard Worker}
333*387f9dfdSAndroid Build Coastguard Worker"""
334*387f9dfdSAndroid Build Coastguard Worker
335*387f9dfdSAndroid Build Coastguard Workerprogram_kprobe = """
336*387f9dfdSAndroid Build Coastguard Workerint mutex_unlock_enter(struct pt_regs *ctx)
337*387f9dfdSAndroid Build Coastguard Worker{
338*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_unlock_enter();
339*387f9dfdSAndroid Build Coastguard Worker}
340*387f9dfdSAndroid Build Coastguard Worker
341*387f9dfdSAndroid Build Coastguard Workerint mutex_lock_return(struct pt_regs *ctx)
342*387f9dfdSAndroid Build Coastguard Worker{
343*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_return();
344*387f9dfdSAndroid Build Coastguard Worker}
345*387f9dfdSAndroid Build Coastguard Worker
346*387f9dfdSAndroid Build Coastguard Workerint mutex_lock_enter(struct pt_regs *ctx)
347*387f9dfdSAndroid Build Coastguard Worker{
348*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_enter(ctx, 0);
349*387f9dfdSAndroid Build Coastguard Worker}
350*387f9dfdSAndroid Build Coastguard Worker"""
351*387f9dfdSAndroid Build Coastguard Worker
352*387f9dfdSAndroid Build Coastguard Workerprogram_kfunc = """
353*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(mutex_unlock, void *lock)
354*387f9dfdSAndroid Build Coastguard Worker{
355*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_unlock_enter();
356*387f9dfdSAndroid Build Coastguard Worker}
357*387f9dfdSAndroid Build Coastguard Worker
358*387f9dfdSAndroid Build Coastguard WorkerKRETFUNC_PROBE(mutex_lock, void *lock, int ret)
359*387f9dfdSAndroid Build Coastguard Worker{
360*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_return();
361*387f9dfdSAndroid Build Coastguard Worker}
362*387f9dfdSAndroid Build Coastguard Worker
363*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(mutex_lock, void *lock)
364*387f9dfdSAndroid Build Coastguard Worker{
365*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_enter(ctx, 3);
366*387f9dfdSAndroid Build Coastguard Worker}
367*387f9dfdSAndroid Build Coastguard Worker
368*387f9dfdSAndroid Build Coastguard Worker"""
369*387f9dfdSAndroid Build Coastguard Worker
370*387f9dfdSAndroid Build Coastguard Workerprogram_kfunc_nested = """
371*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(mutex_unlock, void *lock)
372*387f9dfdSAndroid Build Coastguard Worker{
373*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_unlock_enter();
374*387f9dfdSAndroid Build Coastguard Worker}
375*387f9dfdSAndroid Build Coastguard Worker
376*387f9dfdSAndroid Build Coastguard WorkerKRETFUNC_PROBE(mutex_lock_nested, void *lock, int ret)
377*387f9dfdSAndroid Build Coastguard Worker{
378*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_return();
379*387f9dfdSAndroid Build Coastguard Worker}
380*387f9dfdSAndroid Build Coastguard Worker
381*387f9dfdSAndroid Build Coastguard WorkerKFUNC_PROBE(mutex_lock_nested, void *lock)
382*387f9dfdSAndroid Build Coastguard Worker{
383*387f9dfdSAndroid Build Coastguard Worker    return do_mutex_lock_enter(ctx, 3);
384*387f9dfdSAndroid Build Coastguard Worker}
385*387f9dfdSAndroid Build Coastguard Worker
386*387f9dfdSAndroid Build Coastguard Worker"""
387*387f9dfdSAndroid Build Coastguard Worker
388*387f9dfdSAndroid Build Coastguard Workeris_support_kfunc = BPF.support_kfunc()
389*387f9dfdSAndroid Build Coastguard Workerif is_support_kfunc:
390*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"mutex_lock_nested"):
391*387f9dfdSAndroid Build Coastguard Worker        program += program_kfunc_nested
392*387f9dfdSAndroid Build Coastguard Worker    else:
393*387f9dfdSAndroid Build Coastguard Worker        program += program_kfunc
394*387f9dfdSAndroid Build Coastguard Workerelse:
395*387f9dfdSAndroid Build Coastguard Worker    program += program_kprobe
396*387f9dfdSAndroid Build Coastguard Worker
397*387f9dfdSAndroid Build Coastguard Workerdef sort_list(maxs, totals, counts):
398*387f9dfdSAndroid Build Coastguard Worker    if (not args.sort):
399*387f9dfdSAndroid Build Coastguard Worker        return maxs;
400*387f9dfdSAndroid Build Coastguard Worker
401*387f9dfdSAndroid Build Coastguard Worker    for field in args.sort.split(','):
402*387f9dfdSAndroid Build Coastguard Worker        if (field == "acq_max" or field == "hld_max"):
403*387f9dfdSAndroid Build Coastguard Worker            return maxs
404*387f9dfdSAndroid Build Coastguard Worker        if (field == "acq_total" or field == "hld_total"):
405*387f9dfdSAndroid Build Coastguard Worker            return totals
406*387f9dfdSAndroid Build Coastguard Worker        if (field == "acq_count" or field == "hld_count"):
407*387f9dfdSAndroid Build Coastguard Worker            return counts
408*387f9dfdSAndroid Build Coastguard Worker
409*387f9dfdSAndroid Build Coastguard Worker    print("Wrong sort argument: %s", args.sort)
410*387f9dfdSAndroid Build Coastguard Worker    exit(-1)
411*387f9dfdSAndroid Build Coastguard Worker
412*387f9dfdSAndroid Build Coastguard Workerdef display(sort, maxs, totals, counts):
413*387f9dfdSAndroid Build Coastguard Worker    global missing_stacks
414*387f9dfdSAndroid Build Coastguard Worker    global has_enomem
415*387f9dfdSAndroid Build Coastguard Worker
416*387f9dfdSAndroid Build Coastguard Worker    for k, v in sorted(sort.items(), key=lambda sort: sort[1].value, reverse=True)[:args.locks]:
417*387f9dfdSAndroid Build Coastguard Worker        missing_stacks += int(stack_id_err(k.value))
418*387f9dfdSAndroid Build Coastguard Worker        has_enomem      = has_enomem or (k.value == -errno.ENOMEM)
419*387f9dfdSAndroid Build Coastguard Worker
420*387f9dfdSAndroid Build Coastguard Worker        caller = "[Missed Kernel Stack]"
421*387f9dfdSAndroid Build Coastguard Worker        stack  = []
422*387f9dfdSAndroid Build Coastguard Worker
423*387f9dfdSAndroid Build Coastguard Worker        if (k.value >= 0):
424*387f9dfdSAndroid Build Coastguard Worker            stack  = list(stack_traces.walk(k.value))
425*387f9dfdSAndroid Build Coastguard Worker            caller = b.ksym(stack[1], show_offset=True)
426*387f9dfdSAndroid Build Coastguard Worker
427*387f9dfdSAndroid Build Coastguard Worker            if (args.caller and caller.find(args.caller.encode())):
428*387f9dfdSAndroid Build Coastguard Worker                continue
429*387f9dfdSAndroid Build Coastguard Worker
430*387f9dfdSAndroid Build Coastguard Worker        avg = totals[k].value / counts[k].value
431*387f9dfdSAndroid Build Coastguard Worker
432*387f9dfdSAndroid Build Coastguard Worker        print("%40s %10lu %6lu %10lu %10lu" % (caller, avg, counts[k].value, maxs[k].value, totals[k].value))
433*387f9dfdSAndroid Build Coastguard Worker
434*387f9dfdSAndroid Build Coastguard Worker        for addr in stack[2:args.stacks]:
435*387f9dfdSAndroid Build Coastguard Worker            print("%40s" %  b.ksym(addr, show_offset=True))
436*387f9dfdSAndroid Build Coastguard Worker
437*387f9dfdSAndroid Build Coastguard Worker
438*387f9dfdSAndroid Build Coastguard Workerif args.tid:  # TID trumps PID
439*387f9dfdSAndroid Build Coastguard Worker    program = program.replace('FILTER',
440*387f9dfdSAndroid Build Coastguard Worker        'if (tid != %s) { return 0; }' % args.tid)
441*387f9dfdSAndroid Build Coastguard Workerelif args.pid:
442*387f9dfdSAndroid Build Coastguard Worker    program = program.replace('FILTER',
443*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
444*387f9dfdSAndroid Build Coastguard Workerelse:
445*387f9dfdSAndroid Build Coastguard Worker    program = program.replace('FILTER', '')
446*387f9dfdSAndroid Build Coastguard Worker
447*387f9dfdSAndroid Build Coastguard Workerprogram = program.replace('STACK_STORAGE_SIZE', str(args.stack_storage_size))
448*387f9dfdSAndroid Build Coastguard Worker
449*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=program)
450*387f9dfdSAndroid Build Coastguard Worker
451*387f9dfdSAndroid Build Coastguard Workerif not is_support_kfunc:
452*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="mutex_unlock", fn_name="mutex_unlock_enter")
453*387f9dfdSAndroid Build Coastguard Worker    # Depending on whether DEBUG_LOCK_ALLOC is set, the proper kprobe may be either mutex_lock or mutex_lock_nested
454*387f9dfdSAndroid Build Coastguard Worker    if BPF.get_kprobe_functions(b"mutex_lock_nested"):
455*387f9dfdSAndroid Build Coastguard Worker        b.attach_kretprobe(event="mutex_lock_nested", fn_name="mutex_lock_return")
456*387f9dfdSAndroid Build Coastguard Worker        b.attach_kprobe(event="mutex_lock_nested", fn_name="mutex_lock_enter")
457*387f9dfdSAndroid Build Coastguard Worker    else:
458*387f9dfdSAndroid Build Coastguard Worker        b.attach_kretprobe(event="mutex_lock", fn_name="mutex_lock_return")
459*387f9dfdSAndroid Build Coastguard Worker        b.attach_kprobe(event="mutex_lock", fn_name="mutex_lock_enter")
460*387f9dfdSAndroid Build Coastguard Worker
461*387f9dfdSAndroid Build Coastguard Workerenabled = b.get_table("enabled");
462*387f9dfdSAndroid Build Coastguard Worker
463*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces")
464*387f9dfdSAndroid Build Coastguard Workeraq_counts = b.get_table("aq_report_count")
465*387f9dfdSAndroid Build Coastguard Workeraq_maxs   = b.get_table("aq_report_max")
466*387f9dfdSAndroid Build Coastguard Workeraq_totals = b.get_table("aq_report_total")
467*387f9dfdSAndroid Build Coastguard Worker
468*387f9dfdSAndroid Build Coastguard Workerhl_counts = b.get_table("hl_report_count")
469*387f9dfdSAndroid Build Coastguard Workerhl_maxs   = b.get_table("hl_report_max")
470*387f9dfdSAndroid Build Coastguard Workerhl_totals = b.get_table("hl_report_total")
471*387f9dfdSAndroid Build Coastguard Worker
472*387f9dfdSAndroid Build Coastguard Workeraq_sort = sort_list(aq_maxs, aq_totals, aq_counts)
473*387f9dfdSAndroid Build Coastguard Workerhl_sort = sort_list(hl_maxs, hl_totals, hl_counts)
474*387f9dfdSAndroid Build Coastguard Worker
475*387f9dfdSAndroid Build Coastguard Workerprint("Tracing lock events... Hit Ctrl-C to end.")
476*387f9dfdSAndroid Build Coastguard Worker
477*387f9dfdSAndroid Build Coastguard Worker# duration and interval are mutualy exclusive
478*387f9dfdSAndroid Build Coastguard Workerexiting = 0 if args.interval else 1
479*387f9dfdSAndroid Build Coastguard Workerexiting = 1 if args.duration else 0
480*387f9dfdSAndroid Build Coastguard Worker
481*387f9dfdSAndroid Build Coastguard Workerseconds = 99999999
482*387f9dfdSAndroid Build Coastguard Workerif args.interval:
483*387f9dfdSAndroid Build Coastguard Worker    seconds = args.interval
484*387f9dfdSAndroid Build Coastguard Workerif args.duration:
485*387f9dfdSAndroid Build Coastguard Worker    seconds = args.duration
486*387f9dfdSAndroid Build Coastguard Worker
487*387f9dfdSAndroid Build Coastguard Workermissing_stacks = 0
488*387f9dfdSAndroid Build Coastguard Workerhas_enomem     = False
489*387f9dfdSAndroid Build Coastguard Worker
490*387f9dfdSAndroid Build Coastguard Workerwhile (1):
491*387f9dfdSAndroid Build Coastguard Worker    enabled[ct.c_int(0)] = ct.c_int(1)
492*387f9dfdSAndroid Build Coastguard Worker
493*387f9dfdSAndroid Build Coastguard Worker    try:
494*387f9dfdSAndroid Build Coastguard Worker        sleep(seconds)
495*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
496*387f9dfdSAndroid Build Coastguard Worker        exiting = 1
497*387f9dfdSAndroid Build Coastguard Worker
498*387f9dfdSAndroid Build Coastguard Worker    enabled[ct.c_int(0)] = ct.c_int(0)
499*387f9dfdSAndroid Build Coastguard Worker
500*387f9dfdSAndroid Build Coastguard Worker    print("\n%40s %10s %6s %10s %10s" % ("Caller", "Avg Spin", "Count", "Max spin", "Total spin"))
501*387f9dfdSAndroid Build Coastguard Worker    display(aq_sort, aq_maxs, aq_totals, aq_counts)
502*387f9dfdSAndroid Build Coastguard Worker
503*387f9dfdSAndroid Build Coastguard Worker
504*387f9dfdSAndroid Build Coastguard Worker    print("\n%40s %10s %6s %10s %10s" % ("Caller", "Avg Hold", "Count", "Max hold", "Total hold"))
505*387f9dfdSAndroid Build Coastguard Worker    display(hl_sort, hl_maxs, hl_totals, hl_counts)
506*387f9dfdSAndroid Build Coastguard Worker
507*387f9dfdSAndroid Build Coastguard Worker    if exiting:
508*387f9dfdSAndroid Build Coastguard Worker        break;
509*387f9dfdSAndroid Build Coastguard Worker
510*387f9dfdSAndroid Build Coastguard Worker    stack_traces.clear()
511*387f9dfdSAndroid Build Coastguard Worker    aq_counts.clear()
512*387f9dfdSAndroid Build Coastguard Worker    aq_maxs.clear()
513*387f9dfdSAndroid Build Coastguard Worker    aq_totals.clear()
514*387f9dfdSAndroid Build Coastguard Worker    hl_counts.clear()
515*387f9dfdSAndroid Build Coastguard Worker    hl_maxs.clear()
516*387f9dfdSAndroid Build Coastguard Worker    hl_totals.clear()
517*387f9dfdSAndroid Build Coastguard Worker
518*387f9dfdSAndroid Build Coastguard Workerif missing_stacks > 0:
519*387f9dfdSAndroid Build Coastguard Worker    enomem_str = " Consider increasing --stack-storage-size."
520*387f9dfdSAndroid Build Coastguard Worker    print("WARNING: %d stack traces lost and could not be displayed.%s" %
521*387f9dfdSAndroid Build Coastguard Worker        (missing_stacks, (enomem_str if has_enomem else "")),
522*387f9dfdSAndroid Build Coastguard Worker        file=stderr)
523