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