1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# drsnoop Trace direct reclaim and print details including issuing PID. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# This uses in-kernel eBPF maps to cache process details (PID and comm) by 8*387f9dfdSAndroid Build Coastguard Worker# direct reclaim begin, as well as a starting timestamp for calculating 9*387f9dfdSAndroid Build Coastguard Worker# latency. 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2019 Wenbo Zhang 12*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 13*387f9dfdSAndroid Build Coastguard Worker# 14*387f9dfdSAndroid Build Coastguard Worker# 20-Feb-2019 Wenbo Zhang Created this. 15*387f9dfdSAndroid Build Coastguard Worker# 09-Mar-2019 Wenbo Zhang Updated for show sys mem info. 16*387f9dfdSAndroid Build Coastguard Worker 17*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 18*387f9dfdSAndroid Build Coastguard Workerfrom bcc import ArgString, BPF 19*387f9dfdSAndroid Build Coastguard Workerimport argparse 20*387f9dfdSAndroid Build Coastguard Workerfrom datetime import datetime, timedelta 21*387f9dfdSAndroid Build Coastguard Workerimport os 22*387f9dfdSAndroid Build Coastguard Workerimport math 23*387f9dfdSAndroid Build Coastguard Workerimport sys 24*387f9dfdSAndroid Build Coastguard Worker 25*387f9dfdSAndroid Build Coastguard Worker# symbols 26*387f9dfdSAndroid Build Coastguard Workerkallsyms = "/proc/kallsyms" 27*387f9dfdSAndroid Build Coastguard Worker 28*387f9dfdSAndroid Build Coastguard Worker# arguments 29*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 30*387f9dfdSAndroid Build Coastguard Worker ./drsnoop # trace all direct reclaim 31*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -T # include timestamps 32*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -U # include UID 33*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -P 181 # only trace PID 181 34*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -t 123 # only trace TID 123 35*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -u 1000 # only trace UID 1000 36*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -d 10 # trace for 10 seconds only 37*387f9dfdSAndroid Build Coastguard Worker ./drsnoop -n main # only print process names containing "main" 38*387f9dfdSAndroid Build Coastguard Worker""" 39*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 40*387f9dfdSAndroid Build Coastguard Worker description="Trace direct reclaim", 41*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 42*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 43*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-T", "--timestamp", action="store_true", 44*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 45*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-U", "--print-uid", action="store_true", 46*387f9dfdSAndroid Build Coastguard Worker help="print UID column") 47*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 48*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 49*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--tid", 50*387f9dfdSAndroid Build Coastguard Worker help="trace this TID only") 51*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-u", "--uid", 52*387f9dfdSAndroid Build Coastguard Worker help="trace this UID only") 53*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-d", "--duration", 54*387f9dfdSAndroid Build Coastguard Worker help="total duration of trace in seconds") 55*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-n", "--name", 56*387f9dfdSAndroid Build Coastguard Worker type=ArgString, 57*387f9dfdSAndroid Build Coastguard Worker help="only print process names containing this name") 58*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true", 59*387f9dfdSAndroid Build Coastguard Worker help="show system memory state") 60*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 61*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 62*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 63*387f9dfdSAndroid Build Coastguard Workerdebug = 0 64*387f9dfdSAndroid Build Coastguard Workerif args.duration: 65*387f9dfdSAndroid Build Coastguard Worker args.duration = timedelta(seconds=int(args.duration)) 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Worker 68*387f9dfdSAndroid Build Coastguard Worker# vm_stat 69*387f9dfdSAndroid Build Coastguard Workervm_stat_addr = '' 70*387f9dfdSAndroid Build Coastguard Workerwith open(kallsyms) as syms: 71*387f9dfdSAndroid Build Coastguard Worker for line in syms: 72*387f9dfdSAndroid Build Coastguard Worker (addr, size, name) = line.rstrip().split(" ", 2) 73*387f9dfdSAndroid Build Coastguard Worker name = name.split("\t")[0] 74*387f9dfdSAndroid Build Coastguard Worker if name == "vm_stat": 75*387f9dfdSAndroid Build Coastguard Worker vm_stat_addr = "0x" + addr 76*387f9dfdSAndroid Build Coastguard Worker break 77*387f9dfdSAndroid Build Coastguard Worker if name == "vm_zone_stat": 78*387f9dfdSAndroid Build Coastguard Worker vm_stat_addr = "0x" + addr 79*387f9dfdSAndroid Build Coastguard Worker break 80*387f9dfdSAndroid Build Coastguard Worker if vm_stat_addr == '': 81*387f9dfdSAndroid Build Coastguard Worker print("ERROR: no vm_stat or vm_zone_stat in /proc/kallsyms. Exiting.") 82*387f9dfdSAndroid Build Coastguard Worker print("HINT: the kernel should be built with CONFIG_KALLSYMS_ALL.") 83*387f9dfdSAndroid Build Coastguard Worker exit() 84*387f9dfdSAndroid Build Coastguard Worker 85*387f9dfdSAndroid Build Coastguard WorkerNR_FREE_PAGES = 0 86*387f9dfdSAndroid Build Coastguard Worker 87*387f9dfdSAndroid Build Coastguard WorkerPAGE_SIZE = os.sysconf("SC_PAGE_SIZE") 88*387f9dfdSAndroid Build Coastguard WorkerPAGE_SHIFT = int(math.log(PAGE_SIZE) / math.log(2)) 89*387f9dfdSAndroid Build Coastguard Worker 90*387f9dfdSAndroid Build Coastguard Workerdef K(x): 91*387f9dfdSAndroid Build Coastguard Worker return x << (PAGE_SHIFT - 10) 92*387f9dfdSAndroid Build Coastguard Worker 93*387f9dfdSAndroid Build Coastguard Worker# load BPF program 94*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 95*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 96*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 97*387f9dfdSAndroid Build Coastguard Worker#include <linux/mmzone.h> 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Workerstruct val_t { 100*387f9dfdSAndroid Build Coastguard Worker u64 id; 101*387f9dfdSAndroid Build Coastguard Worker u64 ts; // start time 102*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 103*387f9dfdSAndroid Build Coastguard Worker u64 vm_stat[NR_VM_ZONE_STAT_ITEMS]; 104*387f9dfdSAndroid Build Coastguard Worker}; 105*387f9dfdSAndroid Build Coastguard Worker 106*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 107*387f9dfdSAndroid Build Coastguard Worker u64 id; 108*387f9dfdSAndroid Build Coastguard Worker u32 uid; 109*387f9dfdSAndroid Build Coastguard Worker u64 nr_reclaimed; 110*387f9dfdSAndroid Build Coastguard Worker u64 delta; 111*387f9dfdSAndroid Build Coastguard Worker u64 ts; // end time 112*387f9dfdSAndroid Build Coastguard Worker char name[TASK_COMM_LEN]; 113*387f9dfdSAndroid Build Coastguard Worker u64 vm_stat[NR_VM_ZONE_STAT_ITEMS]; 114*387f9dfdSAndroid Build Coastguard Worker}; 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(start, u64, struct val_t); 117*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 118*387f9dfdSAndroid Build Coastguard Worker 119*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(vmscan, mm_vmscan_direct_reclaim_begin) { 120*387f9dfdSAndroid Build Coastguard Worker struct val_t val = {}; 121*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 122*387f9dfdSAndroid Build Coastguard Worker u32 pid = id >> 32; // PID is higher part 123*387f9dfdSAndroid Build Coastguard Worker u32 tid = id; // Cast and get the lower part 124*387f9dfdSAndroid Build Coastguard Worker u32 uid = bpf_get_current_uid_gid(); 125*387f9dfdSAndroid Build Coastguard Worker u64 ts; 126*387f9dfdSAndroid Build Coastguard Worker 127*387f9dfdSAndroid Build Coastguard Worker PID_TID_FILTER 128*387f9dfdSAndroid Build Coastguard Worker UID_FILTER 129*387f9dfdSAndroid Build Coastguard Worker if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) { 130*387f9dfdSAndroid Build Coastguard Worker val.id = id; 131*387f9dfdSAndroid Build Coastguard Worker val.ts = bpf_ktime_get_ns(); 132*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&val.vm_stat, sizeof(val.vm_stat), (const void *)%s); 133*387f9dfdSAndroid Build Coastguard Worker start.update(&id, &val); 134*387f9dfdSAndroid Build Coastguard Worker } 135*387f9dfdSAndroid Build Coastguard Worker return 0; 136*387f9dfdSAndroid Build Coastguard Worker} 137*387f9dfdSAndroid Build Coastguard Worker 138*387f9dfdSAndroid Build Coastguard WorkerTRACEPOINT_PROBE(vmscan, mm_vmscan_direct_reclaim_end) { 139*387f9dfdSAndroid Build Coastguard Worker u64 id = bpf_get_current_pid_tgid(); 140*387f9dfdSAndroid Build Coastguard Worker struct val_t *valp; 141*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 142*387f9dfdSAndroid Build Coastguard Worker u64 ts = bpf_ktime_get_ns(); 143*387f9dfdSAndroid Build Coastguard Worker 144*387f9dfdSAndroid Build Coastguard Worker valp = start.lookup(&id); 145*387f9dfdSAndroid Build Coastguard Worker if (valp == NULL) { 146*387f9dfdSAndroid Build Coastguard Worker // missed entry 147*387f9dfdSAndroid Build Coastguard Worker return 0; 148*387f9dfdSAndroid Build Coastguard Worker } 149*387f9dfdSAndroid Build Coastguard Worker 150*387f9dfdSAndroid Build Coastguard Worker data.delta = ts - valp->ts; 151*387f9dfdSAndroid Build Coastguard Worker data.ts = ts / 1000; 152*387f9dfdSAndroid Build Coastguard Worker data.id = valp->id; 153*387f9dfdSAndroid Build Coastguard Worker data.uid = bpf_get_current_uid_gid(); 154*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.name, sizeof(data.name), valp->name); 155*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data.vm_stat, sizeof(data.vm_stat), valp->vm_stat); 156*387f9dfdSAndroid Build Coastguard Worker data.nr_reclaimed = args->nr_reclaimed; 157*387f9dfdSAndroid Build Coastguard Worker 158*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(args, &data, sizeof(data)); 159*387f9dfdSAndroid Build Coastguard Worker start.delete(&id); 160*387f9dfdSAndroid Build Coastguard Worker 161*387f9dfdSAndroid Build Coastguard Worker return 0; 162*387f9dfdSAndroid Build Coastguard Worker} 163*387f9dfdSAndroid Build Coastguard Worker""" % vm_stat_addr 164*387f9dfdSAndroid Build Coastguard Worker 165*387f9dfdSAndroid Build Coastguard Workerif args.tid: # TID trumps PID 166*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PID_TID_FILTER', 167*387f9dfdSAndroid Build Coastguard Worker 'if (tid != %s) { return 0; }' % args.tid) 168*387f9dfdSAndroid Build Coastguard Workerelif args.pid: 169*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PID_TID_FILTER', 170*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return 0; }' % args.pid) 171*387f9dfdSAndroid Build Coastguard Workerelse: 172*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('PID_TID_FILTER', '') 173*387f9dfdSAndroid Build Coastguard Workerif args.uid: 174*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('UID_FILTER', 175*387f9dfdSAndroid Build Coastguard Worker 'if (uid != %s) { return 0; }' % args.uid) 176*387f9dfdSAndroid Build Coastguard Workerelse: 177*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('UID_FILTER', '') 178*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf: 179*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 180*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 181*387f9dfdSAndroid Build Coastguard Worker exit() 182*387f9dfdSAndroid Build Coastguard Worker 183*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 184*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 185*387f9dfdSAndroid Build Coastguard Worker 186*387f9dfdSAndroid Build Coastguard Workerinitial_ts = 0 187*387f9dfdSAndroid Build Coastguard Worker 188*387f9dfdSAndroid Build Coastguard Worker# header 189*387f9dfdSAndroid Build Coastguard Workerif args.timestamp: 190*387f9dfdSAndroid Build Coastguard Worker print("%-14s" % ("TIME(s)"), end="") 191*387f9dfdSAndroid Build Coastguard Workerif args.print_uid: 192*387f9dfdSAndroid Build Coastguard Worker print("%-6s" % ("UID"), end="") 193*387f9dfdSAndroid Build Coastguard Workerprint("%-14s %-6s %8s %5s" % 194*387f9dfdSAndroid Build Coastguard Worker ("COMM", "TID" if args.tid else "PID", "LAT(ms)", "PAGES"), end="") 195*387f9dfdSAndroid Build Coastguard Workerif args.verbose: 196*387f9dfdSAndroid Build Coastguard Worker print("%10s" % ("FREE(KB)")) 197*387f9dfdSAndroid Build Coastguard Workerelse: 198*387f9dfdSAndroid Build Coastguard Worker print("") 199*387f9dfdSAndroid Build Coastguard Worker 200*387f9dfdSAndroid Build Coastguard Worker# process event 201*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 202*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 203*387f9dfdSAndroid Build Coastguard Worker 204*387f9dfdSAndroid Build Coastguard Worker global initial_ts 205*387f9dfdSAndroid Build Coastguard Worker 206*387f9dfdSAndroid Build Coastguard Worker if not initial_ts: 207*387f9dfdSAndroid Build Coastguard Worker initial_ts = event.ts 208*387f9dfdSAndroid Build Coastguard Worker 209*387f9dfdSAndroid Build Coastguard Worker if args.name and bytes(args.name) not in event.name: 210*387f9dfdSAndroid Build Coastguard Worker return 211*387f9dfdSAndroid Build Coastguard Worker 212*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 213*387f9dfdSAndroid Build Coastguard Worker delta = event.ts - initial_ts 214*387f9dfdSAndroid Build Coastguard Worker print("%-14.9f" % (float(delta) / 1000000), end="") 215*387f9dfdSAndroid Build Coastguard Worker 216*387f9dfdSAndroid Build Coastguard Worker if args.print_uid: 217*387f9dfdSAndroid Build Coastguard Worker print("%-6d" % event.uid, end="") 218*387f9dfdSAndroid Build Coastguard Worker 219*387f9dfdSAndroid Build Coastguard Worker print("%-14.14s %-6s %8.2f %5d" % 220*387f9dfdSAndroid Build Coastguard Worker (event.name.decode('utf-8', 'replace'), 221*387f9dfdSAndroid Build Coastguard Worker event.id & 0xffffffff if args.tid else event.id >> 32, 222*387f9dfdSAndroid Build Coastguard Worker float(event.delta) / 1000000, event.nr_reclaimed), end="") 223*387f9dfdSAndroid Build Coastguard Worker if args.verbose: 224*387f9dfdSAndroid Build Coastguard Worker print("%10d" % K(event.vm_stat[NR_FREE_PAGES])) 225*387f9dfdSAndroid Build Coastguard Worker else: 226*387f9dfdSAndroid Build Coastguard Worker print("") 227*387f9dfdSAndroid Build Coastguard Worker 228*387f9dfdSAndroid Build Coastguard Worker sys.stdout.flush() 229*387f9dfdSAndroid Build Coastguard Worker 230*387f9dfdSAndroid Build Coastguard Worker 231*387f9dfdSAndroid Build Coastguard Worker# loop with callback to print_event 232*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64) 233*387f9dfdSAndroid Build Coastguard Workerstart_time = datetime.now() 234*387f9dfdSAndroid Build Coastguard Workerwhile not args.duration or datetime.now() - start_time < args.duration: 235*387f9dfdSAndroid Build Coastguard Worker try: 236*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 237*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 238*387f9dfdSAndroid Build Coastguard Worker exit() 239