From 1fd1f5ec3d668048e798ab007e5c237c9ea83296 Mon Sep 17 00:00:00 2001 From: Zhangxinyi <643470801@qq.com> Date: Fri, 22 Mar 2024 11:56:43 +0800 Subject: [PATCH 1/8] =?UTF-8?q?cpu=5Fwatcher=EF=BC=9A=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=8A=A2=E5=8D=A0=E6=97=B6=E9=97=B4=E5=8A=9F=E8=83=BD=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CPU_Subsystem/cpu_watcher/Makefile | 2 +- .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 77 ++++++++++++++++++- .../CPU_Subsystem/cpu_watcher/cpu_watcher.h | 10 ++- .../CPU_Subsystem/cpu_watcher/preempt.bpf.c | 57 ++++++++++++++ 4 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 eBPF_Supermarket/CPU_Subsystem/cpu_watcher/preempt.bpf.c diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile index b9e0c6140..4dc2ab6ba 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/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 =cs_delay sar sc_delay +APPS =cs_delay sar sc_delay preempt TARGETS=cpu_watcher diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index ff3f117fa..81b851a32 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -29,6 +29,7 @@ #include "sar.skel.h" #include "cs_delay.skel.h" #include "sc_delay.skel.h" +#include "preempt.skel.h" typedef long long unsigned int u64; typedef unsigned int u32; @@ -38,6 +39,7 @@ static struct env { bool SAR; bool CS_DELAY; bool SYSCALL_DELAY; + bool PREEMPT; int freq; } env = { .time = 0, @@ -45,12 +47,14 @@ static struct env { .SAR = false, .CS_DELAY = false, .SYSCALL_DELAY = false, + .PREEMPT=false, .freq = 99, }; struct cs_delay_bpf *cs_skel; struct sar_bpf *sar_skel; struct sc_delay_bpf *sc_skel; +struct preempt_bpf *preempt_skel; u64 softirq = 0;//初始化softirq; u64 irqtime = 0;//初始化irq; @@ -67,6 +71,10 @@ int sc_min_time = SYSCALL_MIN_TIME ; int sys_call_count = 0; +int preempt_count = 0 ; +int sum_preemptTime = 0 ; +int preempt_start_print = 0 ; + /*设置传参*/ const char argp_program_doc[] ="cpu wacher is in use ....\n"; static const struct argp_option opts[] = { @@ -74,6 +82,7 @@ static const struct argp_option opts[] = { {"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)"}, { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, {0}, }; @@ -93,6 +102,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'S': env.SYSCALL_DELAY = true; break; + case 'p': + env.PREEMPT = true; + break; case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); break; @@ -400,6 +412,15 @@ static int syscall_delay_print(void *ctx, void *data,unsigned long data_sz) e->pid,e->comm,e->syscall_id,e->delay); return 0; } +//抢占时间输出 +static int preempt_print(void *ctx, void *data, unsigned long data_sz) +{ + const struct preempt_event *e = data; + printf("%-16s %-7d %-7d %-11llu\n", e->comm, e->prev_pid, e->next_pid, e->duration); + preempt_count++; + sum_preemptTime += e->duration; + return 0; +} int main(int argc, char **argv) { @@ -458,6 +479,31 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to create ring buffer\n"); goto cs_delay_cleanup; } + }else if (env.PREEMPT) { + preempt_skel = preempt_bpf__open(); + if (!preempt_skel) { + fprintf(stderr, "Failed to open and load BPF skeleton\n"); + return 1; + } + + err = preempt_bpf__load(preempt_skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto preempt_cleanup; + } + + err = preempt_bpf__attach(preempt_skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto preempt_cleanup; + } + + rb = ring_buffer__new(bpf_map__fd(preempt_skel->maps.rb), preempt_print, NULL, NULL); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto preempt_cleanup; + } }else if (env.SYSCALL_DELAY){ /* Load and verify BPF application */ sc_skel = sc_delay_bpf__open(); @@ -560,8 +606,32 @@ int main(int argc, char **argv) printf("----------------------------------------------------------------------------------------------------------\n"); sleep(1); } + else if (env.PREEMPT) { + err = ring_buffer__poll(rb, 100 /* timeout, ms */); + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + time_t now = time(NULL); + struct tm *localTime = localtime(&now); + if (!preempt_start_print) { + preempt_start_print = 1; + } else { + printf("----------------------------------------------------------------------------------------------------------\n"); + printf("\nAverage_preempt_Time: %8d ns\n", sum_preemptTime / preempt_count); + } + printf("\nTime: %02d:%02d:%02d\n", localTime->tm_hour, localTime->tm_min, localTime->tm_sec); + printf("%-12s %-8s %-8s %11s\n", "COMM", "prev_pid", "next_pid", "duration_ns"); + preempt_count = 0; + sum_preemptTime = 0; + sleep(2); + } else { - printf("正在开发中......\n-c 打印cs_delay:\t对内核函数schedule()的执行时长进行测试;\n-s sar工具;\n-S 打印sc_delay:\t系统调用运行延迟进行检测; \n"); + printf("正在开发中......\n-c 打印cs_delay:\t对内核函数schedule()的执行时长进行测试;\n-s sar工具;\n-y 打印sc_delay:\t系统调用运行延迟进行检测; \n-p 打印preempt_time:\t对抢占调度时间输出;\n"); break; } } @@ -579,4 +649,9 @@ int main(int argc, char **argv) ring_buffer__free(rb); sc_delay_bpf__destroy(sc_skel); return err < 0 ? -err : 0; + +preempt_cleanup: + ring_buffer__free(rb); + preempt_bpf__destroy(preempt_skel); + return err < 0 ? -err : 0; } diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h index 126580054..f4f622ffa 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h @@ -112,7 +112,15 @@ struct syscall_events {//每个进程一个 u64 delay; u64 syscall_id; }; - +/*----------------------------------------------*/ +/* preempt_event结构体 */ +/*----------------------------------------------*/ +struct preempt_event{ + pid_t prev_pid; + pid_t next_pid; + unsigned long long duration; + char comm[TASK_COMM_LEN]; +}; /*----------------------------------------------*/ /* cswch_args结构体 */ /*----------------------------------------------*/ diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/preempt.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/preempt.bpf.c new file mode 100644 index 000000000..0abbbc781 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/preempt.bpf.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "cpu_watcher.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +#define TIF_NEED_RESCHED 3 + +// 记录时间戳 +BPF_HASH(preemptTime, pid_t, u64, 4096); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +SEC("tp_btf/sched_switch") +int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { + u64 start_time = bpf_ktime_get_ns(); + pid_t prev_pid = BPF_CORE_READ(prev, pid); + + if (preempt) { + bpf_map_update_elem(&preemptTime, &prev_pid, &start_time, BPF_ANY); + } + + // 下面的代码被注释掉,因为我们使用`preempt`参数判断是否需要记录时间戳 + // if (prev->thread_info.flags & TIF_NEED_RESCHED) { + // bpf_map_update_elem(&preemptTime, &prev_pid, &start_time, BPF_ANY); + // } + + return 0; +} + +SEC("kprobe/finish_task_switch") +int BPF_KPROBE(finish_task_switch, struct task_struct *prev) { + u64 end_time = bpf_ktime_get_ns(); + pid_t pid = BPF_CORE_READ(prev, pid); + u64 *val; + val = bpf_map_lookup_elem(&preemptTime, &pid); + if (val) { + u64 delta = end_time - *val; + struct preempt_event *e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) { + return 0; + } + e->prev_pid = pid; + e->next_pid = bpf_get_current_pid_tgid() >> 32; + e->duration = delta; + bpf_get_current_comm(&e->comm, sizeof(e->comm)); + bpf_ringbuf_submit(e, 0); + bpf_map_delete_elem(&preemptTime, &pid); + } + + return 0; +} From 1d33d8de95bfd5b18a8c325b343db40244ce0272 Mon Sep 17 00:00:00 2001 From: Zhangxinyi <643470801@qq.com> Date: Fri, 22 Mar 2024 12:28:44 +0800 Subject: [PATCH 2/8] =?UTF-8?q?cpu=5Fwatcher:=E6=B7=BB=E5=8A=A0=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E5=BB=B6=E8=BF=9F=E6=95=B0=E6=8D=AE=E9=87=87=E9=9B=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CPU_Subsystem/cpu_watcher/Makefile | 2 +- .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 93 +++++++++-- .../CPU_Subsystem/cpu_watcher/cpu_watcher.h | 21 +++ .../cpu_watcher/schedule_delay.bpf.c | 150 ++++++++++++++++++ 4 files changed, 251 insertions(+), 15 deletions(-) create mode 100644 eBPF_Supermarket/CPU_Subsystem/cpu_watcher/schedule_delay.bpf.c diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile index 4dc2ab6ba..a1757cf4b 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/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 =cs_delay sar sc_delay preempt +APPS =cs_delay sar sc_delay preempt schedule_delay TARGETS=cpu_watcher diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index 81b851a32..1c8926ccd 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -30,31 +30,37 @@ #include "cs_delay.skel.h" #include "sc_delay.skel.h" #include "preempt.skel.h" +#include "schedule_delay.skel.h" typedef long long unsigned int u64; typedef unsigned int u32; + static struct env { - int time; - bool enable_proc; - bool SAR; - bool CS_DELAY; - bool SYSCALL_DELAY; - bool PREEMPT; - int freq; + int time; + bool enable_proc; + bool SAR; + bool CS_DELAY; + bool SYSCALL_DELAY; + bool PREEMPT; + bool SCHEDULE_DELAY; + int freq; } env = { - .time = 0, - .enable_proc = false, - .SAR = false, - .CS_DELAY = false, - .SYSCALL_DELAY = false, - .PREEMPT=false, - .freq = 99, + .time = 0, + .enable_proc = false, + .SAR = false, + .CS_DELAY = false, + .SYSCALL_DELAY = false, + .PREEMPT = false, + .SCHEDULE_DELAY = false, + .freq = 99 }; + struct cs_delay_bpf *cs_skel; struct sar_bpf *sar_skel; struct sc_delay_bpf *sc_skel; struct preempt_bpf *preempt_skel; +struct schedule_delay_bpf *sd_skel; u64 softirq = 0;//初始化softirq; u64 irqtime = 0;//初始化irq; @@ -83,6 +89,7 @@ static const struct argp_option opts[] = { {"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)"}, { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, {0}, }; @@ -105,6 +112,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'p': env.PREEMPT = true; break; + case 'd': + env.SCHEDULE_DELAY = true; + break; case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); break; @@ -422,6 +432,29 @@ static int preempt_print(void *ctx, void *data, unsigned long data_sz) return 0; } +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; + } + avg_delay = info.sum_delay/info.sum_count; + + printf("%02d:%02d:%02d | %-15lf %-15lf %-15lf |\n", + hour,min,sec,avg_delay/1000.0,info.max_delay/1000.0,info.min_delay/1000.0); + return 0; +} + int main(int argc, char **argv) { struct ring_buffer *rb = NULL; @@ -532,6 +565,23 @@ int main(int argc, char **argv) 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"); + return 1; + } + err = schedule_delay_bpf__load(sd_skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\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 min_delay/μs"); }else if (env.SAR){ /* Load and verify BPF application */ sar_skel = sar_bpf__open(); @@ -630,6 +680,17 @@ int main(int argc, char **argv) sum_preemptTime = 0; sleep(2); } + else if (env.SCHEDULE_DELAY){ + err = schedule_print(sd_skel->maps.sys_schedule); + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + break; + } + sleep(1); + } else { printf("正在开发中......\n-c 打印cs_delay:\t对内核函数schedule()的执行时长进行测试;\n-s sar工具;\n-y 打印sc_delay:\t系统调用运行延迟进行检测; \n-p 打印preempt_time:\t对抢占调度时间输出;\n"); break; @@ -654,4 +715,8 @@ int main(int argc, char **argv) ring_buffer__free(rb); preempt_bpf__destroy(preempt_skel); return err < 0 ? -err : 0; + +schedule_cleanup: + schedule_delay_bpf__destroy(sd_skel); + return err < 0 ? -err : 0; } diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h index f4f622ffa..e21ef66cb 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h @@ -122,6 +122,27 @@ struct preempt_event{ char comm[TASK_COMM_LEN]; }; /*----------------------------------------------*/ +/* schedule_delay相关结构体 */ +/*----------------------------------------------*/ +//标识不同进程 +struct proc_id{ + int pid; + int cpu_id; +}; +//标识该进程的调度信息 +struct schedule_event{ + int pid; + int count;//调度次数 + unsigned long long enter_time; +}; +//整个系统所有调度信息 +struct sum_schedule{ + unsigned long long sum_count; + unsigned long long sum_delay; + unsigned long long max_delay; + unsigned long long min_delay; +}; +/*----------------------------------------------*/ /* cswch_args结构体 */ /*----------------------------------------------*/ struct cswch_args { diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/schedule_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/schedule_delay.bpf.c new file mode 100644 index 000000000..fda48bda6 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/schedule_delay.bpf.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include "cpu_watcher.h" + +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); + + +SEC("tp_btf/sched_wakeup") +int BPF_PROG(sched_wakeup, struct task_struct *p) { + pid_t pid = BPF_CORE_READ(p, pid); + int cpu = bpf_get_smp_processor_id(); + struct schedule_event *schedule_event; + struct proc_id id= {}; + u64 current_time = bpf_ktime_get_ns(); + id.pid = pid; + if (pid == 0) { + id.cpu_id = cpu; + } + schedule_event = bpf_map_lookup_elem(&enter_schedule, &id); + if (!schedule_event) { + struct schedule_event schedule_event1; + bool issched = false; + schedule_event1.pid = pid; + schedule_event1.count = 1; + schedule_event1.enter_time = current_time; + bpf_map_update_elem(&has_scheduled, &id, &issched, BPF_ANY); + bpf_map_update_elem(&enter_schedule, &id, &schedule_event1, BPF_ANY); + } else { + schedule_event->enter_time = current_time; + } + return 0; +} + +SEC("tp_btf/sched_wakeup_new") +int BPF_PROG(sched_wakeup_new, struct task_struct *p) { + pid_t pid = BPF_CORE_READ(p, pid); + int cpu = bpf_get_smp_processor_id(); + struct proc_id id= {}; + u64 current_time = bpf_ktime_get_ns(); + id.pid = pid; + if (pid == 0) { + id.cpu_id = cpu; + } + struct schedule_event schedule_event; + bool issched = false; + schedule_event.pid = pid; + schedule_event.count = 1; + schedule_event.enter_time = current_time; + bpf_map_update_elem(&has_scheduled, &id, &issched, BPF_ANY); + bpf_map_update_elem(&enter_schedule, &id, &schedule_event, BPF_ANY); + return 0; +} + +SEC("tp_btf/sched_switch") +int BPF_PROG(sched_switch, bool preempt, struct task_struct *prev, struct task_struct *next) { + u64 current_time = bpf_ktime_get_ns(); + pid_t prev_pid = prev->pid; + unsigned int prev_state = prev->__state; + int prev_cpu = bpf_get_smp_processor_id(); + pid_t next_pid = next->pid; + int next_cpu = bpf_get_smp_processor_id(); + bool *issched; + struct schedule_event *schedule_event; + struct sum_schedule *sum_schedule; + int key = 0; + struct proc_id next_id= {}; + u64 delay; + if (prev_state == TASK_RUNNING) { + 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 ; + bool issched = false; + schedule_event2.pid = prev_pid; + schedule_event2.count = 1; + schedule_event2.enter_time = current_time; + bpf_map_update_elem(&has_scheduled, &prev_pd, &issched, BPF_ANY); + bpf_map_update_elem(&enter_schedule, &prev_pd, &schedule_event2, BPF_ANY); + } else { + schedule_event->enter_time = current_time; + } + } + + next_id.pid = next_pid; + if (next_pid == 0) { + next_id.cpu_id = next_cpu; + } + schedule_event = bpf_map_lookup_elem(&enter_schedule, &next_id); + if (!schedule_event) return 0; + issched = bpf_map_lookup_elem(&has_scheduled, &next_id); + if (!issched) return 0; + if (*issched) { + schedule_event->count++; + } else { + *issched = true; + } + delay = current_time - schedule_event->enter_time; + sum_schedule = bpf_map_lookup_elem(&sys_schedule, &key); + if (!sum_schedule) { + struct sum_schedule sum_schedule= {}; + sum_schedule.sum_count++; + sum_schedule.sum_delay += delay; + if (delay > sum_schedule.max_delay) + sum_schedule.max_delay = delay; + if (sum_schedule.min_delay == 0 || delay < sum_schedule.min_delay) + sum_schedule.min_delay = delay; + 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) + sum_schedule->max_delay = delay; + if (sum_schedule->min_delay == 0 || delay < sum_schedule->min_delay) + sum_schedule->min_delay = delay; + } + return 0; +} + +SEC("tracepoint/sched/sched_process_exit") +int sched_process_exit(void *ctx) { + 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(); + struct proc_id id= {}; + struct schedule_event *schedule_event; + bool *issched; + int key = 0; + id.pid = pid; + if (pid == 0) id.cpu_id = cpu; + schedule_event = bpf_map_lookup_elem(&enter_schedule, &id); + if (schedule_event) { + bpf_map_delete_elem(&enter_schedule, &id); + } + issched = bpf_map_lookup_elem(&has_scheduled, &id); + if (issched) { + bpf_map_delete_elem(&has_scheduled, &id); + } + return 0; +} From e766da7e1b3ca157f727e115c2e5d5fb2e1c2778 Mon Sep 17 00:00:00 2001 From: vvzxy <145555693+vvzxy@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:45:54 +0800 Subject: [PATCH 3/8] Update cpu_watcher.c --- .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index 1c8926ccd..d5b890ac5 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -436,25 +436,26 @@ static int schedule_print(struct bpf_map *sys_fd) { int key = 0; struct sum_schedule info; - int err, fd = bpf_map__fd(sys_fd); + int err, fd = bpf_map__fd(sys_fd); time_t now = time(NULL); - struct tm *localTime = localtime(&now); + 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; - } - avg_delay = info.sum_delay/info.sum_count; - - printf("%02d:%02d:%02d | %-15lf %-15lf %-15lf |\n", - hour,min,sec,avg_delay/1000.0,info.max_delay/1000.0,info.min_delay/1000.0); + 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; + } + avg_delay = info.sum_delay / info.sum_count; + printf("%02d:%02d:%02d | %-15lf %-15lf %-15lf |\n", + hour, min, sec, avg_delay / 1000.0, info.max_delay / 1000.0, info.min_delay / 1000.0); return 0; } + int main(int argc, char **argv) { struct ring_buffer *rb = NULL; From 6d370f0b6298cc2c8c97c5eea64e39b45309d430 Mon Sep 17 00:00:00 2001 From: Zhangxinyi <643470801@qq.com> Date: Mon, 8 Apr 2024 16:19:42 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9runqlen=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=A0=88=E6=BA=A2=E5=87=BA=EF=BC=8C=E4=BD=BF=E5=85=B6=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 30 +++++++++++-------- .../CPU_Subsystem/cpu_watcher/sar.bpf.c | 16 ++-------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index 8c2beaf39..a2d72dfc5 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -249,15 +249,15 @@ static int print_all() __sched = sched_total - sched; sched = sched_total; - // /*runqlen:*/ - // int key_runqlen = 0;// 设置要查找的键值为0 - // int err_runqlen, fd_runqlen = bpf_map__fd(sar_skel->maps.runqlen);// 获取映射文件描述符 - // int runqlen;// 用于存储从映射中查找到的值 - // err_runqlen = bpf_map_lookup_elem(fd_runqlen, &key_runqlen, &runqlen); // 从映射中查找键为1的值 - // if (err_runqlen < 0) {//没找到 - // fprintf(stderr, "failed to lookup infos of runqlen: %d\n", err_runqlen); - // return -1; - // } + /*runqlen:*/ + int key_runqlen = 0;// 设置要查找的键值为0 + int err_runqlen, fd_runqlen = bpf_map__fd(sar_skel->maps.runqlen);// 获取映射文件描述符 + int runqlen;// 用于存储从映射中查找到的值 + err_runqlen = bpf_map_lookup_elem(fd_runqlen, &key_runqlen, &runqlen); // 从映射中查找键为1的值 + if (err_runqlen < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of runqlen: %d\n", err_runqlen); + return -1; + } /*irqtime:*/ int key_irqtime = 0; @@ -338,9 +338,13 @@ static int print_all() if(env.enable_proc){ time_t now = time(NULL); struct tm *localTime = localtime(&now); - printf("%02d:%02d:%02d %8llu %8llu %8llu %10llu %8llu %8llu %8llu %8lu %8lu\n", + //printf("%02d:%02d:%02d %8llu %8llu %8llu %10llu %8llu %8llu %8llu %8lu %8lu\n", + // localTime->tm_hour, localTime->tm_min, localTime->tm_sec, + // __proc,__sched,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000, + // dtaKT/1000,dtaSysc / 1000000,dtaUTRaw/1000000,dtaSys / 1000000); + printf("%02d:%02d:%02d %8llu %8llu %6d %8llu %10llu %8llu %10llu %8llu %8lu %8lu\n", localTime->tm_hour, localTime->tm_min, localTime->tm_sec, - __proc,__sched,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000, + __proc,__sched,runqlen,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000, dtaKT/1000,dtaSysc / 1000000,dtaUTRaw/1000000,dtaSys / 1000000); } else{ @@ -649,8 +653,8 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to attach BPF skeleton\n"); goto sar_cleanup; } - //printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms BpfCnt\n"); - printf(" time proc/s cswch/s irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms\n"); + printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms \n"); + //printf(" time proc/s cswch/s 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(); diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c index bbbbf8254..e58fa93b8 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c @@ -15,10 +15,8 @@ const volatile long long unsigned int forks_addr = 0; BPF_ARRAY(countMap,int,u64,3); // 记录开始的时间 BPF_ARRAY(procStartTime,pid_t,u64,4096); -// 储存运行队列rq的全局变量 -BPF_ARRAY(rq_map,u32,struct rq,1); //存储运行队列长度 -BPF_PERCPU_ARRAY(runqlen,u32,int,1); +BPF_ARRAY(runqlen,u32,int,4096); //记录软中断开始时间 BPF_HASH(softirqCpuEnterTime,u32,u64,4096); //记录软中断结束时间 @@ -109,17 +107,9 @@ int BPF_KPROBE(finish_task_switch,struct task_struct *prev){ //统计运行队列长度 SEC("kprobe/update_rq_clock") -int kprobe_update_rq_clock(struct pt_regs *ctx){ +int BPF_KPROBE(update_rq_clock,struct rq *rq){ u32 key = 0; - u32 rqkey = 0; - struct rq *p_rq = 0; - p_rq = (struct rq *)bpf_map_lookup_elem(&rq_map, &rqkey); - if (!p_rq) { - return 0; - } - bpf_probe_read_kernel(p_rq, sizeof(struct rq), (void *)PT_REGS_PARM1(ctx)); - //使用bpf_probe_read_kernel函数将内核空间中的数据复制到p_rq所指向的内存区域中,以便后续对该数据进行访问和操作。 - u64 val = p_rq->nr_running; + u64 val = BPF_CORE_READ(rq,nr_running); bpf_map_update_elem(&runqlen,&key,&val,BPF_ANY); return 0; } From 8ec67f61425fb104685f533be6a35650b6fae7e6 Mon Sep 17 00:00:00 2001 From: vvzxy <145555693+vvzxy@users.noreply.github.com> Date: Mon, 8 Apr 2024 16:23:18 +0800 Subject: [PATCH 5/8] Update cpu_watcher.c --- .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index a2d72dfc5..e5a07aef5 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -250,11 +250,11 @@ static int print_all() sched = sched_total; /*runqlen:*/ - int key_runqlen = 0;// 设置要查找的键值为0 - int err_runqlen, fd_runqlen = bpf_map__fd(sar_skel->maps.runqlen);// 获取映射文件描述符 - int runqlen;// 用于存储从映射中查找到的值 - err_runqlen = bpf_map_lookup_elem(fd_runqlen, &key_runqlen, &runqlen); // 从映射中查找键为1的值 - if (err_runqlen < 0) {//没找到 + int key_runqlen = 0; + int err_runqlen, fd_runqlen = bpf_map__fd(sar_skel->maps.runqlen); + int runqlen; + err_runqlen = bpf_map_lookup_elem(fd_runqlen, &key_runqlen, &runqlen); + if (err_runqlen < 0) { fprintf(stderr, "failed to lookup infos of runqlen: %d\n", err_runqlen); return -1; } @@ -338,10 +338,6 @@ static int print_all() if(env.enable_proc){ time_t now = time(NULL); struct tm *localTime = localtime(&now); - //printf("%02d:%02d:%02d %8llu %8llu %8llu %10llu %8llu %8llu %8llu %8lu %8lu\n", - // localTime->tm_hour, localTime->tm_min, localTime->tm_sec, - // __proc,__sched,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000, - // dtaKT/1000,dtaSysc / 1000000,dtaUTRaw/1000000,dtaSys / 1000000); printf("%02d:%02d:%02d %8llu %8llu %6d %8llu %10llu %8llu %10llu %8llu %8lu %8lu\n", localTime->tm_hour, localTime->tm_min, localTime->tm_sec, __proc,__sched,runqlen,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000, @@ -654,7 +650,6 @@ int main(int argc, char **argv) goto sar_cleanup; } printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms \n"); - //printf(" time proc/s cswch/s 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(); From 45cc33a6ec1d9636b18cf7699fbfb085749aafd9 Mon Sep 17 00:00:00 2001 From: vvzxy <145555693+vvzxy@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:02:42 +0800 Subject: [PATCH 6/8] Update sar.bpf.c --- eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c index e58fa93b8..4e48d49c7 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/sar.bpf.c @@ -16,7 +16,7 @@ BPF_ARRAY(countMap,int,u64,3); // 记录开始的时间 BPF_ARRAY(procStartTime,pid_t,u64,4096); //存储运行队列长度 -BPF_ARRAY(runqlen,u32,int,4096); +BPF_ARRAY(runqlen,u32,int,1); //记录软中断开始时间 BPF_HASH(softirqCpuEnterTime,u32,u64,4096); //记录软中断结束时间 From a1052cfd7e5123afef1c07407a42e5f5fb77689c Mon Sep 17 00:00:00 2001 From: vvzxy <145555693+vvzxy@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:44:13 +0800 Subject: [PATCH 7/8] Update README.md --- eBPF_Supermarket/CPU_Subsystem/README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/eBPF_Supermarket/CPU_Subsystem/README.md b/eBPF_Supermarket/CPU_Subsystem/README.md index 4c65c13f5..83ed4e616 100644 --- a/eBPF_Supermarket/CPU_Subsystem/README.md +++ b/eBPF_Supermarket/CPU_Subsystem/README.md @@ -342,7 +342,19 @@ eBPF_proc_image是基于eBPF的Linux系统性能监测工具-进程画像,通 | -A, --all | 开启所有的功能 | | -h, --help | 显示帮助信息 | -### 4. 调研及实现过程的文档 +### 4. cpu_watcher +`cpu_watcher`是一个用于监视系统 CPU 使用情况的工具,它可以帮助用户了解系统在不同负载下的性能表现,并提供详细的统计数据。该工具分为以下几个部分,通过不同的参数控制相关的`ebpf`捕获程序是否加载到内核中: + +| 参数 | 描述 | +| :----------------: | :----------------------------------------: | +| -s :SAR | 实时采集SAR的各项指标,每秒输出一次 | +| -p:preempt | 实时采集当前系统的每次抢占调度详细信息 | +| -d:schedule_delay | 实时采集当前系统的调度时延 | +| -S:syscall_delay | 实时采集当前系统调用时间 | +| -m:mq_delay | 实时采集当前消息队列通信时延 | +| -c:cs_delay | 实时对内核函数schedule()的执行时长进行测试 | + +### 5. 调研及实现过程的文档 位于docs目录下,由于编码兼容性原因,文件名为英文,但文件内容是中文。 From 32660db0a20a6580e18f2acb02fccae6c83e3ec8 Mon Sep 17 00:00:00 2001 From: Zhangxinyi <643470801@qq.com> Date: Wed, 10 Apr 2024 09:37:45 +0800 Subject: [PATCH 8/8] =?UTF-8?q?cpu=5Fwatcher=E9=A1=B9=E7=9B=AE=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0readme=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CPU_Subsystem/cpu_watcher/README.md | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 eBPF_Supermarket/CPU_Subsystem/cpu_watcher/README.md diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/README.md b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/README.md new file mode 100644 index 000000000..b4de8b930 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/README.md @@ -0,0 +1,225 @@ +# cpu_watcher:动态CPU指标实时监测 + +## 一、项目简介 + +​ `CPU_Watcher`是一项基于`eBPF(Extended Berkeley Packet Filter)`技术的项目,旨在实现对`CPU`各项指标的实时动态监测和分析,可以清晰且直观的了解CPU资源利用率以及事件的发生的速率。 + +​ 本工具使用ebpf工具进行实现,`eBPF`是`Linux`内核中的一种强大的工具,它允许在内核空间执行小型程序,用于在运行时过滤、转发和监控系统事件。 + +​ `CPU_Watcher`利用`eBPF`的这一特性,通过在内核空间执行精简的程序来捕获`CPU`相关的事件和指标,从而实现对`CPU`性能的实时监测和分析。 + +## 二、使用方法 + +### 1.使用环境 + +- OS:Ubuntu 22.04 +- kernel:Linux 6.2 + +### 2.编译运行 + +```shell +make 编译 +sudo ./cpu_watcher -[options] 运行 +make clean 清除生成文件 +``` + +## 三、功能介绍 + +​ `cpu_watcher`是一个用于监视系统 CPU 使用情况的工具,它可以帮助用户了解系统在不同负载下的性能表现,并提供详细的统计数据。该工具分为以下几个部分,通过不同的参数控制相关的`ebpf`捕获程序是否加载到内核中: + +| 参数 | 描述 | +| :----------------: | :----------------------------------------: | +| -s :SAR | 实时采集SAR的各项指标,每秒输出一次 | +| -p:preempt_time | 实时采集当前系统的每次抢占调度详细信息 | +| -d:schedule_delay | 实时采集当前系统的调度时延 | +| -S:syscall_delay | 实时采集当前系统调用时间 | +| -m:mq_delay | 实时采集当前消息队列通信时延 | +| -c:cs_delay | 实时对内核函数schedule()的执行时长进行测试 | + +### 1.SAR 统计功能(每秒输出一次): + +#### 输出效果: + +``` + time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms +16:18:03 29 1216 1 1277 19394 1087 2908 662 747 665 +16:18:04 43 2036 2 1262 24823 1432 3981 72 171 76 +16:18:05 0 1371 2 4927 16949 1152 2489 538 636 541 +16:18:06 11 2569 4 10900 9085 518 2967 941 1121 944 +16:18:07 3 5166 4 9929 15864 469 10778 482 1020 493 +16:18:08 30 2426 2 2436 17877 1435 5086 90 262 96 +16:18:09 43 1257 1 351 20457 1713 3040 8 40 11 +16:18:10 0 813 1 20071 30563 1727 117472 41 0 159 +16:18:11 0 751 1 748 14532 1855 3935 16 50 20 +16:18:12 0 1118 1 1115 20750 1733 1956 1 50 3 +16:18:13 29 1083 1 286 18081 1698 3861 50 10 54 +16:18:14 43 1032 1 577 19513 1704 3919 26 10 30 +``` + +对上述参数的解释: + +- `proc/s`: 每秒创建的进程数,此数值是通过fork数来统计的。 +- `cswch/s`: 每秒上下文切换数。 +- `runqlen`:此时CPU的运行队列的长度。 +- `irqTime/us`:CPU响应`irq`中断所占用的时间,是所有CPU时间的叠加。 +- `softirq/us`: CPU执行`softirq`所占用的时间,是所有CPU时间的叠加。 +- `idle/ms`: CPU处于空闲状态的时间,是所有CPU时间的叠加。 +- `kthread/us`: CPU执行内核线程所占用的时间,是所有CPU的叠加。不包括IDLE-0进程,因为此进程只执行空闲指令使CPU闲置。 +- `sysc/ms`: CPU执行用户程序系统调用(`syscall`)所占用的时间,是所有CPU的叠加。 +- ` utime/ms`:CPU执行普通用户进程时,花在用户态的时间,是所有CPU的叠加。 + +### **2.统计抢占调度时间:** + +​ 统计系统中发生抢占调度的情况,包括抢占进程的`pid`与进程名,以及被强占进程的`pid`,和本次抢占时间,单位纳秒。 + +#### 输出效果: + +``` +COMM prev_pid next_pid duration_ns +node 14221 2589 3014 +kworker/u256:1 15144 13516 1277 +node 14221 2589 3115 +kworker/u256:1 15144 13516 1125 +kworker/u256:1 15144 13516 974 +node 14221 2589 2560 +kworker/u256:1 15144 13516 1132 +node 14221 2589 2717 +kworker/u256:1 15144 13516 1206 +kworker/u256:1 15144 13516 1131 +node 14221 2589 3355 +``` + +### 3.**统计调度延迟:** + +​ 分析系统中进程调度的延迟情况,提供相关统计数据,输出包括当前系统的最大调度延迟、最小调度延迟、平均调度延迟。 + +#### 输出效果: + +``` + TIME avg_delay/μs max_delay/μs min_delay/μs +17:31:28 35.005000 97.663000 9.399000 +17:31:29 326.518000 12618.465000 7.994000 +17:31:30 455.837000 217053.545000 6.462000 +17:31:31 422.582000 217053.545000 6.462000 +17:31:32 382.627000 217053.545000 6.462000 +17:31:33 360.499000 217053.545000 6.462000 +17:31:34 364.805000 217053.545000 6.462000 +17:31:35 362.039000 217053.545000 6.462000 +17:31:36 373.751000 217053.545000 6.462000 +``` + +### 4.**统计系统调用响应时间:** + +​ 记录系统调用的响应时间,帮助用户评估系统对外部请求的处理效率, 其输出包括发起本次系统调用的进程的进程名、pid、系统调用号以及响应时间。 + +#### 输出效果: + +``` +Time Pid comm syscall_id delay/us +21:28:07 276073 cpu_watcher 1 21 +21:28:07 2579 node 0 7 +21:28:07 276073 cpu_watcher 4 8 +21:28:07 2579 node 232 6 +21:28:07 2579 node 0 6 +21:28:07 276073 cpu_watcher 1 22 +21:28:07 276073 cpu_watcher 4 8 +``` + +### 5.**统计消息队列延迟:** + +​ 统计进程间通过消息队列通信时,消息块从发送到接收的延迟情况,以便用户了解系统中进程间通信的效率和延迟,其输出内容包括发消息动作(mq_send)的延迟、接收消息动作(mq_receive)的延迟、消息块从发送到接收过程的延迟。 + +#### 输出效果: + +```c + Time Mqdes SND_PID RCV_PID SND_Delay/ms RCV_Delay/ms Delay/ms +21:40:36 3 281101 281167 0.02 0.02 2161.58542 +21:40:46 3 281432 281493 0.02 0.03 1373.68176 +21:40:52 3 281680 281741 0.03 0.05 1494.31408 +21:40:58 3 281909 281945 0.03 0.02 1434.06373 +21:41:01 3 282019 282088 0.03 0.02 1401.26321 +``` + +原理介绍: + +[lmp/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/docs/mq_delay功能介绍.md at develop · albertxu216/lmp (github.com)](https://github.com/albertxu216/lmp/blob/develop/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/docs/mq_delay功能介绍.md) + +### 6.对内核函数schedule()的执行时长进行测试 + +​ 统计每次调度的执行时间,可以输出本次调度的时间,单位为微秒,并用直方图展示汇总结果: + +#### 输出效果: + +``` +t1:4817139183 t2:4817139248 delay:65 +t1:4817139255 t2:4817139319 delay:64 +t1:4817139454 t2:4817139505 delay:51 +t1:4817139512 t2:4817139557 delay:45 +t1:4817139675 t2:4817139735 delay:60 +t1:4817139742 t2:4817139800 delay:58 +t1:4817139936 t2:4817139998 delay:62 +t1:4817140005 t2:4817140065 delay:60 +t1:4817140488 t2:4817140552 delay:64 +t1:4817140559 t2:4817140621 delay:62 +t1:4817140816 t2:4817140878 delay:62 +t1:4817141241 t2:4817141303 delay:62 +``` + +```c +Time : 21:46:45 +cs_delay Count Distribution +0 => 1 585 | +2 => 3 856 | +4 => 7 2271 |** +8 => 15 5792 |***** +16 => 31 8641 |******** +32 => 63 9762 |********* +64 => 127 2041 |** +128 => 255 2158 |** +256 => 511 2075 |** +512 => 1023 751 | +1024 => 2047 301 | +2048 => 4095 112 | +4096 => 8191 36 | +8192 => 16383 0 | +16384 => 32767 0 | +32768 => 65535 0 | +65536 => 131071 0 | +131072 => 262143 0 | +262144 => 524287 0 | +524288 => 1048575 0 | +per_len = 1000 +``` + + + +## 四、实现方式 + +### 1.使用kprobe捕获内核函数的参数 + +​ 使用kprobe、kretprobe捕获挂载的内核函数的参数,从参数中提取有效的数据。比如从finish_task_switch.isra.0内核函数的参数中拿取关于prev进程的相关信息。 + +### 2.使用内核提供的tracepoint捕获特定时间 + +​ 使用tracepoint捕获特定状态的开始和结束,计算持续时间。比如softirq运行时间就是通过内核提供的tracepoint计算的。 + +### 3.获取内核全局变量 + +​ 获取内核全局变量,直接从内核全局变量读取信息。如proc/s就是通过直接读取total_forks内核全局变量来计算每秒产生进程数的。 + + + +## 五、未来展望 + +目前`cpu_watcher`工具的总体框架已经完成,工具所能满足的功能已覆盖CPU所涉及的大部分性能指标。下一阶段,本工具将从以下几个方向进行开发和优化: + +* 完善工具可视化; +* 功能模块化; +* 更细粒度的提取CPU相关指标; +* 完善工具,使其适配更多场景; + + + +如果你也对cpu_watcher或ebpf感兴趣,欢迎加入我们一起开发cpu_watcher工具,希望我们可以共同成长。 + +**cpu_watcher负责人:**albert_xuu@163.com zhangxy1016304@163.com zhangziheng0525@163.com \ No newline at end of file