1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# uthreads Trace thread creation/destruction events in high-level languages. 5*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. 6*387f9dfdSAndroid Build Coastguard Worker# 7*387f9dfdSAndroid Build Coastguard Worker# USAGE: uthreads [-l {c,java,none}] [-v] pid 8*387f9dfdSAndroid Build Coastguard Worker# 9*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Sasha Goldshtein 10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# 25-Oct-2016 Sasha Goldshtein Created this. 13*387f9dfdSAndroid Build Coastguard Worker 14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 15*387f9dfdSAndroid Build Coastguard Workerimport argparse 16*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT, utils 17*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct 18*387f9dfdSAndroid Build Coastguard Workerimport time 19*387f9dfdSAndroid Build Coastguard Workerimport os 20*387f9dfdSAndroid Build Coastguard Worker 21*387f9dfdSAndroid Build Coastguard Workerlanguages = ["c", "java"] 22*387f9dfdSAndroid Build Coastguard Worker 23*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 24*387f9dfdSAndroid Build Coastguard Worker ./uthreads -l java 185 # trace Java threads in process 185 25*387f9dfdSAndroid Build Coastguard Worker ./uthreads -l none 12245 # trace only pthreads in process 12245 26*387f9dfdSAndroid Build Coastguard Worker""" 27*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 28*387f9dfdSAndroid Build Coastguard Worker description="Trace thread creation/destruction events in " + 29*387f9dfdSAndroid Build Coastguard Worker "high-level languages.", 30*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 31*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 32*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-l", "--language", choices=languages + ["none"], 33*387f9dfdSAndroid Build Coastguard Worker help="language to trace (none for pthreads only)") 34*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("pid", type=int, help="process id to attach to") 35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true", 36*387f9dfdSAndroid Build Coastguard Worker help="verbose mode: print the BPF program (for debugging purposes)") 37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 38*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 39*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 40*387f9dfdSAndroid Build Coastguard Worker 41*387f9dfdSAndroid Build Coastguard Workerusdt = USDT(pid=args.pid) 42*387f9dfdSAndroid Build Coastguard Worker 43*387f9dfdSAndroid Build Coastguard Workerprogram = """ 44*387f9dfdSAndroid Build Coastguard Workerstruct thread_event_t { 45*387f9dfdSAndroid Build Coastguard Worker u64 runtime_id; 46*387f9dfdSAndroid Build Coastguard Worker u64 native_id; 47*387f9dfdSAndroid Build Coastguard Worker char type[8]; 48*387f9dfdSAndroid Build Coastguard Worker char name[80]; 49*387f9dfdSAndroid Build Coastguard Worker}; 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(threads); 52*387f9dfdSAndroid Build Coastguard Worker 53*387f9dfdSAndroid Build Coastguard Workerint trace_pthread(struct pt_regs *ctx) { 54*387f9dfdSAndroid Build Coastguard Worker struct thread_event_t te = {}; 55*387f9dfdSAndroid Build Coastguard Worker u64 start_routine = 0; 56*387f9dfdSAndroid Build Coastguard Worker char type[] = "pthread"; 57*387f9dfdSAndroid Build Coastguard Worker te.native_id = bpf_get_current_pid_tgid() & 0xFFFFFFFF; 58*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(2, ctx, &start_routine); 59*387f9dfdSAndroid Build Coastguard Worker te.runtime_id = start_routine; // This is really a function pointer 60*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&te.type, type, sizeof(te.type)); 61*387f9dfdSAndroid Build Coastguard Worker threads.perf_submit(ctx, &te, sizeof(te)); 62*387f9dfdSAndroid Build Coastguard Worker return 0; 63*387f9dfdSAndroid Build Coastguard Worker} 64*387f9dfdSAndroid Build Coastguard Worker""" 65*387f9dfdSAndroid Build Coastguard Workerusdt.enable_probe_or_bail("pthread_start", "trace_pthread") 66*387f9dfdSAndroid Build Coastguard Worker 67*387f9dfdSAndroid Build Coastguard Workerlanguage = args.language 68*387f9dfdSAndroid Build Coastguard Workerif not language: 69*387f9dfdSAndroid Build Coastguard Worker language = utils.detect_language(languages, args.pid) 70*387f9dfdSAndroid Build Coastguard Worker 71*387f9dfdSAndroid Build Coastguard Workerif language == "c": 72*387f9dfdSAndroid Build Coastguard Worker # Nothing to add 73*387f9dfdSAndroid Build Coastguard Worker pass 74*387f9dfdSAndroid Build Coastguard Workerelif language == "java": 75*387f9dfdSAndroid Build Coastguard Worker template = """ 76*387f9dfdSAndroid Build Coastguard Workerint %s(struct pt_regs *ctx) { 77*387f9dfdSAndroid Build Coastguard Worker char type[] = "%s"; 78*387f9dfdSAndroid Build Coastguard Worker struct thread_event_t te = {}; 79*387f9dfdSAndroid Build Coastguard Worker u64 nameptr = 0, id = 0, native_id = 0; 80*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(1, ctx, &nameptr); 81*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(3, ctx, &id); 82*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(4, ctx, &native_id); 83*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_user(&te.name, sizeof(te.name), (void *)nameptr); 84*387f9dfdSAndroid Build Coastguard Worker te.runtime_id = id; 85*387f9dfdSAndroid Build Coastguard Worker te.native_id = native_id; 86*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&te.type, type, sizeof(te.type)); 87*387f9dfdSAndroid Build Coastguard Worker threads.perf_submit(ctx, &te, sizeof(te)); 88*387f9dfdSAndroid Build Coastguard Worker return 0; 89*387f9dfdSAndroid Build Coastguard Worker} 90*387f9dfdSAndroid Build Coastguard Worker """ 91*387f9dfdSAndroid Build Coastguard Worker program += template % ("trace_start", "start") 92*387f9dfdSAndroid Build Coastguard Worker program += template % ("trace_stop", "stop") 93*387f9dfdSAndroid Build Coastguard Worker usdt.enable_probe_or_bail("thread__start", "trace_start") 94*387f9dfdSAndroid Build Coastguard Worker usdt.enable_probe_or_bail("thread__stop", "trace_stop") 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard Workerif args.ebpf or args.verbose: 97*387f9dfdSAndroid Build Coastguard Worker if args.verbose: 98*387f9dfdSAndroid Build Coastguard Worker print(usdt.get_text()) 99*387f9dfdSAndroid Build Coastguard Worker print(program) 100*387f9dfdSAndroid Build Coastguard Worker if args.ebpf: 101*387f9dfdSAndroid Build Coastguard Worker exit() 102*387f9dfdSAndroid Build Coastguard Worker 103*387f9dfdSAndroid Build Coastguard Workerbpf = BPF(text=program, usdt_contexts=[usdt]) 104*387f9dfdSAndroid Build Coastguard Workerprint("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." % 105*387f9dfdSAndroid Build Coastguard Worker (args.pid, language or "none")) 106*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-16s %-8s %-30s" % ("TIME", "ID", "TYPE", "DESCRIPTION")) 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Workerclass ThreadEvent(ct.Structure): 109*387f9dfdSAndroid Build Coastguard Worker _fields_ = [ 110*387f9dfdSAndroid Build Coastguard Worker ("runtime_id", ct.c_ulonglong), 111*387f9dfdSAndroid Build Coastguard Worker ("native_id", ct.c_ulonglong), 112*387f9dfdSAndroid Build Coastguard Worker ("type", ct.c_char * 8), 113*387f9dfdSAndroid Build Coastguard Worker ("name", ct.c_char * 80), 114*387f9dfdSAndroid Build Coastguard Worker ] 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard Workerstart_ts = time.time() 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 119*387f9dfdSAndroid Build Coastguard Worker event = ct.cast(data, ct.POINTER(ThreadEvent)).contents 120*387f9dfdSAndroid Build Coastguard Worker name = event.name 121*387f9dfdSAndroid Build Coastguard Worker if event.type == "pthread": 122*387f9dfdSAndroid Build Coastguard Worker name = bpf.sym(event.runtime_id, args.pid, show_module=True) 123*387f9dfdSAndroid Build Coastguard Worker tid = event.native_id 124*387f9dfdSAndroid Build Coastguard Worker else: 125*387f9dfdSAndroid Build Coastguard Worker tid = "R=%s/N=%s" % (event.runtime_id, event.native_id) 126*387f9dfdSAndroid Build Coastguard Worker print("%-8.3f %-16s %-8s %-30s" % ( 127*387f9dfdSAndroid Build Coastguard Worker time.time() - start_ts, tid, event.type, name)) 128*387f9dfdSAndroid Build Coastguard Worker 129*387f9dfdSAndroid Build Coastguard Workerbpf["threads"].open_perf_buffer(print_event) 130*387f9dfdSAndroid Build Coastguard Workerwhile 1: 131*387f9dfdSAndroid Build Coastguard Worker try: 132*387f9dfdSAndroid Build Coastguard Worker bpf.perf_buffer_poll() 133*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 134*387f9dfdSAndroid Build Coastguard Worker exit() 135