-// SPDX-License-Identifier: GPL-2.0
-// Copyright (c) 2021 Hengqi Chen
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2021 Hengqi Chen */
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#include "gethostlatency.h"
-#define MAX_ENTRIES 10240
+#define MAX_ENTRIES 10240
-const volatile pid_t targ_tgid = 0;
+const volatile pid_t target_pid = 0;
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_ENTRIES);
__type(key, __u32);
- __type(value, struct val_t);
-} start SEC(".maps");
+ __type(value, struct event);
+} starts SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(value_size, sizeof(__u32));
} events SEC(".maps");
-static __always_inline
-int probe_entry(struct pt_regs *ctx) {
+static int probe_entry(struct pt_regs *ctx)
+{
if (!PT_REGS_PARM1(ctx))
return 0;
- struct val_t val = {};
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32)pid_tgid;
+ struct event event = {};
- if (targ_tgid && targ_tgid != pid)
+ if (target_pid && target_pid != pid)
return 0;
- if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
- bpf_probe_read_user(&val.host, sizeof(val.host),
- (void *)PT_REGS_PARM1(ctx));
- val.pid = pid;
- val.time = bpf_ktime_get_ns();
- bpf_map_update_elem(&start, &tid, &val, BPF_ANY);
- }
-
+ event.time = bpf_ktime_get_ns();
+ event.pid = pid;
+ bpf_get_current_comm(&event.comm, sizeof(event.comm));
+ bpf_probe_read_user(&event.host, sizeof(event.host), (void *)PT_REGS_PARM1(ctx));
+ bpf_map_update_elem(&starts, &tid, &event, BPF_ANY);
return 0;
}
-static __always_inline
-int probe_return(struct pt_regs *ctx) {
- struct val_t *valp;
+static int probe_return(struct pt_regs *ctx)
+{
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
__u32 tid = (__u32)pid_tgid;
- __u64 now = bpf_ktime_get_ns();
+ struct event *eventp;
- valp = bpf_map_lookup_elem(&start, &tid);
- if (!valp)
+ eventp = bpf_map_lookup_elem(&starts, &tid);
+ if (!eventp)
return 0;
- // update time from timestamp to delta
- valp->time = now - valp->time;
- bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, valp,
- sizeof(*valp));
- bpf_map_delete_elem(&start, &tid);
+ /* update time from timestamp to delta */
+ eventp->time = bpf_ktime_get_ns() - eventp->time;
+ bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, eventp, sizeof(*eventp));
+ bpf_map_delete_elem(&starts, &tid);
return 0;
}
-// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
-// Copyright (c) 2021 Hengqi Chen
-//
-// Based on gethostlatency(8) from BCC by Brendan Gregg.
-// 24-Mar-2021 Hengqi Chen Created this.
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
+
+/*
+ * gethostlatency Show latency for getaddrinfo/gethostbyname[2] calls.
+ *
+ * Copyright (c) 2021 Hengqi Chen
+ *
+ * Based on gethostlatency(8) from BCC by Brendan Gregg.
+ * 24-Mar-2021 Hengqi Chen Created this.
+ */
#include <argp.h>
#include <errno.h>
#include <signal.h>
#include "trace_helpers.h"
#include "uprobe_helpers.h"
-#define PERF_BUFFER_PAGES 16
-#define PERF_POLL_TIMEOUT_MS 100
+#define PERF_BUFFER_PAGES 16
+#define PERF_POLL_TIMEOUT_MS 100
#define warn(...) fprintf(stderr, __VA_ARGS__)
static volatile sig_atomic_t exiting = 0;
-static pid_t traced_pid = 0;
+static pid_t target_pid = 0;
const char *argp_program_version = "gethostlatency 0.1";
const char *argp_program_bug_address =
warn("Invalid PID: %s\n", arg);
argp_usage(state);
}
- traced_pid = pid;
+ target_pid = pid;
break;
case 'h':
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
exiting = 1;
}
-static const char *strftime_now(char *s, size_t max, const char *format)
+static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
{
+ const struct event *e = data;
struct tm *tm;
+ char ts[16];
time_t t;
- t = time(NULL);
+ time(&t);
tm = localtime(&t);
- if (tm == NULL) {
- warn("localtime: %s\n", strerror(errno));
- return "<failed>";
- }
- if (strftime(s, max, format, tm) == 0) {
- warn("strftime error\n");
- return "<failed>";
- }
- return s;
-}
-
-static void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
-{
- const struct val_t *e = data;
- char s[16] = {};
- const char *now;
-
- now = strftime_now(s, sizeof(s), "%H:%M:%S");
- printf("%-11s %-10d %-20s %-10.2f %-16s\n",
- now, e->pid, e->comm, (double)e->time/1000000, e->host);
+ strftime(ts, sizeof(ts), "%H:%M:%S", tm);
+ printf("%-8s %-7d %-16s %-10.3f %-s\n",
+ ts, e->pid, e->comm, (double)e->time/1000000, e->host);
}
static void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
static int get_libc_path(char *path)
{
FILE *f;
- char buf[256] = {};
+ char buf[PATH_MAX] = {};
char *filename;
float version;
f = fopen("/proc/self/maps", "r");
- if (!f) {
+ if (!f)
return -errno;
- }
while (fscanf(f, "%*x-%*x %*s %*s %*s %*s %[^\n]\n", buf) != EOF) {
- if (strchr(buf, '/') != buf) {
+ if (strchr(buf, '/') != buf)
continue;
- }
filename = strrchr(buf, '/') + 1;
if (sscanf(filename, "libc-%f.so", &version) == 1) {
memcpy(path, buf, strlen(buf));
}
obj->links.handle_entry =
bpf_program__attach_uprobe(obj->progs.handle_entry, false,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_entry);
if (err) {
warn("failed to attach getaddrinfo: %d\n", err);
}
obj->links.handle_return =
bpf_program__attach_uprobe(obj->progs.handle_return, true,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_return);
if (err) {
warn("failed to attach getaddrinfo: %d\n", err);
func_off = get_elf_func_offset(libc_path, "gethostbyname");
if (func_off < 0) {
- warn("Could not find gethostbyname in %s\n", libc_path);
+ warn("could not find gethostbyname in %s\n", libc_path);
return -1;
}
obj->links.handle_entry =
bpf_program__attach_uprobe(obj->progs.handle_entry, false,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_entry);
if (err) {
warn("failed to attach gethostbyname: %d\n", err);
}
obj->links.handle_return =
bpf_program__attach_uprobe(obj->progs.handle_return, true,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_return);
if (err) {
warn("failed to attach gethostbyname: %d\n", err);
func_off = get_elf_func_offset(libc_path, "gethostbyname2");
if (func_off < 0) {
- warn("Could not find gethostbyname2 in %s\n", libc_path);
+ warn("could not find gethostbyname2 in %s\n", libc_path);
return -1;
}
obj->links.handle_entry =
bpf_program__attach_uprobe(obj->progs.handle_entry, false,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_entry);
if (err) {
warn("failed to attach gethostbyname2: %d\n", err);
}
obj->links.handle_return =
bpf_program__attach_uprobe(obj->progs.handle_return, true,
- traced_pid ?: -1, libc_path, func_off);
+ target_pid ?: -1, libc_path, func_off);
err = libbpf_get_error(obj->links.handle_return);
if (err) {
warn("failed to attach gethostbyname2: %d\n", err);
return 1;
}
- obj->rodata->targ_tgid = traced_pid;
+ obj->rodata->target_pid = target_pid;
err = gethostlatency_bpf__load(obj);
if (err) {
}
err = attach_uprobes(obj);
- if (err) {
+ if (err)
goto cleanup;
- }
pb_opts.sample_cb = handle_event;
pb_opts.lost_cb = handle_lost_events;
goto cleanup;
}
- printf("%-11s %-10s %-20s %-10s %-16s\n",
- "TIME", "PID", "COMM", "LATms", "HOST");
+ printf("%-8s %-7s %-16s %-10s %-s\n",
+ "TIME", "PID", "COMM", "LATms", "HOST");
while (1) {
if ((err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS)) < 0)
warn("error polling perf buffer: %d\n", err);
cleanup:
+ perf_buffer__free(pb);
gethostlatency_bpf__destroy(obj);
return err != 0;