blob: 77a8b81dd921e71b4bd0883989aa9c282e487b88 [file] [log] [blame]
Brendan Gregg5a06c2c2016-01-28 23:00:00 -08001#!/usr/bin/python
2#
3# gethostlatency Show latency for getaddrinfo/gethostbyname[2] calls.
4# For Linux, uses BCC, eBPF. Embedded C.
5#
6# This can be useful for identifying DNS latency, by identifying which
7# remote host name lookups were slow, and by how much.
8#
9# This uses dynamic tracing of user-level functions and registers, and may
10# need modifications to match your software and processor architecture.
11#
12# Copyright 2016 Netflix, Inc.
13# Licensed under the Apache License, Version 2.0 (the "License")
14#
15# 28-Jan-2016 Brendan Gregg Created this.
mcaleavyaa9b886c2016-04-02 18:22:37 +010016# 30-Mar-2016 Allan McAleavy updated for BPF_PERF_OUTPUT
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080017
18from __future__ import print_function
19from bcc import BPF
20from time import strftime
Paul Chaignonedca17a2017-01-23 22:43:10 +010021import argparse
mcaleavyaa9b886c2016-04-02 18:22:37 +010022import ctypes as ct
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080023
Paul Chaignonedca17a2017-01-23 22:43:10 +010024examples = """examples:
25 ./gethostlatency # trace all TCP accept()s
26 ./gethostlatency -p 181 # only trace PID 181
27"""
28parser = argparse.ArgumentParser(
29 description="Show latency for getaddrinfo/gethostbyname[2] calls",
30 formatter_class=argparse.RawDescriptionHelpFormatter,
31 epilog=examples)
32parser.add_argument("-p", "--pid", help="trace this PID only", type=int,
33 default=-1)
34args = parser.parse_args()
35
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080036# load BPF program
37bpf_text = """
38#include <uapi/linux/ptrace.h>
mcaleavyaa9b886c2016-04-02 18:22:37 +010039#include <linux/sched.h>
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080040
41struct val_t {
mcaleavyaa9b886c2016-04-02 18:22:37 +010042 u32 pid;
43 char comm[TASK_COMM_LEN];
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080044 char host[80];
45 u64 ts;
46};
mcaleavyaa9b886c2016-04-02 18:22:37 +010047
48struct data_t {
49 u32 pid;
mcaleavyaa9b886c2016-04-02 18:22:37 +010050 u64 delta;
51 char comm[TASK_COMM_LEN];
52 char host[80];
53};
54
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080055BPF_HASH(start, u32, struct val_t);
mcaleavyaa9b886c2016-04-02 18:22:37 +010056BPF_PERF_OUTPUT(events);
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080057
58int do_entry(struct pt_regs *ctx) {
Naveen N. Rao4afa96a2016-05-03 14:54:21 +053059 if (!PT_REGS_PARM1(ctx))
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080060 return 0;
mcaleavyaa9b886c2016-04-02 18:22:37 +010061
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080062 struct val_t val = {};
63 u32 pid = bpf_get_current_pid_tgid();
mcaleavyaa9b886c2016-04-02 18:22:37 +010064
65 if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030066 bpf_probe_read(&val.host, sizeof(val.host),
67 (void *)PT_REGS_PARM1(ctx));
mcaleavyaa9b886c2016-04-02 18:22:37 +010068 val.pid = bpf_get_current_pid_tgid();
69 val.ts = bpf_ktime_get_ns();
70 start.update(&pid, &val);
71 }
72
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080073 return 0;
74}
75
76int do_return(struct pt_regs *ctx) {
77 struct val_t *valp;
mcaleavyaa9b886c2016-04-02 18:22:37 +010078 struct data_t data = {};
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080079 u64 delta;
80 u32 pid = bpf_get_current_pid_tgid();
81
mcaleavyaa9b886c2016-04-02 18:22:37 +010082 u64 tsp = bpf_ktime_get_ns();
83
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080084 valp = start.lookup(&pid);
85 if (valp == 0)
86 return 0; // missed start
87
mcaleavyaa9b886c2016-04-02 18:22:37 +010088 bpf_probe_read(&data.comm, sizeof(data.comm), valp->comm);
89 bpf_probe_read(&data.host, sizeof(data.host), (void *)valp->host);
90 data.pid = valp->pid;
91 data.delta = tsp - valp->ts;
mcaleavyaa9b886c2016-04-02 18:22:37 +010092 events.perf_submit(ctx, &data, sizeof(data));
Brendan Gregg5a06c2c2016-01-28 23:00:00 -080093 start.delete(&pid);
94 return 0;
95}
96"""
97b = BPF(text=bpf_text)
Paul Chaignonedca17a2017-01-23 22:43:10 +010098b.attach_uprobe(name="c", sym="getaddrinfo", fn_name="do_entry", pid=args.pid)
99b.attach_uprobe(name="c", sym="gethostbyname", fn_name="do_entry",
100 pid=args.pid)
101b.attach_uprobe(name="c", sym="gethostbyname2", fn_name="do_entry",
102 pid=args.pid)
103b.attach_uretprobe(name="c", sym="getaddrinfo", fn_name="do_return",
104 pid=args.pid)
105b.attach_uretprobe(name="c", sym="gethostbyname", fn_name="do_return",
106 pid=args.pid)
107b.attach_uretprobe(name="c", sym="gethostbyname2", fn_name="do_return",
108 pid=args.pid)
Brendan Gregg5a06c2c2016-01-28 23:00:00 -0800109
mcaleavyaa9b886c2016-04-02 18:22:37 +0100110TASK_COMM_LEN = 16 # linux/sched.h
Brendan Gregg5a06c2c2016-01-28 23:00:00 -0800111
mcaleavyaa9b886c2016-04-02 18:22:37 +0100112class Data(ct.Structure):
113 _fields_ = [
114 ("pid", ct.c_ulonglong),
mcaleavyaa9b886c2016-04-02 18:22:37 +0100115 ("delta", ct.c_ulonglong),
116 ("comm", ct.c_char * TASK_COMM_LEN),
117 ("host", ct.c_char * 80)
118 ]
119
mcaleavyaa9b886c2016-04-02 18:22:37 +0100120# header
121print("%-9s %-6s %-16s %10s %s" % ("TIME", "PID", "COMM", "LATms", "HOST"))
122
123def print_event(cpu, data, size):
124 event = ct.cast(data, ct.POINTER(Data)).contents
mcaleavyaa9b886c2016-04-02 18:22:37 +0100125 print("%-9s %-6d %-16s %10.2f %s" % (strftime("%H:%M:%S"), event.pid,
Brendan Gregg9aa1d752017-06-22 11:58:21 -0700126 event.comm.decode(), (float(event.delta) / 1000000),
127 event.host.decode()))
mcaleavyaa9b886c2016-04-02 18:22:37 +0100128
mcaleavyaa9b886c2016-04-02 18:22:37 +0100129# loop with callback to print_event
130b["events"].open_perf_buffer(print_event)
Brendan Gregg5a06c2c2016-01-28 23:00:00 -0800131while 1:
mcaleavyaa9b886c2016-04-02 18:22:37 +0100132 b.kprobe_poll()