|
|
@@ -1,45 +1,6 @@
|
|
|
//
|
|
|
// Created by Carl.Guo on 2024/4/1.
|
|
|
//
|
|
|
-/*
|
|
|
- * l7_request_key { __u64 fd;
|
|
|
- __u32 pid;
|
|
|
-__u16 is_tls;
|
|
|
-__s16 stream_id;
|
|
|
-__u32 id;
|
|
|
-}
|
|
|
-l7_request_key_start { __u64 fd; __u32 pid;} value=id
|
|
|
-l7_request_key_end{ __u64 fd; __u32 pid;} value=id
|
|
|
-
|
|
|
-触发一次就id++,然后把id作为l7_request_key组成的一部分
|
|
|
-
|
|
|
-Redis end事件被触发时,l7_request_key_end的value就++,然后查询l7_request_key id=其新增的值
|
|
|
-if redis start {
|
|
|
-l7_request_key_start { __u64 fd; __u32 pid;} value=id
|
|
|
-
|
|
|
-start count ++
|
|
|
-
|
|
|
-update,l7_request_key
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-if redis end {
|
|
|
-
|
|
|
-从l7_request_key_end中获取当前end总数
|
|
|
-end次数+1,构造l7_request_key,获取信息
|
|
|
-
|
|
|
-// clean current
|
|
|
-clean l7_request_key id=end
|
|
|
-
|
|
|
-获取l7_request_key_start信息,
|
|
|
-// clean global
|
|
|
-if start count=end count{
|
|
|
-
|
|
|
-clean l7_request_key_start && l7_request_key_end
|
|
|
-
|
|
|
-}
|
|
|
- */
|
|
|
-#include "apm_trace.h"
|
|
|
|
|
|
struct {
|
|
|
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
@@ -176,132 +137,6 @@ struct {
|
|
|
__uint(max_entries, 1);
|
|
|
} apm_span_context_heap SEC(".maps");
|
|
|
|
|
|
-
|
|
|
-// ---------- 可调参数 ----------
|
|
|
-#define TTL_MS 3600000ULL // 上下文与边的默认有效期(1小时,毫秒)
|
|
|
-#define LAST_WAKE_WINS 0 // 0: 首次唤醒者胜出;1: 最近一次唤醒者胜出(带锁)
|
|
|
-
|
|
|
-static __always_inline __u64 now_ns(void) { return bpf_ktime_get_ns(); }
|
|
|
-static __always_inline __u64 ms_to_ns(__u64 ms) { return ms * 1000ULL * 1000ULL; }
|
|
|
-
|
|
|
-// ---------- 事件结构(tracepoint payload 的最小子集) ----------
|
|
|
-// /sys/kernel/tracing/events/sched/sched_wakeup/format
|
|
|
-// 注意:tracepoint 数据从 offset 8 开始,前面 8 字节是 common 字段
|
|
|
-struct tp_sched_wakeup {
|
|
|
- char comm[16]; // offset 8-23
|
|
|
- __u32 pid; // offset 24-27 (wakee tid)
|
|
|
- __u32 prio; // offset 28-31
|
|
|
- __u32 target_cpu; // offset 32-35
|
|
|
-};
|
|
|
-
|
|
|
-// /sys/kernel/tracing/events/sched/sched_switch/format
|
|
|
-// 注意:tracepoint 数据从 offset 8 开始,前面 8 字节是 common 字段
|
|
|
-struct tp_sched_switch {
|
|
|
- char prev_comm[16]; // offset 8-23
|
|
|
- __u32 prev_pid; // offset 24-27
|
|
|
- __u32 prev_prio; // offset 28-31
|
|
|
- __s64 prev_state; // offset 32-39
|
|
|
- char next_comm[16]; // offset 40-55
|
|
|
- __u32 next_pid; // offset 56-59 (即将运行的 tid)
|
|
|
- __u32 next_prio; // offset 60-63
|
|
|
-};
|
|
|
-
|
|
|
-// ---------- 业务上下文(thread_ctx) ----------
|
|
|
-//struct thread_ctx_t {
|
|
|
-// __u64 token; // 追踪 token / trace_id(入口处写入)
|
|
|
-// __u64 ts_ns; // 最近一次刷新时间
|
|
|
-// __u64 exp_ns; // 过期时间(now + TTL)
|
|
|
-// __u32 root_thread; // 主线程
|
|
|
-// __u32 tgid; // 所属进程
|
|
|
-// __u32 parent_tid; // 父线程(用于调试/回溯)
|
|
|
-// __u8 is_main_thread;// 主线程
|
|
|
-// __u16 level; // 继承层数
|
|
|
-// struct apm_trace_info_t *trace_info;
|
|
|
-// struct apm_trace_key_t trace_key;
|
|
|
-//};
|
|
|
-
|
|
|
-// ---------- waker→wakee 的“边” ----------
|
|
|
-struct edge_t {
|
|
|
-#if LAST_WAKE_WINS
|
|
|
- struct bpf_spin_lock lock; // 仅在“最近一次”策略下使用
|
|
|
-#endif
|
|
|
- __u64 token; // 继承自 waker 的 token
|
|
|
- __u64 ts_ns; // 唤醒时间戳(用于“最近一次”比较)
|
|
|
- __u64 exp_ns; // 边过期时间(过期后允许重建)
|
|
|
- __u32 parent_tid; // waker tid(父)
|
|
|
-};
|
|
|
-
|
|
|
-// thread_ctx:按 tid 存活的上下文
|
|
|
-struct {
|
|
|
- __uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
- __type(key, __u32); // tid
|
|
|
- __type(value, struct thread_ctx_t);
|
|
|
- __uint(max_entries, 65535);
|
|
|
-} thread_ctx SEC(".maps");
|
|
|
-
|
|
|
-// wake_edge:按 wakee_tid 暂存"边"
|
|
|
-struct {
|
|
|
- __uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
- __type(key, __u32); // wakee tid
|
|
|
- __type(value, struct edge_t);
|
|
|
- __uint(max_entries, 65535);
|
|
|
-} wake_edge SEC(".maps");
|
|
|
-
|
|
|
-// tgid_root_thread:按 tgid 查找 root thread tid
|
|
|
-// 用于在无法通过 sched_wakeup/sched_switch 关联时,回退查找同一进程的 root thread context
|
|
|
-struct {
|
|
|
- __uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
- __type(key, __u32); // tgid
|
|
|
- __type(value, __u32); // root_thread tid
|
|
|
- __uint(max_entries, 1024);
|
|
|
-} tgid_root_thread SEC(".maps");
|
|
|
-
|
|
|
-// ---------- 你的“Server trace start”处应当写入的入口函数示例 ----------
|
|
|
-// 注意:这只是示意(uprobe/uretprobe 里的做法),真正入口请在你的用户函数处调用。
|
|
|
-static __always_inline int set_root_ctx(__u64 t, __u64 pidtgid, struct apm_trace_info_t trace_info) {
|
|
|
- __u32 tid = (__u32) pidtgid;
|
|
|
- __u32 tgid = (__u32) (pidtgid >> 32);
|
|
|
- struct thread_ctx_t r = {};
|
|
|
- r.trace_key = trace_info.trace_key;
|
|
|
- r.token = trace_info.trace_id;
|
|
|
- r.tgid = tgid;
|
|
|
- r.root_thread = tid;
|
|
|
- r.ts_ns = t;
|
|
|
- r.exp_ns = t + 30ULL * 1000 * 1000; // 30ms
|
|
|
- r.parent_tid = 0;
|
|
|
- r.is_main_thread = 1;
|
|
|
- r.level = 1;
|
|
|
- bpf_map_update_elem(&thread_ctx, &tid, &r, BPF_ANY);
|
|
|
- // 保存 tgid -> root_thread 映射,用于回退查找
|
|
|
- bpf_map_update_elem(&tgid_root_thread, &tgid, &tid, BPF_ANY);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-//// 线程上下文结构体
|
|
|
-//struct thread_ctx_t {
|
|
|
-// __u64 token;
|
|
|
-// __u32 parent_tid;
|
|
|
-// __u64 ts_ns;
|
|
|
-// __u64 exp_ns;
|
|
|
-// __u32 tgid;
|
|
|
-//};
|
|
|
-//
|
|
|
-//// 线程上下文映射
|
|
|
-//struct {
|
|
|
-// __uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
-// __uint(key_size, sizeof(__u32));
|
|
|
-// __uint(value_size, sizeof(struct thread_ctx_t));
|
|
|
-// __uint(max_entries, 65536);
|
|
|
-//} thread_ctx SEC(".maps");
|
|
|
-//
|
|
|
-//struct tp_sched_wakeup {
|
|
|
-// __u64 pad; // trace_entry 8字节
|
|
|
-// char comm[16]; // 8..23
|
|
|
-// int pid; // 24..27 ← wakee_tid
|
|
|
-// int prio;
|
|
|
-// int target_cpu;
|
|
|
-//};
|
|
|
-
|
|
|
static __inline __attribute__((__always_inline__))
|
|
|
struct apm_trace_key_t get_apm_trace_key(__u64 timeout, bool is_socket_io) {
|
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
@@ -360,64 +195,6 @@ __u64 get_apm_trace_id(__u32 pid, __u32 tid) {
|
|
|
if (trace_info) {
|
|
|
cw_bpf_debug("info_trace_id:%llu", trace_info->trace_id);
|
|
|
return trace_info->trace_id;
|
|
|
- } else {
|
|
|
- struct thread_ctx_t *current_ctx = bpf_map_lookup_elem(&thread_ctx, &tid);
|
|
|
- if (current_ctx) {
|
|
|
- bpf_printk(" [Redis] has context: %u->%u token=%llu", tid, current_ctx->parent_tid, current_ctx->token);
|
|
|
- bpf_printk(" [Redis] has context: %u->%u token=%llu", tid, current_ctx->root_thread, current_ctx->token);
|
|
|
- bpf_printk(" [Redis] has context: trace_key tid:%d,pid", current_ctx->trace_key.pid);
|
|
|
- // 优先查找 root 线程的最新上下文(可能已被新请求刷新)
|
|
|
- struct thread_ctx_t *has_root_ctx = bpf_map_lookup_elem(&thread_ctx, ¤t_ctx->trace_key.pid);
|
|
|
- if (has_root_ctx && has_root_ctx->exp_ns > bpf_ktime_get_ns()) {
|
|
|
- // root 线程有有效上下文,使用其最新 token(解决跨请求 token 过期问题)
|
|
|
- bpf_printk(" [R0] root active: root_tid=%u token=%llu (child cached=%llu)",
|
|
|
- current_ctx->trace_key.pid, has_root_ctx->token, current_ctx->token);
|
|
|
- return has_root_ctx->token;
|
|
|
- }
|
|
|
- if (!has_root_ctx) {
|
|
|
- bpf_printk("thead is inactive.");
|
|
|
- // root 线程没有 context,回退通过 tgid_root_thread 查找
|
|
|
- bpf_printk(" [R1] tid:%d has NO context, trying fallback: pid=%u (tgid)", tid, pid);
|
|
|
- __u32 *root_tid_ptr = bpf_map_lookup_elem(&tgid_root_thread, &pid);
|
|
|
- if (root_tid_ptr) {
|
|
|
- __u32 root_tid = *root_tid_ptr;
|
|
|
- bpf_printk(" [R2] Found root thread: tgid=%u -> root_tid=%u", pid, root_tid);
|
|
|
- struct thread_ctx_t *root_ctx = bpf_map_lookup_elem(&thread_ctx, &root_tid);
|
|
|
- if (root_ctx && root_ctx->exp_ns > bpf_ktime_get_ns()) {
|
|
|
- bpf_printk(" [R3] Found root context: token=%llu", root_ctx->token);
|
|
|
- return root_ctx->token;
|
|
|
- } else {
|
|
|
- bpf_printk(" [R] Root context not found or expired for root_tid=%u", root_tid);
|
|
|
- }
|
|
|
- } else {
|
|
|
- bpf_printk(" [R4] No root thread mapping found for tgid=%u", pid);
|
|
|
- }
|
|
|
- }
|
|
|
- // root 已过期且回退也找不到,使用子线程缓存的 token
|
|
|
- return current_ctx->token;
|
|
|
- } else {
|
|
|
- // 线程没有 context,尝试回退查找同一进程的 root thread context
|
|
|
- // 这解决了仅依赖 sched_wakeup/sched_switch 无法关联的问题
|
|
|
- bpf_printk(" [R6] tid:%d has NO context, trying fallback: pid=%u (tgid)", tid, pid);
|
|
|
- // 通过 tgid 查找 root thread
|
|
|
- __u32 *root_tid_ptr = bpf_map_lookup_elem(&tgid_root_thread, &pid);
|
|
|
- if (root_tid_ptr) {
|
|
|
- __u32 root_tid = *root_tid_ptr;
|
|
|
- bpf_printk(" [R7] Found root thread: tgid=%u -> root_tid=%u", pid, root_tid);
|
|
|
-
|
|
|
- // 通过 root thread 查找 context
|
|
|
- struct thread_ctx_t *root_ctx = bpf_map_lookup_elem(&thread_ctx, &root_tid);
|
|
|
- if (root_ctx && root_ctx->exp_ns > bpf_ktime_get_ns()) {
|
|
|
- bpf_printk(" [R8] Found root context: token=%llu", root_ctx->token);
|
|
|
- return root_ctx->token;
|
|
|
- } else {
|
|
|
- bpf_printk(" [R9] Root context not found or expired for root_tid=%u", root_tid);
|
|
|
- }
|
|
|
- } else {
|
|
|
- bpf_printk(" [R10] No root thread mapping found for tgid=%u", pid);
|
|
|
- bpf_printk(" [R11] This thread may have been created before trace start or was not captured by sched_wakeup");
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -477,12 +254,12 @@ struct apm_trace_info_t *get_apm_trace_info_v2(struct apm_trace_key_t trace_key,
|
|
|
|
|
|
static __inline __attribute__((__always_inline__))
|
|
|
struct apm_trace_info_t *
|
|
|
-get_apm_trace_info_v3(struct apm_trace_key_t trace_key, __u64 tgid_pid, __u32 tgid, __u32 tid) {
|
|
|
- struct apm_trace_info_t *trace_info = get_apm_trace_info_v2(trace_key, tgid, tid);
|
|
|
+get_apm_trace_info_v3(struct apm_trace_key_t trace_key, __u64 tgid_pid, __u32 tgid, __u32 pid) {
|
|
|
+ struct apm_trace_info_t *trace_info = get_apm_trace_info_v2(trace_key, tgid, pid);
|
|
|
struct goid_trace_key_t key_goid = {.tgid = tgid, .goid = trace_key.goid};
|
|
|
|
|
|
if (trace_info != NULL) {
|
|
|
- trace_info->type = APM_TRACE_INFO_TYPE_FIRST_FOUND;
|
|
|
+ trace_info->type = 1;
|
|
|
// trace_info = get_apm_trace_info_v2(id, pid, tid);
|
|
|
// trace_id = trace_info->trace_id;
|
|
|
trace_info->goid_trace_key = key_goid;
|
|
|
@@ -511,7 +288,7 @@ get_apm_trace_info_v3(struct apm_trace_key_t trace_key, __u64 tgid_pid, __u32 tg
|
|
|
// 将key保存在trace_info用于后续清除
|
|
|
trace_info->goid_trace_key = key_goid;
|
|
|
// Second or multiple times
|
|
|
- trace_info->type = APM_TRACE_INFO_TYPE_REUSE_FOUND;
|
|
|
+ trace_info->type = 2;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -522,23 +299,8 @@ get_apm_trace_info_v3(struct apm_trace_key_t trace_key, __u64 tgid_pid, __u32 tg
|
|
|
trace_info = bpf_map_lookup_elem(&thread_trace_info_heap, &t_key);
|
|
|
if (trace_info != NULL) {
|
|
|
// bpf_printk("ttttttttttttt trace_id:%llu", trace_info->trace_id);
|
|
|
- trace_info->type = APM_TRACE_INFO_TYPE_THREAD_FOUND;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (trace_info == NULL) {
|
|
|
- struct thread_ctx_t *current_ctx = bpf_map_lookup_elem(&thread_ctx, &tid);
|
|
|
- if (current_ctx) {
|
|
|
-// bpf_printk(" [HTTP] has context: %u->%u token=%llu", tid, current_ctx->parent_tid, current_ctx->token);
|
|
|
-// bpf_printk(" [HTTP] has context: %u->%u token=%llu", tid, current_ctx->root_thread, current_ctx->token);
|
|
|
- trace_info = get_apm_trace_info_by_trace_key(current_ctx->trace_key);
|
|
|
- if (trace_info != NULL) {
|
|
|
- trace_info->type = APM_TRACE_INFO_TYPE_CTX_FOUND;
|
|
|
- }
|
|
|
- } else {
|
|
|
- bpf_printk(" [HTTP] tid:%d has NO context", tid);
|
|
|
+ trace_info->type = 3;
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
return trace_info;
|
|
|
}
|
|
|
@@ -612,12 +374,7 @@ struct apm_span_context *cw_get_parent_tracking_span() {
|
|
|
struct apm_span_context *apm_sc = {0};
|
|
|
struct apm_span_context *span_contexts = bpf_map_lookup_elem(&apm_parent_span_context_map, &trace_key);
|
|
|
// bpf_printk("-------");
|
|
|
- if (!span_contexts) {
|
|
|
- struct thread_ctx_t *current_ctx = bpf_map_lookup_elem(&thread_ctx, &trace_key.pid);
|
|
|
- if (current_ctx) {
|
|
|
- span_contexts = bpf_map_lookup_elem(&apm_parent_span_context_map, ¤t_ctx->trace_key);
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
if (span_contexts) {
|
|
|
/*for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
|
|
|
bpf_printk("type_from[%d] = %02x", i, span_contexts->type_from[i]);
|
|
|
@@ -681,8 +438,7 @@ __u64 clear_current_span_context() {
|
|
|
}
|
|
|
|
|
|
static __inline __attribute__((__always_inline__))
|
|
|
-__u64 cw_clear_trace(__u32 tgid, __u32 tid, __u32 fd) {
|
|
|
-
|
|
|
+__u64 cw_clear_trace(__u32 tgid, __u32 pid, __u32 fd) {
|
|
|
struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
|
|
|
struct fd_trace_key_t fd_trace_key = get_fd_trace_key(tgid, fd);
|
|
|
// 清除 trace_info_heap
|
|
|
@@ -697,14 +453,6 @@ __u64 cw_clear_trace(__u32 tgid, __u32 tid, __u32 fd) {
|
|
|
bpf_map_delete_elem(&trace_info_heap, &trace_key);
|
|
|
bpf_map_delete_elem(&fd_trace_info_heap, &fd_trace_key);
|
|
|
bpf_map_delete_elem(&apm_parent_span_context_map, &trace_key);
|
|
|
-
|
|
|
- // 清理 tgid_root_thread:trace end 一定在 root thread 中执行
|
|
|
- // 直接删除映射即可,因为 trace start 和 trace end 都在同一个线程
|
|
|
- bpf_map_delete_elem(&tgid_root_thread, &tgid);
|
|
|
- // 最后删除 thread_ctx
|
|
|
- bpf_map_delete_elem(&thread_ctx, &tid);
|
|
|
- bpf_printk("clean trace %d",tid);
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -712,14 +460,13 @@ __u64 cw_clear_trace(__u32 tgid, __u32 tid, __u32 fd) {
|
|
|
static __inline __attribute__((__always_inline__))
|
|
|
void cw_save_current_tracking_span(struct apm_span_context *sc) {
|
|
|
struct apm_trace_key_t trace_key = get_apm_trace_key(120 * NS_PER_SEC, true);
|
|
|
- bpf_printk(" [build header] [save cw sc] tid:(%d)",trace_key.pid);
|
|
|
+// bpf_printk("[save cw sc]%d",trace_key.goid);
|
|
|
bpf_map_update_elem(&apm_current_span_context_map, &trace_key, sc, BPF_ANY);
|
|
|
}
|
|
|
|
|
|
|
|
|
static __inline __attribute__((__always_inline__))
|
|
|
-struct apm_span_context *
|
|
|
-cw_get_current_tracking_span(struct apm_trace_info_t *trace_info, struct apm_trace_key_t origin_trace_key) {
|
|
|
+struct apm_span_context *cw_get_current_tracking_span(struct apm_trace_info_t *trace_info) {
|
|
|
struct apm_trace_key_t trace_key = {0};
|
|
|
if (trace_info){
|
|
|
trace_key = trace_info->trace_key;
|
|
|
@@ -735,16 +482,10 @@ cw_get_current_tracking_span(struct apm_trace_info_t *trace_info, struct apm_tra
|
|
|
if (trace_info->routine_reuse == true) {
|
|
|
// bpf_printk("[get cw sc bbb] :%llu", trace_info->trace_key.goid);
|
|
|
struct apm_trace_key_t ancestor_trace_key = trace_info->trace_key;
|
|
|
- trace_key = ancestor_trace_key;
|
|
|
span_contexts = bpf_map_lookup_elem(&apm_current_span_context_map, &ancestor_trace_key);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!span_contexts) {
|
|
|
- trace_key = origin_trace_key;
|
|
|
- span_contexts = bpf_map_lookup_elem(&apm_current_span_context_map, &origin_trace_key);
|
|
|
- }
|
|
|
-
|
|
|
if (span_contexts) {
|
|
|
/*for (int i = 0; i < APM_TYPE_FROM_SIZE; i++) {
|
|
|
bpf_printk("cw_get_current_tracking_span-type_from[%d] = %02x", i, span_contexts->type_from[i]);
|
|
|
@@ -771,7 +512,6 @@ cw_get_current_tracking_span(struct apm_trace_info_t *trace_info, struct apm_tra
|
|
|
bpf_printk("cw_get_current_tracking_span-span_id[%d] = %02x", i, span_contexts->span_id[i]);
|
|
|
}*/
|
|
|
apm_sc = span_contexts;
|
|
|
- bpf_map_delete_elem(&apm_current_span_context_map, &trace_key);
|
|
|
}
|
|
|
// bpf_printk("-------end");
|
|
|
|
|
|
@@ -865,7 +605,7 @@ struct apm_trace_info_t cw_save_trace_info(__u64 id, __u32 pid, __u64 fd) {
|
|
|
bpf_map_update_elem(&trace_info_heap, &trace_info.trace_key, &trace_info, BPF_NOEXIST);
|
|
|
bpf_map_update_elem(&fd_trace_info_heap, &trace_info.fd_trace_key, &trace_info, BPF_NOEXIST);
|
|
|
bpf_map_update_elem(&thread_trace_info_heap, &trace_info.thread_trace_key, &trace_info, BPF_NOEXIST);
|
|
|
- set_root_ctx(uid_base, id, trace_info);
|
|
|
+
|
|
|
|
|
|
// struct goid_trace_key_t key = {.tgid = id, .goid = get_current_goroutine()};
|
|
|
// bpf_map_update_elem(&goid_trace_info_heap, &key, &trace_info, BPF_NOEXIST);
|