diff --git a/.github/workflows/ebpf_cpu_watcher.yml b/.github/workflows/ebpf_cpu_watcher.yml index 93dbf8441..41364689f 100644 --- a/.github/workflows/ebpf_cpu_watcher.yml +++ b/.github/workflows/ebpf_cpu_watcher.yml @@ -31,3 +31,10 @@ jobs: cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher/ make sudo ./cpu_watcher + + - name: Run test_cpuwatcher + + run: | + cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test + make + ./test_cpuwatcher diff --git a/.github/workflows/ebpf_net_watcher.yml b/.github/workflows/ebpf_net_watcher.yml index 025578510..efce13059 100644 --- a/.github/workflows/ebpf_net_watcher.yml +++ b/.github/workflows/ebpf_net_watcher.yml @@ -46,4 +46,6 @@ jobs: sudo timeout -s SIGINT 5 ./netwatcher -k -T || if [[ $? != 124 && $? != 0 ]];then exit $?;fi sudo timeout -s SIGINT 5 ./netwatcher -I || if [[ $? != 124 && $? != 0 ]];then exit $?;fi sudo timeout -s SIGINT 5 ./netwatcher -S || if [[ $? != 124 && $? != 0 ]];then exit $?;fi + sudo timeout -s SIGINT 5 ./netwatcher -D || if [[ $? != 124 && $? != 0 ]];then exit $?;fi + sudo timeout -s SIGINT 5 ./netwatcher -M || if [[ $? != 124 && $? != 0 ]];then exit $?;fi timeout-minutes: 5 diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile index 8d20c7c63..bcc7c1236 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile @@ -44,6 +44,7 @@ ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) APPS =cs_delay sar sc_delay preempt schedule_delay mq_delay TARGETS=cpu_watcher +CONTROLLER := controller SRC_DIR = ./include @@ -81,12 +82,12 @@ $(call allow-override,CC,$(CROSS_COMPILE)cc) $(call allow-override,LD,$(CROSS_COMPILE)ld) .PHONY: all -all: $(TARGETS) +all: $(CONTROLLER) $(TARGETS) .PHONY: clean clean: $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) $(TARGETS) + $(Q)rm -rf $(OUTPUT) $(TARGETS) $(CONTROLLER) $(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): $(call msg,MKDIR,$@) @@ -132,11 +133,19 @@ $(OUTPUT)/%.o: $(SRC_DIR)/%.c | $(OUTPUT) $(call msg,CC,$@) $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ +$(OUTPUT)/%.o: $(CONTROLLER).c | $(OUTPUT) + $(call msg,CC,$@) + $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + $(OUTPUT)/$(TARGETS).o: $(TARGETS).c $(APPS) | $(OUTPUT) $(call msg,CC,$@) $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ # Build application binary +$(CONTROLLER): %: $(OUTPUT)/%.o $(COMMON_OBJ) $(LIBBPF_OBJ) | $(OUTPUT) + $(call msg,BINARY,$@) + $(Q)$(CC) $^ $(ALL_LDFLAGS) -lstdc++ -lelf -lz -o $@ + $(TARGETS): %: $(OUTPUT)/%.o $(COMMON_OBJ) $(LIBBPF_OBJ) | $(OUTPUT) $(call msg,BINARY,$@) $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lstdc++ -lelf -lz -o $@ diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/cs_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/cs_delay.bpf.c index 3434d6a8a..caaf8c408 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/cs_delay.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/cs_delay.bpf.c @@ -21,17 +21,28 @@ #include "cpu_watcher.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; - +const int ctrl_key = 0; //记录时间戳; BPF_ARRAY(start,int,u64,1); +BPF_ARRAY(cs_ctrl_map,int,struct cs_ctrl,1); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); +static inline struct cs_ctrl *get_cs_ctrl(void) { + struct cs_ctrl *cs_ctrl; + cs_ctrl = bpf_map_lookup_elem(&cs_ctrl_map, &ctrl_key); + if (!cs_ctrl || !cs_ctrl->cs_func) { + return NULL; + } + return cs_ctrl; +} + SEC("kprobe/schedule") int BPF_KPROBE(schedule) { + struct cs_ctrl *cs_ctrl = get_cs_ctrl(); u64 t1; t1 = bpf_ktime_get_ns()/1000; int key =0; @@ -42,6 +53,7 @@ int BPF_KPROBE(schedule) SEC("kretprobe/schedule") int BPF_KRETPROBE(schedule_exit) { + struct cs_ctrl *cs_ctrl = get_cs_ctrl(); u64 t2 = bpf_ktime_get_ns()/1000; u64 t1,delay; int key = 0; diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mq_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mq_delay.bpf.c index becb4c27c..3aa9dd92e 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mq_delay.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mq_delay.bpf.c @@ -23,15 +23,26 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; - +const int ctrl_key = 0; BPF_HASH(send_msg1,pid_t,struct send_events,1024);//记录pid->u_msg_ptr的关系;do_mq_timedsend入参 BPF_HASH(send_msg2,u64,struct send_events,1024);//记录msg->time的关系; BPF_HASH(rcv_msg1,pid_t,struct rcv_events,1024);//记录pid->u_msg_ptr的关系;do_mq_timedsend入参 +BPF_ARRAY(mq_ctrl_map,int,struct mq_ctrl,1); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); +static inline struct mq_ctrl *get_mq_ctrl(void) { + struct mq_ctrl *mq_ctrl; + mq_ctrl = bpf_map_lookup_elem(&mq_ctrl_map, &ctrl_key); + if (!mq_ctrl || !mq_ctrl->mq_func) { + return NULL; + } + return mq_ctrl; +} + + // int print_send_info(struct send_events * mq_send_info,int flag){ // bpf_printk("---------------------test----------------------------test--------------------------test--------------------------------------------test---------------------test---------------------test\n"); // bpf_printk("send_msg_prio: %-8lu\n",mq_send_info->msg_prio); @@ -63,6 +74,7 @@ int BPF_KPROBE(mq_timedsend,mqd_t mqdes, const char *u_msg_ptr, size_t msg_len, unsigned int msg_prio, struct timespec64 *ts) { + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); u64 send_enter_time = bpf_ktime_get_ns();//开始发送信息时间; int pid = bpf_get_current_pid_tgid();//发送端pid @@ -82,6 +94,7 @@ int BPF_KPROBE(mq_timedsend,mqd_t mqdes, const char *u_msg_ptr, /*仅获取mq_send_info -> src*/ SEC("kprobe/load_msg") int BPF_KPROBE(load_msg_enter,const void *src, size_t len){ + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); int pid = bpf_get_current_pid_tgid();//发送端pid /*记录load入参src*/ struct send_events *mq_send_info = bpf_map_lookup_elem(&send_msg1, &pid); @@ -96,6 +109,7 @@ int BPF_KPROBE(load_msg_enter,const void *src, size_t len){ /*获取消息块作为key,并建立 message -> mq_send_info 的哈希表*/ SEC("kretprobe/load_msg") int BPF_KRETPROBE(load_msg_exit,void *ret){ + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); int pid = bpf_get_current_pid_tgid();//发送端pid /*构建消息块结构体,作为key*/ struct send_events *mq_send_info = bpf_map_lookup_elem(&send_msg1, &pid); @@ -121,6 +135,7 @@ int BPF_KRETPROBE(load_msg_exit,void *ret){ SEC("kretprobe/do_mq_timedsend") int BPF_KRETPROBE(do_mq_timedsend_exit,void *ret) { + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); bpf_printk("do_mq_timedsend_exit----------------------------------------------------------------\n"); u64 send_exit_time = bpf_ktime_get_ns();//开始发送信息时间; int pid = bpf_get_current_pid_tgid();//发送端pid @@ -148,6 +163,7 @@ int BPF_KPROBE(mq_timedreceive_entry,mqd_t mqdes, const char __user *u_msg_ptr, size_t msg_len, unsigned int msg_prio, struct timespec64 *ts) { + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); u64 rcv_enter_time = bpf_ktime_get_ns(); int pid = bpf_get_current_pid_tgid(); @@ -165,6 +181,7 @@ int BPF_KPROBE(mq_timedreceive_entry,mqd_t mqdes, const char __user *u_msg_ptr, SEC("kprobe/store_msg") int BPF_KPROBE(store_msg,void __user *dest, struct msg_msg *msg, size_t len) { + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); int pid = bpf_get_current_pid_tgid(); /*make key*/ @@ -192,6 +209,7 @@ int BPF_KPROBE(store_msg,void __user *dest, struct msg_msg *msg, size_t len) SEC("kretprobe/do_mq_timedreceive") int BPF_KRETPROBE(do_mq_timedreceive_exit,void *ret){ + struct mq_ctrl *mq_ctrl = get_mq_ctrl(); u64 rcv_exit_time = bpf_ktime_get_ns(); int pid = bpf_get_current_pid_tgid(); u64 send_enter_time,delay; diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/preempt.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/preempt.bpf.c index 57043e3bb..bf650a6e0 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/preempt.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/preempt.bpf.c @@ -23,17 +23,27 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; #define TIF_NEED_RESCHED 3 - +const int ctrl_key = 0; // 记录时间戳 BPF_HASH(preemptTime, pid_t, u64, 4096); - +BPF_ARRAY(preempt_ctrl_map,int,struct preempt_ctrl,1); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); +static inline struct preempt_ctrl *get_preempt_ctrl(void) { + struct preempt_ctrl *preempt_ctrl; + preempt_ctrl = bpf_map_lookup_elem(&preempt_ctrl_map, &ctrl_key); + if (!preempt_ctrl || !preempt_ctrl->preempt_func) { + return NULL; + } + return preempt_ctrl; +} + SEC("tp_btf/sched_switch") int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { + struct preempt_ctrl *preempt_ctrl = get_preempt_ctrl(); u64 start_time = bpf_ktime_get_ns(); pid_t prev_pid = BPF_CORE_READ(prev, pid); @@ -52,6 +62,7 @@ int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_s // SEC("kprobe/finish_task_switch") SEC("kprobe/finish_task_switch.isra.0") int BPF_KPROBE(finish_task_switch, struct task_struct *prev) { + struct preempt_ctrl *preempt_ctrl = get_preempt_ctrl(); u64 end_time = bpf_ktime_get_ns(); pid_t pid = BPF_CORE_READ(prev, pid); u64 *val; diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sar.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sar.bpf.c index 2fe6b43f5..eb4012def 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sar.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sar.bpf.c @@ -23,7 +23,7 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; const volatile long long unsigned int forks_addr = 0; - +const int ctrl_key = 0; #define PF_IDLE 0x00000002 /* I am an IDLE thread */ #define PF_KTHREAD 0x00200000 /* I am a kernel thread */ @@ -51,11 +51,23 @@ BPF_ARRAY(kt_LastTime,u32,u64,1); BPF_ARRAY(ut_LastTime,u32,u64,1); BPF_ARRAY(tick_user,u32,u64,1); BPF_ARRAY(symAddr,u32,u64,1); +BPF_ARRAY(sar_ctrl_map,int,struct sar_ctrl,1); + +static inline struct sar_ctrl *get_sar_ctrl(void) { + struct sar_ctrl *sar_ctrl; + sar_ctrl = bpf_map_lookup_elem(&sar_ctrl_map, &ctrl_key); + if (!sar_ctrl || !sar_ctrl->sar_func) { + return NULL; + } + return sar_ctrl; +} + // 统计fork数 SEC("kprobe/finish_task_switch.isra.0") // SEC("kprobe/finish_task_switch") int kprobe__finish_task_switch(struct pt_regs *ctx) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = 0; u64 val, *valp = NULL; unsigned long total_forks; @@ -73,6 +85,7 @@ int kprobe__finish_task_switch(struct pt_regs *ctx) //获取进程切换数; SEC("tracepoint/sched/sched_switch") int trace_sched_switch2(struct cswch_args *info) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); pid_t prev = info->prev_pid, next = info->next_pid; if (prev != next) { u32 key = 0; @@ -94,6 +107,7 @@ int trace_sched_switch2(struct cswch_args *info) { // SEC("kprobe/finish_task_switch") SEC("kprobe/finish_task_switch.isra.0") int BPF_KPROBE(finish_task_switch,struct task_struct *prev){ + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); pid_t pid=BPF_CORE_READ(prev,pid); u64 *val, time = bpf_ktime_get_ns(); u64 delta; @@ -124,6 +138,7 @@ int BPF_KPROBE(finish_task_switch,struct task_struct *prev){ //统计运行队列长度 SEC("kprobe/update_rq_clock") int BPF_KPROBE(update_rq_clock,struct rq *rq){ + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = 0; u64 val = BPF_CORE_READ(rq,nr_running); bpf_map_update_elem(&runqlen,&key,&val,BPF_ANY); @@ -133,6 +148,7 @@ int BPF_KPROBE(update_rq_clock,struct rq *rq){ //软中断 SEC("tracepoint/irq/softirq_entry") int trace_softirq_entry(struct __softirq_info *info) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = info->vec; u64 val = bpf_ktime_get_ns(); bpf_map_update_elem(&softirqCpuEnterTime, &key, &val, BPF_ANY); @@ -141,6 +157,7 @@ int trace_softirq_entry(struct __softirq_info *info) { SEC("tracepoint/irq/softirq_exit") int trace_softirq_exit(struct __softirq_info *info) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = info->vec; u64 now = bpf_ktime_get_ns(), *valp = 0; valp =bpf_map_lookup_elem(&softirqCpuEnterTime, &key); @@ -159,6 +176,7 @@ int trace_softirq_exit(struct __softirq_info *info) { 注意这是所有CPU时间的叠加,平均到每个CPU应该除以CPU个数。*/ SEC("tracepoint/irq/irq_handler_entry") int trace_irq_handler_entry(struct __irq_info *info) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = info->irq; u64 ts = bpf_ktime_get_ns(); bpf_map_update_elem(&irq_cpu_enter_start, &key, &ts, BPF_ANY); @@ -167,6 +185,7 @@ int trace_irq_handler_entry(struct __irq_info *info) { SEC("tracepoint/irq/irq_handler_exit") int trace_irq_handler_exit(struct __irq_info *info) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u32 key = info->irq; u64 now = bpf_ktime_get_ns(), *ts = 0; ts = bpf_map_lookup_elem(&irq_cpu_enter_start, &key); @@ -186,6 +205,7 @@ int trace_irq_handler_exit(struct __irq_info *info) { //tracepoint:power_cpu_idle 表征了CPU进入IDLE的状态,比较准确 SEC("tracepoint/power/cpu_idle") int trace_cpu_idle(struct idleStruct *pIDLE) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); u64 delta, time = bpf_ktime_get_ns(); u32 key = pIDLE->cpu_id; if (pIDLE->state == -1) { @@ -215,6 +235,7 @@ static __always_inline int user_mode(struct pt_regs *regs) // 两个CPU各自会产生一个调用,这正好方便我们使用 SEC("perf_event") int tick_update(struct pt_regs *ctx) { + struct sar_ctrl *sar_ctrl = get_sar_ctrl(); // bpf_trace_printk("cs_rpl = %x\n", ctx->cs & 3); u32 key = 0; diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sc_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sc_delay.bpf.c index 23eaf2200..ee224283a 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sc_delay.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/sc_delay.bpf.c @@ -15,27 +15,38 @@ // author: albert_xuu@163.com zhangxy1016304@163.com zhangziheng0525@163.com #include "vmlinux.h" -#include //包含了BPF 辅助函数 +#include #include #include "cpu_watcher.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; -// 定义数组映射 -//BPF_PERCPU_HASH(SyscallEnterTime,pid_t,struct syscall_flags,512);//记录时间戳 -BPF_PERCPU_HASH(SyscallEnterTime,pid_t,u64,512);//记录时间戳 + +const int ctrl_key = 0; +BPF_PERCPU_HASH(SyscallEnterTime,pid_t,u64,512); BPF_PERCPU_HASH(Events,pid_t,u64,10); +BPF_ARRAY(sc_ctrl_map,int,struct sc_ctrl,1); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps");//环形缓冲区; +static inline struct sc_ctrl *get_sc_ctrl(void) { + struct sc_ctrl *sc_ctrl; + sc_ctrl = bpf_map_lookup_elem(&sc_ctrl_map, &ctrl_key); + if (!sc_ctrl || !sc_ctrl->sc_func) { + return NULL; + } + return sc_ctrl; +} + -SEC("tracepoint/raw_syscalls/sys_enter")//进入系统调用 +SEC("tracepoint/raw_syscalls/sys_enter") int tracepoint__syscalls__sys_enter(struct trace_event_raw_sys_enter *args){ - u64 start_time = bpf_ktime_get_ns()/1000;//ms - pid_t pid = bpf_get_current_pid_tgid();//获取到当前进程的pid + struct sc_ctrl *sc_ctrl = get_sc_ctrl(); + u64 start_time = bpf_ktime_get_ns()/1000; + pid_t pid = bpf_get_current_pid_tgid(); u64 syscall_id = (u64)args->id; //bpf_printk("ID:%ld\n",syscall_id); @@ -44,13 +55,13 @@ int tracepoint__syscalls__sys_enter(struct trace_event_raw_sys_enter *args){ return 0; } -SEC("tracepoint/raw_syscalls/sys_exit")//退出系统调用 +SEC("tracepoint/raw_syscalls/sys_exit") int tracepoint__syscalls__sys_exit(struct trace_event_raw_sys_exit *args){ - u64 exit_time = bpf_ktime_get_ns()/1000;//ms - pid_t pid = bpf_get_current_pid_tgid() ;//获取到当前进程的pid + struct sc_ctrl *sc_ctrl = get_sc_ctrl(); + u64 exit_time = bpf_ktime_get_ns()/1000; + pid_t pid = bpf_get_current_pid_tgid() ; u64 syscall_id; u64 start_time, delay; - u64 *val = bpf_map_lookup_elem(&SyscallEnterTime, &pid); if(val !=0){ start_time = *val; @@ -59,7 +70,6 @@ int tracepoint__syscalls__sys_exit(struct trace_event_raw_sys_exit *args){ }else{ return 0; } - u64 *val2 = bpf_map_lookup_elem(&Events, &pid); if(val2 !=0){ syscall_id = *val2; @@ -67,19 +77,13 @@ int tracepoint__syscalls__sys_exit(struct trace_event_raw_sys_exit *args){ }else{ return 0; } - - struct syscall_events *e; e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); if (!e) return 0; - e->pid = pid; e->delay = delay; bpf_get_current_comm(&e->comm, sizeof(e->comm)); e->syscall_id = syscall_id; - bpf_ringbuf_submit(e, 0); - - return 0; } diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/schedule_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/schedule_delay.bpf.c index a51e52459..db1b2a363 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/schedule_delay.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/schedule_delay.bpf.c @@ -23,14 +23,27 @@ char LICENSE[] SEC("license") = "Dual BSD/GPL"; #define TASK_RUNNING 0x0000 -BPF_HASH(has_scheduled,struct proc_id, bool, 10240); -BPF_HASH(enter_schedule,struct proc_id, struct schedule_event, 10240); -BPF_ARRAY(sys_schedule,int,struct sum_schedule,1); +const int ctrl_key = 0; +BPF_HASH(has_scheduled,struct proc_id, bool, 10240);//记录该进程是否调度过 +BPF_HASH(enter_schedule,struct proc_id, struct schedule_event, 10240);//记录该进程上运行队列的时间 +BPF_ARRAY(sys_schedule,int,struct sum_schedule,1);//记录整个系统的调度延迟 +BPF_ARRAY(threshold_schedule,int,struct proc_schedule,10240);//记录每个进程的调度延迟 +BPF_HASH(proc_histories,struct proc_id, struct proc_history, 10240);//记录每个进程运行前的两个进程 +BPF_ARRAY(schedule_ctrl_map,int,struct schedule_ctrl,1); +static inline struct schedule_ctrl *get_schedule_ctrl(void) { + struct schedule_ctrl *sched_ctrl; + sched_ctrl = bpf_map_lookup_elem(&schedule_ctrl_map, &ctrl_key); + if (!sched_ctrl || !sched_ctrl->schedule_func) { + return NULL; + } + return sched_ctrl; +}//查找控制结构体 SEC("tp_btf/sched_wakeup") int BPF_PROG(sched_wakeup, struct task_struct *p) { - pid_t pid = BPF_CORE_READ(p, pid); + struct schedule_ctrl *sched_ctrl = get_schedule_ctrl(); + pid_t pid = p->pid; int cpu = bpf_get_smp_processor_id(); struct schedule_event *schedule_event; struct proc_id id= {}; @@ -56,7 +69,11 @@ int BPF_PROG(sched_wakeup, struct task_struct *p) { SEC("tp_btf/sched_wakeup_new") int BPF_PROG(sched_wakeup_new, struct task_struct *p) { - pid_t pid = BPF_CORE_READ(p, pid); + struct schedule_ctrl *sched_ctrl = get_schedule_ctrl(); + sched_ctrl = bpf_map_lookup_elem(&schedule_ctrl_map,&ctrl_key); + if(!sched_ctrl || !sched_ctrl->schedule_func) + return 0; + pid_t pid = p->pid; int cpu = bpf_get_smp_processor_id(); struct proc_id id= {}; u64 current_time = bpf_ktime_get_ns(); @@ -76,6 +93,9 @@ int BPF_PROG(sched_wakeup_new, struct task_struct *p) { SEC("tp_btf/sched_switch") int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { + struct schedule_ctrl *sched_ctrl = get_schedule_ctrl(); + struct proc_history *history; + struct proc_history new_history; u64 current_time = bpf_ktime_get_ns(); pid_t prev_pid = prev->pid; unsigned int prev_state = prev->__state; @@ -86,17 +106,17 @@ int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_s struct schedule_event *schedule_event; struct sum_schedule *sum_schedule; int key = 0; - struct proc_id next_id= {}; + struct proc_id next_id = {}; u64 delay; if (prev_state == TASK_RUNNING) { - struct proc_id prev_pd= {}; + struct proc_id prev_pd = {}; prev_pd.pid = prev_pid; if (prev_pid == 0) { prev_pd.cpu_id = prev_cpu; - } + } schedule_event = bpf_map_lookup_elem(&enter_schedule, &prev_pd); if (!schedule_event) { - struct schedule_event schedule_event2 ; + struct schedule_event schedule_event2; bool issched = false; schedule_event2.pid = prev_pid; schedule_event2.count = 1; @@ -113,50 +133,71 @@ int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_s next_id.cpu_id = next_cpu; } schedule_event = bpf_map_lookup_elem(&enter_schedule, &next_id); - if (!schedule_event) return 0; + if (!schedule_event) return 0; issched = bpf_map_lookup_elem(&has_scheduled, &next_id); - if (!issched) return 0; + if (!issched) return 0; if (*issched) { schedule_event->count++; } else { *issched = true; - } + } delay = current_time - schedule_event->enter_time; + struct proc_schedule proc_schedule; + proc_schedule.delay = delay; + proc_schedule.id= next_id; + bpf_probe_read_kernel_str(&proc_schedule.proc_name, sizeof(proc_schedule.proc_name), next->comm); + bpf_map_update_elem(&threshold_schedule, &key, &proc_schedule, BPF_ANY); sum_schedule = bpf_map_lookup_elem(&sys_schedule, &key); if (!sum_schedule) { - struct sum_schedule sum_schedule= {}; + struct sum_schedule sum_schedule = {}; sum_schedule.sum_count++; sum_schedule.sum_delay += delay; - if (delay > sum_schedule.max_delay){ + if (delay > sum_schedule.max_delay) { sum_schedule.max_delay = delay; - if(next->pid!=0){ - sum_schedule.pid_max = next->pid; + if (next->pid != 0) { + bpf_probe_read_kernel_str(&sum_schedule.proc_name_max, sizeof(sum_schedule.proc_name_max), next->comm); } - }else if (sum_schedule.min_delay == 0 || delay < sum_schedule.min_delay) + } else if (sum_schedule.min_delay == 0 || delay < sum_schedule.min_delay) { sum_schedule.min_delay = delay; - if(next->pid!=0){ - sum_schedule.pid_min = next->pid; + if (next->pid != 0) { + bpf_probe_read_kernel_str(&sum_schedule.proc_name_min, sizeof(sum_schedule.proc_name_min), next->comm); } + } bpf_map_update_elem(&sys_schedule, &key, &sum_schedule, BPF_ANY); } else { sum_schedule->sum_count++; sum_schedule->sum_delay += delay; - if (delay > sum_schedule->max_delay){ + if (delay > sum_schedule->max_delay) { sum_schedule->max_delay = delay; - if(next->pid!=0){ - sum_schedule->pid_max = next->pid; - } - }else if (sum_schedule->min_delay == 0 || delay < sum_schedule->min_delay) + bpf_probe_read_kernel_str(&sum_schedule->proc_name_max, sizeof(sum_schedule->proc_name_max), next->comm); + } else if (sum_schedule->min_delay == 0 || delay < sum_schedule->min_delay) { sum_schedule->min_delay = delay; - if(next->pid!=0){ - sum_schedule->pid_min = next->pid; + if (next->pid != 0) { + bpf_probe_read_kernel_str(&sum_schedule->proc_name_min, sizeof(sum_schedule->proc_name_min), next->comm); } + } + } + history = bpf_map_lookup_elem(&proc_histories, &next_id); + if (history) { + // 如果找到了,更新历史记录 + new_history.last[0] = history->last[1]; + new_history.last[1].pid = prev->pid; + bpf_probe_read_kernel_str(&new_history.last[1].comm, sizeof(new_history.last[1].comm), prev->comm); + bpf_map_update_elem(&proc_histories, &next_id, &new_history, BPF_ANY); + } else { + // 如果没有找到,初始化新的历史记录 + new_history.last[0].pid = 0; // 初始化为0,表示没有历史信息 + new_history.last[0].comm[0] = '\0'; + new_history.last[1].pid = prev->pid; + bpf_probe_read_kernel_str(&new_history.last[1].comm, sizeof(new_history.last[1].comm), prev->comm); + bpf_map_update_elem(&proc_histories, &next_id, &new_history, BPF_ANY); } return 0; } SEC("tracepoint/sched/sched_process_exit") int sched_process_exit(void *ctx) { + struct schedule_ctrl *sched_ctrl = get_schedule_ctrl(); struct task_struct *p = (struct task_struct *)bpf_get_current_task(); pid_t pid = BPF_CORE_READ(p, pid); int cpu = bpf_get_smp_processor_id(); @@ -175,4 +216,4 @@ int sched_process_exit(void *ctx) { bpf_map_delete_elem(&has_scheduled, &id); } return 0; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/controller.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/controller.c new file mode 100644 index 000000000..7c8cde155 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/controller.c @@ -0,0 +1,245 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: albert_xuu@163.com zhangxy1016304@163.com zhangziheng0525@163.com +// +// used to control the execution of proc_image tool +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpu_watcher_helper.h" + +static struct env { + // 1代表activate;2代表unactivate;3代表finish + int usemode; + bool SAR; + bool percent; + bool CS_DELAY; + bool SYSCALL_DELAY; + bool MIN_US_SET; + int MIN_US; + bool PREEMPT; + bool SCHEDULE_DELAY; + bool MQ_DELAY; + int freq; +} env = { + .usemode = 0, + .SAR = false, + .percent = false, + .CS_DELAY = false, + .SYSCALL_DELAY = false, + .MIN_US_SET = false, + .MIN_US = 10000, + .PREEMPT = false, + .SCHEDULE_DELAY = false, + .MQ_DELAY = false, + .freq = 99, +}; + +const char argp_program_doc[] ="Trace process to get cpu watcher.\n"; + +static const struct argp_option opts[] = { + { "activate", 'a', NULL, 0, "Set startup policy of proc_image tool" }, + { "unactivate", 'u', NULL, 0, "Initialize to the original unactivated state" }, + { "finish", 'f', NULL, 0, "Finish to run eBPF tool" }, + {"libbpf_sar", 's', 0, 0, "Print sar_info (the data of cpu)" }, + {"percent", 'P', 0, 0, "Format data as percentages" }, + {"cs_delay", 'c', 0, 0, "Print cs_delay (the data of cpu)" }, + {"syscall_delay", 'S', 0, 0, "Print syscall_delay (the data of syscall)" }, + {"preempt_time", 'p', 0, 0, "Print preempt_time (the data of preempt_schedule)" }, + {"schedule_delay", 'd', 0, 0, "Print schedule_delay (the data of cpu)" }, + {"schedule_delay_min_us_set", 'e', "THRESHOLD", 0, "Print scheduling delays that exceed the threshold (the data of cpu)" }, + {"mq_delay", 'm', 0, 0, "Print mq_delay(the data of proc)" }, + { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, + {}, +}; + +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'a': + env.usemode = 1; + break; + case 'u': + env.usemode = 2; + break; + case 'f': + env.usemode = 3; + break; + case 's': + env.SAR = true; + break; + case 'P': + env.percent = true; + case 'c': + env.CS_DELAY = true; + break; + case 'S': + env.SYSCALL_DELAY = true; + break; + case 'p': + env.PREEMPT = true; + break; + case 'd': + env.SCHEDULE_DELAY = true; + break; + case 'e': + env.MIN_US_SET = true; + if (arg) { + env.MIN_US = strtol(arg, NULL, 10); + if (env.MIN_US <= 0) { + fprintf(stderr, "Invalid value for min_us: %d\n", env.MIN_US); + argp_usage(state); + } + } else { + env.MIN_US = 10000; + } + break; + case 'm': + env.MQ_DELAY = true; + break; + case 'h': + argp_state_help(state, stderr, ARGP_HELP_STD_HELP); + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +int deactivate_mode(){ + int err; + + if(env.SAR){ + struct sar_ctrl sar_ctrl = {false,false,0}; + err = update_sar_ctrl_map(sar_ctrl); + if(err < 0) return err; + } + if(env.CS_DELAY){ + struct cs_ctrl cs_ctrl = {false,0}; + err = update_cs_ctrl_map(cs_ctrl); + if(err < 0) return err; + } + if(env.SYSCALL_DELAY){ + struct sc_ctrl sc_ctrl = {false,0}; + err = update_sc_ctrl_map(sc_ctrl); + if(err < 0) return err; + } + if(env.PREEMPT){ + struct preempt_ctrl preempt_ctrl = {false,0}; + err = update_preempt_ctrl_map(preempt_ctrl); + if(err < 0) return err; + } + if(env.SCHEDULE_DELAY){ + struct schedule_ctrl schedule_ctrl = {false,false,10000,0}; + err = update_schedule_ctrl_map(schedule_ctrl); + if(err < 0) return err; + } + if(env.MQ_DELAY){ + struct mq_ctrl mq_ctrl = {false,0}; + err = update_mq_ctrl_map(mq_ctrl); + if(err < 0) return err; + } + return 0; +} + +static void sig_handler(int signo) +{ + deactivate_mode(); +} + +int main(int argc, char **argv) +{ + int err; + static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, + }; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + signal(SIGALRM,sig_handler); + signal(SIGINT,sig_handler); + signal(SIGTERM,sig_handler); + + if(env.usemode == 1){ // activate mode + if(env.SAR){ + struct sar_ctrl sar_ctrl = {true,env.percent,SAR_WACTHER+env.percent}; + err = update_sar_ctrl_map(sar_ctrl); + if(err < 0) return err; + } + + if(env.CS_DELAY){ + struct cs_ctrl cs_ctrl = {true,CS_WACTHER}; + err = update_cs_ctrl_map(cs_ctrl); + if(err < 0) return err; + } + + if(env.SYSCALL_DELAY){ + struct sc_ctrl sc_ctrl = {true,SC_WACTHER}; + err = update_sc_ctrl_map(sc_ctrl); + if(err < 0) return err; + } + + if(env.PREEMPT){ + struct preempt_ctrl preempt_ctrl = {true,PREEMPT_WACTHER}; + err = update_preempt_ctrl_map(preempt_ctrl); + if(err < 0) return err; + } + + if(env.SCHEDULE_DELAY){ + /* + *1.未设置env.MIN_US_SET时, prev_watcher = SCHEDULE_WACTHER + 0;输出方式为schedule输出 + *2.已设置env.MIN_US_SET时, prev_watcher = SCHEDULE_WACTHER + 1;输出方式为-e输出 + */ + struct schedule_ctrl schedule_ctrl = {true,env.MIN_US_SET,env.MIN_US,SCHEDULE_WACTHER+env.MIN_US_SET}; + err = update_schedule_ctrl_map(schedule_ctrl); + if(err < 0) return err; + } + + if(env.MQ_DELAY){ + struct mq_ctrl mq_ctrl = {true,MQ_WACTHER}; + err = update_mq_ctrl_map(mq_ctrl); + if(err < 0) return err; + } + }else if(env.usemode == 2){ // deactivate mode + err = deactivate_mode(); + if(err<0){ + fprintf(stderr, "Failed to deactivate\n"); + return err; + } + }else if(env.usemode == 3){ // finish mode + const char *command = "pkill cpu_watcher"; + int status = system(command); + if (status == -1) { + perror("system"); + } + }else{ + // 输出help信息 + printf("Please enter the usage mode(activate/deactivate/finish) before selecting the function\n"); + argp_help(&argp, stderr, ARGP_HELP_LONG, argv[0]); + } + + return 0; +} diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index fe3832719..0cdf445f5 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -28,7 +28,7 @@ #include #include #include -#include "cpu_watcher.h" +#include "cpu_watcher_helper.h" #include "sar.skel.h" #include "cs_delay.skel.h" #include "sc_delay.skel.h" @@ -38,7 +38,7 @@ typedef long long unsigned int u64; typedef unsigned int u32; -#define MAX_BUF 512 + struct list_head { struct list_head *next; @@ -54,31 +54,34 @@ struct msg_msg { static struct env { int time; - int period; - bool percent; + int period; bool enable_proc; bool SAR; bool CS_DELAY; bool SYSCALL_DELAY; bool PREEMPT; bool SCHEDULE_DELAY; - bool MQ_DELAY; + bool MQ_DELAY; int freq; + bool EWMA; + int cycle; } env = { .time = 0, - .period = 1, - .percent = false, + .period = 1, .enable_proc = false, .SAR = false, .CS_DELAY = false, .SYSCALL_DELAY = false, .PREEMPT = false, .SCHEDULE_DELAY = false, - .MQ_DELAY = false, - .freq = 99 + .MQ_DELAY = false, + .freq = 99, + .EWMA = false, + .cycle = 0, }; + struct cs_delay_bpf *cs_skel; struct sar_bpf *sar_skel; struct sc_delay_bpf *sc_skel; @@ -86,6 +89,17 @@ struct preempt_bpf *preempt_skel; struct schedule_delay_bpf *sd_skel; struct mq_delay_bpf *mq_skel; +static int csmap_fd; +static int sarmap_fd; +struct sar_ctrl sar_ctrl= {}; +static int scmap_fd; +static int preemptmap_fd; +static int schedulemap_fd; +struct schedule_ctrl sd_ctrl = {}; +static int mqmap_fd; + +//static int prev_watcher = 0;//上一个使用的工具,用于在切换使用功能时,打印不用功能的表头; + u64 softirq = 0; u64 irqtime = 0; u64 idle = 0; @@ -108,59 +122,65 @@ int sum_preemptTime = 0 ; int preempt_start_print = 0 ; /*设置传参*/ -const char argp_program_doc[] ="cpu wacher is in use ....\n"; +const char argp_program_doc[] = "cpu watcher is in use ....\n"; static const struct argp_option opts[] = { - { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, - { "period", 'i', "INTERVAL", 0, "Period interval in seconds" }, - {"percent",'P',0,0,"format data as percentages"}, - {"libbpf_sar", 's', 0,0,"print sar_info (the data of cpu)"}, - {"cs_delay", 'c', 0,0,"print cs_delay (the data of cpu)"}, - {"syscall_delay", 'S', 0,0,"print syscall_delay (the data of syscall)"}, - {"preempt_time", 'p', 0,0,"print preempt_time (the data of preempt_schedule)"}, - {"schedule_delay", 'd', 0,0,"print schedule_delay (the data of cpu)"}, - {"mq_delay", 'm', 0,0,"print mq_delay(the data of proc)"}, - { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, - {0}, + { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, + { "period", 'i', "INTERVAL", 0, "Period interval in seconds" }, + {"libbpf_sar", 's', 0, 0, "Print sar_info (the data of cpu)" }, + {"cs_delay", 'c', 0, 0, "Print cs_delay (the data of cpu)" }, + {"syscall_delay", 'S', 0, 0, "Print syscall_delay (the data of syscall)" }, + {"preempt_time", 'p', 0, 0, "Print preempt_time (the data of preempt_schedule)" }, + {"schedule_delay", 'd', 0, 0, "Print schedule_delay (the data of cpu)" }, + {"mq_delay", 'm', 0, 0, "Print mq_delay(the data of proc)" }, + {"ewma", 'E',0,0,"dynamic filte the data"}, + {"cycle", 'T',"CYCLE",0,"Periods of the ewma"}, + { NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" }, + { 0 }, }; + static error_t parse_arg(int key, char *arg, struct argp_state *state) { - switch (key) { - case 't': - env.time = strtol(arg, NULL, 10); - if(env.time) alarm(env.time); - break; - case 'i': - env.period = strtol(arg, NULL, 10); - break; - case 'P': - env.percent = true; - break; - case 's': - env.SAR = true; + switch (key) { + case 't': + env.time = strtol(arg, NULL, 10); + if (env.time) alarm(env.time); + break; + case 'i': + env.period = strtol(arg, NULL, 10); + break; + case 's': + env.SAR = true; + break; + case 'c': + env.CS_DELAY = true; + break; + case 'S': + env.SYSCALL_DELAY = true; + break; + case 'p': + env.PREEMPT = true; + break; + case 'd': + env.SCHEDULE_DELAY = true; + break; + case 'm': + env.MQ_DELAY = true; + break; + case 'E': + env.EWMA = true; break; - case 'c': - env.CS_DELAY = true; - break; - case 'S': - env.SYSCALL_DELAY = true; + case 'T': + env.cycle = strtol(arg, NULL, 10); break; - case 'p': - env.PREEMPT = true; - break; - case 'd': - env.SCHEDULE_DELAY = true; - break; - case 'm': - env.MQ_DELAY = true; - break; - case 'h': - argp_state_help(state, stderr, ARGP_HELP_STD_HELP); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; + case 'h': + argp_state_help(state, stderr, ARGP_HELP_STD_HELP); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; } + static const struct argp argp = { .options = opts, .parser = parse_arg, @@ -236,6 +256,28 @@ u64 find_ksym(const char* target_symbol) { static int print_all() { + int err,key=0; + err = bpf_map_lookup_elem(sarmap_fd, &key, &sar_ctrl); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + if(!sar_ctrl.sar_func) return 0; + if(sar_ctrl.prev_watcher == SAR_WACTHER + 1) { + printf(" time proc/s cswch/s runqlen irqTime/%% softirq/%% idle/%% kthread/%% sysc/%% utime/%% sys/%% \n"); + sar_ctrl.prev_watcher = SAR_WACTHER + 2; + err = bpf_map_update_elem(sarmap_fd, &key, &sar_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + } + }else if (sar_ctrl.prev_watcher == SAR_WACTHER){ + printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms \n"); + sar_ctrl.prev_watcher = SAR_WACTHER + 2; + err = bpf_map_update_elem(sarmap_fd, &key, &sar_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + } + } int nprocs = get_nprocs(); /*proc:*/ int key_proc = 1; @@ -352,7 +394,7 @@ static int print_all() if(env.enable_proc){ time_t now = time(NULL); struct tm *localTime = localtime(&now); - if (env.percent == true){ + if (sar_ctrl.percent == true){ printf("%02d:%02d:%02d %8llu %8llu %6d ",localTime->tm_hour, localTime->tm_min, localTime->tm_sec,__proc, __sched, runqlen); // 大于百分之60的标红输出 double values[7] = { @@ -459,15 +501,42 @@ static void histogram() } +struct ewma_info ewma_syscall_delay = {}; static int syscall_delay_print(void *ctx, void *data,unsigned long data_sz) { + int err,key = 0; + struct sc_ctrl sc_ctrl ={}; + + err = bpf_map_lookup_elem(scmap_fd,&key,&sc_ctrl); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + if(!sc_ctrl.sc_func) return 0; const struct syscall_events *e = data; - printf("pid: %-8u comm: %-10s syscall_id: %-8lld delay: %-8lld\n", - e->pid,e->comm,e->syscall_id,e->delay); + if(e->delay<0||e->delay>1000000) return 0; + time_t now = time(NULL);// 获取当前时间 + struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 + + if(env.EWMA==0){ + printf("%02d:%02d:%02d %-8u %-15lld %-15lld\n", + localTime->tm_hour, localTime->tm_min, localTime->tm_sec, + e->pid,e->syscall_id,e->delay); + } + else{ + ewma_syscall_delay.cycle = env.cycle; + if(dynamic_filter(&ewma_syscall_delay,e->delay)){ + printf("%02d:%02d:%02d %-8u %-15lld %-15lld\n", + localTime->tm_hour, localTime->tm_min, localTime->tm_sec, + e->pid,e->syscall_id,e->delay); + } + } + return 0; } + //抢占时间输出 static int preempt_print(void *ctx, void *data, unsigned long data_sz) { @@ -478,66 +547,126 @@ static int preempt_print(void *ctx, void *data, unsigned long data_sz) return 0; } -char* get_process_name_by_pid(int pid) { - static char buf[MAX_BUF]; - char command[MAX_BUF]; - snprintf(command, sizeof(command), "cat /proc/%d/status | grep Name", pid); - FILE* fp = popen(command, "r"); - if (fp == NULL) { - perror("popen"); - return NULL; - } - char* name = NULL; - while (fgets(buf, sizeof(buf), fp)) { - if (strncmp(buf, "Name:", 5) == 0) { - name = strdup(buf + 6); - break; - } - } - pclose(fp); - if (name != NULL) { - size_t len = strlen(name); - if (len > 0 && name[len - 1] == '\n') { - name[len - 1] = '\0'; +// 定义一个结构来存储已输出的条目 +struct output_entry { + int pid; + char comm[16]; + long long delay; +}; + +// 定义一个数组来存储已输出的条目 +struct output_entry seen_entries[MAX_ENTRIES]; +int seen_count = 0; + +// 检查条目是否已存在 +bool entry_exists(int pid, const char *comm, long long delay) { + for (int i = 0; i < seen_count; i++) { + if (seen_entries[i].pid == pid && + strcmp(seen_entries[i].comm, comm) == 0 && + seen_entries[i].delay == delay) { + return true; } } - return name; + return false; } -static int schedule_print(struct bpf_map *sys_fd) -{ - int key = 0; - struct sum_schedule info; - int err, fd = bpf_map__fd(sys_fd); - time_t now = time(NULL); - struct tm *localTime = localtime(&now); - int hour = localTime->tm_hour; - int min = localTime->tm_min; - int sec = localTime->tm_sec; - unsigned long long avg_delay; - err = bpf_map_lookup_elem(fd, &key, &info); - if (err < 0) { - fprintf(stderr, "failed to lookup infos: %d\n", err); - return -1; +// 添加条目到已输出的条目列表 +void add_entry(int pid, const char *comm, long long delay) { + if (seen_count < MAX_ENTRIES) { + seen_entries[seen_count].pid = pid; + strncpy(seen_entries[seen_count].comm, comm, sizeof(seen_entries[seen_count].comm)); + seen_entries[seen_count].delay = delay; + seen_count++; } - avg_delay = info.sum_delay / info.sum_count; - if(!ifprint){ - ifprint=1; - }else{ - char* proc_name_max = get_process_name_by_pid(info.pid_max); - char* proc_name_min = get_process_name_by_pid(info.pid_min); - printf("%02d:%02d:%02d %-15lf %-15lf %10s %15lf %15s\n", - hour, min, sec, avg_delay / 1000.0, info.max_delay / 1000.0,proc_name_max,info.min_delay / 1000.0,proc_name_min); - if (proc_name_max != NULL) { - free(proc_name_max); +} +static int schedule_print() +{ + int err,key = 0; + err = bpf_map_lookup_elem(schedulemap_fd,&key,&sd_ctrl); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + if(!sd_ctrl.schedule_func) return 0; + + if(sd_ctrl.prev_watcher == SCHEDULE_WACTHER ){ + printf("%-8s %s\n", " TIME ", "avg_delay/μs max_delay/μs max_proc_name min_delay/μs min_proc_name"); + sd_ctrl.prev_watcher = SCHEDULE_WACTHER + 9;//打印表头功能关 + err = bpf_map_update_elem(schedulemap_fd, &key, &sd_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + } + } + else if(sd_ctrl.prev_watcher == SCHEDULE_WACTHER +1){ + // printf("sd_ctrl.prev_watcher = %d\n",sd_ctrl.prev_watcher); + printf("调度延时大于%dms的进程:\n",sd_ctrl.min_us/1000); + printf("%s\n","pid COMM schedule_delay/us"); + sd_ctrl.prev_watcher = SCHEDULE_WACTHER + 9;//打印表头功能关. + err = bpf_map_update_elem(schedulemap_fd, &key, &sd_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + } + } + + if(!sd_ctrl.min_us_set){ + struct sum_schedule info; + int err, fd = bpf_map__fd(sd_skel->maps.sys_schedule); + time_t now = time(NULL); + struct tm *localTime = localtime(&now); + int hour = localTime->tm_hour; + int min = localTime->tm_min; + int sec = localTime->tm_sec; + unsigned long long avg_delay; + err = bpf_map_lookup_elem(fd, &key, &info); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; } - if (proc_name_min != NULL) { - free(proc_name_min); + avg_delay = info.sum_delay / info.sum_count; + if (!ifprint) { + ifprint=1; + }else{ + printf("%02d:%02d:%02d %-15lf %-15lf %10s %15lf %15s\n", + hour, min, sec, avg_delay / 1000.0, info.max_delay / 1000.0,info.proc_name_max,info.min_delay / 1000.0,info.proc_name_min); } } + else{ + struct proc_schedule info; + struct proc_id id_key; + struct proc_history prev_info; + int key = 0; + int err, fd1 = bpf_map__fd(sd_skel->maps.threshold_schedule),fd2 = bpf_map__fd(sd_skel->maps.proc_histories); + err = bpf_map_lookup_elem(fd1, &key, &info); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + if (info.delay / 1000 > sd_ctrl.min_us&&info.id.pid!=0) { + id_key.pid = info.id.pid; + id_key.cpu_id = info.id.cpu_id; + err = bpf_map_lookup_elem(fd2, &id_key, &prev_info); + if (err < 0) { + fprintf(stderr, "Failed to lookup proc_histories with PID %d and CPU ID %d: %d\n", id_key.pid, id_key.cpu_id, err); + return -1; + } + if (!entry_exists(info.id.pid, info.proc_name, info.delay / 1000)) { + printf("%-10d %-16s %15lld", info.id.pid, info.proc_name, info.delay / 1000); + add_entry(info.id.pid, info.proc_name, info.delay / 1000); + for (int i = 0; i < 2; i++) { + if (prev_info.last[i].pid != 0) { + printf(" Previous Process %d: PID=%-10d Name=%-16s ", i+1, prev_info.last[i].pid, prev_info.last[i].comm); + } + } + printf("\n"); + } + + } + } + return 0; } + static int mq_event(void *ctx, void *data,unsigned long data_sz) { time_t now = time(NULL);// 获取当前时间 @@ -568,6 +697,13 @@ static int mq_event(void *ctx, void *data,unsigned long data_sz) int main(int argc, char **argv) { struct ring_buffer *rb = NULL; + struct bpf_map *cs_ctrl_map = NULL; + struct bpf_map *sar_ctrl_map = NULL; + struct bpf_map *sc_ctrl_map = NULL; + struct bpf_map *preempt_ctrl_map = NULL; + struct bpf_map *schedule_ctrl_map = NULL; + struct bpf_map *mq_ctrl_map = NULL; + int key = 0; int err; err = argp_parse(&argp, argc, argv, 0, NULL, NULL); if (err) @@ -609,6 +745,19 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cs_delay_cleanup; } + + err = common_pin_map(&cs_ctrl_map,cs_skel->obj,"cs_ctrl_map",cs_ctrl_path); + if(err < 0){ + goto cs_delay_cleanup; + } + csmap_fd = bpf_map__fd(cs_ctrl_map); + struct cs_ctrl init_value = {false,CS_WACTHER}; + err = bpf_map_update_elem(csmap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto cs_delay_cleanup; + } + /* Attach tracepoints */ err = cs_delay_bpf__attach(cs_skel); if (err) @@ -635,6 +784,17 @@ int main(int argc, char **argv) goto preempt_cleanup; } + err = common_pin_map(&preempt_ctrl_map,preempt_skel->obj,"preempt_ctrl_map",preempt_ctrl_path); + if(err < 0){ + goto preempt_cleanup; + } + preemptmap_fd = bpf_map__fd(preempt_ctrl_map); + struct preempt_ctrl init_value = {false,PREEMPT_WACTHER}; + err = bpf_map_update_elem(preemptmap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto preempt_cleanup; + } err = preempt_bpf__attach(preempt_skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); @@ -662,6 +822,17 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto sc_delay_cleanup; } + err = common_pin_map(&sc_ctrl_map,sc_skel->obj,"sc_ctrl_map",sc_ctrl_path); + if(err < 0){ + goto sc_delay_cleanup; + } + scmap_fd = bpf_map__fd(sc_ctrl_map); + struct sc_ctrl init_value = {false,SC_WACTHER}; + err = bpf_map_update_elem(scmap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto sc_delay_cleanup; + } /* Attach tracepoints */ err = sc_delay_bpf__attach(sc_skel); if (err) @@ -669,13 +840,18 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to attach BPF skeleton\n"); goto sc_delay_cleanup; } + printf("%-8s %-8s %-15s %-15s\n","Time","Pid","syscall_id","delay/ms"); rb = ring_buffer__new(bpf_map__fd(sc_skel->maps.rb), syscall_delay_print, NULL, NULL); //ring_buffer__new() API,允许在不使用额外选项数据结构下指定回调 if (!rb) { err = -1; fprintf(stderr, "Failed to create ring buffer\n"); goto sc_delay_cleanup; } + + }else if(env.SCHEDULE_DELAY){ + + sd_skel = schedule_delay_bpf__open(); if (!sd_skel) { fprintf(stderr, "Failed to open and load BPF skeleton\n"); @@ -686,12 +862,23 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto schedule_cleanup; } + err = common_pin_map(&schedule_ctrl_map,sd_skel->obj,"schedule_ctrl_map",schedule_ctrl_path); + if(err < 0){ + goto schedule_cleanup; + } + schedulemap_fd = bpf_map__fd(schedule_ctrl_map); + struct schedule_ctrl init_value = {false,false,10000,SCHEDULE_WACTHER}; + + err = bpf_map_update_elem(schedulemap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto schedule_cleanup; + } err = schedule_delay_bpf__attach(sd_skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); goto schedule_cleanup; } - printf("%-8s %s\n", " TIME ", "avg_delay/μs max_delay/μs max_proc_name min_delay/μs min_proc_name"); }else if (env.SAR){ /* Load and verify BPF application */ sar_skel = sar_bpf__open(); @@ -714,15 +901,24 @@ int main(int argc, char **argv) if (err) goto sar_cleanup; + err = common_pin_map(&sar_ctrl_map,sar_skel->obj,"sar_ctrl_map",sar_ctrl_path); + if(err < 0){ + goto sar_cleanup; + } + sarmap_fd = bpf_map__fd(sar_ctrl_map); + struct sar_ctrl init_value = {false,false,SAR_WACTHER}; + err = bpf_map_update_elem(sarmap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto sar_cleanup; + } + err = sar_bpf__attach(sar_skel); if (err) { fprintf(stderr, "Failed to attach BPF skeleton\n"); goto sar_cleanup; } - if (env.percent){ - printf(" time proc/s cswch/s runqlen irqTime/%% softirq/%% idle/%% kthread/%% sysc/%% utime/%% sys/%% \n"); - }else{printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms \n");} }else if(env.MQ_DELAY){ /* Load and verify BPF application */ mq_skel = mq_delay_bpf__open(); @@ -738,6 +934,19 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto mq_delay_cleanup; } + + err = common_pin_map(&mq_ctrl_map,mq_skel->obj,"mq_ctrl_map",mq_ctrl_path); + if(err < 0){ + goto mq_delay_cleanup; + } + mqmap_fd = bpf_map__fd(mq_ctrl_map); + struct mq_ctrl init_value = {false,MQ_WACTHER}; + err = bpf_map_update_elem(mqmap_fd, &key, &init_value, 0); + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto mq_delay_cleanup; + } + /* Attach tracepoints */ err = mq_delay_bpf__attach(mq_skel); if (err) @@ -790,11 +999,11 @@ int main(int argc, char **argv) printf("Error polling perf buffer: %d\n", err); break; } - time_t now = time(NULL);// 获取当前时间 - struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 - printf("\n\nTime: %02d:%02d:%02d\n",localTime->tm_hour, localTime->tm_min, localTime->tm_sec); - printf("----------------------------------------------------------------------------------------------------------\n"); - sleep(1); + // time_t now = time(NULL);// 获取当前时间 + // struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 + // printf("\n\nTime: %02d:%02d:%02d\n",localTime->tm_hour, localTime->tm_min, localTime->tm_sec); + // printf("----------------------------------------------------------------------------------------------------------\n"); + // sleep(1); } else if (env.PREEMPT) { err = ring_buffer__poll(rb, 100 /* timeout, ms */); @@ -821,7 +1030,7 @@ int main(int argc, char **argv) sleep(2); } else if (env.SCHEDULE_DELAY){ - err = schedule_print(sd_skel->maps.sys_schedule); + err = schedule_print(); if (err == -EINTR) { err = 0; break; @@ -829,7 +1038,9 @@ int main(int argc, char **argv) if (err < 0) { break; } - sleep(1); + if(env.SCHEDULE_DELAY&&!sd_ctrl.min_us_set){ + sleep(1); + } } else if(env.MQ_DELAY){ err = ring_buffer__poll(rb, 1000 /* timeout, s */); @@ -849,30 +1060,36 @@ int main(int argc, char **argv) } cs_delay_cleanup: + bpf_map__unpin(cs_ctrl_map, cs_ctrl_path); ring_buffer__free(rb); cs_delay_bpf__destroy(cs_skel); return err < 0 ? -err : 0; sar_cleanup: + bpf_map__unpin(sar_ctrl_map, sar_ctrl_path); sar_bpf__destroy(sar_skel); return err < 0 ? -err : 0; sc_delay_cleanup: + bpf_map__unpin(sc_ctrl_map, sc_ctrl_path); ring_buffer__free(rb); sc_delay_bpf__destroy(sc_skel); return err < 0 ? -err : 0; preempt_cleanup: + bpf_map__unpin(preempt_ctrl_map, preempt_ctrl_path); ring_buffer__free(rb); preempt_bpf__destroy(preempt_skel); return err < 0 ? -err : 0; schedule_cleanup: + bpf_map__unpin(schedule_ctrl_map, schedule_ctrl_path); schedule_delay_bpf__destroy(sd_skel); return err < 0 ? -err : 0; mq_delay_cleanup: + bpf_map__unpin(mq_ctrl_map, mq_ctrl_path); ring_buffer__free(rb); mq_delay_bpf__destroy(mq_skel); return err < 0 ? -err : 0; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/grafana_cpu_watcher_dashboard.json b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/grafana_cpu_watcher_dashboard.json new file mode 100644 index 000000000..9177bf611 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/grafana_cpu_watcher_dashboard.json @@ -0,0 +1,1177 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"avg_delay/us\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"max_delay/us\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"min_delay/μs\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "schedule_delay", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"irqTime/us\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "irqTime", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"duration_ns\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "preempt_delay", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 3, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"proc/s\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "procs", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"sys/ms\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "sys", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"softirq/us\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "softirqTime", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"utime/ms\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "utime", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"idle/ms\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "idle", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"kthread/us\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "kthread", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"cswch/s\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "cswch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "continuous-GrYlRd" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "scheme", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "smooth", + "lineWidth": 3, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "right", + "showLegend": false + }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddlnxe6bsiha8c" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"delay/ms\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "interval": "1", + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "sys_delay", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "cpu_watcher_vis", + "uid": "cdlnxoxcy4zr4b", + "version": 4, + "weekStart": "" +} \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h index bc67e3e5b..eadd0d874 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h @@ -13,6 +13,8 @@ // limitations under the License. // // author: albert_xuu@163.com zhangxy1016304@163.com zhangziheng0525@163.com +#ifndef CPU_WATCHER_H +#define CPU_WATCHER_H #include #include @@ -134,10 +136,26 @@ struct sum_schedule { unsigned long long sum_delay; unsigned long long max_delay; unsigned long long min_delay; - int pid_max; - int pid_min; + char proc_name_max[TASK_COMM_LEN]; + char proc_name_min[TASK_COMM_LEN]; }; +struct proc_schedule { + struct proc_id id; + unsigned long long delay; + char proc_name[TASK_COMM_LEN]; +}; + +struct proc_info { + pid_t pid; + char comm[TASK_COMM_LEN]; +}; + +struct proc_history { + struct proc_info last[2]; // 存储最后两个调度的进程信息 +}; + + /*----------------------------------------------*/ /* mq_delay相关结构体 */ /*----------------------------------------------*/ @@ -211,4 +229,42 @@ struct idleStruct { u64 pad; unsigned int state; unsigned int cpu_id; -}; \ No newline at end of file +}; + +/*----------------------------------------------*/ +/* 控制板块 */ +/*----------------------------------------------*/ +struct sar_ctrl{ + bool sar_func; + bool percent; + int prev_watcher; +}; + +struct cs_ctrl{ + bool cs_func; + int prev_watcher; +}; + +struct sc_ctrl{ + bool sc_func; + int prev_watcher; +}; + +struct preempt_ctrl{ + bool preempt_func; + int prev_watcher; +}; + +struct schedule_ctrl{ + bool schedule_func; + bool min_us_set; + int min_us; + int prev_watcher; +}; + +struct mq_ctrl{ + bool mq_func; + int prev_watcher; +}; + +#endif // CPU_WATCHER_H \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher_helper.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher_helper.h new file mode 100644 index 000000000..5250aef89 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher_helper.h @@ -0,0 +1,202 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: albert_xuu@163.com zhangxy1016304@163.com zhangziheng0525@163.com +#ifndef CPU_WATCHER_HELPER_H +#define CPU_WATCHER_HELPER_H + +#include +#include "cpu_watcher.h" + +#define SAR_WACTHER 10 +#define CS_WACTHER 20 +#define SC_WACTHER 30 +#define PREEMPT_WACTHER 40 +#define SCHEDULE_WACTHER 50 +#define MQ_WACTHER 60 + +/*----------------------------------------------*/ +/* ewma算法 */ +/*----------------------------------------------*/ +//滑动窗口周期,用于计算alpha +#define CYCLE 10 +//阈值容错空间; +#define TOLERANCE 1.0 +struct ewma_info{ + double previousEWMA; + int count; + int cycle;//cycle是滑动窗口周期大小 +}; + +double calculateEWMA(double previousEWMA, double dataPoint, double alpha) { + return alpha * dataPoint + (1 - alpha) * previousEWMA;//当前时间点的ewma +} + +bool dynamic_filter(struct ewma_info *ewma_syscall_delay, double dataPoint) { + double alpha,threshold; + if(ewma_syscall_delay->cycle==0) alpha = 2.0 /(CYCLE + 1); // 计算 alpha + else alpha = 2.0 /(ewma_syscall_delay->cycle + 1); + + if(ewma_syscall_delay->previousEWMA == 0) {//初始化ewma算法,则赋值previousEWMA = dataPoint 并打印 + ewma_syscall_delay->previousEWMA = dataPoint; + return 1; + } + if(ewma_syscall_delay->count <30){ + ewma_syscall_delay->previousEWMA = calculateEWMA(ewma_syscall_delay->previousEWMA,dataPoint,alpha);//计算 + return 1; + } + else{ + ewma_syscall_delay->previousEWMA = calculateEWMA(ewma_syscall_delay->previousEWMA,dataPoint,alpha);//计算 + threshold = ewma_syscall_delay->previousEWMA * TOLERANCE; + if(dataPoint >= threshold) return 1; + } + return 0; +} + + +const char *sar_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/sar_ctrl_map"; +const char *cs_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/cs_ctrl_map"; +const char *sc_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/sc_ctrl_map"; +const char *preempt_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/preempt_ctrl_map"; +const char *schedule_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/schedule_ctrl_map"; +const char *mq_ctrl_path = "/sys/fs/bpf/cpu_watcher_map/mq_ctrl_map"; + +int common_pin_map(struct bpf_map **bpf_map, const struct bpf_object *obj, const char *map_name, const char *ctrl_path) +{ + int ret; + + *bpf_map = bpf_object__find_map_by_name(obj, map_name);//查找具有指定名称的 BPF 映射 + if (!*bpf_map) { + fprintf(stderr, "Failed to find BPF map\n"); + return -1; + } + // 用于防止上次没有成功 unpin 掉这个 map + bpf_map__unpin(*bpf_map, ctrl_path); + ret = bpf_map__pin(*bpf_map, ctrl_path); + if (ret){ + fprintf(stderr, "Failed to pin BPF map\n"); + return -1; + }//找到pin上 + + return 0; +} + +int update_sar_ctrl_map(struct sar_ctrl sar_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(sar_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open sar_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&sar_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update sar_ctrl_map elem\n"); + return err; + } + + return 0; +} + +int update_cs_ctrl_map(struct cs_ctrl cs_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(cs_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open cs_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&cs_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update cs_ctrl_map elem\n"); + return err; + } + + return 0; +} + +int update_sc_ctrl_map(struct sc_ctrl sc_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(sc_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open sc_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&sc_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update sc_ctrl_map elem\n"); + return err; + } + + return 0; +} + +int update_preempt_ctrl_map(struct preempt_ctrl preempt_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(preempt_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open preempt_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&preempt_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update preempt_ctrl_map elem\n"); + return err; + } + + return 0; +} + +int update_schedule_ctrl_map(struct schedule_ctrl schedule_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(schedule_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open schedule_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&schedule_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update schedule_ctrl_map elem\n"); + return err; + } + + return 0; +} + +int update_mq_ctrl_map(struct mq_ctrl mq_ctrl){ + int err,key = 0; + int srcmap_fd; + + srcmap_fd = bpf_obj_get(mq_ctrl_path); + if (srcmap_fd < 0) { + fprintf(stderr,"Failed to open mq_ctrl_map file\n"); + return srcmap_fd; + } + err = bpf_map_update_elem(srcmap_fd,&key,&mq_ctrl, 0); + if(err < 0){ + fprintf(stderr, "Failed to update mq_ctrl_map elem\n"); + return err; + } + + return 0; +} +#endif // CPU_WATCHER_HELPER_H \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c index 0d5561ebd..ada9abd83 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c @@ -174,7 +174,9 @@ int main(int argc, char **argv){ } if(env.preempt_test){ - /*preempt_delay的测试代码*/ + printf("PREEMPT_TEST----------------------------------------------\n"); + //PREEMPT功能测试逻辑:无限循环的线程函数,不断调用 sched_yield() 来放弃 CPU 使用权,模拟高调度负载。 + start_schedule_stress_test(10); // 创建10个线程进行调度压力测试 } if(env.schedule_test){ @@ -186,7 +188,6 @@ int main(int argc, char **argv){ printf("执行指令 sysbench --threads=32 --time=10 cpu run\n"); execve("/usr/bin/sysbench", argvv, envp); perror("execve"); - printf("\n"); } diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/Makefile b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/Makefile index ae93b43c6..af43eaec8 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/Makefile +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/Makefile @@ -42,7 +42,7 @@ INCLUDES := -I$(OUTPUT) -I../../../libbpf/include/uapi -I$(dir $(VMLINUX)) -I$(L CFLAGS := -g -Wall ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) -APPS = lifecycle_image lock_image newlife_image keytime_image +APPS = lifecycle_image lock_image newlife_image keytime_image migrate_image CARGO ?= $(shell which cargo) ifeq ($(strip $(CARGO)),) diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.bpf.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.bpf.c new file mode 100644 index 000000000..886481e22 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.bpf.c @@ -0,0 +1,79 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: albert_xuu@163.com + +#include "vmlinux.h" +#include //包含了BPF 辅助函数 +#include +#include +#include "migrate_image.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(pid_t)); + __uint(value_size, sizeof(struct migrate_event)); + __uint(max_entries, 128); +} migrate SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 16); +} t SEC(".maps"); + +SEC("tracepoint/sched/sched_migrate_task") +int tracepoint_sched_migrate_task(struct trace_event_raw_sched_migrate_task *args){ + u64 time = bpf_ktime_get_ns();//当前转移时间点; + pid_t pid = args->pid; + struct migrate_event *migrate_event; + migrate_event = bpf_map_lookup_elem(&migrate,&pid); + if(!migrate_event){ + int key = 0,*count=bpf_map_lookup_elem(&t,&key); + if(!count){ + int init = 1; + bpf_map_update_elem(&t,&key,&init,BPF_ANY); + } + else *count +=1; + + struct migrate_event migrate_event = {}; + migrate_event.pid = pid; + migrate_event.prio = args->prio; + migrate_event.migrate_info[0].time = time; + migrate_event.migrate_info[0].orig_cpu = args->orig_cpu; + migrate_event.migrate_info[0].dest_cpu = args->dest_cpu; + migrate_event.count = 1; + bpf_map_update_elem(&migrate, &pid, &migrate_event, BPF_ANY); + } + /*&& (migrate_event->migrate_info + migrate_event->count) < (migrate_event->migrate_info + MAX_MIGRATE)*/ + else if(migrate_event->count>0 && migrate_event->countmigrate_info + migrate_event->count) < (migrate_event->migrate_info + MAX_MIGRATE) ) + { + migrate_event->migrate_info[migrate_event->count].time = time; + migrate_event->migrate_info[migrate_event->count].orig_cpu = args->orig_cpu; + migrate_event->migrate_info[migrate_event->count++].dest_cpu = args->dest_cpu; + } + else if(migrate_event->count>=MAX_MIGRATE) + { + migrate_event->migrate_info[migrate_event->count % MAX_MIGRATE].time = time; + migrate_event->migrate_info[migrate_event->count % MAX_MIGRATE].orig_cpu = args->orig_cpu; + migrate_event->migrate_info[migrate_event->count % MAX_MIGRATE].dest_cpu = args->dest_cpu; + migrate_event->count++; + migrate_event->rear ++; + } + + //bpf_printk("Time:%llu\tpid:%d\tcomm:%s\tprio:%d\torig_cpu:%d\tdest_cpu:%d\t\n",time,args->pid,args->comm,args->prio,args->orig_cpu,args->dest_cpu); + return 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.c new file mode 100644 index 000000000..ae04ea7e7 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.c @@ -0,0 +1,248 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: albert_xuu@163.com + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "migrate_image.skel.h" +#include "migrate_image.h" +#include "trace_helpers.h" + +#define warn(...) fprintf(stderr, __VA_ARGS__) + +static volatile bool exiting = false; +struct migrate_image_bpf *skel; +// static struct env { +// int pid; +// int time; +// int cpu_id; +// int stack_count; +// bool set_stack; +// bool enable_cs; +// } env = { +// .pid = 0, +// .time = 0, +// .cpu_id = 0, +// .stack_count = 0, +// .set_stack = false, +// .enable_cs = false, +// }; + +static struct ksyms *ksyms = NULL; + +const char argp_program_doc[] ="Trace process to get process life cycle image.\n"; + +// static const struct argp_option opts[] = { +// { "pid", 'p', "PID", 0, "Process ID to trace" }, +// { "cpuid", 'C', "CPUID", 0, "Set For Tracing Process 0(other processes don't need to set this parameter)" }, +// { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, +// { "cs-reason", 'r', NULL, 0, "Process context switch reasons annotation" }, +// { "stack", 's', "STACK-COUNT", 0, "The number of kernel stacks printed when the process is under the CPU" }, +// { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, +// {}, +// }; + +// static error_t parse_arg(int key, char *arg, struct argp_state *state) +// { +// long pid; +// long cpu_id; +// long stack; +// switch (key) { +// case 'p': +// errno = 0; +// pid = strtol(arg, NULL, 10); +// if (errno || pid < 0) { +// warn("Invalid PID: %s\n", arg); +// // 调用argp_usage函数,用于打印用法信息并退出程序 +// argp_usage(state); +// } +// env.pid = pid; +// break; +// case 'C': +// cpu_id = strtol(arg, NULL, 10); +// if(cpu_id < 0){ +// warn("Invalid CPUID: %s\n", arg); +// argp_usage(state); +// } +// env.cpu_id = cpu_id; +// break; +// case 't': +// env.time = strtol(arg, NULL, 10); +// if(env.time) alarm(env.time); +// break; +// case 'r': +// env.enable_cs = true; +// break; +// case 's': +// stack = strtol(arg, NULL, 10); +// if (stack < 0) { +// warn("Invalid STACK-COUNT: %s\n", arg); +// // 调用argp_usage函数,用于打印用法信息并退出程序 +// argp_usage(state); +// } +// env.stack_count = stack; +// env.set_stack = true; +// break; +// case 'h': +// argp_state_help(state, stderr, ARGP_HELP_STD_HELP); +// break; +// default: +// return ARGP_ERR_UNKNOWN; +// } + +// return 0; +// } + +static void sig_handler(int sig) +{ + exiting = true; +} + + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +{ + return vfprintf(stderr, format, args); +} + +static int migrate_print(){ + time_t now = time(NULL);// 获取当前时间 + struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 + printf("Time: %02d:%02d:%02d\n",localTime->tm_hour, localTime->tm_min, localTime->tm_sec); + printf("---------------------------------------------------------------------------------\n"); + int err,migrate_fd =bpf_map__fd(skel->maps.migrate),t_fd =bpf_map__fd(skel->maps.t); + int key =0,count; + err = bpf_map_lookup_elem(t_fd,&key,&count); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + printf("total process %d\n",count); + count = 0; + bpf_map_update_elem(t_fd,&key,&count,BPF_ANY); + + pid_t lookup_key = -1 ,next_key; + struct migrate_event migrate_event; + while(!bpf_map_get_next_key(migrate_fd, &lookup_key, &next_key)){//遍历打印hash map + err = bpf_map_lookup_elem(migrate_fd,&next_key,&migrate_event); + if (err < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err); + return -1; + } + if(migrate_event.count == migrate_event.rear) { + lookup_key = next_key; + continue; + } + u64 last_time_stamp = 0; + printf("\npid:%d\tprio:%d\tcount:%d\trear:%d\n",migrate_event.pid,migrate_event.prio,migrate_event.count,migrate_event.rear); + for(int i=migrate_event.rear;i%d\t", + migrate_event.migrate_info[i%MAX_MIGRATE].time,migrate_event.migrate_info[i%MAX_MIGRATE].orig_cpu,migrate_event.migrate_info[i%MAX_MIGRATE].dest_cpu); + if(i==migrate_event.rear && last_time_stamp == 0) { + last_time_stamp = migrate_event.migrate_info[i%MAX_MIGRATE].time; + printf("delay: /\n"); + }else{ + printf("delay: %d us\n",(migrate_event.migrate_info[i%MAX_MIGRATE].time - last_time_stamp)/1000); + last_time_stamp = migrate_event.migrate_info[i%MAX_MIGRATE].time; + } + } + migrate_event.rear = migrate_event.count; + bpf_map_update_elem(migrate_fd,&next_key,&migrate_event,BPF_ANY); + lookup_key = next_key; + } + printf("---------------------------------------------------------------------------------\n\n"); + return 0; +} + +int main(int argc, char **argv) +{ + struct ring_buffer *rb = NULL; + int err; + // static const struct argp argp = { + // .options = opts, + // .parser = parse_arg, + // .doc = argp_program_doc, + // }; + + // err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + // if (err) + // return err; + + + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + /* 设置libbpf错误和调试信息回调 */ + libbpf_set_print(libbpf_print_fn); + + /* 更干净地处理Ctrl-C + SIGINT:由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 + SIGTERM:请求中止进程,kill命令发送 + */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGALRM,sig_handler); + + /* 打开BPF应用程序 */ + skel = migrate_image_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + + /* 加载并验证BPF程序 */ + err = migrate_image_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + ksyms = ksyms__load(); + if (!ksyms) { + fprintf(stderr, "failed to load kallsyms\n"); + goto cleanup; + } + + /* 附加跟踪点处理程序 */ + err = migrate_image_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + /* 处理事件 */ + while (!exiting) { + sleep(1); + err = migrate_print(); + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + } + +/* 卸载BPF程序 */ +cleanup: + // ring_buffer__free(rb); + migrate_image_bpf__destroy(skel); + return err < 0 ? -err : 0; +} diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.h b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.h new file mode 100644 index 000000000..0bb280c34 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.h @@ -0,0 +1,23 @@ +#include +#include + +typedef unsigned long long u64; +typedef unsigned int u32; +/*----------------------------------------------*/ +/* migrate_event结构体 */ +/*----------------------------------------------*/ +#define MAX_MIGRATE 16 +// #define ARRY_OVERFLOW -1 +struct per_migrate{//每次迁移,记录该次迁移信息; + u64 time; + u32 orig_cpu; + u32 dest_cpu; +}; +//每个进程的迁移信息; +struct migrate_event{ + int erro; + pid_t pid; + int prio; + int count,rear;//迁移频率 + struct per_migrate migrate_info[MAX_MIGRATE];//该进程每次迁移信息; +}; diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.bpf.c index 50d0bb29c..135a863fd 100644 --- a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.bpf.c +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.bpf.c @@ -1,63 +1,77 @@ -#include "vmlinux.h" -#include //包含了BPF 辅助函数 +#define BPF_NO_GLOBAL_DATA +#include +#include #include -#include "open.h" +#include -char LICENSE[] SEC("license") = "Dual BSD/GPL"; +#define TASK_COMM_LEN 100 +#define path_size 256 -// 定义哈希映射 struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, pid_t); - __type(value, u64); -} fdtmp SEC(".maps"); + __type(value, char[TASK_COMM_LEN]); +} data SEC(".maps"); + +struct event { + int pid_; + char path_name_[path_size]; + int n_; + char comm[TASK_COMM_LEN]; +}; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); -} rb SEC(".maps"); - -SEC("kprobe/do_sys_openat2") -int BPF_KPROBE(do_sys_openat2) -{ - struct fs_t fs; - pid_t pid; - - //pid - pid = bpf_get_current_pid_tgid() >> 32; - fs.pid = pid; - - //uid - fs.uid = bpf_get_current_uid_gid(); - - //fd,file descriptor - int fd = PT_REGS_RC(ctx); - if (fd >= 0) - fs.fd = fd; - else - fs.fd= -1; - - //time - unsigned long long ts = bpf_ktime_get_ns(); - fs.ts = ts; - bpf_map_update_elem(&fdtmp, &pid, &ts, BPF_ANY); - - //从环形缓冲区(ring buffer)中分配一块内存来存储一个名为 struct fs_t 类型的数据,并将该内存块的指针赋值给指针变量 e - struct fs_t *e; +} rb SEC(".maps"); // 环形缓冲区 + + +SEC("tracepoint/syscalls/sys_enter_openat") +int do_syscall_trace(struct trace_event_raw_sys_enter *ctx) +{ + struct event *e; + char comm[TASK_COMM_LEN]; + bpf_get_current_comm(&comm,sizeof(comm)); e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); - if (!e) return 0; - - //给变量e赋值 - e->pid = fs.pid; - e->uid = fs.uid; - e->fd = fs.fd; - e->ts = fs.ts; - bpf_get_current_comm(e->comm, sizeof(e->comm)); - - // 成功地将其提交到用户空间进行后期处理 + if (!e) + return 0; + + char filename[path_size]; + struct task_struct *task = (struct task_struct *)bpf_get_current_task(), + *real_parent; + if (task == NULL) { + bpf_printk("task\n"); + bpf_ringbuf_discard(e, 0); + return 0; + } + int pid = bpf_get_current_pid_tgid() >> 32, tgid; + + bpf_map_update_elem(&data, &pid, &comm, BPF_ANY); + + int ppid = BPF_CORE_READ(task, real_parent, tgid); + + bpf_probe_read_str(e->path_name_, sizeof(e->path_name_), + (void *)(ctx->args[1])); + + bpf_printk("path name: %s,pid:%d,ppid:%d\n", e->path_name_, pid, ppid); + + struct fdtable *fdt = BPF_CORE_READ(task, files, fdt); + if (fdt == NULL) { + bpf_printk("fdt\n"); + bpf_ringbuf_discard(e, 0); + return 0; + } + + unsigned int i = 0, count = 0, n = BPF_CORE_READ(fdt, max_fds); + bpf_printk("n:%d\n", n); + + e->n_ = n; + e->pid_ = pid; + bpf_ringbuf_submit(e, 0); - return 0; + return 0; } +char LICENSE[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.c index 9a48be42f..ed01c10e5 100644 --- a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.c +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.c @@ -1,10 +1,38 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2020 Facebook */ +#include #include -#include +#include +#include +#include +#include #include #include -#include -#include "open.skel.h" //包含了 BPF 字节码和相关的管理函数 -#include "open.h" +#include +#include +#include +#include "open.skel.h" +#include +#include +#include + +#define path_size 256 +#define TASK_COMM_LEN 16 + +struct event { + int pid_; + char path_name_[path_size]; + int n_; + char comm[TASK_COMM_LEN]; +}; + +#define warn(...) fprintf(stderr, __VA_ARGS__) + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, + va_list args) +{ + return vfprintf(stderr, format, args); +} static volatile bool exiting = false; @@ -13,18 +41,34 @@ static void sig_handler(int sig) exiting = true; } -static int handle_event(void *ctx, void *data,unsigned long data_sz) +static int handle(void *ctx, void *data, size_t data_sz) { - const struct fs_t *e = data; - printf("pid:%d uid:%llu time:%llu fd:%d comm:%s\n",e->pid,e->uid,e->ts,e->fd,e->comm); - - return 0; -} - + struct event *e = (struct event *)data; + char *filename = strrchr(e->path_name_, '/'); + ++filename; -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) -{ - return vfprintf(stderr, format, args); + char fd_path[path_size]; + char actual_path[path_size]; + char comm[TASK_COMM_LEN]; + int i = 0; + int map_fd = *(int *)ctx;//传递map得文件描述符 + + for (; i < e->n_; ++i) { + snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", e->pid_,i); + ssize_t len = readlink(fd_path, actual_path, sizeof(actual_path) - 1); + if (len != -1) { + actual_path[len] = '\0'; + int result = strcmp(e->path_name_, actual_path); + if (result == 0) { + if(bpf_map_lookup_elem(map_fd,&e->pid_,&comm)==0){ + printf("get , filename:%s , fd:%d , pid:%d ,comm:%s\n", e->path_name_, i,e->pid_,comm); + }else{ + fprintf(stderr, "Failed to lookup value for key %d\n", e->pid_); + } + } + } + } + return 0; } int main(int argc, char **argv) @@ -33,50 +77,51 @@ int main(int argc, char **argv) struct open_bpf *skel; int err; - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - /* 设置libbpf错误和调试信息回调 */ + /* Set up libbpf errors and debug info callback */ libbpf_set_print(libbpf_print_fn); - /* 更干净地处理Ctrl-C - SIGINT:由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 - SIGTERM:请求中止进程,kill命令发送 - */ - signal(SIGINT, sig_handler); //signal设置某一信号的对应动作 + /* Cleaner handling of Ctrl-C */ + signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); - /* 打开BPF应用程序 */ + /* Load and verify BPF application */ skel = open_bpf__open(); if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); + fprintf(stderr, "Failed to open and load BPF skeleton\n"); return 1; } - - /* 加载并验证BPF程序 */ + + /* Load & verify BPF programs */ err = open_bpf__load(skel); if (err) { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; } - - /* 附加跟踪点处理程序 */ - err = open_bpf__attach(skel); - if (err) { + + int attach = open_bpf__attach(skel); + if (attach) { fprintf(stderr, "Failed to attach BPF skeleton\n"); + err = -1; goto cleanup; } - - /* 设置环形缓冲区轮询 */ - rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); //ring_buffer__new() API,允许在不使用额外选项数据结构下指定回调 + + int map_fd = bpf_map__fd(skel->maps.data); + if(!map_fd){ + fprintf(stderr, "Failed to find BPF map\n"); + return -1; + } + + rb = ring_buffer__new( + bpf_map__fd(skel->maps.rb), handle, &map_fd, NULL); // 创建一个环形缓冲区,并设置好缓冲区的回调函数 if (!rb) { err = -1; fprintf(stderr, "Failed to create ring buffer\n"); goto cleanup; } - - /* 处理事件 */ + while (!exiting) { - err = ring_buffer__poll(rb, 100 /* timeout, ms */); //ring_buffer__poll(),轮询打开ringbuf缓冲区。如果有事件,handle_event函数会执行 - /* Ctrl-C will cause -EINTR */ + err = ring_buffer__poll(rb, 100); + if (err == -EINTR) { err = 0; break; @@ -85,15 +130,11 @@ int main(int argc, char **argv) printf("Error polling perf buffer: %d\n", err); break; } - - //exiting = true; //使用该程序时,将该行代码注释掉 - } - -/* 卸载BPF程序 */ cleanup: + /* Clean up */ ring_buffer__free(rb); open_bpf__destroy(skel); - + return err < 0 ? -err : 0; -} +} \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.h b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.h index 835cd90fa..a8194600c 100644 --- a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.h +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/open.h @@ -5,12 +5,11 @@ #define TASK_COMM_LEN 16 #endif -struct fs_t { - int pid; - unsigned long long uid; - int fd; - unsigned long long ts; - char comm[TASK_COMM_LEN]; +struct event { + int pid_; + char path_name_[path_size]; + int n_; + char comm[TASK_COMM_LEN]; }; #endif /* __OPEN_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c index 91735d5ea..2b5f34811 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c @@ -209,10 +209,10 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'n': env.part2 = true; break; case 'P': env.choose_pid = strtol(arg, NULL, 10); break; case 'R': env.rss = true; break; - case 'l': env.memleak = true; break; - case 'm': env.print_time = true; break; - case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); break; - default: return ARGP_ERR_UNKNOWN; + case 'l': env.memleak = true; break; + case 'm': env.print_time = true; break; + case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); break; + default: return ARGP_ERR_UNKNOWN; } return 0; } @@ -246,6 +246,7 @@ static __u64 adjust_time_to_program_start_time(__u64 first_query_time); static int update_addr_times(struct memleak_bpf *skel_memleak); static int print_time(struct memleak_bpf *skel_memleak); + // Main function int main(int argc, char **argv) { int err; diff --git a/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.mod b/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.mod index 2c47343f5..675073ee9 100644 --- a/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.mod +++ b/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.mod @@ -3,7 +3,7 @@ module lmp/eTrafficManager go 1.20 require ( - github.com/cilium/cilium v1.14.8 + github.com/cilium/cilium v1.14.12 github.com/cilium/ebpf v0.11.0 github.com/prometheus/client_golang v1.16.0 github.com/prometheus/common v0.42.0 @@ -83,7 +83,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect + k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.sum b/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.sum index 101946f56..183679d98 100644 --- a/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.sum +++ b/eBPF_Supermarket/Network_Subsystem/TrafficManager/go.sum @@ -52,8 +52,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/checkmate v1.0.3 h1:CQC5eOmlAZeEjPrVZY3ZwEBH64lHlx9mXYdUehEwI5w= -github.com/cilium/cilium v1.14.8 h1:Jm54iA7XxWJn+GdZrfzcEyeoNUb58w8y0g8ZB2lVcJw= -github.com/cilium/cilium v1.14.8/go.mod h1:7cWSSEl+dU9Q5CqnEWT//c0w8yLSazShw287Uop6xVs= +github.com/cilium/cilium v1.14.12 h1:lQ4XilTUJK5R6BrZnSm4pYxj6jsBQFWlBuRHA5FHJ1I= +github.com/cilium/cilium v1.14.12/go.mod h1:Pjy+qd1hrrXulp78Hs76ahKCttij64LvjxFui9XquVA= github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -756,8 +756,8 @@ k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/README.md b/eBPF_Supermarket/Network_Subsystem/net_watcher/README.md index 533ce30a5..355cf2f18 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/README.md +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/README.md @@ -34,6 +34,8 @@ netwatcher能够追踪TCP、UDP、ICMP协议数据包从应用程序发出开始 - TCP、UDP、ICMP相关信息监测:追踪TCP、UDP、ICMP协议数据包,并实现对主机接收和发送的所有相关数据包的时延数据和流量信息 - 监测TCP连接状态信息:包括三次握手以及四次挥手的状态转变和时延数据 - 丢包事件的监控:分析导致丢包的地址以及丢包原因 +- DNS协议相关信息监控:通过截取UDP包,对DNS协议包进行解析,获取事务ID、标志字段、问题部分计数、应答记录计数、授权记录计数、附加记录计数、域名等信息 +- 主机环境下对用户态mysql的分析:uprobe实现对mysql的监测,其监测内容有进程pid、进程名、sql语句、sql语句执行时间。 #### TODO - [ ] 应用层协议的支持 @@ -72,6 +74,8 @@ netwatcher能够追踪TCP、UDP、ICMP协议数据包从应用程序发出开始 - dropreason.h :skb_drop_reason定义77种丢包原因。 - icmp.bpf.h: icmp时延具体实现细节。 - comm.bpf.h :辅助函数、宏、BPF映射、以及内核中使用到的结构体。 +- mysql,bpf.h : 处理mysql的具体实现逻辑。 +- mysql_helper.bpf : mysql相关数据结构。 ## 二、快速开始 ### 2.1 安装依赖 @@ -98,13 +102,25 @@ sudo make test # 测试 ```bash Usage: netwatcher [OPTION...] Watch tcp/ip in network subsystem +Usage: netwatcher [OPTION...] +Watch tcp/ip in network subsystem + -a, --all set to trace CLOSED connection + -A, --stack set to trace of stack -d, --dport=DPORT trace this destination port only + -D, --dns set to trace dns information info include Id + 事务ID、Flags 标志字段、Qd + 问题部分计数、An 应答记录计数、Ns + 授权记录计数、Ar 附加记录计数、Qr + 域名、rx 收发包 -e, --err set to trace TCP error packets -i, --http set to trace http info -I, --icmptime set to trace layer time of icmp -k, --drop_reason trace kfree -L, --timeload analysis time load + -M, --mysql set to trace mysql information info include Pid + 进程id、Comm 进程名、Size + sql语句字节大小、Sql 语句 -n, --net_filter trace ipv4 packget filter -r, --retrans set to trace extra retrans info -s, --sport=SPORT trace this source port only @@ -114,6 +130,7 @@ Watch tcp/ip in network subsystem -u, --udp trace the udp message -x, --extra set to trace extra conn info -?, --help Give this help list + --usage Give a short usage message ``` - 参数`-d`,`-s`用于指定监控某个源端口/目的端口 @@ -149,6 +166,8 @@ Watch tcp/ip in network subsystem - 指定 `-I` 参数监控ICMP协议数据包收发过程中的时延。 - 指定 `-T` 参数将捕获到的丢包事件虚拟地址转换成函数名+偏移量形式。 - 指定 `-L` 参数监测网络协议栈数据包经过各层的时延,采用指数加权移动法对异常的时延数据进行监控并发出警告信息。 +- 指定 `-D` 参数监测DNS协议包信息。截取UDP包,对DNS协议包进行解析,获取其基本指标,包含事务ID、标志字段、问题部分计数、应答记录计数、域名等相关信息。 +- 指定 `-M` 参数监测Mysql信息。实现用户态下mysql监控,获取其sql语句及sql执行耗时,单位μs。 ### 3.1 监控连接信息 `netwatcher`会将保存在内存中的连接相关信息实时地在`data/connects.log`中更新。默认情况下,为节省资源消耗,`netwatcher`会实时删除已CLOSED的TCP连接相关信息,并只会保存每个TCP连接的基本信息。 @@ -194,30 +213,34 @@ packet{sock="0xffff9d1ecb3ba300",seq="279168002",ack="629372873",mac_time="-",ip ```c sudo ./netwatcher -t -SOCK SEQ ACK MAC_TIME IP_TIME TRAN_TIME RX HTTP -0xffffa069b1271200 3401944293 1411917682 4 15 15 0 - -0xffffa06982943600 537486036 4194537197 16 14 123 1 - -0xffffa06982943600 537486036 4194537197 16 14 130 1 - -0xffffa06982946c00 3341452281 1920160519 3 13 12 0 - +SOCK Saddr Sport Daddr Dport MAC_TIME/μs IP_TIME/μs TRAN_TIME/μs RX/direction HTTP +0xffff939118a9ad00 192.168.60.136 36236 1.1.1.1 80 2 5 11 0 - +0xffff939118a9ad00 1.1.1.1 80 192.168.60.136 36236 6 10 111 1 - +0xffff93911049b600 192.168.60.136 36244 1.1.1.1 80 6 18 38 0 - +0xffff93911049b600 1.1.1.1 80 192.168.60.136 36244 14 17 263 1 - +0xffff93911049ad00 192.168.60.136 36246 1.1.1.1 80 2 4 16 0 - ``` 指定参数`-u`,查看UDP数据包处理时延并记录于`data/udp.log`中,单位为微妙。 ```c sudo ./netwatcher -u -saddr daddr sprot dprot udp_time rx len -192.168.60.2 192.168.60.136 38151 53 7 1 119 -192.168.60.2 192.168.60.136 36524 53 5 1 89 +Saddr Daddr Sprot Dprot udp_time/μs RX/direction len/byte +192.168.60.136 192.168.60.2 53643 53 2 0 39 +192.168.60.136 192.168.60.2 34272 53 3 0 42 +192.168.60.2 192.168.60.136 53 53643 12 1 230 +192.168.60.136 192.168.60.2 34442 53 1 0 40 +192.168.60.2 192.168.60.136 53 59996 2 1 190 ``` 指定参数`-I`,查看ICMP数据包处理时延,单位为微妙。 ```c sudo ./netwatcher -I -saddr daddr time flag -192.168.60.136 192.168.60.136 11 1 -192.168.60.136 192.168.60.136 5 0 -192.168.60.136 192.168.60.136 80 1 +Saddr Daddr icmp_time/μs RX/direction +192.168.60.136 192.168.60.136 11 1 +192.168.60.136 192.168.60.136 5 0 +192.168.60.136 192.168.60.136 80 1 ``` 指定参数`-n`,查看数据包在Netfilter框架(包括PRE_ROUTING、LOCAL_IN、FORWARD、LOCAL_OUT、POST_ROUTING链中处理的时间),单位为微妙,其网络数据包路径为: @@ -228,11 +251,11 @@ saddr daddr time flag ```c sudo ./netwatcher -n -saddr daddr dprot sprot PreRT L_IN FW PostRT L_OUT rx -192.168.60.136 192.168.60.1 22 51729 0 0 0 2 3 0 -192.168.60.136 192.168.60.1 22 51729 0 0 0 1 3 0 -127.0.0.1 127.0.0.1 771 10787 2 2 0 0 0 1 -127.0.0.1 127.0.0.1 771 15685 2 2 0 0 0 1 +Saddr Daddr Sprot Dprot PreRT/μs L_IN/μs FW/μs PostRT/μs L_OUT/μs RX/direction +127.0.0.53 127.0.0.1 53 60590 3 2 0 0 0 1 +127.0.0.1 127.0.0.1 55858 40327 0 0 0 2 4 0 +127.0.0.1 127.0.0.1 55858 40327 1 1 0 0 0 1 +127.0.0.1 127.0.0.1 40327 55858 0 0 0 1 5 0 ``` #### 3.2.2 监控错误数据包 @@ -249,9 +272,11 @@ packet{sock="0xffff13235ac8ac8e",seq="1318124482",ack="2468218244",reason="Inval ```c sudo ./netwatcher -i -SOCK SEQ ACK MAC_TIME IP_TIME TCP_TIME RX HTTP -0xffff9d1ecb3b9180 3705894662 522176002 - - - 0 GET / HTTP/1.1 -0xffff9d1ecb3b9180 522176002 3705894739 - - - 1 HTTP/1.1 200 OK +SOCK Saddr Sport Daddr Dport MAC_TIME/μs IP_TIME/μs TRAN_TIME/μs RX/direction HTTP +0xffff93911049d100 192.168.60.136 44152 1.1.1.1 80 0 0 0 0 0 - +0xffff93911049d100 1.1.1.1 80 192.168.60.136 44152 0 0 0 1 1 HTTP/1.1 301 Moved Permanently +0xffff9391601a6c00 192.168.60.136 44154 1.1.1.1 80 0 0 0 0 0 - +0xffff9391601a6c00 1.1.1.1 80 192.168.60.136 44154 0 0 0 1 1 HTTP/1.1 301 Moved Permanently ``` #### 3.2.3 过滤指定目的端口、源端口 @@ -266,9 +291,10 @@ sudo ./netwatcher -d 80 或者 sudo ./netwatcher -s 80 ```C sudo ./netwatcher -S -saddr daddr sport dport oldstate newstate time -192.168.60.136 1.1.1.1 41586 80 FIN_WAIT1 FIN_WAIT2 386 -192.168.60.136 1.1.1.1 41586 80 FIN_WAIT2 CLOSE 19 +Saddr Daddr Sport Dport oldstate newstate time/μs +192.168.60.136 1.1.1.1 0 80 CLOSE SYN_SENT 0 +192.168.60.136 1.1.1.1 41312 80 SYN_SENT ESTABLISHED 181270 +192.168.60.136 1.1.1.1 41312 80 ESTABLISHED FIN_WAIT1 183729 ``` #### 3.2.5 捕捉丢包及原因 @@ -277,18 +303,20 @@ saddr daddr sport dport oldstate newstate time ```c sudo ./netwatcher -k -time saddr daddr sprot dprot prot addr -reason -14:45:11 127.0.0.1 127.0.0.1 51162 36623 ipv4 ffffffff920fbf89 SKB_DROP_REASON_TCP_OLD_DATA +Time Saddr Daddr Sprot Dprot prot addr reason +13:44:03 1.1.1.1 192.168.60.136 80 49668 ipv4 ffffffff9c914464 SKB_DROP_REASON_NOT_SPECIFIED +13:44:03 1.1.1.1 192.168.60.136 80 49680 ipv4 ffffffff9c914464 SKB_DROP_REASON_NOT_SPECIFIED ``` -指定参数`-T`,可以将虚拟地址转换成函数名+偏移的形式,在此处可以捕捉发生丢包的内核函数名称。 +指定参数`-k -T`,可以将虚拟地址转换成函数名+偏移的形式,在此处可以捕捉发生丢包的内核函数名称。 ```C sudo ./netwatcher -k -T -time saddr daddr sprot dprot prot addr reason -14:48:54 192.168.60.136 192.168.60.136 45828 8090 ipv4 tcp_v4_rcv+0x84 SKB_DROP_REASON_NO_SOCKET -14:49:04 118.105.115.105 110.103.32.49 26210 24435 other unix_dgram_sendmsg+0x521 SKB_DROP_REASON_NOT_SPECIFIED +Time Saddr Daddr Sprot Dprot prot addr reason +13:44:22 1.1.1.1 192.168.60.136 80 37078 ipv4 tcp_v4_rcv+0x84 SKB_DROP_REASON_NOT_SPECIFIED +13:44:22 1.1.1.1 192.168.60.136 80 37092 ipv4 tcp_v4_rcv+0x84 SKB_DROP_REASON_NOT_SPECIFIED +13:44:24 1.1.1.1 192.168.60.136 80 37104 ipv4 tcp_v4_rcv+0x84 SKB_DROP_REASON_NOT_SPECIFIED +13:44:24 1.1.1.1 192.168.60.136 80 37118 ipv4 tcp_v4_rcv+0x84 SKB_DROP_REASON_NOT_SPECIFIED ``` #### 3.2.7 异常时延监控 @@ -297,8 +325,38 @@ time saddr daddr sprot dprot prot addr ```C sudo ./netwatcher -t -L -saddr daddr sprot dprot udp_time rx len -127.0.0.1 127.0.0.53 44530 53 1593 0 51 abnoermal data +SOCK Saddr Sport Daddr Dport MAC_TIME/μs IP_TIME/μs TRAN_TIME/μs RX/direction HTTP +0xffff939118a9c800 192.168.60.136 53788 1.1.1.1 80 2 4 20 0 - +0xffff939118a9c800 1.1.1.1 80 192.168.60.136 53788 14 22 345 1 - +0xffff9391601a7500 192.168.60.136 53790 1.1.1.1 80 3 11 31 0 - +0xffff9391601a7500 1.1.1.1 80 192.168.60.136 53790 22 37 170 1 - +0xffff9391107dec00 113.137.56.223 443 192.168.60.136 34104 11 10 1442 1 abnormal data +``` + +#### 3.2.8 DNS协议包监控 + +选择`udp_rcv`和`udp_send_skb`挂载捕获DNS收包和发包相关信息,从UDP头部开始分析并定位DNS数据部分获取其信息,头部信息存储在`query.header`,数据部分读取存储于`data`,可以获取到DNS协议包的事务ID、标志字段、问题部分计数、应答记录计数、授权记录计数、附加记录计数、域名等信息。 + +```C +sudo ./netwatcher -D +Saddr Daddr Id Flags Qd An Ns Ar Qr RX/direction +192.168.60.2 192.168.60.136 0x7894 0x8180 1 2 0 0 baidu.com 0 +127.0.0.53 0.0.0.0 0xc247 0x8180 1 2 0 1 baidu.com 1 +127.0.0.1 127.0.0.53 0x7637 0x120 1 0 0 1 contile.services.mozilla.com 1 +192.168.60.136 192.168.60.2 0x2c35 0x100 1 0 0 0 contile.services.mozilla.com 1 +``` + +#### 3.2.9 Mysql监控 + +利用uprobe和uretprobe挂载mysql-server层的命令分发处理函数`dispatch_command`,探测该函数获取进程pid、进程名comm、sql语句、sql执行耗时(μs)。 + +```C +sudo ./netwatcher -M +Pid Comm Size Sql duration/μs +1121 connection 32 select @@version_comment limit 1 295 +1121 connection 17 SELECT DATABASE() 277 +1121 connection 14 show databases 1361 +1121 connection 11 show tables 1080 ``` ### 3.3 与Prometheus连接进行可视化 diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h index 1ad6d1771..9fa88f752 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h @@ -102,6 +102,11 @@ struct dns_query { char data[64];// 可变长度数据(域名+类型+类) }; +struct dns{ + u32 saddr; + u32 daddr; +}; + // 操作BPF映射的一个辅助函数 static __always_inline void * //__always_inline强制内联 bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { @@ -148,6 +153,11 @@ struct { __uint(max_entries, 256 * 1024); } netfilter_rb SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} mysql_rb SEC(".maps"); + struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); @@ -224,12 +234,44 @@ struct { __type(value, __u64); } tcp_state SEC(".maps"); +//sql 耗时 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256*1024); + __type(key, __u32); + __type(value, __u64); +} mysql_time SEC(".maps"); + +//sql请求数 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key,__u32); + __type(value,__u64); +} sql_count SEC(".maps"); + +//dns计数根据每个saddr、daddr +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key,struct dns); + __type(value,__u64); +} dns_request_count SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key,struct dns); + __type(value,__u64); +} dns_response_count SEC(".maps"); + const volatile int filter_dport = 0; const volatile int filter_sport = 0; const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info =0,net_filter = 0, - drop_reason = 0,icmp_info = 0 ,tcp_info = 0 ,dns_info = 0 ,stack_info = 0; - + drop_reason = 0,icmp_info = 0 ,tcp_info = 0 ,dns_info = 0 ,stack_info = 0, + mysql_info = 0, redis_info; + /* help macro */ #define FILTER \ diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log b/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log index 733723688..e69de29bb 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/data/connects.log @@ -1 +0,0 @@ -connection{pid="214827",sock="0xffff944e0c3dda00",src="192.168.239.132:35422",dst="20.189.173.1:443",is_server="0",backlog="-",maxbacklog="-",cwnd="-",ssthresh="-",sndbuf="-",wmem_queued="-",rx_bytes="-",tx_bytes="-",srtt="-",duration="-",total_retrans="-",fast_retrans="-",timeout_retrans="-"} diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h new file mode 100644 index 000000000..cff8c950f --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h @@ -0,0 +1,90 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// mysql + +#include "common.bpf.h" +#include "mysql_helper.bpf.h" +static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { + // dispatch_command(THD *thd, const COM_DATA *com_data, enum + char comm[16]; + enum enum_server_command command = PT_REGS_PARM3(ctx); + union COM_DATA *com_data = (union COM_DATA *)PT_REGS_PARM2(ctx); + + pid_t pid = bpf_get_current_pid_tgid() >> 32; + pid_t tid = bpf_get_current_pid_tgid(); + void *thd = (void *)PT_REGS_PARM1(ctx); + char *sql; + u32 size = 0; + + if (command != COM_QUERY) { + return 0; + } + + u64 start_time = bpf_ktime_get_ns() / 1000; + bpf_map_update_elem(&mysql_time, &pid, &start_time, BPF_ANY); + + struct mysql_query *message = + bpf_ringbuf_reserve(&mysql_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + + bpf_probe_read(&message->size, sizeof(message->size), + &com_data->com_query.length); + bpf_probe_read_str(&sql, sizeof(sql), &com_data->com_query.query); + bpf_probe_read_str(&message->msql, sizeof(message->msql), sql); + + message->pid = pid; + message->tid = tid; + bpf_get_current_comm(&message->comm, sizeof(comm)); + + bpf_ringbuf_submit(message, 0); + + return 0; +} + +static __always_inline int __handle_mysql_end(struct pt_regs *ctx) { + + pid_t pid = bpf_get_current_pid_tgid() >> 32; + pid_t tid = bpf_get_current_pid_tgid(); + u64 *start_time_ptr, duration; + u64 end_time = bpf_ktime_get_ns() / 1000; + start_time_ptr = bpf_map_lookup_elem(&mysql_time, &pid); + if (!start_time_ptr) { + return 0; + } + + duration = end_time - *start_time_ptr; + struct mysql_query *message = + bpf_ringbuf_reserve(&mysql_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + u64 *count_ptr, count = 1; + count_ptr = bpf_map_lookup_elem(&sql_count, &tid); + if (count_ptr) { + count = *count_ptr + 1; + } + message->count = count; + bpf_map_update_elem(&sql_count, &tid, &count, BPF_ANY); + + message->duratime = duration; + + bpf_ringbuf_submit(message, 0); + bpf_map_delete_elem(&mysql_time, &pid); + + return 0; +} diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql_helper.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql_helper.bpf.h new file mode 100644 index 000000000..222764e1c --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql_helper.bpf.h @@ -0,0 +1,171 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// netwatcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __MYSQL_HELPER_BPF_H +#define __MYSQL_HELPER_BPF_H + +#include "netwatcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +enum enum_server_command { + COM_SLEEP, + COM_QUIT, + COM_INIT_DB, + COM_QUERY, + COM_FIELD_LIST, + COM_CREATE_DB, + COM_DROP_DB, + COM_REFRESH, + COM_SHUTDOWN, + COM_STATISTICS, + COM_PROCESS_INFO, + COM_CONNECT, + COM_PROCESS_KILL, + COM_DEBUG, + COM_PING, + COM_TIME, + COM_DELAYED_INSERT, + COM_CHANGE_USER, + COM_BINLOG_DUMP, + COM_TABLE_DUMP, + COM_CONNECT_OUT, + COM_REGISTER_SLAVE, + COM_STMT_PREPARE, + COM_STMT_EXECUTE, + COM_STMT_SEND_LONG_DATA, + COM_STMT_CLOSE, + COM_STMT_RESET, + COM_SET_OPTION, + COM_STMT_FETCH, + COM_DAEMON, + COM_BINLOG_DUMP_GTID, + COM_RESET_CONNECTION, + /* don't forget to update const char *command_name[] in sql_parse.cc */ + /* Must be last */ + COM_END +}; + +typedef struct st_com_init_db_data { + const char *db_name; + unsigned long length; +} COM_INIT_DB_DATA; + +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) + +#define LOCK_MODE_MASK 0xFUL +#define LOCK_TYPE_MASK 0xF0UL + +enum mysql_enum_shutdown_level { + SHUTDOWN_DEFAULT = 0, + SHUTDOWN_WAIT_CONNECTIONS = MYSQL_SHUTDOWN_KILLABLE_CONNECT, + SHUTDOWN_WAIT_TRANSACTIONS = MYSQL_SHUTDOWN_KILLABLE_TRANS, + SHUTDOWN_WAIT_UPDATES = MYSQL_SHUTDOWN_KILLABLE_UPDATE, + SHUTDOWN_WAIT_ALL_BUFFERS = (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + SHUTDOWN_WAIT_CRITICAL_BUFFERS = (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + KILL_QUERY = 254, + KILL_CONNECTION = 255 +}; + +typedef struct st_com_refresh_data { + unsigned char options; +} COM_REFRESH_DATA; + +typedef struct st_com_shutdown_data { + enum mysql_enum_shutdown_level level; +} COM_SHUTDOWN_DATA; + +typedef struct st_com_kill_data { + unsigned long id; +} COM_KILL_DATA; + +typedef struct st_com_set_option_data { + unsigned int opt_command; +} COM_SET_OPTION_DATA; + +typedef struct st_com_stmt_execute_data { + unsigned long stmt_id; + unsigned long flags; + unsigned char *params; + unsigned long params_length; +} COM_STMT_EXECUTE_DATA; + +typedef struct st_com_stmt_fetch_data { + unsigned long stmt_id; + unsigned long num_rows; +} COM_STMT_FETCH_DATA; + +typedef struct st_com_stmt_send_long_data_data { + unsigned long stmt_id; + unsigned int param_number; + unsigned char *longdata; + unsigned long length; +} COM_STMT_SEND_LONG_DATA_DATA; + +typedef struct st_com_stmt_prepare_data { + const char *query; + unsigned int length; +} COM_STMT_PREPARE_DATA; + +typedef struct st_stmt_close_data { + unsigned int stmt_id; +} COM_STMT_CLOSE_DATA; + +typedef struct st_com_stmt_reset_data { + unsigned int stmt_id; +} COM_STMT_RESET_DATA; + +typedef struct st_com_query_data { + const char *query; + unsigned int length; +} COM_QUERY_DATA; + +typedef struct st_com_field_list_data { + unsigned char *table_name; + unsigned int table_name_length; + const unsigned char *query; + unsigned int query_length; +} COM_FIELD_LIST_DATA; + +union COM_DATA { + COM_INIT_DB_DATA com_init_db; + COM_REFRESH_DATA com_refresh; + COM_SHUTDOWN_DATA com_shutdown; + COM_KILL_DATA com_kill; + COM_SET_OPTION_DATA com_set_option; + COM_STMT_EXECUTE_DATA com_stmt_execute; + COM_STMT_FETCH_DATA com_stmt_fetch; + COM_STMT_SEND_LONG_DATA_DATA com_stmt_send_long_data; + COM_STMT_PREPARE_DATA com_stmt_prepare; + COM_STMT_CLOSE_DATA com_stmt_close; + COM_STMT_RESET_DATA com_stmt_reset; + COM_QUERY_DATA com_query; + COM_FIELD_LIST_DATA com_field_list; +}; + +/* help functions end */ + +#endif diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index f0fead939..3a76a9a39 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -28,6 +28,10 @@ #include "udp.bpf.h" +#include "mysql.bpf.h" + +#include "redis.bpf.h" + #include "drop.bpf.h" // accecpt an TCP connection @@ -102,7 +106,9 @@ int BPF_KPROBE(eth_type_trans, struct sk_buff *skb) { /** in only ipv4 */ SEC("kprobe/ip_rcv_core") // 跟踪记录ipv4数据包在内核中的处理时间 -int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { return __ip_rcv_core(skb); } +int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { + return __ip_rcv_core(skb); +} /** in only ipv6 */ SEC("kprobe/ip6_rcv_core") int BPF_KPROBE(ip6_rcv_core, struct sk_buff *skb) { @@ -111,11 +117,15 @@ int BPF_KPROBE(ip6_rcv_core, struct sk_buff *skb) { /**in only ipv4 */ // 接收数据包 SEC("kprobe/tcp_v4_rcv") // 记录数据包在tcpv4层时间戳 -int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { return __tcp_v4_rcv(skb); } +int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { + return __tcp_v4_rcv(skb); +} /** in only ipv6 */ SEC("kprobe/tcp_v6_rcv") // 接收tcpv6数据包 -int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { return __tcp_v6_rcv(skb); } +int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { + return __tcp_v6_rcv(skb); +} // v4 & v6 do_rcv to get sk and other info SEC("kprobe/tcp_v4_do_rcv") @@ -288,10 +298,14 @@ int BPF_KPROBE(ip_forward, struct sk_buff *skb) { // drop SEC("tp/skb/kfree_skb") -int tp_kfree(struct trace_event_raw_kfree_skb *ctx) { return __tp_kfree(ctx); } +int tp_kfree(struct trace_event_raw_kfree_skb *ctx) { + return __tp_kfree(ctx); +} SEC("kprobe/icmp_rcv") -int BPF_KPROBE(icmp_rcv, struct sk_buff *skb) { return __icmp_time(skb); } +int BPF_KPROBE(icmp_rcv, struct sk_buff *skb) { + return __icmp_time(skb); +} SEC("kprobe/__sock_queue_rcv_skb") int BPF_KPROBE(__sock_queue_rcv_skb, struct sock *sk, struct sk_buff *skb) { @@ -306,6 +320,21 @@ int BPF_KPROBE(icmp_reply, struct icmp_bxm *icmp_param, struct sk_buff *skb) { // tcpstate SEC("tracepoint/sock/inet_sock_set_state") int handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { - return __handle_set_state(ctx); } + +// mysql +SEC("uprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") +int BPF_KPROBE(query__start) { + return __handle_mysql_start(ctx); +} + +SEC("uretprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") +int BPF_KPROBE(query__end){ + return __handle_mysql_end(ctx); +} + +SEC("uprobe/processCommand") +int BPF_KPROBE(query__start_redis) { + return __handle_redis_start(ctx); +} \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index e2b5c3d09..cbe4a5765 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -43,7 +43,8 @@ static int sport = 0, dport = 0; // for filter static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, - time_load = 0, dns_info = 0, stack_info=0; // flag + time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, + redis_info = 0 ,count_info = 0;// flag static const char *tcp_states[] = { [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", @@ -54,7 +55,6 @@ static const char *tcp_states[] = { }; static const char argp_program_doc[] = "Watch tcp/ip in network subsystem \n"; - static const struct argp_option opts[] = { {"all", 'a', 0, 0, "set to trace CLOSED connection"}, {"err", 'e', 0, 0, "set to trace TCP error packets"}, @@ -74,8 +74,14 @@ static const struct argp_option opts[] = { {"dns", 'D', 0, 0, "set to trace dns information info include Id 事务ID、Flags 标志字段、Qd " "问题部分计数、An 应答记录计数、Ns 授权记录计数、Ar 附加记录计数、Qr " - "域名、rx 收发包 "}, + "域名、rx 收发包 、Qc请求数、Sc响应数"}, {"stack", 'A', 0, 0, "set to trace of stack "}, + {"mysql", 'M', 0, 0, + "set to trace mysql information info include Pid 进程id、Comm " + "进程名、Size sql语句字节大小、Sql 语句"}, + {"redis", 'R', 0, 0}, + {"count", 'C', "NUMBER", 0, + "specify the time to count the number of requests"}, {}}; static error_t parse_arg(int key, char *arg, struct argp_state *state) { @@ -132,6 +138,15 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'A': stack_info = 1; break; + case 'M': + mysql_info = 1; + break; + case 'R': + redis_info = 1; + break; + case 'C': + count_info = strtoul(arg, &end, 10); + break; default: return ARGP_ERR_UNKNOWN; } @@ -156,6 +171,8 @@ enum MonitorMode { MODE_ICMP, MODE_TCP, MODE_DNS, + MODE_MYSQL, + MODE_REDIS, MODE_DEFAULT }; @@ -172,7 +189,12 @@ enum MonitorMode get_monitor_mode() { return MODE_TCP; } else if (dns_info) { return MODE_DNS; - } else { + } else if (mysql_info) { + return MODE_MYSQL; + } else if (redis_info) { + return MODE_REDIS; + } + else { return MODE_DEFAULT; } } @@ -212,7 +234,38 @@ void print_logo() { pclose(lolcat_pipe); } - +static char binary_path[64]=""; +#define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ + do { \ + LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ + .retprobe = is_retprobe); \ + skel->links.prog_name = bpf_program__attach_uprobe_opts( \ + skel->progs.prog_name, -1, binary_path, 0, &uprobe_opts); \ + } while (false) + +#define __CHECK_PROGRAM(skel, prog_name) \ + do { \ + if (!skel->links.prog_name) { \ + perror("no program attached for " #prog_name); \ + return -errno; \ + } \ + } while (false) + +#define __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, is_retprobe) \ + do { \ + __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe); \ + __CHECK_PROGRAM(skel, prog_name); \ + } while (false) + +#define ATTACH_UPROBE(skel, sym_name, prog_name) \ + __ATTACH_UPROBE(skel, sym_name, prog_name, false) +#define ATTACH_URETPROBE(skel, sym_name, prog_name) \ + __ATTACH_UPROBE(skel, sym_name, prog_name, true) + +#define ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name) \ + __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, false) +#define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) \ + __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, true) struct SymbolEntry symbols[300000]; int num_symbols = 0; // 定义快表 @@ -316,6 +369,9 @@ struct LayerDelayInfo { #define GRANULARITY 3 #define ALPHA 0.2 // 衰减因子 #define MAXTIME 10000 +#define SLOW_QUERY_THRESHOLD 10000 // +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_RESET "\x1b[0m" // 全局变量用于存储每层的移动平均值 float ewma_values[NUM_LAYERS] = {0}; @@ -369,6 +425,8 @@ static void set_rodata_flags(struct netwatcher_bpf *skel) { skel->rodata->icmp_info = icmp_info; skel->rodata->dns_info = dns_info; skel->rodata->stack_info = stack_info; + skel->rodata->mysql_info = mysql_info; + skel->rodata->redis_info = redis_info; } static void set_disable_load(struct netwatcher_bpf *skel) { @@ -502,6 +560,12 @@ static void set_disable_load(struct netwatcher_bpf *skel) { bpf_program__set_autoload(skel->progs.icmp_reply, icmp_info ? true : false); bpf_program__set_autoload(skel->progs.handle_set_state, tcp_info ? true : false); + bpf_program__set_autoload(skel->progs.query__start, + mysql_info ? true : false); + bpf_program__set_autoload(skel->progs.query__end, + mysql_info ? true : false); + bpf_program__set_autoload(skel->progs.query__start_redis, + redis_info ? true : false); } static void print_header(enum MonitorMode mode) { @@ -550,9 +614,26 @@ static void print_header(enum MonitorMode mode) { "====================DNS " "INFORMATION====================================================" "============================\n"); - printf("%-20s %-20s %-12s %-12s %-5s %-5s %-5s %-5s %-47s %5s \n", + printf("%-20s %-20s %-12s %-12s %-5s %-5s %-5s %-5s %-47s %-10s %-10s " + "%-10s \n", "Saddr", "Daddr", "Id", "Flags", "Qd", "An", "Ns", "Ar", "Qr", - "RX/direction"); + "Qc", "Sc", "RX/direction"); + break; + case MODE_MYSQL: + printf("===============================================================" + "====================MYSQL " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-40s %-20s %-20s \n", "Pid", "Tid", + "Comm", "Size", "Sql", "Duration/μs", "Request"); + break; + case MODE_REDIS: + printf("===============================================================" + "====================MYSQL " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-40s %-20s \n", "Pid", "Comm", "Size", "Sql", + "duration/μs"); break; case MODE_DEFAULT: printf("===============================================================" @@ -702,7 +783,7 @@ static int print_conns(struct netwatcher_bpf *skel) { static int print_packet(void *ctx, void *packet_info, size_t size) { if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || - dns_info) + dns_info || mysql_info||redis_info) return 0; const struct pack_t *pack_info = packet_info; if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || @@ -827,7 +908,8 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { const struct udp_message *pack_info = packet_info; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; - if(pack_info->tran_time > MAXTIME||(daddr & 0x0000FFFF) == 0x0000007F || (saddr & 0x0000FFFF) == 0x0000007F) + if (pack_info->tran_time > MAXTIME || (daddr & 0x0000FFFF) == 0x0000007F || + (saddr & 0x0000FFFF) == 0x0000007F) return 0; printf("%-20s %-20s %-20u %-20u %-20llu %-20d %-20d", inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), @@ -866,6 +948,9 @@ static int print_netfilter(void *ctx, void *packet_info, size_t size) { return 0; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; + // if ((daddr & 0x0000FFFF) == 0x0000007F || + // (saddr & 0x0000FFFF) == 0x0000007F) + // return 0; printf("%-20s %-20s %-12d %-12d %-8lld %-8lld% -8lld %-8lld %-8lld %-8d", inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, @@ -976,6 +1061,7 @@ static int print_icmptime(void *ctx, void *packet_info, size_t size) { printf("\n"); return 0; } + // 从DNS数据包中提取并打印域名 static void print_domain_name(const unsigned char *data, char *output) { const unsigned char *next = data; @@ -1011,55 +1097,97 @@ static int print_dns(void *ctx, void *packet_info, size_t size) { inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)); print_domain_name((const unsigned char *)pack_info->data, domain_name); - - printf("%-20s %-20s %-#12x %-#12x %-5x %-5x %-5x %-5x %-47s %-10d\n", + if (pack_info->daddr == 0) { + return 0; + } + printf("%-20s %-20s %-#12x %-#12x %-5x %-5x %-5x %-5x %-47s %-10d %-10d " + "%-10d \n", s_str, d_str, pack_info->id, pack_info->flags, pack_info->qdcount, pack_info->ancount, pack_info->nscount, pack_info->arcount, - domain_name, pack_info->rx); - + domain_name, pack_info->request_count, pack_info->response_count, + pack_info->rx); return 0; } +static mysql_query last_query; + +static int print_mysql(void *ctx, void *packet_info, size_t size) { + if (!mysql_info) { + return 0; + } + + const mysql_query *pack_info = packet_info; + if (pack_info->duratime == 0) { + + memcpy(&last_query, pack_info, sizeof(mysql_query)); + } else { + printf("%-20d %-20d %-20s %-20u %-40s", last_query.pid, last_query.tid, + last_query.comm, last_query.size, last_query.msql); + // 当 duratime 大于 count_info 时,才打印 duratime + if (pack_info->duratime > count_info) { + printf("%-21llu", pack_info->duratime); + } else { + printf("%-21s", ""); + } + + printf("%-20d\n", pack_info->count); + memset(&last_query, 0, sizeof(mysql_query)); + } + return 0; +} static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { return vfprintf(stderr, format, args); } -static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) -{ +static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { int i; printf("-----------------------------------\n"); - for (i = 1; i < stack_sz; i++) { - if(addr_to_func) - { - struct SymbolEntry data= findfunc(stack[i]); + for (i = 1; i < stack_sz; i++) { + if (addr_to_func) { + struct SymbolEntry data = findfunc(stack[i]); char result[40]; sprintf(result, "%s+0x%llx", data.name, stack[i] - data.addr); - printf("%-10d [<%016llx>]=%s\n", i, stack[i], result); - } - else - { + printf("%-10d [<%016llx>]=%s\n", i, stack[i], result); + } else { printf("%-10d [<%016llx>]\n", i, stack[i]); } - } + } printf("-----------------------------------\n"); } -static int print_trace(void *_ctx, void *data, size_t size) -{ +static int print_trace(void *_ctx, void *data, size_t size) { struct stacktrace_event *event = data; - if (event->kstack_sz <= 0 && event->ustack_sz <= 0) - return 1; + if (event->kstack_sz <= 0 && event->ustack_sz <= 0) + return 1; - printf("COMM: %s (pid=%d) @ CPU %d\n", event->comm, event->pid, event->cpu_id); + printf("COMM: %s (pid=%d) @ CPU %d\n", event->comm, event->pid, + event->cpu_id); - if (event->kstack_sz > 0) { - printf("Kernel:\n"); - show_stack_trace(event->kstack, event->kstack_sz / sizeof(__u64), 0); - } else { - printf("No Kernel Stack\n"); - } - printf("\n"); - return 0; + if (event->kstack_sz > 0) { + printf("Kernel:\n"); + show_stack_trace(event->kstack, event->kstack_sz / sizeof(__u64), 0); + } else { + printf("No Kernel Stack\n"); + } + printf("\n"); + return 0; +} + +int attach_uprobe_mysql(struct netwatcher_bpf *skel) { + + ATTACH_UPROBE_CHECKED( + skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, + query__start); + ATTACH_URETPROBE_CHECKED( + skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, + query__end); + return 0; +} +int attach_uprobe_redis(struct netwatcher_bpf *skel) { + ATTACH_UPROBE_CHECKED( + skel, processCommand, + query__start_redis); + return 0; } int main(int argc, char **argv) { char *last_slash = strrchr(argv[0], '/'); @@ -1082,6 +1210,7 @@ int main(int argc, char **argv) { struct ring_buffer *tcp_rb = NULL; struct ring_buffer *dns_rb = NULL; struct ring_buffer *trace_rb = NULL; + struct ring_buffer *mysql_rb = NULL; struct netwatcher_bpf *skel; int err; /* Parse command line arguments */ @@ -1116,14 +1245,35 @@ int main(int argc, char **argv) { } /* Attach tracepoint handler */ - err = netwatcher_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto cleanup; + if (mysql_info) { + strcpy(binary_path, "/usr/sbin/mysqld"); + err = attach_uprobe_mysql(skel); + if (err) { + fprintf(stderr, "failed to attach uprobes\n"); + + goto cleanup; + } + } + else if(redis_info) + { + strcpy(binary_path, "/usr/bin/redis-server"); + err = attach_uprobe_redis(skel); + if (err) { + fprintf(stderr, "failed to attach uprobes\n"); + + goto cleanup; + } + } + else { + err = netwatcher_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } } enum MonitorMode mode = get_monitor_mode(); - print_logo(); + //print_logo(); print_header(mode); @@ -1169,12 +1319,20 @@ int main(int argc, char **argv) { fprintf(stderr, "Failed to create ring buffer(dns)\n"); goto cleanup; } - trace_rb =ring_buffer__new(bpf_map__fd(skel->maps.trace_rb), print_trace, NULL, NULL); + trace_rb = ring_buffer__new(bpf_map__fd(skel->maps.trace_rb), print_trace, + NULL, NULL); if (!trace_rb) { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } + mysql_rb = ring_buffer__new(bpf_map__fd(skel->maps.mysql_rb), print_mysql, + NULL, NULL); + if (!mysql_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; + } /* Set up ring buffer polling */ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); if (!rb) { @@ -1195,6 +1353,7 @@ int main(int argc, char **argv) { err = ring_buffer__poll(tcp_rb, 100 /* timeout, ms */); err = ring_buffer__poll(dns_rb, 100 /* timeout, ms */); err = ring_buffer__poll(trace_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(mysql_rb, 100 /* timeout, ms */); print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h index 4a36a807e..de8aa5e7a 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h @@ -155,16 +155,29 @@ struct dns_information { u16 arcount; char data[64]; int rx; + int response_count; + int request_count; }; #define MAX_STACK_DEPTH 128 typedef u64 stack_trace_t[MAX_STACK_DEPTH]; struct stacktrace_event { - u32 pid; - u32 cpu_id; - char comm[16]; - signed int kstack_sz; - signed int ustack_sz; - stack_trace_t kstack; - stack_trace_t ustack; + u32 pid; + u32 cpu_id; + char comm[16]; + signed int kstack_sz; + signed int ustack_sz; + stack_trace_t kstack; + stack_trace_t ustack; }; + +typedef struct mysql_query { + int pid; + int tid; + char comm[20]; + u32 size; + char msql[256]; + u64 duratime; + int count; +} mysql_query; + #endif /* __NETWATCHER_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h new file mode 100644 index 000000000..66ef4364b --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h @@ -0,0 +1,60 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// mysql + +#include "common.bpf.h" +#include "redis_helper.bpf.h" +#define MAXEPOLL 10 +static __always_inline int __handle_redis_start(struct pt_regs *ctx) { + struct client *cli = (struct client *)PT_REGS_PARM1(ctx); + int argc; + void *ptr; + char name[100]=""; + int argv_len; + bpf_probe_read(&argc, sizeof(argc), &cli->argc); + bpf_printk("%d",argc); + robj **arg0; + robj *arg1; + //unsigned type; + unsigned encoding; + unsigned lru; + int refcount; + bpf_probe_read(&arg0, sizeof(arg0), &cli->argv); + + // 读取 argv[0],即第一个命令参数 + bpf_probe_read(&arg1, sizeof(arg1), &arg0[0]); + + for(int i=0;iptr 中的字符串 + bpf_probe_read(&ptr, sizeof(ptr),&arg1->ptr); + bpf_probe_read_str(name, sizeof(name),ptr); + bpf_printk("%s",name); + } + // 读取 argv[0]->ptr 中的字符串 + bpf_probe_read(&ptr, sizeof(ptr),&arg1->ptr); + bpf_probe_read_str(name, sizeof(name),ptr); + + + bpf_probe_read(&argv_len, sizeof(argv_len), &cli->argv_len_sum); + + bpf_printk("%d",argv_len); + + pid_t pid = bpf_get_current_pid_tgid() >> 32; + return 0; +} + diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h new file mode 100644 index 000000000..21f2031f7 --- /dev/null +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis_helper.bpf.h @@ -0,0 +1,55 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// netwatcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __REDIS_HELPER_BPF_H +#define __REDIS_HELPER_BPF_H + +#include "netwatcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +#define LRU_BITS 24 +typedef struct redisObject { + unsigned type:4; + unsigned encoding:4; + unsigned lru:24; + int refcount; + void *ptr; +} robj; + +struct client { + u64 id; /* Client incremental unique ID. */ + u64 conn; + int resp; /* RESP protocol version. Can be 2 or 3. */ + u64 db; /* Pointer to currently SELECTed DB. */ + robj *name; /* As set by CLIENT SETNAME. */ + char* querybuf; /* Buffer we use to accumulate client queries. */ + unsigned long qb_pos; /* The position we have read in querybuf. */ + char* pending_querybuf; + unsigned long querybuf_peak; /* Recent (100ms or more) peak of querybuf size. */ + int argc; /* Num of arguments of current command. */ + robj **argv; /* Arguments of current command. */ + unsigned long argv_len_sum; /* Size of argv array (may be more than argc) */ +}; + +#endif diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h index af739e859..d39da361d 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/udp.bpf.h @@ -123,7 +123,8 @@ static __always_inline int __ip_send_skb(struct sk_buff *skb) { static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { if (skb == NULL) return 0; - + u16 QR_flags; + u64 *count_ptr, response_count = 0, request_count = 0; struct sock *sk = BPF_CORE_READ(skb, sk); struct packet_tuple pkt_tuple = { .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), @@ -131,6 +132,8 @@ static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { .sport = BPF_CORE_READ(sk, __sk_common.skc_num), .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), .tran_flag = UDP}; + // 使用saddr、daddr作为key + struct dns key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr}; if ((pkt_tuple.sport != 53) && (pkt_tuple.dport != 53)) return 0; @@ -151,7 +154,39 @@ static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { bpf_probe_read_kernel(message->data, sizeof(message->data), BPF_CORE_READ(skb, head) + dns_offset + sizeof(struct dns_header)); - + QR_flags = __bpf_ntohs(query.header.flags); + /* + 1000 0000 0000 0000 + &运算提取最高位QR, QR=1 Response QR=0 Request + */ + if (QR_flags & 0x8000) { // 响应 + count_ptr = bpf_map_lookup_elem(&dns_response_count, &key); + if (count_ptr) { + response_count = *count_ptr + 1; + } else { + response_count = 1; + } + bpf_map_update_elem(&dns_response_count, &key, &response_count, + BPF_ANY); + // 保留映射中的请求计数值 + count_ptr = bpf_map_lookup_elem(&dns_request_count, &key); + if (count_ptr) { + request_count = *count_ptr; + } + } else { // 请求 + count_ptr = bpf_map_lookup_elem(&dns_request_count, &key); + if (count_ptr) { + request_count = *count_ptr + 1; + } else { + request_count = 1; + } + bpf_map_update_elem(&dns_request_count, &key, &request_count, BPF_ANY); + // 保留映射中的响应计数值 + count_ptr = bpf_map_lookup_elem(&dns_response_count, &key); + if (count_ptr) { + response_count = *count_ptr; + } + } message->saddr = rx ? pkt_tuple.saddr : pkt_tuple.daddr; message->daddr = rx ? pkt_tuple.daddr : pkt_tuple.saddr; message->id = __bpf_ntohs(query.header.id); @@ -160,6 +195,8 @@ static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { message->ancount = __bpf_ntohs(query.header.ancount); message->nscount = __bpf_ntohs(query.header.nscount); message->arcount = __bpf_ntohs(query.header.arcount); + message->request_count = request_count; + message->response_count = response_count; message->rx = rx; bpf_ringbuf_submit(message, 0); diff --git a/eBPF_Supermarket/Stack_Analyser/Makefile b/eBPF_Supermarket/Stack_Analyser/Makefile index 0b17426e8..83731b94e 100644 --- a/eBPF_Supermarket/Stack_Analyser/Makefile +++ b/eBPF_Supermarket/Stack_Analyser/Makefile @@ -104,7 +104,7 @@ $(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT) $(BPF_SKEL): $(Q)mkdir -p $@ # Build libbpf -$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf +$(LIBBPF_OBJ): $(LIBBPF_SRC) $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf $(call msg,LIB,$@) $(Q)$(MAKE) -C $(LIBBPF_SRC) BUILD_STATIC_ONLY=1 \ OBJDIR=$(dir $@)/libbpf DESTDIR=$(dir $@) \ @@ -112,7 +112,7 @@ $(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPU install # Build bpftool -$(BPFTOOL): | $(BPFTOOL_OUTPUT) +$(BPFTOOL): $(BPFTOOL_SRC) | $(BPFTOOL_OUTPUT) $(call msg,BPFTOOL,$@) $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap diff --git a/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h b/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h index 44ba9e125..56ea5549d 100644 --- a/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h +++ b/eBPF_Supermarket/Stack_Analyser/include/sa_ebpf.h @@ -20,6 +20,7 @@ #define STACK_ANALYZER_EBPF #include "sa_common.h" +#include #define PF_KTHREAD 0x00200000 @@ -79,6 +80,9 @@ #define TS bpf_ktime_get_ns() +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) +#define CHECK_FREQ(_ts) +#else /* 内置函数: bool __atomic_compare_exchange_n ( @@ -113,6 +117,7 @@ __ATOMIC_RELAXED, __ATOMIC_RELAXED)) \ return 0; \ } +#endif #define GET_CURR \ (struct task_struct *)bpf_get_current_task() @@ -129,9 +134,15 @@ #define GET_KNODE(_task) \ BPF_CORE_READ(_task, cgroups, dfl_cgrp, kn) +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) +#define CHECK_CGID(_knode) \ + if (target_cgroupid > 0 && BPF_CORE_READ(_knode, id.id) != target_cgroupid) \ + return 0; +#else #define CHECK_CGID(_knode) \ if (target_cgroupid > 0 && BPF_CORE_READ(_knode, id) != target_cgroupid) \ return 0; +#endif #define TRY_SAVE_INFO(_task, _pid, _tgid, _knode) \ if (!bpf_map_lookup_elem(&pid_info_map, &_pid)) \ diff --git a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp index ee599ec51..d3aa81547 100644 --- a/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp +++ b/eBPF_Supermarket/Stack_Analyser/src/bpf_wapper/eBPFStackCollector.cpp @@ -24,6 +24,7 @@ #include #include #include +#include std::string getLocalDateTime(void) { @@ -53,25 +54,44 @@ std::vector *StackCollector::sortedCountList(void) auto val_size = bpf_map__value_size(psid_count_map); auto value_fd = bpf_object__find_map_fd_by_name(obj, "psid_count_map"); + auto D = new std::vector(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) + for (psid prev_key = {0}, curr_key = {0};; prev_key = curr_key) + { + if (bpf_map_get_next_key(value_fd, &prev_key, &curr_key)) + { + if (errno != ENOENT) + perror("map get next key error"); + break; // no more keys, done + } + if (showDelta) + bpf_map_delete_elem(value_fd, &prev_key); + char val[val_size]; + memset(val, 0, val_size); + if (bpf_map_lookup_elem(value_fd, &curr_key, &val)) + { + if (errno != ENOENT) + { + perror("map lookup error"); + break; + } + continue; + } + CountItem d(curr_key, count_values(val)); + D->insert(std::lower_bound(D->begin(), D->end(), d), d); + } +#else auto keys = new psid[MAX_ENTRIES]; auto vals = new char[MAX_ENTRIES * val_size]; uint32_t count = MAX_ENTRIES; psid next_key; int err; if (showDelta) - { err = bpf_map_lookup_and_delete_batch(value_fd, NULL, &next_key, keys, vals, &count, NULL); - } else - { err = bpf_map_lookup_batch(value_fd, NULL, &next_key, keys, vals, &count, NULL); - } if (err == EFAULT) - { return NULL; - } - - auto D = new std::vector(); for (uint32_t i = 0; i < count; i++) { CountItem d(keys[i], count_values(vals + val_size * i)); @@ -79,6 +99,7 @@ std::vector *StackCollector::sortedCountList(void) } delete[] keys; delete[] vals; +#endif return D; }; diff --git a/eBPF_Supermarket/kvm_watcher/docs/Visualization_conf.md b/eBPF_Supermarket/kvm_watcher/docs/Visualization_conf.md index 318b8755e..043259e7e 100644 --- a/eBPF_Supermarket/kvm_watcher/docs/Visualization_conf.md +++ b/eBPF_Supermarket/kvm_watcher/docs/Visualization_conf.md @@ -110,6 +110,7 @@ make start_service #进入lmp/eBPF_Visualization/eBPF_prometheus目录,执行以下操作 #开启ebpf程序,并且向8090端口推送ebpf程序采集的数据,发送给prometheus服务端 #这里以监测vcpu调度的数据来举例: +#目前-e、-o、-i、-f -m功能的数据格式已经适配了可视化工具,请读者使用以上四种功能的数据来进行可视化展示 ./data-visual collect lmp/eBPF_Supermarket/kvm_watcher/kvm_watcher -o -p [进程号] ``` diff --git a/eBPF_Supermarket/kvm_watcher/docs/grafana_kvm_watcher_dashboard.json b/eBPF_Supermarket/kvm_watcher/docs/grafana_kvm_watcher_dashboard.json new file mode 100644 index 000000000..166cc6917 --- /dev/null +++ b/eBPF_Supermarket/kvm_watcher/docs/grafana_kvm_watcher_dashboard.json @@ -0,0 +1,522 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 5, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"DELAY(us)\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "mmio_delay", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"DELAY\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "irq_delay", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"MAX_TIME\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"min_time\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"max_time\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "C", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"total_time\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "D", + "useBackend": false + } + ], + "title": "vcpu_load", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"MAX_TIME\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"MIN_TIME\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "cdncx8i00775sa" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bpf_metrics{bpf_out_data=\"TOTAL_TIME\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "vm_exit", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "123123", + "uid": "edonx3cyzyyv4d", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c index daf3c22d7..1d08fb50f 100644 --- a/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c +++ b/eBPF_Supermarket/kvm_watcher/src/kvm_watcher.c @@ -566,6 +566,12 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { } case PAGE_FAULT: { // 使用 e->page_fault_data 访问 PAGE_FAULT 特有成员 + if (env.show) { + printf("%-18.6f %-10u %-6u %-10.4f\n", timestamp_ms, + e->process.pid, e->page_fault_data.count, + NS_TO_US_WITH_DECIMAL(e->page_fault_data.delay)); + break; + } printf("%-18.6f %-15s %-10u %-12llx %-6u %-10.4f ", timestamp_ms, e->process.comm, e->process.pid, e->page_fault_data.addr, e->page_fault_data.count, @@ -670,11 +676,19 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { break; } case IRQ_INJECT: { - printf("%-18.6f %-15s %-10d %-10lld %#-10x %-10d %-10lld %-10s\n", - timestamp_ms, e->process.comm, e->process.pid, - e->irq_inject_data.delay, e->irq_inject_data.irq_nr, - e->irq_inject_data.vcpu_id, e->irq_inject_data.injections, - e->irq_inject_data.soft ? "Soft/INTn" : "IRQ"); + if (env.show) { + printf("%-18.6f %-10d %-10lld %-10d %-10d %-10lld\n", + timestamp_ms, e->process.pid, e->irq_inject_data.delay, + e->irq_inject_data.irq_nr, e->irq_inject_data.vcpu_id, + e->irq_inject_data.injections); + } else { + printf( + "%-18.6f %-15s %-10d %-10lld %#-10x %-10d %-10lld %-10s\n", + timestamp_ms, e->process.comm, e->process.pid, + e->irq_inject_data.delay, e->irq_inject_data.irq_nr, + e->irq_inject_data.vcpu_id, e->irq_inject_data.injections, + e->irq_inject_data.soft ? "Soft/INTn" : "IRQ"); + } break; } case HYPERCALL: { @@ -758,18 +772,29 @@ static int print_event_head(struct env *env) { "USERSPACE_ADDR", "SLOT_ID"); break; case PAGE_FAULT: - printf("%-18s %-15s %-10s %-12s %-6s %-10s %-20s %-17s %-10s %s\n", - "TIME(ms)", "COMM", "PID", "GPA", "COUNT", "DELAY(us)", - "HVA", "PFN", "MEM_SLOTID", "ERROR_TYPE"); + if (env->show) { + printf("%-18s %-10s %-6s %-10s \n", "TIME(ms)", "PID", "COUNT", + "DELAY(us)"); + } else { + printf( + "%-18s %-15s %-10s %-12s %-6s %-10s %-20s %-17s %-10s %s\n", + "TIME(ms)", "COMM", "PID", "GPA", "COUNT", "DELAY(us)", + "HVA", "PFN", "MEM_SLOTID", "ERROR_TYPE"); + } break; case IRQCHIP: printf("%-18s %-15s %-10s %-10s %-14s %-10s %-10s\n", "TIME(ms)", "COMM", "PID", "DELAY", "TYPE/PIN", "DST/VEC", "OTHERS"); break; case IRQ_INJECT: - printf("%-18s %-15s %-10s %-10s %-10s %-10s %-10s %-10s\n", - "TIME(ms)", "COMM", "PID", "DELAY", "IRQ_NR", "VCPU_ID", - "INJECTIONS", "TYPE"); + if (env->show) { + printf("%-18s %-10s %-10s %-10s %-10s %-10s \n", "TIME(ms)", + "PID", "DELAY", "IRQ_NR", "VCPU_ID", "INJECTIONS"); + } else { + printf("%-18s %-15s %-10s %-10s %-10s %-10s %-10s %-10s\n", + "TIME(ms)", "COMM", "PID", "DELAY", "IRQ_NR", "VCPU_ID", + "INJECTIONS", "TYPE"); + } break; case HYPERCALL: { printf("Waiting hypercall ... \n"); @@ -1202,9 +1227,6 @@ int main(int argc, char **argv) { struct ring_buffer *rb = NULL; struct kvm_watcher_bpf *skel; int err; - //可视化调整输出格式 - // print_logo(); - /*解析命令行参数*/ err = argp_parse(&argp, argc, argv, 0, NULL, NULL); if (err) @@ -1256,6 +1278,8 @@ int main(int argc, char **argv) { fprintf(stderr, "Invalid env parm\n"); goto cleanup; } + if (!env.show) + print_logo(); /*打印信息头*/ err = print_event_head(&env);