From 1bee8eed670f4e25108b4a50305f48483c2efe30 Mon Sep 17 00:00:00 2001 From: yunwei37 <1067852565@qq.com> Date: Mon, 2 Sep 2024 06:20:32 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20eunomia-?= =?UTF-8?q?bpf/bpf-developer-tutorial@9c2bba3e16edc13e95a8a498fbe9682a611a?= =?UTF-8?q?6117=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 31-goroutine/goroutine.bpf.c | 4 +- 31-goroutine/goroutine.c | 172 ------------------ {32-http2 => 33-funclatency}/.gitignore | 0 {32-http2 => 33-funclatency}/Makefile | 8 +- 33-funclatency/bits.bpf.h | 31 ++++ .../funclatency.bpf.c | 14 -- {32-http2 => 33-funclatency}/funclatency.c | 37 ++-- {32-http2 => 33-funclatency}/funclatency.h | 0 39-nginx/trace.bt | 49 +++++ 9 files changed, 101 insertions(+), 214 deletions(-) delete mode 100644 31-goroutine/goroutine.c rename {32-http2 => 33-funclatency}/.gitignore (100%) rename {32-http2 => 33-funclatency}/Makefile (95%) create mode 100644 33-funclatency/bits.bpf.h rename {32-http2 => 33-funclatency}/funclatency.bpf.c (84%) rename {32-http2 => 33-funclatency}/funclatency.c (88%) rename {32-http2 => 33-funclatency}/funclatency.h (100%) create mode 100644 39-nginx/trace.bt diff --git a/31-goroutine/goroutine.bpf.c b/31-goroutine/goroutine.bpf.c index 5fc152f..8ea21b9 100644 --- a/31-goroutine/goroutine.bpf.c +++ b/31-goroutine/goroutine.bpf.c @@ -28,8 +28,6 @@ #include #include - - #define GOID_OFFSET 0x98 struct { @@ -40,7 +38,7 @@ struct { SEC("uprobe/./go-server-http/main:runtime.casgstatus") int uprobe_runtime_casgstatus(struct pt_regs *ctx) { int newval = ctx->cx; - void *gp = ctx->ax; + void *gp = (void*)ctx->ax; struct goroutine_execute_data *data; u64 goid; if (bpf_probe_read_user(&goid, sizeof(goid), gp + GOID_OFFSET) == 0) { diff --git a/31-goroutine/goroutine.c b/31-goroutine/goroutine.c deleted file mode 100644 index 89c9ee9..0000000 --- a/31-goroutine/goroutine.c +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include "goroutine.h" -#include "goroutine.skel.h" - -static struct env { - bool verbose; - long min_duration_ms; -} env; - -const char *argp_program_version = "goroutine 0.0"; -const char *argp_program_bug_address = ""; -const char argp_program_doc[] = -"BPF goroutine demo application.\n" -"\n" -"It traces process start and exits and shows associated \n" -"information (filename, process duration, PID and PPID, etc).\n" -"\n" -"USAGE: ./goroutine [-d ] [-v]\n"; - -static const struct argp_option opts[] = { - { "verbose", 'v', NULL, 0, "Verbose debug output" }, - { "duration", 'd', "DURATION-MS", 0, "Minimum process duration (ms) to report" }, - {}, -}; - -static error_t parse_arg(int key, char *arg, struct argp_state *state) -{ - switch (key) { - case 'v': - env.verbose = true; - break; - case 'd': - errno = 0; - env.min_duration_ms = strtol(arg, NULL, 10); - if (errno || env.min_duration_ms <= 0) { - fprintf(stderr, "Invalid duration: %s\n", arg); - argp_usage(state); - } - break; - case ARGP_KEY_ARG: - argp_usage(state); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static const struct argp argp = { - .options = opts, - .parser = parse_arg, - .doc = argp_program_doc, -}; - -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) -{ - if (level == LIBBPF_DEBUG && !env.verbose) - return 0; - return vfprintf(stderr, format, args); -} - -static volatile bool exiting = false; - -static void sig_handler(int sig) -{ - exiting = true; -} - -static int handle_event(void *ctx, void *data, size_t data_sz) -{ - const struct event *e = data; - struct tm *tm; - char ts[32]; - time_t t; - - time(&t); - tm = localtime(&t); - strftime(ts, sizeof(ts), "%H:%M:%S", tm); - - if (e->exit_event) { - printf("%-8s %-5s %-16s %-7d %-7d [%u]", - ts, "EXIT", e->comm, e->pid, e->ppid, e->exit_code); - if (e->duration_ns) - printf(" (%llums)", e->duration_ns / 1000000); - printf("\n"); - } else { - printf("%-8s %-5s %-16s %-7d %-7d %s\n", - ts, "EXEC", e->comm, e->pid, e->ppid, e->filename); - } - - return 0; -} - -int main(int argc, char **argv) -{ - struct ring_buffer *rb = NULL; - struct goroutine_bpf *skel; - int err; - - /* Parse command line arguments */ - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); - if (err) - return err; - - /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); - - /* Cleaner handling of Ctrl-C */ - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - - /* Load and verify BPF application */ - skel = goroutine_bpf__open(); - if (!skel) { - fprintf(stderr, "Failed to open and load BPF skeleton\n"); - return 1; - } - - /* Parameterize BPF code with minimum duration parameter */ - skel->rodata->min_duration_ns = env.min_duration_ms * 1000000ULL; - - /* Load & verify BPF programs */ - err = goroutine_bpf__load(skel); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto cleanup; - } - - /* Attach tracepoints */ - err = goroutine_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto cleanup; - } - - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto cleanup; - } - - /* Process events */ - printf("%-8s %-5s %-16s %-7s %-7s %s\n", - "TIME", "EVENT", "COMM", "PID", "PPID", "FILENAME/EXIT CODE"); - while (!exiting) { - err = ring_buffer__poll(rb, 100 /* timeout, ms */); - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; - } - if (err < 0) { - printf("Error polling perf buffer: %d\n", err); - break; - } - } - -cleanup: - /* Clean up */ - ring_buffer__free(rb); - goroutine_bpf__destroy(skel); - - return err < 0 ? -err : 0; -} diff --git a/32-http2/.gitignore b/33-funclatency/.gitignore similarity index 100% rename from 32-http2/.gitignore rename to 33-funclatency/.gitignore diff --git a/32-http2/Makefile b/33-funclatency/Makefile similarity index 95% rename from 32-http2/Makefile rename to 33-funclatency/Makefile index 6b1b0b3..eac2df7 100644 --- a/32-http2/Makefile +++ b/33-funclatency/Makefile @@ -5,7 +5,7 @@ LIBBPF_SRC := $(abspath ../third_party/libbpf/src) BPFTOOL_SRC := $(abspath ../third_party/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) -BPFTOOL ?= $(BPFTOOL_OUTPUT)/funclatency/bpftool +BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool LIBBLAZESYM_SRC := $(abspath ../third_party/blazesym/) LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym.a) LIBBLAZESYM_HEADER := $(abspath $(OUTPUT)/blazesym.h) @@ -24,13 +24,13 @@ INCLUDES := -I$(OUTPUT) -I../third_party/libbpf/include/uapi -I$(dir $(VMLINUX)) CFLAGS := -g -Wall ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) -APPS = funclatency # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall +APPS = funclatency CARGO ?= $(shell which cargo) ifeq ($(strip $(CARGO)),) BZS_APPS := else -BZS_APPS := # profile +BZS_APPS := APPS += $(BZS_APPS) # Required by libblazesym ALL_LDFLAGS += -lrt -ldl -lpthread -lm @@ -91,7 +91,7 @@ $(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPU # Build bpftool $(BPFTOOL): | $(BPFTOOL_OUTPUT) $(call msg,BPFTOOL,$@) - $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) funclatency + $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap $(LIBBLAZESYM_SRC)/target/release/libblazesym.a:: diff --git a/33-funclatency/bits.bpf.h b/33-funclatency/bits.bpf.h new file mode 100644 index 0000000..a2b7bb9 --- /dev/null +++ b/33-funclatency/bits.bpf.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BITS_BPF_H +#define __BITS_BPF_H + +#define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) +#define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = val) + +static __always_inline u64 log2(u32 v) +{ + u32 shift, r; + + r = (v > 0xFFFF) << 4; v >>= r; + shift = (v > 0xFF) << 3; v >>= shift; r |= shift; + shift = (v > 0xF) << 2; v >>= shift; r |= shift; + shift = (v > 0x3) << 1; v >>= shift; r |= shift; + r |= (v >> 1); + + return r; +} + +static __always_inline u64 log2l(u64 v) +{ + u32 hi = v >> 32; + + if (hi) + return log2(hi) + 32; + else + return log2(v); +} + +#endif /* __BITS_BPF_H */ diff --git a/32-http2/funclatency.bpf.c b/33-funclatency/funclatency.bpf.c similarity index 84% rename from 32-http2/funclatency.bpf.c rename to 33-funclatency/funclatency.bpf.c index 5e67572..aed880b 100644 --- a/32-http2/funclatency.bpf.c +++ b/33-funclatency/funclatency.bpf.c @@ -33,13 +33,6 @@ static void entry(void) bpf_map_update_elem(&starts, &pid, &nsec, BPF_ANY); } -SEC("fentry/dummy_fentry") -int BPF_PROG(dummy_fentry) -{ - entry(); - return 0; -} - SEC("kprobe/dummy_kprobe") int BPF_KPROBE(dummy_kprobe) { @@ -76,13 +69,6 @@ static void exit(void) __sync_fetch_and_add(&hist[slot], 1); } -SEC("fexit/dummy_fexit") -int BPF_PROG(dummy_fexit) -{ - exit(); - return 0; -} - SEC("kretprobe/dummy_kretprobe") int BPF_KRETPROBE(dummy_kretprobe) { diff --git a/32-http2/funclatency.c b/33-funclatency/funclatency.c similarity index 88% rename from 32-http2/funclatency.c rename to 33-funclatency/funclatency.c index 2c94e96..961d01a 100644 --- a/32-http2/funclatency.c +++ b/33-funclatency/funclatency.c @@ -22,8 +22,6 @@ #include #include "funclatency.h" #include "funclatency.skel.h" -#include "trace_helpers.h" -#include "uprobe_helpers.h" #define warn(...) fprintf(stderr, __VA_ARGS__) @@ -63,7 +61,7 @@ static const char program_doc[] = " ./funclatency -m do_nanosleep # time do_nanosleep(), in milliseconds\n" " ./funclatency -u vfs_read # time vfs_read(), in microseconds\n" " ./funclatency -p 181 vfs_read # time process 181 only\n" - " ./funclatency -p 181 c:read # time the read() C library function\n" + " ./funclatency -p 181 /usr/lib/x86_64-linux-gnu/libc.so.6:read # time the read() C library function\n" " ./funclatency -p 181 :foo # time foo() from pid 181's userspace\n" " ./funclatency -i 2 -d 10 vfs_read # output every 2 seconds, for 10s\n" " ./funclatency -mTi 5 vfs_read # output every 5 seconds, with timestamps\n"; @@ -223,8 +221,6 @@ static int attach_kprobes(struct funclatency_bpf *obj) static int attach_uprobes(struct funclatency_bpf *obj) { char *binary, *function; - char bin_path[PATH_MAX]; - off_t func_off; int ret = -1; long err; @@ -234,6 +230,7 @@ static int attach_uprobes(struct funclatency_bpf *obj) warn("strdup failed"); return -1; } + printf("tracing %s...\n", binary); function = strchr(binary, ':'); if (!function) { @@ -242,20 +239,15 @@ static int attach_uprobes(struct funclatency_bpf *obj) } *function = '\0'; function++; + printf("tracing func %s in %s...\n", function, binary); - if (resolve_binary_path(binary, env.pid, bin_path, sizeof(bin_path))) - goto out_binary; - - func_off = get_elf_func_offset(bin_path, function); - if (func_off < 0) - { - warn("Could not find %s in %s\n", function, bin_path); - goto out_binary; - } + LIBBPF_OPTS(bpf_uprobe_opts, opts); + opts.func_name = function; + opts.retprobe = false; obj->links.dummy_kprobe = - bpf_program__attach_uprobe(obj->progs.dummy_kprobe, false, - env.pid ?: -1, bin_path, func_off); + bpf_program__attach_uprobe_opts(obj->progs.dummy_kprobe, + env.pid ?: -1, binary, 0, &opts); if (!obj->links.dummy_kprobe) { err = -errno; @@ -263,9 +255,11 @@ static int attach_uprobes(struct funclatency_bpf *obj) goto out_binary; } + opts.retprobe = true; + obj->links.dummy_kretprobe = - bpf_program__attach_uprobe(obj->progs.dummy_kretprobe, true, - env.pid ?: -1, bin_path, func_off); + bpf_program__attach_uprobe_opts(obj->progs.dummy_kretprobe, + env.pid ?: -1, binary, 0, &opts); if (!obj->links.dummy_kretprobe) { err = -errno; @@ -290,6 +284,10 @@ static void sig_hand(int signr) static struct sigaction sigact = {.sa_handler = sig_hand}; +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + static void print_stars(unsigned int val, unsigned int val_max, int width) { int num_stars, num_spaces, i; @@ -362,9 +360,7 @@ int main(int argc, char **argv) struct tm *tm; char ts[32]; time_t t; - int idx, cg_map_fd; int cgfd = -1; - bool used_fentry = false; err = argp_parse(&argp, argc, argv, 0, NULL, &env); if (err) @@ -439,7 +435,6 @@ int main(int argc, char **argv) cleanup: funclatency_bpf__destroy(obj); - cleanup_core_btf(&open_opts); if (cgfd > 0) close(cgfd); diff --git a/32-http2/funclatency.h b/33-funclatency/funclatency.h similarity index 100% rename from 32-http2/funclatency.h rename to 33-funclatency/funclatency.h diff --git a/39-nginx/trace.bt b/39-nginx/trace.bt new file mode 100644 index 0000000..0e34bf5 --- /dev/null +++ b/39-nginx/trace.bt @@ -0,0 +1,49 @@ +#!/usr/sbin/bpftrace + +// Monitor the start of HTTP request processing +uprobe:/usr/sbin/nginx:ngx_http_process_request +{ + printf("HTTP request processing started (tid: %d)\n", tid); + @start[tid] = nsecs; +} + +// Monitor when an HTTP request is finalized +uretprobe:/usr/sbin/nginx:ngx_http_finalize_request +/@start[tid]/ +{ + $elapsed = nsecs - @start[tid]; + printf("HTTP request processed in %d ns (tid: %d)\n", $elapsed, tid); + delete(@start[tid]); +} + +// Monitor the start of sending a request to an upstream server +uprobe:/usr/sbin/nginx:ngx_http_upstream_send_request +{ + printf("Upstream request sending started (tid: %d)\n", tid); + @upstream_start[tid] = nsecs; +} + +// Monitor when the upstream request is sent +uretprobe:/usr/sbin/nginx:ngx_http_upstream_send_request +/@upstream_start[tid]/ +{ + $elapsed = nsecs - @upstream_start[tid]; + printf("Upstream request sent in %d ns (tid: %d)\n", $elapsed, tid); + delete(@upstream_start[tid]); +} + +// Monitor the start of event processing +uprobe:/usr/sbin/nginx:ngx_event_process_posted +{ + printf("Event processing started (tid: %d)\n", tid); + @event_start[tid] = nsecs; +} + +// Monitor when event processing is completed +uretprobe:/usr/sbin/nginx:ngx_event_process_posted +/@event_start[tid]/ +{ + $elapsed = nsecs - @event_start[tid]; + printf("Event processed in %d ns (tid: %d)\n", $elapsed, tid); + delete(@event_start[tid]); +}