1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Workerimport argparse 3*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep 4*387f9dfdSAndroid Build Coastguard Workerfrom sys import argv 5*387f9dfdSAndroid Build Coastguard Workerimport ctypes as ct 6*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT 7*387f9dfdSAndroid Build Coastguard Workerimport inspect 8*387f9dfdSAndroid Build Coastguard Workerimport os 9*387f9dfdSAndroid Build Coastguard Worker 10*387f9dfdSAndroid Build Coastguard Worker# Parse command line arguments 11*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(description="Trace the latency of an operation using usdt probes.", 12*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter) 13*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", type=int, help="The id of the process to trace.") 14*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-f", "--filterstr", type=str, default="", help="The prefix filter for the operation input. If specified, only operations for which the input string starts with the filterstr are traced.") 15*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="If true, will output generated bpf program and verbose logging information.") 16*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--sdt", dest="sdt", action="store_true", help="If true, will use the probes, created by systemtap's dtrace.") 17*387f9dfdSAndroid Build Coastguard Worker 18*387f9dfdSAndroid Build Coastguard Workerparser.set_defaults(verbose=False) 19*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 20*387f9dfdSAndroid Build Coastguard Workerthis_pid = int(args.pid) 21*387f9dfdSAndroid Build Coastguard Workerthis_filter = str(args.filterstr) 22*387f9dfdSAndroid Build Coastguard Worker 23*387f9dfdSAndroid Build Coastguard WorkerdebugLevel=0 24*387f9dfdSAndroid Build Coastguard Workerif args.verbose: 25*387f9dfdSAndroid Build Coastguard Worker debugLevel=4 26*387f9dfdSAndroid Build Coastguard Worker 27*387f9dfdSAndroid Build Coastguard Worker# BPF program 28*387f9dfdSAndroid Build Coastguard Workerbpf_text_shared = "%s/bpf_text_shared.c" % os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 29*387f9dfdSAndroid Build Coastguard Workerbpf_text = open(bpf_text_shared, 'r').read() 30*387f9dfdSAndroid Build Coastguard Workerbpf_text += """ 31*387f9dfdSAndroid Build Coastguard Worker 32*387f9dfdSAndroid Build Coastguard Worker/** 33*387f9dfdSAndroid Build Coastguard Worker * @brief Contains the latency data w.r.t. the complete operation from request to response. 34*387f9dfdSAndroid Build Coastguard Worker */ 35*387f9dfdSAndroid Build Coastguard Workerstruct end_data_t 36*387f9dfdSAndroid Build Coastguard Worker{ 37*387f9dfdSAndroid Build Coastguard Worker u64 operation_id; ///< The id of the operation. 38*387f9dfdSAndroid Build Coastguard Worker char input[64]; ///< The request (input) string. 39*387f9dfdSAndroid Build Coastguard Worker char output[64]; ///< The response (output) string. 40*387f9dfdSAndroid Build Coastguard Worker u64 start; ///< The start timestamp of the operation. 41*387f9dfdSAndroid Build Coastguard Worker u64 end; ///< The end timestamp of the operation. 42*387f9dfdSAndroid Build Coastguard Worker u64 duration; ///< The duration of the operation. 43*387f9dfdSAndroid Build Coastguard Worker}; 44*387f9dfdSAndroid Build Coastguard Worker 45*387f9dfdSAndroid Build Coastguard Worker/** 46*387f9dfdSAndroid Build Coastguard Worker * The output buffer, which will be used to push the latency event data to user space. 47*387f9dfdSAndroid Build Coastguard Worker */ 48*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(operation_event); 49*387f9dfdSAndroid Build Coastguard Worker 50*387f9dfdSAndroid Build Coastguard Worker/** 51*387f9dfdSAndroid Build Coastguard Worker * @brief Reads the operation response arguments, calculates the latency event data, and writes it to the user output buffer. 52*387f9dfdSAndroid Build Coastguard Worker * @param ctx The BPF context. 53*387f9dfdSAndroid Build Coastguard Worker */ 54*387f9dfdSAndroid Build Coastguard Workerint trace_operation_end(struct pt_regs* ctx) 55*387f9dfdSAndroid Build Coastguard Worker{ 56*387f9dfdSAndroid Build Coastguard Worker u64 operation_id; 57*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg(1, ctx, &operation_id); 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker struct start_data_t* start_data = start_hash.lookup(&operation_id); 60*387f9dfdSAndroid Build Coastguard Worker if (0 == start_data) { 61*387f9dfdSAndroid Build Coastguard Worker return 0; 62*387f9dfdSAndroid Build Coastguard Worker } 63*387f9dfdSAndroid Build Coastguard Worker 64*387f9dfdSAndroid Build Coastguard Worker struct end_data_t end_data = {}; 65*387f9dfdSAndroid Build Coastguard Worker end_data.operation_id = operation_id; 66*387f9dfdSAndroid Build Coastguard Worker bpf_usdt_readarg_p(2, ctx, &end_data.output, sizeof(end_data.output)); 67*387f9dfdSAndroid Build Coastguard Worker end_data.end = bpf_ktime_get_ns(); 68*387f9dfdSAndroid Build Coastguard Worker end_data.start = start_data->start; 69*387f9dfdSAndroid Build Coastguard Worker end_data.duration = end_data.end - end_data.start; 70*387f9dfdSAndroid Build Coastguard Worker __builtin_memcpy(&end_data.input, start_data->input, sizeof(end_data.input)); 71*387f9dfdSAndroid Build Coastguard Worker 72*387f9dfdSAndroid Build Coastguard Worker start_hash.delete(&end_data.operation_id); 73*387f9dfdSAndroid Build Coastguard Worker 74*387f9dfdSAndroid Build Coastguard Worker operation_event.perf_submit(ctx, &end_data, sizeof(end_data)); 75*387f9dfdSAndroid Build Coastguard Worker return 0; 76*387f9dfdSAndroid Build Coastguard Worker} 77*387f9dfdSAndroid Build Coastguard Worker""" 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace("FILTER_STRING", this_filter) 80*387f9dfdSAndroid Build Coastguard Workerif this_filter: 81*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("FILTER_STATEMENT", "if (!filter(start_data.input)) { return 0; }") 82*387f9dfdSAndroid Build Coastguard Workerelse: 83*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("FILTER_STATEMENT", "") 84*387f9dfdSAndroid Build Coastguard Worker 85*387f9dfdSAndroid Build Coastguard Worker# Create USDT context 86*387f9dfdSAndroid Build Coastguard Workerprint("latency.py - Attaching probes to pid: %d; filter: %s" % (this_pid, this_filter)) 87*387f9dfdSAndroid Build Coastguard Workerusdt_ctx = USDT(pid=this_pid) 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Workerif args.sdt: 90*387f9dfdSAndroid Build Coastguard Worker usdt_ctx.enable_probe(probe="usdt_sample_lib1_sdt:operation_start_sdt", fn_name="trace_operation_start") 91*387f9dfdSAndroid Build Coastguard Worker usdt_ctx.enable_probe(probe="usdt_sample_lib1_sdt:operation_end_sdt", fn_name="trace_operation_end") 92*387f9dfdSAndroid Build Coastguard Workerelse: 93*387f9dfdSAndroid Build Coastguard Worker usdt_ctx.enable_probe(probe="usdt_sample_lib1:operation_start", fn_name="trace_operation_start") 94*387f9dfdSAndroid Build Coastguard Worker usdt_ctx.enable_probe(probe="usdt_sample_lib1:operation_end", fn_name="trace_operation_end") 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard Worker# Create BPF context, load BPF program 97*387f9dfdSAndroid Build Coastguard Workerbpf_ctx = BPF(text=bpf_text, usdt_contexts=[usdt_ctx], debug=debugLevel) 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Worker# Define latency event and print function 100*387f9dfdSAndroid Build Coastguard Workerclass OperationEventData(ct.Structure): 101*387f9dfdSAndroid Build Coastguard Worker _fields_ = [("operation_id", ct.c_ulonglong), 102*387f9dfdSAndroid Build Coastguard Worker ("input", ct.c_char * 64), 103*387f9dfdSAndroid Build Coastguard Worker ("output", ct.c_char * 64), 104*387f9dfdSAndroid Build Coastguard Worker ("start", ct.c_ulonglong), 105*387f9dfdSAndroid Build Coastguard Worker ("end", ct.c_ulonglong), 106*387f9dfdSAndroid Build Coastguard Worker ("duration", ct.c_ulonglong)] 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard Workerstart = 0 109*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 110*387f9dfdSAndroid Build Coastguard Worker global start 111*387f9dfdSAndroid Build Coastguard Worker event = ct.cast(data, ct.POINTER(OperationEventData)).contents 112*387f9dfdSAndroid Build Coastguard Worker if start == 0: 113*387f9dfdSAndroid Build Coastguard Worker start = event.start 114*387f9dfdSAndroid Build Coastguard Worker time_s = (float(event.start - start)) / 1000000000 115*387f9dfdSAndroid Build Coastguard Worker latency = (float(event.duration) / 1000) 116*387f9dfdSAndroid Build Coastguard Worker print("%-18.9f %-10d %-32s %-32s %16d %16d %16d" % (time_s, event.operation_id, event.input, event.output, event.start, event.end, latency)) 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Worker# Print header 119*387f9dfdSAndroid Build Coastguard Workerprint("Tracing... Hit Ctrl-C to end.") 120*387f9dfdSAndroid Build Coastguard Workerprint("%-18s %-10s %-32s %-32s %16s %16s %16s" % ("time(s)", "id", "input", "output", "start (ns)", "end (ns)", "duration (us)")) 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Worker# Output latency events 123*387f9dfdSAndroid Build Coastguard Workerbpf_ctx["operation_event"].open_perf_buffer(print_event) 124*387f9dfdSAndroid Build Coastguard Workerwhile 1: 125*387f9dfdSAndroid Build Coastguard Worker bpf_ctx.perf_buffer_poll() 126