From 3ae04315afb0891a238fc0529e6a52dd14bfae45 Mon Sep 17 00:00:00 2001 From: zmx Date: Thu, 27 Jun 2024 13:49:19 +0800 Subject: [PATCH 01/12] change the uprobe function --- .../Network_Subsystem/net_watcher/netwatcher.bpf.c | 4 ++-- .../Network_Subsystem/net_watcher/netwatcher.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index 4ae7d22f6..b7888b1c6 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -334,8 +334,8 @@ int BPF_KPROBE(query__end){ return __handle_mysql_end(ctx); } -SEC("uprobe/call") -int BPF_KPROBE(query__start_redis) { +SEC("uprobe/processCommand") +int BPF_KPROBE(query__start_redis_process) { return __handle_redis_start(ctx); } SEC("uretprobe/call") diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index 190c2689e..154740ead 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -564,10 +564,10 @@ static void set_disable_load(struct netwatcher_bpf *skel) { 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); bpf_program__set_autoload(skel->progs.query__end_redis, redis_info ? true : false); + bpf_program__set_autoload(skel->progs.query__start_redis_process, + redis_info ? true : false); } static void print_header(enum MonitorMode mode) { @@ -1200,12 +1200,12 @@ int attach_uprobe_mysql(struct netwatcher_bpf *skel) { return 0; } int attach_uprobe_redis(struct netwatcher_bpf *skel) { - ATTACH_UPROBE_CHECKED( - skel, call, - query__start_redis); ATTACH_UPROBE_CHECKED( skel, call, query__end_redis); + ATTACH_UPROBE_CHECKED( + skel, processCommand, + query__start_redis_process); return 0; } int main(int argc, char **argv) { From 1cc743b8106bdb9a92f078a8248925a829fe8316 Mon Sep 17 00:00:00 2001 From: zmx Date: Thu, 27 Jun 2024 13:54:53 +0800 Subject: [PATCH 02/12] delete the useless --- eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c | 2 +- eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index 154740ead..1c095fe19 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -1146,7 +1146,7 @@ static int print_redis(void *ctx, void *packet_info, size_t size) { strcat(redis, pack_info->redis[i]); strcat(redis, " "); } - printf("%-20d %-20s %-20d %-20s %-21llu\n", pack_info->pid, + printf("%-20d %-20s %-20d %-20s %-21llu\n", pack_info->pid, pack_info->comm,pack_info->argc, redis,pack_info->duratime); strcpy(redis,""); return 0; diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h index ae4cf559a..c3e319ce3 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/redis.bpf.h @@ -17,7 +17,7 @@ #include "common.bpf.h" #include "redis_helper.bpf.h" -#define MAXEPOLL 4 +#define MAXEPOLL 5 static __always_inline int __handle_redis_start(struct pt_regs *ctx) { struct client *cli = (struct client *)PT_REGS_PARM1(ctx); struct redis_query start={}; @@ -34,7 +34,6 @@ static __always_inline int __handle_redis_start(struct pt_regs *ctx) { bpf_probe_read(&arg1, sizeof(arg1), &arg0[i]); bpf_probe_read(&ptr, sizeof(ptr),&arg1->ptr); bpf_probe_read_str(&start.redis[i], sizeof(start.redis[i]), ptr); - //bpf_printk("%s",start.redis[i]); } pid_t pid = bpf_get_current_pid_tgid() >> 32; u64 start_time = bpf_ktime_get_ns() / 1000; @@ -64,7 +63,6 @@ static __always_inline int __handle_redis_end(struct pt_regs *ctx) { } bpf_probe_read_str(&message->redis, sizeof(start->redis), start->redis); message->duratime = end_time - start->begin_time; - bpf_printk("%llu - %llu = %llu",end_time,start->begin_time,message->duratime); bpf_ringbuf_submit(message, 0); return 0; } \ No newline at end of file From 89b17f28bc003bf5639b49b914113f61e8ac251b Mon Sep 17 00:00:00 2001 From: albertxu216 <145351853+albertxu216@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:11:00 +0800 Subject: [PATCH 03/12] =?UTF-8?q?Proc=5Fimage:=E5=AF=B9migate=5Fimage?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9B=B4=E5=A4=9A=E6=8C=87=E6=A0=87=E7=9A=84?= =?UTF-8?q?=E9=87=87=E9=9B=86=20(#841)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * mmodify ebpf_cpu_watche.yml * migrate_image工具采集更多数据 * migrate_image工具采集更多数据 * migrate_image增加新指标 --------- Co-authored-by: 徐晗博 Co-authored-by: helight --- .../eBPF_proc_image/tools/migrate_image.bpf.c | 96 +++++++++++++------ .../eBPF_proc_image/tools/migrate_image.c | 52 +++++----- .../eBPF_proc_image/tools/migrate_image.h | 26 ++++- 3 files changed, 120 insertions(+), 54 deletions(-) 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 index 886481e22..bff87d0ac 100644 --- 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 @@ -25,55 +25,91 @@ struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(key_size, sizeof(pid_t)); __uint(value_size, sizeof(struct migrate_event)); - __uint(max_entries, 128); + __uint(max_entries, 1024); } 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"); + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(struct minfo_key)); + __uint(value_size, sizeof(struct per_migrate)); + __uint(max_entries, 1024); +} migrate_info 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; + struct task_struct *task = (struct task_struct *)bpf_get_current_task(); + struct rq *orig_rq = BPF_CORE_READ(task,se.cfs_rq,rq); + struct cfs_rq *orig_cfs = BPF_CORE_READ(task,se.cfs_rq); + + bpf_printk("[se]:Pload_avg:%llu\tPutil_avg:%llu\n",BPF_CORE_READ(task,se.avg.load_avg),BPF_CORE_READ(task,se.avg.util_avg)); + bpf_printk("[rq]: nr_running :%d cpu_capacity : %ld cpu_capacity_orig : %ld\n", + BPF_CORE_READ(orig_rq,cpu),BPF_CORE_READ(orig_rq,nr_running), + BPF_CORE_READ(orig_rq,cpu_capacity),BPF_CORE_READ(orig_rq,cpu_capacity_orig)); + bpf_printk("Cload_avg:%ld\n",BPF_CORE_READ(orig_cfs,avg.runnable_avg)); 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 = {}; + struct per_migrate per_migrate = {}; + struct minfo_key mkey = {}; + mkey.pid = pid; + mkey.count = 1; 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; + migrate_event.rear = 1; + per_migrate.time = time; + per_migrate.orig_cpu = args->orig_cpu; + per_migrate.dest_cpu = args->dest_cpu; + + per_migrate.cpu_capacity = BPF_CORE_READ(orig_rq,cpu_capacity); + per_migrate.cpu_capacity_orig = BPF_CORE_READ(orig_rq,cpu_capacity_orig); + per_migrate.cpu_load_avg = BPF_CORE_READ(orig_cfs,avg.runnable_avg); + + + per_migrate.pload_avg = BPF_CORE_READ(task,se.avg.load_avg);//进程的量化负载; + per_migrate.putil_avg = BPF_CORE_READ(task,se.avg.util_avg);//进程的实际算力; + per_migrate.mem_usage = BPF_CORE_READ(task,mm,total_vm) << PAGE_SHIFT; + + + per_migrate.read_bytes = BPF_CORE_READ(task,ioac.read_bytes); + per_migrate.write_bytes = BPF_CORE_READ(task,ioac.write_bytes); + + per_migrate.context_switches = BPF_CORE_READ(task,nvcsw) + BPF_CORE_READ(task,nivcsw); + // per_migrate.runtime = BPF_CORE_READ(task,se.sum_exec_runtime); + bpf_map_update_elem(&migrate_info, &mkey, &per_migrate, BPF_ANY); 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) ) + else if(migrate_event->count>0 && migrate_event->countmigrate_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; + struct per_migrate per_migrate = {}; + struct minfo_key mkey = {}; migrate_event->count++; - migrate_event->rear ++; - } + mkey.pid = pid; + mkey.count = migrate_event->count; + per_migrate.time = time; + per_migrate.orig_cpu = args->orig_cpu; + per_migrate.dest_cpu = args->dest_cpu; + + per_migrate.cpu_capacity = BPF_CORE_READ(orig_rq,cpu_capacity); + per_migrate.cpu_capacity_orig = BPF_CORE_READ(orig_rq,cpu_capacity_orig); + per_migrate.cpu_load_avg = BPF_CORE_READ(orig_cfs,avg.runnable_avg); + + per_migrate.pload_avg = BPF_CORE_READ(task,se.avg.load_avg);//进程的量化负载; + per_migrate.putil_avg = BPF_CORE_READ(task,se.avg.util_avg);//进程的实际算力; + per_migrate.mem_usage = BPF_CORE_READ(task,mm,total_vm) << PAGE_SHIFT; - //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); + + per_migrate.read_bytes = BPF_CORE_READ(task,ioac.read_bytes); + per_migrate.write_bytes = BPF_CORE_READ(task,ioac.write_bytes); + + per_migrate.context_switches = BPF_CORE_READ(task,nvcsw) + BPF_CORE_READ(task,nivcsw); + // per_migrate.runtime = BPF_CORE_READ(task,se.sum_exec_runtime); + + bpf_map_update_elem(&migrate_info, &mkey, &per_migrate, BPF_ANY); + } 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 index ae04ea7e7..af2958210 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.c @@ -126,45 +126,53 @@ static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va 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); + printf("\nTime: %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),migrate_info_fd =bpf_map__fd(skel->maps.migrate_info); 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); + fprintf(stderr, "failed to lookup infos2: %d\n", err); return -1; } - if(migrate_event.count == migrate_event.rear) { + 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); + printf("---------------------------------------------------------------------------------\n"); + for(int i=migrate_event.rear;i<=migrate_event.count;i++){ + struct per_migrate migrate_info; + struct minfo_key mkey; + mkey.pid = migrate_event.pid; + mkey.count = i; + err = bpf_map_lookup_elem(migrate_info_fd,&mkey,&migrate_info); + if (err < 0) { + fprintf(stderr, "failed to lookup infos err %d mkey_pid: %d mkey_count: %d\n", err,mkey.pid,i); + continue; + } + printf("time_stamp:%llu\t%d->%d \t PROC_LOAD:%llu \t PROC_UTIL:%llu\t", + migrate_info.time,migrate_info.orig_cpu,migrate_info.dest_cpu,migrate_info.pload_avg,migrate_info.putil_avg); + printf("CPU_LOAD: %ld \t Cpu_Capacity:[%ld:%ld] \t ",migrate_info.cpu_load_avg,migrate_info.cpu_capacity,migrate_info.cpu_capacity_orig); + printf("mmem_usage:%llu kb \t\t read:%llu kb \t\t wite:%llu kb \t\t context_switch:%llu\t", + migrate_info.mem_usage/1024,migrate_info.read_bytes/1024,migrate_info.write_bytes/1024, + migrate_info.context_switches); + if(i==migrate_event.rear && last_time_stamp == 0) { - last_time_stamp = migrate_event.migrate_info[i%MAX_MIGRATE].time; + last_time_stamp = migrate_info.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; + printf("delay: %d us\n",(migrate_info.time - last_time_stamp)/1000); + last_time_stamp = migrate_info.time; } + bpf_map_delete_elem(migrate_info_fd,&mkey);//删除已经打印了的数据 + } - migrate_event.rear = migrate_event.count; + migrate_event.rear = migrate_event.count + 1; bpf_map_update_elem(migrate_fd,&next_key,&migrate_event,BPF_ANY); lookup_key = next_key; } @@ -235,7 +243,7 @@ int main(int argc, char **argv) break; } if (err < 0) { - printf("Error polling perf buffer: %d\n", err); + printf("Error: %d\n", err); break; } } 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 index 0bb280c34..685cf0374 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.h +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/tools/migrate_image.h @@ -6,12 +6,34 @@ typedef unsigned int u32; /*----------------------------------------------*/ /* migrate_event结构体 */ /*----------------------------------------------*/ -#define MAX_MIGRATE 16 +#define MAX_MIGRATE 1024 +#define PAGE_SHIFT 13 // #define ARRY_OVERFLOW -1 +struct minfo_key{ + pid_t pid; + int count; +}; struct per_migrate{//每次迁移,记录该次迁移信息; u64 time; u32 orig_cpu; u32 dest_cpu; + + u64 orig_cpu_load;//cfs->avg.runnale_avg 就绪队列所有调度实体;量化负载总和 + u64 dest_cpu_load; + int cpu_capacity;//计算机算力 + int cpu_capacity_orig;//额定算力 + u64 cpu_load_avg; + u64 pload_avg; + u64 putil_avg; + + int on_cpu; + u64 mem_usage; + u64 read_bytes; + u64 write_bytes; + // u64 syscr; + // u64 syscw; + u64 context_switches; + u64 runtime; }; //每个进程的迁移信息; struct migrate_event{ @@ -19,5 +41,5 @@ struct migrate_event{ pid_t pid; int prio; int count,rear;//迁移频率 - struct per_migrate migrate_info[MAX_MIGRATE];//该进程每次迁移信息; + //struct per_migrate *migrate_info;//该进程每次迁移信息; }; From 9faff7b90aa306d24725b04591a9c51292ad95ac Mon Sep 17 00:00:00 2001 From: vvzxy <145555693+vvzxy@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:11:42 +0800 Subject: [PATCH 04/12] =?UTF-8?q?cpu=5Fwatcher=EF=BC=9A=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=86=85=E6=A0=B8=E6=80=81=E4=BA=92=E6=96=A5=E9=94=81=E4=BA=89?= =?UTF-8?q?=E7=94=A8=E6=95=B0=E6=8D=AE=E9=87=87=E9=9B=86=20(#856)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cpu_watcher:schedule_delay增加阈值选项&&workflow增加测试流程 * . * cpu_watcher:增加controller功能 * cpu_watcher:schedule_delay增加dump出调度延迟过大task的前两个task * sar功能适配controller * . * proc_image:增加进程画像子功能使用说明 * 增加内核态互斥锁争用数据采集 * helper --- .../CPU_Subsystem/cpu_watcher/Makefile | 2 +- .../cpu_watcher/bpf/mutrace.bpf.c | 172 ++++++++++++++++++ .../CPU_Subsystem/cpu_watcher/cpu_watcher.c | 100 +++++++--- .../cpu_watcher/include/cpu_watcher.h | 21 +++ .../cpu_watcher/include/cpu_watcher_helper.h | 82 ++++++++- 5 files changed, 347 insertions(+), 30 deletions(-) create mode 100644 eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile index bcc7c1236..1e1d4eaab 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 schedule_delay mq_delay +APPS =cs_delay sar sc_delay preempt schedule_delay mq_delay mutrace TARGETS=cpu_watcher CONTROLLER := controller diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c new file mode 100644 index 000000000..e2e24aa65 --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c @@ -0,0 +1,172 @@ +// 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 + +#include +#include +#include +#include +#include "cpu_watcher.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +BPF_HASH(mutex_info_map,u64,struct mutex_info, 1024); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + + +/*----------------------------------------------*/ +/* 内核态互斥锁 */ +/*----------------------------------------------*/ + +SEC("kprobe/mutex_lock") +int BPF_KPROBE(trace_mutex_lock, struct mutex *lock) { + u64 lock_addr = (u64)lock; // 获取锁地址 + u64 ts = bpf_ktime_get_ns(); + struct mutex_info *info = bpf_map_lookup_elem(&mutex_info_map, &lock_addr); + if (info) { + info->acquire_time = ts; // 保存锁获取时间 + } else { + struct mutex_info new_info = { + .locked_total = 0, + .locked_max = 0, + .contended_total = 0, + .last_owner = 0, + .acquire_time = ts, + .ptr = lock_addr + }; + bpf_map_update_elem(&mutex_info_map, &lock_addr, &new_info, BPF_ANY); + } + return 0; +} + +SEC("kprobe/mutex_trylock") +int BPF_KPROBE(trace_mutex_trylock, struct mutex *lock) { + int ret = PT_REGS_RC(ctx); + if (ret == 0) { // 成功获取锁 + u64 lock_addr = (u64)lock; // 获取锁地址 + u64 ts = bpf_ktime_get_ns(); + struct mutex_info *info = bpf_map_lookup_elem(&mutex_info_map, &lock_addr); + if (info) { + info->acquire_time = ts; + } else { + struct mutex_info new_info = { + .locked_total = 0, + .locked_max = 0, + .contended_total = 0, + .last_owner = 0, + .acquire_time = ts, + .ptr = lock_addr + }; + bpf_map_update_elem(&mutex_info_map, &lock_addr, &new_info, BPF_ANY); + } + } + return 0; +} + +SEC("kprobe/__mutex_lock_slowpath") +int BPF_KPROBE(trace_mutex_lock_slowpath, struct mutex *lock) { + struct mutex_contention_event *e; + struct task_struct *owner_task; + struct task_struct *contender_task; + pid_t pid = bpf_get_current_pid_tgid(); + long owner; + u64 lock_addr = (u64)lock; + u64 ts = bpf_ktime_get_ns(); + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) { + return 0; + } + e->contender_pid = pid; + e->ptr = lock_addr; + bpf_get_current_comm(&e->contender_name, sizeof(e->contender_name)); + bpf_probe_read_kernel(&owner, sizeof(owner), &lock->owner); + owner_task = (struct task_struct *)(owner & ~0x1L); + contender_task = (struct task_struct *)bpf_get_current_task(); + bpf_probe_read_kernel(&e->contender_prio, sizeof(e->contender_prio), &contender_task->prio); + if (owner_task) { + bpf_probe_read_kernel(&e->owner_pid, sizeof(e->owner_pid), &owner_task->pid); + bpf_probe_read_kernel_str(&e->owner_name, sizeof(e->owner_name), owner_task->comm); + bpf_probe_read_kernel(&e->owner_prio, sizeof(e->owner_prio), &owner_task->prio); + } else { + e->owner_pid = 0; + __builtin_memset(e->owner_name, 0, sizeof(e->owner_name)); + } + struct mutex_info *info = bpf_map_lookup_elem(&mutex_info_map, &lock_addr); + if (info) { + info->contended_total += ts - info->acquire_time; + } else { + struct mutex_info new_info = { + .locked_total = 0, + .locked_max = 0, + .contended_total = ts, + .last_owner = 0, + .acquire_time = 0, + .ptr = lock_addr + }; + bpf_map_update_elem(&mutex_info_map, &lock_addr, &new_info, BPF_ANY); + } + bpf_ringbuf_submit(e, 0); + return 0; +} + +SEC("kprobe/mutex_unlock") +int BPF_KPROBE(trace_mutex_unlock, struct mutex *lock) { + u64 lock_addr = (u64)lock; + u64 ts = bpf_ktime_get_ns(); + pid_t pid = bpf_get_current_pid_tgid(); + struct mutex_info *info = bpf_map_lookup_elem(&mutex_info_map, &lock_addr); + if (info) { + u64 held_time = ts - info->acquire_time; // 计算锁被持有的时间 + info->locked_total += held_time; // 更新锁被持有的总时间 + if (held_time > info->locked_max) { + info->locked_max = held_time; // 更新锁被持有的最长时间 + } + info->last_owner = pid; // 更新最后一次持有该锁的线程ID + } + return 0; +} + +/*----------------------------------------------*/ +/* 用户态互斥锁 */ +/*----------------------------------------------*/ + +// SEC("uprobe") +// int BPF_KPROBE(pthread_mutex_lock_init, pthread_mutex_t *mutex){ + +// } + +// SEC("uprobe") +// int BPF_KPROBE(pthread_mutex_lock,pthread_mutex_t *mutex){ + +// } + +// SEC("uprobe") +// int BPF_KPROBE(pthread_mutex_try, pthread_mutex_t *mutex){ + +// } + +// SEC("uprobe") +// int BPF_KPROBE(pthread_mutex_unlock, pthread_mutex_t *mutex){ + +// } + +// SEC("uprobe") +// int BPF_KPROBE(pthread_mutex_destroy, pthread_mutex_t *mutex){ + +// } \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c index 0cdf445f5..36a533d09 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -35,11 +35,13 @@ #include "preempt.skel.h" #include "schedule_delay.skel.h" #include "mq_delay.skel.h" +#include "mutrace.skel.h" typedef long long unsigned int u64; typedef unsigned int u32; + struct list_head { struct list_head *next; struct list_head *prev; @@ -65,6 +67,7 @@ static struct env { int freq; bool EWMA; int cycle; + int MUTRACE; } env = { .time = 0, .period = 1, @@ -78,6 +81,7 @@ static struct env { .freq = 99, .EWMA = false, .cycle = 0, + .MUTRACE = false, }; @@ -88,6 +92,7 @@ struct sc_delay_bpf *sc_skel; struct preempt_bpf *preempt_skel; struct schedule_delay_bpf *sd_skel; struct mq_delay_bpf *mq_skel; +struct mutrace_bpf *mu_skel; static int csmap_fd; static int sarmap_fd; @@ -132,6 +137,7 @@ static const struct argp_option opts[] = { {"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)" }, + {"mutrace", 'x', 0, 0, "Print mutrace data(the data of cpu)" }, {"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" }, @@ -166,6 +172,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'm': env.MQ_DELAY = true; break; + case 'x': + env.MUTRACE = true; + break; case 'E': env.EWMA = true; break; @@ -547,38 +556,23 @@ static int preempt_print(void *ctx, void *data, unsigned long data_sz) return 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 false; -} -// 添加条目到已输出的条目列表 -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++; +//mutrace输出 +static int mutrace_print(void *ctx, void *data, unsigned long data_sz) { + const struct mutex_contention_event *e = data; + if (e->owner_pid == 0 || e->contender_pid == 0||e->owner_pid == 1) { + return 0; } + // 增加锁争用次数 + increment_lock_count(e->ptr); + uint64_t contention_count = get_lock_count(e->ptr); + printf("%15llu %15d %15s %15d %15d %15s %15d %15ld\n", e->ptr, e->owner_pid, e->owner_name, e->owner_prio,e->contender_pid, e->contender_name, e->contender_prio,contention_count); + return 0; } + + + static int schedule_print() { int err,key = 0; @@ -961,6 +955,40 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to create ring buffer\n"); goto mq_delay_cleanup; } + }else if (env.MUTRACE) { + mu_skel = mutrace_bpf__open(); + if (!mu_skel) { + fprintf(stderr, "Failed to open and load BPF skeleton\n"); + return 1; + } + + err = mutrace_bpf__load(mu_skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto mutrace_cleanup; + } + //ctrl + if(err < 0){ + goto mutrace_cleanup; + } + //ctrl + if(err < 0){ + fprintf(stderr, "Failed to update elem\n"); + goto mutrace_cleanup; + } + err = mutrace_bpf__attach(mu_skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto mutrace_cleanup; + } + + rb = ring_buffer__new(bpf_map__fd(mu_skel->maps.rb), mutrace_print, NULL, NULL); + printf("%s\n"," lock_ptr owner_pid owner_comm owner_prio contender_pid contender_comm contender_prio contender_count"); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto mutrace_cleanup; + } } while (!exiting) { if(env.SAR){ @@ -1053,6 +1081,17 @@ int main(int argc, char **argv) break; } } + else if (env.MUTRACE) { + 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; + } + } else { printf("正在开发中......\n-c 打印cs_delay:\t对内核函数schedule()的执行时长进行测试;\n-s sar工具;\n-y 打印sc_delay:\t系统调用运行延迟进行检测; \n-p 打印preempt_time:\t对抢占调度时间输出;\n"); break; @@ -1092,4 +1131,9 @@ int main(int argc, char **argv) ring_buffer__free(rb); mq_delay_bpf__destroy(mq_skel); return err < 0 ? -err : 0; + +mutrace_cleanup: + ring_buffer__free(rb); + mutrace_bpf__destroy(mu_skel); + return err < 0 ? -err : 0; } \ 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 eadd0d874..3425e8975 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher.h @@ -155,6 +155,27 @@ struct proc_history { struct proc_info last[2]; // 存储最后两个调度的进程信息 }; +/*----------------------------------------------*/ +/* mutrace相关结构体 */ +/*----------------------------------------------*/ +struct mutex_info { + u64 locked_total;//锁被持有的总时间 + u64 locked_max;//锁被持有的最长时间 + u64 contended_total;//锁发生竞争的总时间 + pid_t last_owner;//最后一次持有该锁的线程 ID + u64 acquire_time; // 锁每次被获取的时间戳,方便后续计算 + u64 ptr;//地址 +}; + +struct mutex_contention_event { + u64 ptr;//锁地址 + pid_t owner_pid;//持有者pid + pid_t contender_pid;//抢占者pid + char contender_name[TASK_COMM_LEN]; + char owner_name[TASK_COMM_LEN]; + int owner_prio; + int contender_prio; +}; /*----------------------------------------------*/ /* mq_delay相关结构体 */ 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 index 5250aef89..dc78f2622 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher_helper.h +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/include/cpu_watcher_helper.h @@ -25,6 +25,7 @@ #define PREEMPT_WACTHER 40 #define SCHEDULE_WACTHER 50 #define MQ_WACTHER 60 +#define HASH_SIZE 1024 /*----------------------------------------------*/ /* ewma算法 */ @@ -64,7 +65,9 @@ bool dynamic_filter(struct ewma_info *ewma_syscall_delay, double dataPoint) { return 0; } - +/*----------------------------------------------*/ +/* bpf file system */ +/*----------------------------------------------*/ 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"; @@ -199,4 +202,81 @@ int update_mq_ctrl_map(struct mq_ctrl mq_ctrl){ return 0; } + +/*----------------------------------------------*/ +/* mutex_count */ +/*----------------------------------------------*/ + +typedef struct { + uint64_t ptr; + uint64_t count; +} lock_count_t; + +lock_count_t lock_counts[HASH_SIZE]; + +static uint64_t hash(uint64_t ptr) { + return ptr % HASH_SIZE; +} + +static void increment_lock_count(uint64_t ptr) { + uint64_t h = hash(ptr); + while (lock_counts[h].ptr != 0 && lock_counts[h].ptr != ptr) { + h = (h + 1) % HASH_SIZE; + } + if (lock_counts[h].ptr == 0) { + lock_counts[h].ptr = ptr; + lock_counts[h].count = 1; + } else { + lock_counts[h].count++; + } +} + +static uint64_t get_lock_count(uint64_t ptr) { + uint64_t h = hash(ptr); + while (lock_counts[h].ptr != 0 && lock_counts[h].ptr != ptr) { + h = (h + 1) % HASH_SIZE; + } + if (lock_counts[h].ptr == 0) { + return 0; + } else { + return lock_counts[h].count; + } +} + +/*----------------------------------------------*/ +/* hash */ +/*----------------------------------------------*/ + + +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 false; +} + + +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++; + } +} #endif // CPU_WATCHER_HELPER_H \ No newline at end of file From 36e9187cdd870b597d4089f99254bac510917ced Mon Sep 17 00:00:00 2001 From: gaoyixiang1 <1739037263@qq.com> Date: Tue, 9 Jul 2024 17:52:48 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E8=8E=B7=E5=8F=96=20node=20=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E6=89=80=E6=9C=89=20zone=20=E7=9A=84=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ebpf_frag.yml | 37 +++++ .../Memory_Subsystem/fraginfo/Makefile | 131 ++++++++++++++++++ .../fraginfo/src/fraginfo.bpf.c | 76 ++++++++++ .../Memory_Subsystem/fraginfo/src/fraginfo.c | 121 ++++++++++++++++ .../Memory_Subsystem/fraginfo/src/fraginfo.h | 22 +++ 5 files changed, 387 insertions(+) create mode 100644 .github/workflows/ebpf_frag.yml create mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile create mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c create mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c create mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h diff --git a/.github/workflows/ebpf_frag.yml b/.github/workflows/ebpf_frag.yml new file mode 100644 index 000000000..a41ec8a31 --- /dev/null +++ b/.github/workflows/ebpf_frag.yml @@ -0,0 +1,37 @@ +name: fraginfo + +on: + push: + branches: + - "*" + paths: + - 'eBPF_Supermarket/Memory_Subsystem/frag/**' + - '.github/workflows/ebpf_frag.yml' + pull_request: + branches: + - "*" + paths: + - 'eBPF_Supermarket/Memory_Subsystem/frag/**' + - '.github/workflows/ebpf_frag.yml' + + +jobs: + fraginfo-build-and-test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Install dependencies + run: | + sudo apt update + sudo apt install libbpf-dev clang llvm libelf-dev libpcap-dev gcc-multilib build-essential linux-tools-$(uname -r) + git submodule update --init --recursive + + - name: Run fraginfo + continue-on-error: true + run: | + cd eBPF_Supermarket/Memory_Subsystem/frag + bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h + make + sudo ./fraginfo -i 5 + \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile b/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile new file mode 100644 index 000000000..2427d210d --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile @@ -0,0 +1,131 @@ + +# Makefile +OUTPUT := .output +CLANG ?= clang + +LIBBPF_SRC := $(abspath ../libbpf/src) +BPFTOOL_SRC := $(abspath ../bpftool/src) +LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) +BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) +BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool + +ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ + | sed 's/arm.*/arm/' \ + | sed 's/aarch64/arm64/' \ + | sed 's/ppc64le/powerpc/' \ + | sed 's/mips.*/mips/' \ + | sed 's/riscv64/riscv/' \ + | sed 's/loongarch64/loongarch/') +VMDIR := ../vmlinux +VMLINUXSRC := $(VMDIR)/$(ARCH) +VMLINUX := $(VMLINUXSRC)/vmlinux.h +# Use our own libbpf API headers and Linux UAPI headers distributed with +# libbpf to avoid dependency on system-wide headers, which could be missing or +# outdated +INCLUDES := -I$(OUTPUT) -I../../lib/libbpf/include/uapi -I$(dir $(VMLINUX)) -I./include +CFLAGS := -g -Wall +ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) + +APPS = fraginfo + +# Get Clang's default includes on this system. We'll explicitly add these dirs +# to the includes list when compiling with `-target bpf` because otherwise some +# architecture-specific dirs will be "missing" on some architectures/distros - +# headers such as asm/types.h, asm/byteorder.h, asm/socket.h, asm/sockios.h, +# sys/cdefs.h etc. might be missing. +# +# Use '-idirafter': Don't interfere with include mechanics except where the +# build would have failed anyways. +CLANG_BPF_SYS_INCLUDES = $(shell $(CLANG) -v -E - &1 \ + | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') + +ifeq ($(V),1) + Q = + msg = +else + Q = @ + msg = @printf ' %-8s %s%s\n' \ + "$(1)" \ + "$(patsubst $(abspath $(OUTPUT))/%,%,$(2))" \ + "$(if $(3), $(3))"; + MAKEFLAGS += --no-print-directory +endif + +define allow-override + $(if $(or $(findstring environment,$(origin $(1))),\ + $(findstring command line,$(origin $(1)))),,\ + $(eval $(1) = $(2))) +endef + +$(call allow-override,CC,$(CROSS_COMPILE)cc) +$(call allow-override,LD,$(CROSS_COMPILE)ld) + +.PHONY: all +all: deps $(APPS) + +.PHONY: deps +deps: + mkdir -p $(VMLINUXSRC) + bpftool btf dump file /sys/kernel/btf/vmlinux format c > $(VMLINUX) + +.PHONY: clean +clean: + $(call msg,CLEAN) + $(Q)rm -rf $(OUTPUT) $(APPS) + rm -rf $(VMDIR) + +.PHONY: clean2 +clean2: + $(call msg,CLEAN) + rm -f $(APPS) + rm -f $(OUTPUT)/*.skel.h + rm -f $(OUTPUT)/*.o + rm -rf $(VMDIR) + +$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): + $(call msg,MKDIR,$@) + $(Q)mkdir -p $@ + +# Build libbpf +$(LIBBPF_OBJ): $(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 $@) \ + INCLUDEDIR= LIBDIR= UAPIDIR= \ + install + +# Build bpftool +$(BPFTOOL): | $(BPFTOOL_OUTPUT) + $(call msg,BPFTOOL,$@) + $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap + +# Build BPF code +$(OUTPUT)/%.bpf.o: src/%.bpf.c $(LIBBPF_OBJ) $(wildcard src/*.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) + $(call msg,BPF,$@) + $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ + $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ + -c $(filter %.c,$^) -o $(patsubst %.bpf.o,%.tmp.bpf.o,$@) + $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) + +# Generate BPF skeletons +$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) + $(call msg,GEN-SKEL,$@) + $(Q)$(BPFTOOL) gen skeleton $< > $@ + +# Build user-space code +$(patsubst %,$(OUTPUT)/%.o,$(APPS)): $(OUTPUT)/%.o: src/%.c $(OUTPUT)/%.skel.h $(wildcard src/*.h) | $(OUTPUT) + $(call msg,CC,$@) + $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ + +# Build application binary +$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) + $(call msg,BINARY,$@) + $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@ + +# delete failed targets +.DELETE_ON_ERROR: + +# keep intermediate (.skel.h, .bpf.o, etc) targets +.SECONDARY: + +SHELL := /bin/bash diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c new file mode 100644 index 000000000..45b5c5c54 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c @@ -0,0 +1,76 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fraginfo.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 102400); + __type(key, u64); + __type(value, struct zone_info); +} zones SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 102400); + __type(key, u64); + __type(value, struct pgdat_info); +} nodes SEC(".maps"); + +static void fill_contig_page_info(struct zone *zone, unsigned int suitable_order, + struct contig_page_info *info) +{ + unsigned int order; + info->free_pages = 0; + info->free_blocks_total = 0; + info->free_blocks_suitable = 0; + for (order = 0; order <= MAX_ORDER; order++) { + unsigned long blocks; + unsigned long nr_free; + nr_free = BPF_CORE_READ(&zone->free_area[order], nr_free); + blocks = nr_free; + info->free_blocks_total += blocks; + info->free_pages += blocks << order; + if (order >= suitable_order) + info->free_blocks_suitable += blocks << (order - suitable_order); + } +} + +SEC("kprobe/get_page_from_freelist") +int BPF_KPROBE(get_page_from_freelist, gfp_t gfp_mask, unsigned int order, int alloc_flags, + const struct alloc_context *ac) +{ + struct pgdat_info node_info = {}; + struct zone_info zone_data = {}; + + struct pglist_data *pgdat; + struct zoneref *zref; + struct zone *z; + int i; + + pgdat = BPF_CORE_READ(ac, preferred_zoneref, zone, zone_pgdat); + node_info.node_id = BPF_CORE_READ(pgdat, node_id); + node_info.nr_zones = BPF_CORE_READ(pgdat, nr_zones); + node_info.pgdat_ptr = (u64)pgdat; + u64 key = (u64)pgdat; + + bpf_map_update_elem(&nodes, &key, &node_info, BPF_ANY); + + for (i = 0; i < __MAX_NR_ZONES; i++) { + zref = &pgdat->node_zonelists[0]._zonerefs[i]; + z = BPF_CORE_READ(zref, zone); + if ((u64)z == 0) break; + zone_data.zone_ptr = (u64)z; + u64 zone_key = (u64)z; + zone_data.zone_start_pfn = BPF_CORE_READ(z, zone_start_pfn); + zone_data.spanned_pages = BPF_CORE_READ(z, spanned_pages); + zone_data.present_pages = BPF_CORE_READ(z, present_pages); + bpf_probe_read_kernel_str(zone_data.comm, sizeof(zone_data.comm), BPF_CORE_READ(z, name)); + bpf_map_update_elem(&zones, &zone_key, &zone_data, BPF_ANY); + } + + return 0; +} diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c new file mode 100644 index 000000000..71b9fd356 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c @@ -0,0 +1,121 @@ +#include "fraginfo.skel.h" +#include +#include +#include +#include +#include +#include +#include +#include "fraginfo.h" + +static struct env { + int interval; + int duration; +} env = { + .interval = 1, + .duration = 10, +}; + +const char *argp_program_version = "fraginfo 0.1"; +const char *argp_program_bug_address = ""; +const char argp_program_doc[] = +"Fraginfo BPF program.\n" +"\n" +"USAGE: ./fraginfo [--interval INTERVAL] [--duration DURATION]\n"; + +static const struct argp_option opts[] = { + { "interval", 'i', "INTERVAL", 0, "Print interval in seconds (default 1)"}, + { "duration", 'd', "DURATION", 0, "Total duration in seconds to run (default 10)"}, + {}, +}; + +static error_t parse_arg(int key, char *arg, struct argp_state *state) { + switch (key) { + case 'i': + env.interval = atoi(arg); + break; + case 'd': + env.duration = atoi(arg); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static volatile bool exiting = false; + +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); +} + +void print_nodes(int fd) { + struct pgdat_info pinfo; + __u64 key = 0, next_key; + printf(" Node ID PGDAT_PTR NR_ZONES \n"); + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { + bpf_map_lookup_elem(fd, &next_key, &pinfo); + printf(" %5d 0x%llx %5d\n", + pinfo.node_id, pinfo.pgdat_ptr, pinfo.nr_zones); + key = next_key; + } +} + +void print_zones(int fd) { + struct zone_info zinfo; + __u64 key = 0, next_key; + printf(" COMM ZONE_PTR ZONE_PFN SUM_PAGES FACT_PAGES \n"); + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { + bpf_map_lookup_elem(fd, &next_key, &zinfo); + printf(" %s 0x%llx %llu %5llu %llu \n", zinfo.comm, zinfo.zone_ptr, zinfo.zone_start_pfn,zinfo.spanned_pages,zinfo.present_pages); + key = next_key; + } +} + +int main(int argc, char **argv) { + struct fraginfo_bpf *skel; + int err; + + struct argp argp = { opts, parse_arg, NULL, argp_program_doc }; + err = argp_parse(&argp, argc, argv, 0, 0, NULL); + if (err) + return err; + + // libbpf_set_print(libbpf_print_fn); + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + skel = fraginfo_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + + err = fraginfo_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load BPF skeleton\n"); + goto cleanup; + } + + err = fraginfo_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + printf("Tracing... Press Ctrl-C to end.\n"); + + while (!exiting) { + sleep(env.interval); + print_nodes(bpf_map__fd(skel->maps.nodes)); + print_zones(bpf_map__fd(skel->maps.zones)); + } + +cleanup: + fraginfo_bpf__destroy(skel); + return -err; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h new file mode 100644 index 000000000..7041bcfc6 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h @@ -0,0 +1,22 @@ +#ifndef FRAGINFO_H +#define FRAGINFO_H + +#define MAX_ORDER 10 +typedef __u64 u64; + + +struct zone_info { + u64 zone_ptr; + u64 zone_start_pfn; + u64 spanned_pages; + u64 present_pages; + char comm[32]; +}; + +struct pgdat_info { + u64 pgdat_ptr; + int nr_zones; + int node_id; +}; + +#endif From 9d92fdbe9dc11f49c63ffa135d8afa6defddd519 Mon Sep 17 00:00:00 2001 From: gaoyixiang1 <1739037263@qq.com> Date: Tue, 9 Jul 2024 17:58:02 +0800 Subject: [PATCH 06/12] update workflow --- .github/workflows/ebpf_frag.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ebpf_frag.yml b/.github/workflows/ebpf_frag.yml index a41ec8a31..b2a6bac03 100644 --- a/.github/workflows/ebpf_frag.yml +++ b/.github/workflows/ebpf_frag.yml @@ -1,3 +1,4 @@ + name: fraginfo on: @@ -5,33 +6,31 @@ on: branches: - "*" paths: - - 'eBPF_Supermarket/Memory_Subsystem/frag/**' + - 'eBPF_Supermarket/Memory_Subsystem/fraginfo/**' - '.github/workflows/ebpf_frag.yml' pull_request: branches: - "*" paths: - - 'eBPF_Supermarket/Memory_Subsystem/frag/**' + - 'eBPF_Supermarket/Memory_Subsystem/fraginfo/**' - '.github/workflows/ebpf_frag.yml' - jobs: - fraginfo-build-and-test: + fraginfo-project-build-and-test: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 - - name: Install dependencies + - name: Install dependencies run: | sudo apt update sudo apt install libbpf-dev clang llvm libelf-dev libpcap-dev gcc-multilib build-essential linux-tools-$(uname -r) git submodule update --init --recursive - + - name: Run fraginfo continue-on-error: true run: | - cd eBPF_Supermarket/Memory_Subsystem/frag + cd eBPF_Supermarket/Memory_Subsystem/fraginfo/ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h make - sudo ./fraginfo -i 5 - \ No newline at end of file + sudo ./fraginfo -i 5 From b4d0c697c5f6fd36edb8fc1176cc7815ce9c3111 Mon Sep 17 00:00:00 2001 From: zmx Date: Tue, 9 Jul 2024 21:27:24 +0800 Subject: [PATCH 07/12] add the dependence and export the version for CORE --- .../Network_Subsystem/net_watcher/Makefile | 47 ++++++++++++++++++- .../net_watcher/common.bpf.h | 6 ++- .../net_watcher/packet.bpf.h | 7 +-- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/Makefile b/eBPF_Supermarket/Network_Subsystem/net_watcher/Makefile index c110196c1..c8c6e30fe 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/Makefile +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/Makefile @@ -6,7 +6,14 @@ BPFTOOL_SRC := $(abspath ../../lib/bpftool/src) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool - +VERSION_INFO := $(shell uname -r | cut -d'-' -f1) +VERSION_MAJOR := $(shell echo $(VERSION_INFO) | cut -d'.' -f1) +VERSION_MINOR := $(shell echo $(VERSION_INFO) | cut -d'.' -f2) +VERSION_PATCH := $(shell echo $(VERSION_INFO) | cut -d'.' -f3) +export VERSION_INFO +export VERSION_MAJOR +export VERSION_MINOR +export VERSION_PATCH ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ | sed 's/arm.*/arm/' \ | sed 's/aarch64/arm64/' \ @@ -63,10 +70,42 @@ $(call allow-override,LD,$(CROSS_COMPILE)ld) all: deps $(APPS) #更新vmlinux.h文件 .PHONY: deps -deps: +deps:check_bpftool check_clang check_multilib + @echo "Kernel version is $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)" mkdir -p $(VMLINUXSRC) bpftool btf dump file /sys/kernel/btf/vmlinux format c > $(VMLINUX) +.PHONY: check_bpftool +check_bpftool: + @if ! command -v bpftool &> /dev/null; then \ + echo "bpftool 未安装,正在安装..."; \ + sudo apt-get update; \ + sudo apt-get install -y linux-tools-$(shell uname -r); \ + else \ + echo "bpftool 已经安装"; \ + fi +.PHONY: check_clang + +check_clang: + @if ! command -v clang &> /dev/null; then \ + echo "clang 未安装,正在安装..."; \ + sudo apt-get update; \ + sudo apt-get install -y clang; \ + else \ + echo "clang 已经安装"; \ + fi + +# 检查 multilib 是否安装,如果没有则安装 +.PHONY: check_multilib +check_multilib: + @if [ ! -f /usr/include/x86_64-linux-gnu/gnu/stubs-32.h ]; then \ + echo "multilib 未安装,正在安装..."; \ + sudo apt-get update; \ + sudo apt-get install -y gcc-multilib g++-multilib; \ + else \ + echo "multilib 已经安装"; \ + fi + .PHONY: clean clean: $(call msg,CLEAN) @@ -105,6 +144,10 @@ $(BPFTOOL): | $(BPFTOOL_OUTPUT) $(OUTPUT)/%.bpf.o: %.bpf.c $(LIBBPF_OBJ) $(wildcard *.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) $(call msg,BPF,$@) $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ + -D__TARGET_ARCH_$(ARCH) \ + -DVERSION_MAJOR=$(VERSION_MAJOR) \ + -DVERSION_MINOR=$(VERSION_MINOR) \ + -DVERSION_PATCH=$(VERSION_PATCH) \ $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ -c $(filter %.c,$^) -o $(patsubst %.bpf.o,%.tmp.bpf.o,$@) $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h index 0c71f53ba..e10ec20a4 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h @@ -500,7 +500,11 @@ int getstack(void *ctx) { return 0; } - +#if KERNEL_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) >= KERNEL_VERSION(6, 3, 1) +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) +#else +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) +#endif /* help functions end */ #endif diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h index a712d1755..d515ef54b 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h @@ -393,12 +393,7 @@ int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) // TX HTTP info if (http_info) { - // #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 1) - // u8 *user_data = BPF_CORE_READ(msg, msg_iter.__iov, iov_base); - // #else - // u8 *user_data = BPF_CORE_READ(msg, msg_iter.iov,iov_base); - // #endif - u8 *user_data = BPF_CORE_READ(msg, msg_iter.__iov, iov_base); + u8 *user_data = GET_USER_DATA(msg); tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, &zero); if (tinfo == NULL) { From 26f90f854360075b5be099e21a781c6094948de4 Mon Sep 17 00:00:00 2001 From: Y_y_s <78297703+Monkey857@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:29:48 +0800 Subject: [PATCH 08/12] =?UTF-8?q?proc=5Fimage&kvm=5Fwatcher=EF=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=87=87=E9=9B=86=E5=AE=B9=E5=99=A8=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E7=9A=84=E7=B3=BB=E7=BB=9F=E8=B0=83=E7=94=A8=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20(#854)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * container * container proc * kvm_container_syscall * mod_pr --- .../eBPF_proc_image/bpf/syscall_image.bpf.c | 66 ++++++++- .../eBPF_proc_image/controller.c | 10 +- .../eBPF_proc_image/include/proc_image.h | 1 + .../eBPF_proc_image/proc_image.c | 16 ++- .../kvm_watcher/include/bpf/container.h | 136 ++++++++++++++++++ eBPF_Supermarket/kvm_watcher/include/common.h | 15 +- .../kvm_watcher/src/kvm_watcher.bpf.c | 24 ++++ .../kvm_watcher/src/kvm_watcher.c | 37 ++++- 8 files changed, 293 insertions(+), 12 deletions(-) create mode 100644 eBPF_Supermarket/kvm_watcher/include/bpf/container.h diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/syscall_image.bpf.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/syscall_image.bpf.c index c33ef5f88..b608d77be 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/syscall_image.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/syscall_image.bpf.c @@ -23,8 +23,9 @@ #include "proc_image.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; - +#define MAX_NODENAME_LEN 64 const volatile pid_t ignore_tgid = -1; +const volatile char hostname[MAX_NODENAME_LEN] = ""; const int key = 0; pid_t pre_target_pid = -1;//上一个监测的进程; int pre_target_tgid = -1;//上一个监测的进程组; @@ -48,14 +49,69 @@ struct { __uint(max_entries,256 * 10240); } syscall_rb SEC(".maps"); +struct { + __uint(type,BPF_MAP_TYPE_HASH); + __uint(max_entries, 8192); + __type(key, pid_t); + __type(value,struct container_id); +}container_id_map SEC(".maps"); + +struct container_id{ + char container_id[20]; +}; + +struct data_t { + char nodename[MAX_NODENAME_LEN]; +}; + +static bool is_container_task(const volatile char hostname[MAX_NODENAME_LEN]){ + struct task_struct *task; + struct nsproxy *ns; + struct uts_namespace *uts; + struct data_t data = {}; + // 获取当前任务的 task_struct + task = (struct task_struct *)bpf_get_current_task(); + // 获取 nsproxy + bpf_probe_read_kernel(&ns, sizeof(ns), &task->nsproxy); + if (!ns) { + return false; + } + // 获取 uts_namespace + bpf_probe_read_kernel(&uts, sizeof(uts), &ns->uts_ns); + if (!uts) { + return false; + } + // 读取主机名 + bpf_probe_read_kernel_str(&data.nodename, sizeof(data.nodename), uts->name.nodename); + // 打印主机名 + bool is_equal = true; + for(int i = 0;isc_func) + if(!sc_ctrl || !sc_ctrl->sc_func) return 0; - + if(sc_ctrl->is_container) + if(!is_container_task(hostname)) + return 0; pid_t pid = bpf_get_current_pid_tgid(); int tgid = bpf_get_current_pid_tgid() >> 32; @@ -104,7 +160,9 @@ int sys_exit(struct trace_event_raw_sys_exit *args) sc_ctrl = bpf_map_lookup_elem(&sc_ctrl_map,&key); if(!sc_ctrl || !sc_ctrl->sc_func) return 0; - + if(sc_ctrl->is_container) + if(!is_container_task(hostname)) + return 0; pid_t pid = bpf_get_current_pid_tgid(); int tgid = bpf_get_current_pid_tgid() >> 32; diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/controller.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/controller.c index 121a8fdb1..718feda25 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/controller.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/controller.c @@ -49,6 +49,7 @@ static struct env { bool enable_lock; bool enable_syscall; bool enable_schedule; + bool is_container; } env = { .usemode = 0, .pid = -1, @@ -68,6 +69,7 @@ static struct env { .enable_lock = false, .enable_syscall = false, .enable_schedule = false, + .is_container = false, }; const char argp_program_doc[] ="Trace process to get process image.\n"; @@ -78,6 +80,7 @@ static const struct argp_option opts[] = { { "finish", 'f', NULL, 0, "Finish to run eBPF tool" }, { "pid", 'p', "PID", 0, "Process ID to trace" }, { "tgid", 'P', "TGID", 0, "Thread group to trace" }, + { "containerproc", 'o', NULL, 0, "Thread of containerproc to trace" }, { "cpuid", 'c', "CPUID", 0, "Set For Tracing per-CPU Process(other processes don't need to set this parameter)" }, { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, { "myproc", 'm', NULL, 0, "Trace the process of the tool itself (not tracked by default)" }, @@ -143,6 +146,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'm': env.enable_myproc = true; break; + case 'o': + env.is_container = true; + break; case 'r': env.enable_resource = true; break; @@ -201,7 +207,7 @@ int deactivate_mode(){ } if(env.enable_syscall){ - struct sc_ctrl sc_ctrl = {false,false,-1,-1,0}; + struct sc_ctrl sc_ctrl = {false,false,false,-1,-1,0}; err = update_sc_ctrl_map(sc_ctrl); if(err < 0) return err; } @@ -257,7 +263,7 @@ int main(int argc, char **argv) } if(env.enable_syscall){ - struct sc_ctrl sc_ctrl = {true,env.enable_myproc,env.pid,env.tgid,env.syscalls}; + struct sc_ctrl sc_ctrl = {true,env.enable_myproc, env.is_container,env.pid,env.tgid,env.syscalls}; err = update_sc_ctrl_map(sc_ctrl); if(err < 0) return err; } diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/include/proc_image.h b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/include/proc_image.h index ecfc1905f..589ca5063 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/include/proc_image.h +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/include/proc_image.h @@ -65,6 +65,7 @@ struct total_rsc{ struct sc_ctrl { bool sc_func; bool enable_myproc; + bool is_container; pid_t target_pid; pid_t target_tgid; int syscalls; diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c index b52a77712..9577b3482 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c @@ -65,6 +65,7 @@ static struct env { int lock_prev_tgid; int sched_prev_tgid; int sc_prev_tgid; + char hostname[64]; } env = { .output_resourse = false, .output_schedule = false, @@ -88,6 +89,7 @@ static struct env { .lock_prev_tgid = 0, .sched_prev_tgid = 0, .sc_prev_tgid = 0, + .hostname = "", }; struct hashmap *map = NULL; @@ -723,6 +725,16 @@ static void sig_handler(int signo) exiting = true; } +void get_hostname() { + char hostname[64]; + int result = gethostname(hostname, sizeof(hostname)); + if (result == 0) { + strcpy(env.hostname,hostname); + } else { + perror("gethostname"); + } +} + int main(int argc, char **argv) { struct resource_image_bpf *resource_skel = NULL; @@ -802,7 +814,9 @@ int main(int argc, char **argv) } syscall_skel->rodata->ignore_tgid = env.ignore_tgid; - + get_hostname(); + strcpy(syscall_skel->rodata->hostname,env.hostname); + err = syscall_image_bpf__load(syscall_skel); if (err) { fprintf(stderr, "Failed to load and verify BPF syscall skeleton\n"); diff --git a/eBPF_Supermarket/kvm_watcher/include/bpf/container.h b/eBPF_Supermarket/kvm_watcher/include/bpf/container.h new file mode 100644 index 000000000..5271054ef --- /dev/null +++ b/eBPF_Supermarket/kvm_watcher/include/bpf/container.h @@ -0,0 +1,136 @@ +// 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: yys2020haha@163.com +// +// Kernel space BPF program used for counting container sys_entry/sys_exit info. + +#ifndef __CONTAINER_H +#define __CONTAINER_H + +#include "common.h" +#include "vmlinux.h" +#include +#include +#include +#define MAX_NODENAME_LEN 64 +struct { + __uint(type,BPF_MAP_TYPE_HASH); + __uint(max_entries, 8192); + __type(key, pid_t); + __type(value, u64); +}time_info SEC(".maps"); + +struct { + __uint(type,BPF_MAP_TYPE_HASH); + __uint(max_entries, 8192); + __type(key, pid_t); + __type(value, u64); +}id SEC(".maps"); + +struct { + __uint(type,BPF_MAP_TYPE_HASH); + __uint(max_entries, 8192); + __type(key, pid_t); + __type(value,struct container_id); +}container_id_map SEC(".maps"); + + +static int trace_container_sys_entry(struct trace_event_raw_sys_enter *args){ + u64 st = bpf_ktime_get_ns(); + pid_t pid = bpf_get_current_pid_tgid(); + u64 syscall_id = (u64)args->id; + bpf_map_update_elem(&time_info,&pid,&st,BPF_ANY); + bpf_map_update_elem(&id,&pid,&syscall_id,BPF_ANY); + return 0; +} +static int trace_container_sys_exit(struct trace_event_raw_sys_exit *args,void *rb,struct common_event *e){ + u64 exit_time = bpf_ktime_get_ns(); + pid_t pid = bpf_get_current_pid_tgid(); + u64 delay,start_time,syscallid; + u64 *st = bpf_map_lookup_elem(&time_info,&pid); + if( st !=0){ + start_time = *st; + delay = (exit_time - start_time)/1000; + bpf_map_delete_elem(&time_info, &pid); + }else{ + return 0; + } + u64 *sc_id = bpf_map_lookup_elem(&id,&pid); + if( sc_id != 0){ + syscallid = *sc_id; + bpf_map_delete_elem(&id, &pid); + }else{ + return 0; + } + const void *contain_id = bpf_map_lookup_elem(&container_id_map,&pid); + if(contain_id != NULL){ + bpf_printk("hostname=%s\n",contain_id); + }else{ + return 0; + } + RESERVE_RINGBUF_ENTRY(rb, e); + e->syscall_data.delay = delay; + bpf_get_current_comm(&e->syscall_data.comm, sizeof(e->syscall_data.comm)); + e->syscall_data.pid = pid; + bpf_probe_read_kernel_str(&(e->syscall_data.container_id),sizeof(e->syscall_data.container_id),contain_id); + e->syscall_data.syscall_id = syscallid; + bpf_ringbuf_submit(e, 0); + return 0; +} + +struct data_t { + char nodename[MAX_NODENAME_LEN]; +}; +static bool is_container_task(const volatile char hostname[MAX_NODENAME_LEN]){ + struct task_struct *task; + struct nsproxy *ns; + struct uts_namespace *uts; + struct data_t data = {}; + // 获取当前任务的 task_struct + task = (struct task_struct *)bpf_get_current_task(); + + // 获取 nsproxy + bpf_probe_read_kernel(&ns, sizeof(ns), &task->nsproxy); + if (!ns) { + return false; + } + + // 获取 uts_namespace + bpf_probe_read_kernel(&uts, sizeof(uts), &ns->uts_ns); + if (!uts) { + return false; + } + // 读取主机名 + bpf_probe_read_kernel_str(&data.nodename, sizeof(data.nodename), uts->name.nodename); + // 打印主机名 + bool is_equal = true; + for(int i = 0;ievent_type = VCPU_LOAD; } else if (env->execute_timer) { env->event_type = TIMER; + } else if (env->execute_container_syscall) { + env->event_type = CONTAINER_SYSCALL; } else { env->event_type = NONE_TYPE; // 或者根据需要设置一个默认的事件类型 } @@ -544,6 +562,12 @@ static int handle_event(void *ctx, void *data, size_t data_sz) { case VCPU_LOAD: { break; } + case CONTAINER_SYSCALL: { + printf("%-8u %-22s %-10lld %-10lld %-16s\n", e->syscall_data.pid, + e->syscall_data.container_id, e->syscall_data.delay, + e->syscall_data.syscall_id, e->syscall_data.comm); + break; + } case HALT_POLL: { // 使用 e->halt_poll_data 访问 HALT_POLL 特有成员 printf("%-18.6f %-15s %-6d/%-8d %-10s %-7d %-7d --> %d \n", @@ -754,6 +778,10 @@ static int print_event_head(struct env *env) { "DUR_HALT(ms)", "COMM", "PID/TID", "VCPU_ID", "WAIT/POLL", "VAILD?"); break; + case CONTAINER_SYSCALL: + printf("%-8s %-22s %-9s %10s %-16s\n", "PID", "CONTAINER_ID", + "DELAY(us)", "SYSCALLID", "COMM"); + break; case EXIT: //可视化调整输出格式 // printf("Waiting vm_exit ... \n"); @@ -862,7 +890,10 @@ static void set_disable_load(struct kvm_watcher_bpf *skel) { if (env.execute_hypercall) { SET_KP_OR_FENTRY_LOAD(kvm_emulate_hypercall, kvm); } - + bpf_program__set_autoload(skel->progs.tp_container_sys_entry, + env.execute_container_syscall ? true : false); + bpf_program__set_autoload(skel->progs.tracepoint__syscalls__sys_exit, + env.execute_container_syscall ? true : false); bpf_program__set_autoload(skel->progs.tp_vcpu_wakeup, env.execute_vcpu_wakeup ? true : false); bpf_program__set_autoload(skel->progs.tp_exit, @@ -1221,7 +1252,6 @@ int attach_probe(struct kvm_watcher_bpf *skel) { } return kvm_watcher_bpf__attach(skel); } - int main(int argc, char **argv) { // 定义一个环形缓冲区 struct ring_buffer *rb = NULL; @@ -1233,7 +1263,6 @@ int main(int argc, char **argv) { return err; /*设置libbpf的错误和调试信息回调*/ libbpf_set_print(libbpf_print_fn); - /* Cleaner handling of Ctrl-C */ signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); @@ -1247,7 +1276,7 @@ int main(int argc, char **argv) { /* Parameterize BPF code with parameter */ skel->rodata->vm_pid = env.vm_pid; - + strcpy(skel->rodata->hostname, env.hostname); /* 禁用或加载内核挂钩函数 */ set_disable_load(skel); From 4f31f2af35fb4d019323a846bd2d52c0b027a9a9 Mon Sep 17 00:00:00 2001 From: shangfan <45649554+sf1999817@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:35:03 +0800 Subject: [PATCH 09/12] =?UTF-8?q?fs=5Fwatcher:=E6=8A=8Aopen=E3=80=81read?= =?UTF-8?q?=E3=80=81write=E8=BF=99=E4=B8=89=E4=B8=AAebpf=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E6=95=B4=E5=90=88=E5=88=B0=E4=BA=86=E4=B8=80=E4=B8=AA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=B9=B6=E4=B8=94=E4=BF=AE=E6=94=B9write?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=8F=90=E5=8F=96inode=5Fn?= =?UTF-8?q?umber=E5=8F=82=E6=95=B0=E4=BF=A1=E6=81=AF=20(#858)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * write_expaned Signed-off-by: shangfan <45649554+sf1999817@users.noreply.github.com> * fs_watcher_new Signed-off-by: shangfan <45649554+sf1999817@users.noreply.github.com> --------- Signed-off-by: shangfan <45649554+sf1999817@users.noreply.github.com> --- .../fs_watcher/bpf/open.bpf.c | 77 +++++ .../fs_watcher/bpf/read.bpf.c | 99 ++++++ .../fs_watcher/bpf/write.bpf.c | 62 ++++ .../fs_watcher/fs_watcher.bpf.c | 5 + .../fs_watcher/fs_watcher.c | 308 ++++++++++++++++++ .../fs_watcher/include/fs_watcher.h | 31 ++ .../old_project/write.bpf.c | 62 ++++ .../Filesystem_Subsystem/old_project/write.c | 101 ++++++ .../Filesystem_Subsystem/old_project/write.h | 11 + 9 files changed, 756 insertions(+) create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/open.bpf.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/read.bpf.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/write.bpf.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.bpf.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/include/fs_watcher.h create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/old_project/write.bpf.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/old_project/write.c create mode 100644 eBPF_Supermarket/Filesystem_Subsystem/old_project/write.h diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/open.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/open.bpf.c new file mode 100644 index 000000000..135a863fd --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/open.bpf.c @@ -0,0 +1,77 @@ +#define BPF_NO_GLOBAL_DATA +#include +#include +#include +#include + +#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, 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("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; + + 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; +} + +char LICENSE[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/read.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/read.bpf.c new file mode 100644 index 000000000..f04e973ec --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/read.bpf.c @@ -0,0 +1,99 @@ +#include "vmlinux.h" +#include +#include +#include +#include "read.h" +#define MAX_FILENAME_LEN 256 + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +// 手动定义文件类型宏 +#define S_IFMT 0170000 // 文件类型掩码 +#define S_IFREG 0100000 // 普通文件 +#define S_IFCHR 0020000 // 字符设备 +#define S_IFDIR 0040000 // 目录 +#define S_IFLNK 0120000 // 符号链接 +#define S_IFBLK 0060000 // 块设备 +#define S_IFIFO 0010000 // FIFO(命名管道) +#define S_IFSOCK 0140000 // 套接字 + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, pid_t); + __type(value, MAX_FILENAME_LEN); +} data SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +const volatile unsigned long long min_duration_ns = 0; + +SEC("kprobe/vfs_read") +int kprobe_enter_read(struct pt_regs *ctx) +{ + struct file *filp = (struct file *)PT_REGS_PARM1(ctx);   + pid_t pid; + struct event *e; + u64 ts; + char buf[256]; + pid = bpf_get_current_pid_tgid() >> 32; + ts = bpf_ktime_get_ns()/1000; + int count_size = PT_REGS_RC(ctx); + if (min_duration_ns) + return 0; + + //获取文件路径结构体 + struct dentry *dentry = BPF_CORE_READ(filp, f_path.dentry); + if(!dentry){ + bpf_printk("Failed to read dentry\n"); + return 0; + } + struct qstr d_name = BPF_CORE_READ(dentry,d_name); + + //读文件名称到缓冲区 + int ret = bpf_probe_read_kernel(buf, sizeof(buf), d_name.name); + if(ret != 0){ + bpf_printk("failed to read file name\n"); + } + // 判断文件类型,并过滤掉设备文件 + unsigned short file_type = BPF_CORE_READ(dentry, d_inode, i_mode) & S_IFMT; + bpf_map_update_elem(&data, &pid, &buf, BPF_ANY); + switch (file_type) { + case S_IFREG: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFCHR: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFDIR: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFLNK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFBLK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFIFO: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + case S_IFSOCK: + bpf_printk("Regular file name: %s,count_size :%d", buf,count_size); + break; + default: + bpf_printk("other!!!"); + break; + } + /* reserve sample from BPF ringbuf */ + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) + return 0; + e->pid = pid; + e->duration_ns = ts; + /* successfully submit it to user-space for post-processing */ + bpf_ringbuf_submit(e, 0); + return 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/write.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/write.bpf.c new file mode 100644 index 000000000..2240e657d --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/bpf/write.bpf.c @@ -0,0 +1,62 @@ +#include "vmlinux.h" +#include +#include +#include +#include "write.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; +#define PATH_MAX 256 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, pid_t); + __type(value, int); +} data SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries,256 * 1024); +} rb SEC(".maps"); + + +SEC("kprobe/vfs_write") +int kprobe_vfs_write(struct pt_regs *ctx) +{ + pid_t pid; + struct fs_t *e; + unsigned long inode_number;//定义用于存储inode号码的变量 + + //探测的是第一个参数,文件指针,读取inode_number + struct file *filp = (struct file *)PT_REGS_PARM1(ctx);   + struct dentry *dentry = BPF_CORE_READ(filp,f_path.dentry); + if(!dentry){ + bpf_printk("Failed to read dentry\n"); + return 0; + } + struct inode *inode = BPF_CORE_READ(dentry,d_inode); + if(!inode){ + bpf_printk("Failed to read inode\n"); + return 0; + } + int ret = bpf_probe_read_kernel(&inode_number,sizeof(inode_number),&inode->i_ino); + + //探测的是第三个参数,要写入的字节数 + size_t count = (size_t)PT_REGS_PARM3(ctx); + + //这是vfs_write的返回值,它是一个实际写入的字节数 + size_t real_count = PT_REGS_RC(ctx); + + pid = bpf_get_current_pid_tgid() >> 32; + e = bpf_ringbuf_reserve(&rb,sizeof(*e),0); + if(!e) + return 0; + + e->pid = pid; + e->real_count = real_count; + e->count = count; + e->inode_number = inode_number; + + //这里将获取到的文件指针不为空时 + bpf_ringbuf_submit(e, 0); + return 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.bpf.c new file mode 100644 index 000000000..00abd4b44 --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.bpf.c @@ -0,0 +1,5 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fs_watcher.h" \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.c b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.c new file mode 100644 index 000000000..abcc8defe --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/fs_watcher.c @@ -0,0 +1,308 @@ +// 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 +#include +#include +#include +#include +#include "open.skel.h" +#include "read.skel.h" +#include "write.skel.h" +#include "fs_watcher.h" + +const char argp_program_doc[] = "fs_watcher is in use ....\n"; + +#define PROCESS_SKEL(skel, func) \ + skel = func##_bpf__open(); \ + if (!skel) { \ + fprintf(stderr, "Failed to open and load BPF skeleton\n"); \ + return 1; \ + } \ + process_##func(skel) + + +#define POLL_RING_BUFFER(rb, timeout, err) \ + while (!exiting) { \ + err = ring_buffer__poll(rb, timeout); \ + if (err == -EINTR) { \ + err = 0; \ + break; \ + } \ + if (err < 0) { \ + printf("Error polling perf buffer: %d\n", err); \ + break; \ + } \ + } + +#define LOAD_AND_ATTACH_SKELETON(skel, event) \ + do { \ + err = event##_bpf__load(skel); \ + if (err) { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, NULL, NULL); \ + if (!rb) { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while(0) + + +#define LOAD_AND_ATTACH_SKELETON_MAP(skel, event) \ + do { \ + err = event##_bpf__load(skel); \ + if (err) { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + 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_event_##event, &map_fd, NULL); \ + if (!rb) { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while(0) + +static struct env{ + bool open; + bool read; + bool write; +}env = { + .open = false, + .read = false, + .write = false, +}; + +static const struct argp_option opts[] = { + {"select-function", 0, 0, 0, "Select function:", 1}, + + {"open", 'o', 0, 0, "Print open (open系统调用检测报告)"}, + + {"read", 'r', 0, 0, "Print read (read系统调用检测报告)"}, + + {"write", 'w', 0, 0, "Print write (write系统调用检测报告)"}, + + {0} // 结束标记,用于指示选项列表的结束 +}; + + +static error_t parse_arg(int key, char *arg, struct argp_state *state) { + switch(key){ + case 'o': + env.open = true;break; + case 'r': + env.read = true;break; + case 'w': + env.write = true;break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, +}; +#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; + +static void sig_handler(int sig) +{ + exiting = true; +} + +static int handle_event_open(void *ctx, void *data, size_t data_sz); +static int handle_event_read(void *ctx, void *data, size_t data_sz); +static int handle_event_write(void *ctx, void *data, size_t data_sz); + +static int process_open(struct open_bpf *skel_open); +static int process_read(struct read_bpf *skel_read); +static int process_write(struct write_bpf *skel_write); + + + + +int main(int argc,char **argv){ + + int err; + struct open_bpf *skel_open; + + struct read_bpf *skel_read; + struct write_bpf *skel_write; + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + /* Cleaner handling of Ctrl-C */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGALRM, sig_handler); + + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + printf("success!\n"); + if (err) + return err; + + if(env.open){ + PROCESS_SKEL(skel_open,open); + }else if(env.read){ + PROCESS_SKEL(skel_read,read); + }else if(env.write){ + PROCESS_SKEL(skel_write,write); + } + +} + + static int handle_event_open(void *ctx, void *data, size_t data_sz) +{ + struct event_open *e = (struct event_open *)data; + char *filename = strrchr(e->path_name_, '/'); + ++filename; + + 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; +} + + +static int handle_event_read(void *ctx, void *data, size_t data_sz) +{ + const struct event_read *e = data; + struct tm *tm; + char ts[32]; + time_t t; + + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + + printf("%-8s %-7d %-7llu\n", ts, e->pid,e->duration_ns); + return 0; +} + +static int handle_event_write(void *ctx, void *data, size_t data_sz) +{ + const struct fs_t *e = data; + struct tm *tm; + char ts[32]; + time_t t; + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + printf("ts:%-8s pid:%-7ld inode_number:%-3ld cout:%-3ld real_count:%-3ld\n", ts, e->pid,e->inode_number,e->count,e->real_count); + return 0; +} + +static int process_open(struct open_bpf *skel_open){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON_MAP(skel_open,open); + + printf("%-8s %-8s %-8s %-8s\n","filenamename","fd","pid","comm"); + POLL_RING_BUFFER(rb, 1000, err); + +open_cleanup: + ring_buffer__free(rb); + open_bpf__destroy(skel_open); + + return err; +} + +static int process_read(struct read_bpf *skel_read){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_read,read); + + printf("%-8s %-8s %-8s %-8s\n","filename","fd","pid","ds"); + POLL_RING_BUFFER(rb, 1000, err); + +read_cleanup: + ring_buffer__free(rb); + read_bpf__destroy(skel_read); + + return err; +} + +static int process_write(struct write_bpf *skel_write){ + int err; + struct ring_buffer *rb; + + LOAD_AND_ATTACH_SKELETON(skel_write,write); + + printf("%-8s %-8s %-8s %-8s %-8s\n","ds","inode_number","pid","real_count","count"); + POLL_RING_BUFFER(rb, 1000, err); + +write_cleanup: + ring_buffer__free(rb); + write_bpf__destroy(skel_write); + + return err; +} + diff --git a/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/include/fs_watcher.h b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/include/fs_watcher.h new file mode 100644 index 000000000..ccbf59f1d --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/fs_watcher/include/fs_watcher.h @@ -0,0 +1,31 @@ +#ifndef __FS_WATCHER_H +#define __FS_WATCHER_H + +/*open*/ +#define path_size 256 +#define TASK_COMM_LEN 16 + +struct event_open { + int pid_; + char path_name_[path_size]; + int n_; + char comm[TASK_COMM_LEN]; +}; + +/*read*/ + +struct event_read { + int pid; + unsigned long long duration_ns; +}; + +/*write*/ +struct fs_t { + unsigned long inode_number; + pid_t pid; + size_t real_count; + size_t count; +}; + + +#endif /* __MEM_WATCHER_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.bpf.c b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.bpf.c new file mode 100644 index 000000000..2240e657d --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.bpf.c @@ -0,0 +1,62 @@ +#include "vmlinux.h" +#include +#include +#include +#include "write.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; +#define PATH_MAX 256 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, pid_t); + __type(value, int); +} data SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries,256 * 1024); +} rb SEC(".maps"); + + +SEC("kprobe/vfs_write") +int kprobe_vfs_write(struct pt_regs *ctx) +{ + pid_t pid; + struct fs_t *e; + unsigned long inode_number;//定义用于存储inode号码的变量 + + //探测的是第一个参数,文件指针,读取inode_number + struct file *filp = (struct file *)PT_REGS_PARM1(ctx);   + struct dentry *dentry = BPF_CORE_READ(filp,f_path.dentry); + if(!dentry){ + bpf_printk("Failed to read dentry\n"); + return 0; + } + struct inode *inode = BPF_CORE_READ(dentry,d_inode); + if(!inode){ + bpf_printk("Failed to read inode\n"); + return 0; + } + int ret = bpf_probe_read_kernel(&inode_number,sizeof(inode_number),&inode->i_ino); + + //探测的是第三个参数,要写入的字节数 + size_t count = (size_t)PT_REGS_PARM3(ctx); + + //这是vfs_write的返回值,它是一个实际写入的字节数 + size_t real_count = PT_REGS_RC(ctx); + + pid = bpf_get_current_pid_tgid() >> 32; + e = bpf_ringbuf_reserve(&rb,sizeof(*e),0); + if(!e) + return 0; + + e->pid = pid; + e->real_count = real_count; + e->count = count; + e->inode_number = inode_number; + + //这里将获取到的文件指针不为空时 + bpf_ringbuf_submit(e, 0); + return 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.c b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.c new file mode 100644 index 000000000..cbe451557 --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include "write.h" +#include "write.skel.h" + +#define PATH_MAX 128 + +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; + +static void sig_handler(int sig) +{ + exiting = true; +} + +static int write_event(void *ctx, void *data, size_t data_sz) +{ + const struct fs_t *e = data; + struct tm *tm; + char ts[32]; + time_t t; + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + printf("ts:%-8s pid:%-7ld inode_number:%-7ld cout:%-7ld real_count:%-7ld\n", ts, e->pid,e->inode_number,e->count,e->real_count); + return 0; +} + +int main(int argc, char **argv) +{ + struct ring_buffer *rb = NULL; + struct write_bpf *skel; + int err; + + /* Set up libbpf errors and debug info callback */ + libbpf_set_print(libbpf_print_fn); + + + /* Cleaner handling of Ctrl-C */ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + /* Open BPF application */ + skel = write_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + + /* Load & verify BPF programs */ + err = write_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + /* Attach tracepoints */ + err = write_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + /* Set up ring buffer polling */ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), write_event, NULL, NULL); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto cleanup; + } + + /* Process events */ + while (!exiting) { + err = ring_buffer__poll(rb, 100 /* timeout, ms */); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + } + +cleanup: + /* Clean up */ + ring_buffer__free(rb); + write_bpf__destroy(skel); + + return err < 0 ? -err : 0; +} \ No newline at end of file diff --git a/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.h b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.h new file mode 100644 index 000000000..3959afcbf --- /dev/null +++ b/eBPF_Supermarket/Filesystem_Subsystem/old_project/write.h @@ -0,0 +1,11 @@ +#ifndef __WRITE_H +#define __WRITE_H + +struct fs_t { + unsigned long inode_number; + pid_t pid; + size_t real_count; + size_t count; +}; + +#endif /* __WRITE_H */ \ No newline at end of file From d8d193cae242faff1dee44f337a074f7e8247c02 Mon Sep 17 00:00:00 2001 From: Super-Lzzx <145275401+Super-Lzzx@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:35:57 +0800 Subject: [PATCH 10/12] =?UTF-8?q?Mem=5Fwatcher:=E5=A2=9E=E5=8A=A0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=9A=84=E6=B5=8B=E8=AF=95=E7=A8=8B=E5=BA=8F=20(#855)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 增加项目的测试程序 * 修改可视化文档 --------- Co-authored-by: qcloud --- .../docs/mem_watcher_vision.md | 2 +- .../mem_watcher/test/sysstat_test/Makefile | 11 +++++ .../test/sysstat_test/sysstat_test.c | 49 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/Makefile create mode 100644 eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/sysstat_test.c diff --git a/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md b/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md index 4226d65fe..b64ce6a24 100644 --- a/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md +++ b/eBPF_Supermarket/Memory_Subsystem/docs/mem_watcher_vision.md @@ -17,7 +17,7 @@ - 执行`make start_service`指令,配置下载docker镜像并启动grafana和prometheus服务 - 执行如下指令开始采集数据以及相关处理: ```c - ./data-visual collect /home/ubuntu/lmp/eBPF_Supermarket/Memory_Subsystem/mem_watcher -p + ./data-visual collect lmp/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher -p ``` 切记根据自己的文件所在目录进行修改,如果不知道或者不确定的可以在自己的程序文件下输入`pwd`命令进行查看,如果目录出现错误会失败。 diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/Makefile b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/Makefile new file mode 100644 index 000000000..9e3fbbded --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/Makefile @@ -0,0 +1,11 @@ +CC = gcc +CFLAGS = -Wall -O2 +TARGET = sysstat_test + +all: $(TARGET) + +$(TARGET): sysstat_test.c + $(CC) $(CFLAGS) -o $(TARGET) sysstat_test.c + +clean: + rm -f $(TARGET) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/sysstat_test.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/sysstat_test.c new file mode 100644 index 000000000..c0e7e64b5 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/test/sysstat_test/sysstat_test.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#define ALLOC_SIZE_SMALL 512*1024*1024 // 分配 512 MB 内存 +#define ALLOC_SIZE_LARGE 1024*1024*1024 // 分配 1 GB 内存 + +void allocate_memory(size_t size) { + void *memory; + + printf("Allocating %lu MB memory...\n", size / (1024*1024)); + memory = malloc(size); + if (!memory) { + perror("Failed to allocate memory"); + return; + } + + // 填充内存以确保页面被分配 + printf("Filling memory...\n"); + for (size_t i = 0; i < size; ++i) { + ((char*)memory)[i] = (char)i; + } + + printf("Freeing memory...\n"); + free(memory); + + // 给内核更多时间处理回收 + printf("Sleeping for 10 seconds...\n"); + sleep(10); // 增加等待时间到 10 秒 + + printf("Memory management operation finished.\n"); +} + +int main() { + printf("Starting memory management demo...\n"); + + // 分配和释放多次小块内存 + for (int i = 0; i < 5; ++i) { + allocate_memory(ALLOC_SIZE_SMALL); + } + + // 分配和释放多次大块内存 + for (int i = 0; i < 5; ++i) { + allocate_memory(ALLOC_SIZE_LARGE); + } + + printf("Memory management demo finished.\n"); + return 0; +} From 071f189efc816ea68734ebb56abbc51a36005099 Mon Sep 17 00:00:00 2001 From: gaoyixiang1 <1739037263@qq.com> Date: Thu, 11 Jul 2024 09:31:19 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E5=90=88=E5=B9=B6=20fraginfo=20=E5=88=B0?= =?UTF-8?q?=20mem=5Fwatcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: gaoyixiang1 <1739037263@qq.com> --- .github/workflows/ebpf_mem_watcher.yml | 2 +- .../Memory_Subsystem/mem_watcher/Makefile | 2 +- .../mem_watcher/bpf/fraginfo.bpf.c | 94 ++ .../mem_watcher/include/fraginfo.h | 33 + .../mem_watcher/mem_watcher.c | 971 +++++++++++------- 5 files changed, 719 insertions(+), 383 deletions(-) create mode 100644 eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/fraginfo.bpf.c create mode 100644 eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/fraginfo.h diff --git a/.github/workflows/ebpf_mem_watcher.yml b/.github/workflows/ebpf_mem_watcher.yml index a3c72420a..6a056740c 100644 --- a/.github/workflows/ebpf_mem_watcher.yml +++ b/.github/workflows/ebpf_mem_watcher.yml @@ -32,4 +32,4 @@ jobs: cd eBPF_Supermarket/Memory_Subsystem/mem_watcher/ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h make - sudo timeout 20 ./mem_watcher + sudo ./mem_watcher -f -i 10 diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile index 06e256892..7c08e2775 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/Makefile @@ -24,7 +24,7 @@ INCLUDES := -I$(OUTPUT) -I../../libbpf/include/uapi -I$(dir $(VMLINUX)) -I$(LIBB CFLAGS := -g -Wall ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) -APPS = paf pr procstat sysstat memleak +APPS = paf pr procstat sysstat memleak fraginfo CARGO ?= $(shell which cargo) ifeq ($(strip $(CARGO)),) diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/fraginfo.bpf.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/fraginfo.bpf.c new file mode 100644 index 000000000..c05191dac --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/bpf/fraginfo.bpf.c @@ -0,0 +1,94 @@ +#include "vmlinux.h" +#include +#include +#include +#include "fraginfo.h" + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 102400); + __type(key, u64); + __type(value, struct zone_info); +} zones SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 102400); + __type(key, u64); + __type(value, struct pgdat_info); +} nodes SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 102400); + __type(key,struct order_zone); + __type(value, struct ctg_info); +} orders SEC(".maps"); + +static void fill_contig_page_info(struct zone *zone, unsigned int suitable_order, + struct contig_page_info *info) +{ + unsigned int order; + info->free_pages = 0; + info->free_blocks_total = 0; + info->free_blocks_suitable = 0; + for (order = 0; order <= MAX_ORDER; order++) { + unsigned long blocks; + unsigned long nr_free; + nr_free = BPF_CORE_READ(&zone->free_area[order], nr_free); + blocks = nr_free; + info->free_blocks_total += blocks; + info->free_pages += blocks << order; + if (order >= suitable_order) + info->free_blocks_suitable += blocks << (order - suitable_order); + } +} + +SEC("kprobe/get_page_from_freelist") +int BPF_KPROBE(get_page_from_freelist, gfp_t gfp_mask, unsigned int order, int alloc_flags, + const struct alloc_context *ac) +{ + bpf_printk("1111"); + struct pgdat_info node_info = {}; + struct zone_info zone_data = {}; + + struct pglist_data *pgdat; + struct zoneref *zref; + struct zone *z; + int i; + unsigned int a_order; + + pgdat = BPF_CORE_READ(ac, preferred_zoneref, zone, zone_pgdat); + node_info.node_id = BPF_CORE_READ(pgdat, node_id); + node_info.nr_zones = BPF_CORE_READ(pgdat, nr_zones); + node_info.pgdat_ptr = (u64)pgdat; + u64 key = (u64)pgdat; + + bpf_map_update_elem(&nodes, &key, &node_info, BPF_ANY); + + for (i = 0; i < __MAX_NR_ZONES; i++) { + zref = &pgdat->node_zonelists[0]._zonerefs[i]; + z = BPF_CORE_READ(zref, zone); + if ((u64)z == 0) break; + zone_data.zone_ptr = (u64)z; + u64 zone_key = (u64)z; + zone_data.zone_start_pfn = BPF_CORE_READ(z, zone_start_pfn); + zone_data.spanned_pages = BPF_CORE_READ(z, spanned_pages); + zone_data.present_pages = BPF_CORE_READ(z, present_pages); + bpf_probe_read_kernel_str(zone_data.comm, sizeof(zone_data.comm), BPF_CORE_READ(z, name)); + for (a_order = 0; a_order <= MAX_ORDER; ++a_order) { + zone_data.order = a_order; + struct order_zone order_key = {}; + order_key.order = a_order; + order_key.zone_ptr = (u64)z; + struct contig_page_info ctg_info = {}; + fill_contig_page_info(z, a_order, &ctg_info); + bpf_map_update_elem(&orders,&order_key,&ctg_info,BPF_ANY); + } + bpf_map_update_elem(&zones, &zone_key, &zone_data, BPF_ANY); + } + + return 0; +} diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/fraginfo.h b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/fraginfo.h new file mode 100644 index 000000000..c2c15f9a9 --- /dev/null +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/include/fraginfo.h @@ -0,0 +1,33 @@ +#ifndef FRAGINFO_H +#define FRAGINFO_H + +#define MAX_ORDER 10 +typedef __u64 u64; +struct order_zone{ + unsigned int order; + u64 zone_ptr; +}; +struct ctg_info { + long unsigned int free_pages; + long unsigned int free_blocks_total; + long unsigned int free_blocks_suitable; +}; + +struct zone_info +{ + u64 zone_ptr; + u64 zone_start_pfn; + u64 spanned_pages; + u64 present_pages; + char comm[32]; + unsigned int order; +}; + +struct pgdat_info +{ + u64 pgdat_ptr; + int nr_zones; + int node_id; +}; + +#endif diff --git a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c index 2b5f34811..6f851f007 100644 --- a/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c +++ b/eBPF_Supermarket/Memory_Subsystem/mem_watcher/mem_watcher.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -31,13 +32,15 @@ #include "pr.skel.h" #include "procstat.skel.h" #include "sysstat.skel.h" +#include "fraginfo.skel.h" #include "memleak.skel.h" #include "mem_watcher.h" +#include "fraginfo.h" #include "blazesym.h" -static const int perf_max_stack_depth = 127; //stack id 对应的堆栈的深度 -static const int stack_map_max_entries = 10240; //最大允许存储多少个stack_id +static const int perf_max_stack_depth = 127; // stack id 对应的堆栈的深度 +static const int stack_map_max_entries = 10240; // 最大允许存储多少个stack_id static __u64 *g_stacks = NULL; static size_t g_stacks_size = 0; @@ -48,9 +51,10 @@ static struct blaze_symbolizer *symbolizer; static int attach_pid; pid_t own_pid; -static char binary_path[128] = { 0 }; +static char binary_path[128] = {0}; -struct allocation { +struct allocation +{ int stack_id; __u64 size; size_t count; @@ -60,92 +64,107 @@ static struct allocation *allocs; static volatile bool exiting = false; -#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, \ - attach_pid, \ - 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(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, \ + attach_pid, \ + 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) + 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) -#define PROCESS_SKEL(skel, func) \ - skel = func##_bpf__open(); \ - if (!skel) { \ - fprintf(stderr, "Failed to open and load BPF skeleton\n"); \ - return 1; \ - } \ - process_##func(skel) - -#define POLL_RING_BUFFER(rb, timeout, err) \ - while (!exiting) { \ - err = ring_buffer__poll(rb, timeout); \ - if (err == -EINTR) { \ - err = 0; \ - break; \ - } \ - if (err < 0) { \ - printf("Error polling perf buffer: %d\n", err); \ - break; \ - } \ - } +#define PROCESS_SKEL(skel, func) \ + skel = func##_bpf__open(); \ + if (!skel) \ + { \ + fprintf(stderr, "Failed to open and load BPF skeleton\n"); \ + return 1; \ + } \ + process_##func(skel) + +#define POLL_RING_BUFFER(rb, timeout, err) \ + while (!exiting) \ + { \ + err = ring_buffer__poll(rb, timeout); \ + if (err == -EINTR) \ + { \ + err = 0; \ + break; \ + } \ + if (err < 0) \ + { \ + printf("Error polling perf buffer: %d\n", err); \ + break; \ + } \ + } -#define LOAD_AND_ATTACH_SKELETON(skel, event) \ - do { \ - skel->bss->user_pid = own_pid; \ - err = event##_bpf__load(skel); \ - if (err) { \ - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ - goto event##_cleanup; \ - } \ - \ - err = event##_bpf__attach(skel); \ - if (err) { \ - fprintf(stderr, "Failed to attach BPF skeleton\n"); \ - goto event##_cleanup; \ - } \ - \ - rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, NULL, NULL); \ - if (!rb) { \ - fprintf(stderr, "Failed to create ring buffer\n"); \ - goto event##_cleanup; \ - } \ - } while(0) - -static struct env { +#define LOAD_AND_ATTACH_SKELETON(skel, event) \ + do \ + { \ + skel->bss->user_pid = own_pid; \ + err = event##_bpf__load(skel); \ + if (err) \ + { \ + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + err = event##_bpf__attach(skel); \ + if (err) \ + { \ + fprintf(stderr, "Failed to attach BPF skeleton\n"); \ + goto event##_cleanup; \ + } \ + \ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event_##event, NULL, NULL); \ + if (!rb) \ + { \ + fprintf(stderr, "Failed to create ring buffer\n"); \ + goto event##_cleanup; \ + } \ + } while (0) + +static struct env +{ int time; bool paf; bool pr; bool procstat; bool sysstat; bool memleak; + bool fraginfo; bool kernel_trace; bool print_time; - + int interval; + int duration; bool part2; long choose_pid; @@ -157,11 +176,14 @@ static struct env { .procstat = false, .sysstat = false, .memleak = false, + .fraginfo = false, .kernel_trace = true, .print_time = false, .rss = false, .part2 = false, .choose_pid = 0, + .interval = 1, + .duration = 10, }; const char argp_program_doc[] = "mem_watcher is in use ....\n"; @@ -182,39 +204,76 @@ static const struct argp_option opts[] = { {0, 0, 0, 0, "sysstat:", 6}, {"sysstat", 's', 0, 0, "print sysstat (系统内存状态报告)"}, - + {"part2", 'n', NULL, 0, "系统内存状态报告2", 7}, {0, 0, 0, 0, "memleak:", 8}, {"memleak", 'l', 0, 0, "print memleak (内核态内存泄漏检测)", 8}, {"choose_pid", 'P', "PID", 0, "选择进程号打印, print memleak (用户态内存泄漏检测)", 9}, {"print_time", 'm', 0, 0, "打印申请地址时间 (用户态)", 10}, - - + {"print_time", 'f', 0, 0, "打印申请地址时间 (用户态)", 10}, {"time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)", 11}, + + {0, 0, 0, 0, "fraginfo:", 12}, + {"fraginfo", 'f', 0, 0, "print fraginfo",12}, + {"interval", 'i', "INTERVAL", 0, "Print interval in seconds (default 1)"}, + {"duration", 'd', "DURATION", 0, "Total duration in seconds to run (default 10)"}, {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 'a': env.paf = true; break; - case 'p': env.pr = true; break; - case 'r': env.procstat = true; break; - case 's': env.sysstat = true; break; - 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; - } - return 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 'a': + env.paf = true; + break; + case 'p': + env.pr = true; + break; + case 'r': + env.procstat = true; + break; + case 'f': + env.fraginfo = true; + break; + case 's': + env.sysstat = true; + break; + 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; + case 'i': + env.interval = atoi(arg); + break; + case 'd': + env.duration = atoi(arg); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; } static const struct argp argp = { @@ -224,7 +283,7 @@ static const struct argp argp = { }; // Function prototypes -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args); +// static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args); static void sig_handler(int sig); static void setup_signals(void); static void disable_kernel_tracepoints(struct memleak_bpf *skel); @@ -242,40 +301,56 @@ static int process_pr(struct pr_bpf *skel_pr); static int process_procstat(struct procstat_bpf *skel_procstat); static int process_sysstat(struct sysstat_bpf *skel_sysstat); static int process_memleak(struct memleak_bpf *skel_memleak, struct env); +static int process_fraginfo(struct fraginfo_bpf *skel_fraginfo); 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; - struct paf_bpf *skel_paf; - struct pr_bpf *skel_pr; - struct procstat_bpf *skel_procstat; - struct sysstat_bpf *skel_sysstat; - struct memleak_bpf *skel_memleak; - - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); - if (err) - return err; - - own_pid = getpid(); - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - libbpf_set_print(libbpf_print_fn); - - setup_signals(); - - if (env.paf) { +int main(int argc, char **argv) +{ + int err; + struct paf_bpf *skel_paf; + struct pr_bpf *skel_pr; + struct procstat_bpf *skel_procstat; + struct sysstat_bpf *skel_sysstat; + struct memleak_bpf *skel_memleak; + struct fraginfo_bpf *skel_fraginfo; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + own_pid = getpid(); + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + // libbpf_set_print(libbpf_print_fn); + + setup_signals(); + + if (env.paf) + { PROCESS_SKEL(skel_paf, paf); - } else if (env.pr) { + } + else if (env.pr) + { PROCESS_SKEL(skel_pr, pr); - } else if (env.procstat) { + } + else if (env.procstat) + { PROCESS_SKEL(skel_procstat, procstat); - } else if (env.sysstat) { + } + else if (env.fraginfo) + { + PROCESS_SKEL(skel_fraginfo, fraginfo); + } + else if (env.sysstat) + { PROCESS_SKEL(skel_sysstat, sysstat); - } else if (env.memleak) { - if (env.choose_pid != 0) { + } + else if (env.memleak) + { + if (env.choose_pid != 0) + { printf("用户态内存泄漏\n"); env.kernel_trace = false; attach_pid = env.choose_pid; @@ -288,17 +363,18 @@ int main(int argc, char **argv) { allocs = calloc(ALLOCS_MAX_ENTRIES, sizeof(*allocs)); /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); + // libbpf_set_print(libbpf_print_fn); /* Load and verify BPF application */ skel_memleak = memleak_bpf__open(); - if (!skel_memleak) { + if (!skel_memleak) + { fprintf(stderr, "Failed to open BPF skeleton\n"); return 1; } process_memleak(skel_memleak, env); } - return 0; + return 0; } int alloc_size_compare(const void *a, const void *b) @@ -317,35 +393,45 @@ int alloc_size_compare(const void *a, const void *b) return 0; } -static void print_frame(const char *name, uintptr_t input_addr, uintptr_t addr, uint64_t offset, const blaze_symbolize_code_info *code_info) { +static void print_frame(const char *name, uintptr_t input_addr, uintptr_t addr, uint64_t offset, const blaze_symbolize_code_info *code_info) +{ // If we have an input address we have a new symbol. - if (input_addr != 0) { + if (input_addr != 0) + { printf("%016lx: %s @ 0x%lx+0x%lx", input_addr, name, addr, offset); - if (code_info != NULL && code_info->dir != NULL && code_info->file != NULL) { + if (code_info != NULL && code_info->dir != NULL && code_info->file != NULL) + { printf(" %s/%s:%u\n", code_info->dir, code_info->file, code_info->line); } - else if (code_info != NULL && code_info->file != NULL) { + else if (code_info != NULL && code_info->file != NULL) + { printf(" %s:%u\n", code_info->file, code_info->line); } - else { + else + { printf("\n"); } } - else { + else + { printf("%16s %s", "", name); - if (code_info != NULL && code_info->dir != NULL && code_info->file != NULL) { + if (code_info != NULL && code_info->dir != NULL && code_info->file != NULL) + { printf("@ %s/%s:%u [inlined]\n", code_info->dir, code_info->file, code_info->line); } - else if (code_info != NULL && code_info->file != NULL) { + else if (code_info != NULL && code_info->file != NULL) + { printf("@ %s:%u [inlined]\n", code_info->file, code_info->line); } - else { + else + { printf("[inlined]\n"); } } } -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) +{ const struct blaze_symbolize_inlined_fn *inlined; const struct blaze_result *result; const struct blaze_sym *sym; @@ -353,23 +439,26 @@ static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { assert(sizeof(uintptr_t) == sizeof(uint64_t)); - if (pid) { + if (pid) + { struct blaze_symbolize_src_process src = { .type_size = sizeof(src), .pid = pid, }; result = blaze_symbolize_process_abs_addrs(symbolizer, &src, (const uintptr_t *)stack, stack_sz); } - else { + else + { struct blaze_symbolize_src_kernel src = { .type_size = sizeof(src), }; result = blaze_symbolize_kernel_abs_addrs(symbolizer, &src, (const uintptr_t *)stack, stack_sz); } - - for (i = 0; i < stack_sz; i++) { - if (!result || result->cnt <= i || result->syms[i].name == NULL) { + for (i = 0; i < stack_sz; i++) + { + if (!result || result->cnt <= i || result->syms[i].name == NULL) + { printf("%016llx: \n", stack[i]); continue; } @@ -377,7 +466,8 @@ static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { sym = &result->syms[i]; print_frame(sym->name, stack[i], sym->addr, sym->offset, &sym->code_info); - for (j = 0; j < sym->inlined_cnt; j++) { + for (j = 0; j < sym->inlined_cnt; j++) + { inlined = &sym->inlined[j]; print_frame(sym->name, 0, 0, 0, &inlined->code_info); } @@ -386,7 +476,8 @@ static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { blaze_result_free(result); } -int print_outstanding_allocs(struct memleak_bpf *skel) { +int print_outstanding_allocs(struct memleak_bpf *skel) +{ const size_t allocs_key_size = bpf_map__key_size(skel->maps.allocs); time_t t = time(NULL); @@ -395,12 +486,15 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { size_t nr_allocs = 0; // for each struct alloc_info "alloc_info" in the bpf map "allocs" - for (__u64 prev_key = 0, curr_key = 0; ; prev_key = curr_key) { + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) + { struct alloc_info alloc_info = {}; memset(&alloc_info, 0, sizeof(alloc_info)); - if (bpf_map__get_next_key(skel->maps.allocs, &prev_key, &curr_key, allocs_key_size)) { - if (errno == ENOENT) { + if (bpf_map__get_next_key(skel->maps.allocs, &prev_key, &curr_key, allocs_key_size)) + { + if (errno == ENOENT) + { break; // no more keys, done } @@ -409,7 +503,8 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { return -errno; } - if (bpf_map__lookup_elem(skel->maps.allocs, &curr_key, allocs_key_size, &alloc_info, sizeof(alloc_info), 0)) { + if (bpf_map__lookup_elem(skel->maps.allocs, &curr_key, allocs_key_size, &alloc_info, sizeof(alloc_info), 0)) + { if (errno == ENOENT) continue; @@ -419,7 +514,8 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { } // filter invalid stacks - if (alloc_info.stack_id < 0) { + if (alloc_info.stack_id < 0) + { continue; } @@ -427,10 +523,12 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { // increment size with alloc_info.size bool stack_exists = false; - for (size_t i = 0; !stack_exists && i < nr_allocs; ++i) { + for (size_t i = 0; !stack_exists && i < nr_allocs; ++i) + { struct allocation *alloc = &allocs[i]; - if (alloc->stack_id == alloc_info.stack_id) { + if (alloc->stack_id == alloc_info.stack_id) + { alloc->size += alloc_info.size; alloc->count++; @@ -461,14 +559,16 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { size_t nr_allocs_to_show = nr_allocs < 10 ? nr_allocs : 10; printf("[%d:%d:%d] Top %zu stacks with outstanding allocations:\n", - tm->tm_hour, tm->tm_min, tm->tm_sec, nr_allocs_to_show); + tm->tm_hour, tm->tm_min, tm->tm_sec, nr_allocs_to_show); - for (size_t i = 0; i < nr_allocs_to_show;i++) { + for (size_t i = 0; i < nr_allocs_to_show; i++) + { if (bpf_map__lookup_elem(skel->maps.stack_traces, - &allocs[i].stack_id, sizeof(allocs[i].stack_id), g_stacks, g_stacks_size, 0)) { - perror("failed to lookup stack traces!"); - return -errno; - } + &allocs[i].stack_id, sizeof(allocs[i].stack_id), g_stacks, g_stacks_size, 0)) + { + perror("failed to lookup stack traces!"); + return -errno; + } } show_stack_trace(g_stacks, nr_allocs_to_show, 0); @@ -476,147 +576,171 @@ int print_outstanding_allocs(struct memleak_bpf *skel) { return 0; } -int print_outstanding_combined_allocs(struct memleak_bpf *skel, pid_t pid) { - const size_t combined_allocs_key_size = bpf_map__key_size(skel->maps.combined_allocs); - const size_t stack_traces_key_size = bpf_map__key_size(skel->maps.stack_traces); - - for (__u64 prev_key = 0, curr_key = 0; ; prev_key = curr_key) { - - if (bpf_map__get_next_key(skel->maps.combined_allocs, - &prev_key, &curr_key, combined_allocs_key_size)) { - if (errno == ENOENT) { - break; //no more keys, done! - } - perror("map get next key failed!"); - - return -errno; - } - - // stack_id = curr_key - union combined_alloc_info cinfo; - memset(&cinfo, 0, sizeof(cinfo)); - - if (bpf_map__lookup_elem(skel->maps.combined_allocs, - &curr_key, combined_allocs_key_size, &cinfo, sizeof(cinfo), 0)) { - if (errno == ENOENT) { - continue; - } - - perror("map lookup failed!"); - return -errno; - } - - if (bpf_map__lookup_elem(skel->maps.stack_traces, - &curr_key, stack_traces_key_size, g_stacks, g_stacks_size, 0)) { - perror("failed to lookup stack traces!"); - return -errno; - } - - printf("stack_id=0x%llx with outstanding allocations: total_size=%llu nr_allocs=%llu\n", - curr_key, (__u64)cinfo.total_size, (__u64)cinfo.number_of_allocs); - - int stack_sz = 0; - for (int i = 0; i < perf_max_stack_depth; i++) { - if (g_stacks[i] == 0) { - break; - } - stack_sz++; - //printf("[%3d] 0x%llx\n", i, g_stacks[i]); - } - - show_stack_trace(g_stacks, stack_sz, pid); - } +int print_outstanding_combined_allocs(struct memleak_bpf *skel, pid_t pid) +{ + const size_t combined_allocs_key_size = bpf_map__key_size(skel->maps.combined_allocs); + const size_t stack_traces_key_size = bpf_map__key_size(skel->maps.stack_traces); + + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) + { + + if (bpf_map__get_next_key(skel->maps.combined_allocs, + &prev_key, &curr_key, combined_allocs_key_size)) + { + if (errno == ENOENT) + { + break; // no more keys, done! + } + perror("map get next key failed!"); + + return -errno; + } + + // stack_id = curr_key + union combined_alloc_info cinfo; + memset(&cinfo, 0, sizeof(cinfo)); + + if (bpf_map__lookup_elem(skel->maps.combined_allocs, + &curr_key, combined_allocs_key_size, &cinfo, sizeof(cinfo), 0)) + { + if (errno == ENOENT) + { + continue; + } - return 0; + perror("map lookup failed!"); + return -errno; + } + + if (bpf_map__lookup_elem(skel->maps.stack_traces, + &curr_key, stack_traces_key_size, g_stacks, g_stacks_size, 0)) + { + perror("failed to lookup stack traces!"); + return -errno; + } + + printf("stack_id=0x%llx with outstanding allocations: total_size=%llu nr_allocs=%llu\n", + curr_key, (__u64)cinfo.total_size, (__u64)cinfo.number_of_allocs); + + int stack_sz = 0; + for (int i = 0; i < perf_max_stack_depth; i++) + { + if (g_stacks[i] == 0) + { + break; + } + stack_sz++; + // printf("[%3d] 0x%llx\n", i, g_stacks[i]); + } + + show_stack_trace(g_stacks, stack_sz, pid); + } + + return 0; } // 在更新时间之前获取当前时间并调整为相对于程序启动时的时间 -static __u64 adjust_time_to_program_start_time(__u64 first_query_time) { - struct timespec current_time; - clock_gettime(CLOCK_MONOTONIC, ¤t_time); - //printf("current_time: %ld\n", current_time.tv_sec); - __u64 adjusted_time; - adjusted_time = current_time.tv_sec - first_query_time; - - //printf("adjusted_time: %lld\n", adjusted_time); - return adjusted_time; +static __u64 adjust_time_to_program_start_time(__u64 first_query_time) +{ + struct timespec current_time; + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + // printf("current_time: %ld\n", current_time.tv_sec); + __u64 adjusted_time; + adjusted_time = current_time.tv_sec - first_query_time; + + // printf("adjusted_time: %lld\n", adjusted_time); + return adjusted_time; } - // 在更新时间时,先将时间调整为相对于程序启动的时间 -static int update_addr_times(struct memleak_bpf *skel) { - const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); - const size_t first_time_key_size = bpf_map__key_size(skel->maps.first_time); - for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { - if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { - if (errno == ENOENT) { - break; // no more keys, done! - } - - perror("map get next key failed!"); - return -errno; - } - - // Check if the address exists in the first_time map - __u64 first_query_time; - if (bpf_map__lookup_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_query_time, sizeof(first_query_time), 0)) { - // Address doesn't exist in the first_time map, add it with the current time - struct timespec first_time_alloc; - clock_gettime(CLOCK_MONOTONIC, &first_time_alloc); - if (bpf_map__update_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_time_alloc.tv_sec, sizeof(first_time_alloc.tv_sec), 0)) { - perror("map update failed!"); - return -errno; - } - } - else { - // Address exists in the first_time map - // This is the first time updating timestamp - __u64 adjusted_time = adjust_time_to_program_start_time(first_query_time); - //printf("update_addr_times adjusted_time: %lld\n", adjusted_time); - - // Save the adjusted time to addr_times map - __u64 timestamp = adjusted_time; - - // write the updated timestamp back to the map - if (bpf_map__update_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0)) { - perror("map update failed!"); - return -errno; - } - } - } - return 0; +static int update_addr_times(struct memleak_bpf *skel) +{ + const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); + const size_t first_time_key_size = bpf_map__key_size(skel->maps.first_time); + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) + { + if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) + { + if (errno == ENOENT) + { + break; // no more keys, done! + } + + perror("map get next key failed!"); + return -errno; + } + + // Check if the address exists in the first_time map + __u64 first_query_time; + if (bpf_map__lookup_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_query_time, sizeof(first_query_time), 0)) + { + // Address doesn't exist in the first_time map, add it with the current time + struct timespec first_time_alloc; + clock_gettime(CLOCK_MONOTONIC, &first_time_alloc); + if (bpf_map__update_elem(skel->maps.first_time, &curr_key, first_time_key_size, &first_time_alloc.tv_sec, sizeof(first_time_alloc.tv_sec), 0)) + { + perror("map update failed!"); + return -errno; + } + } + else + { + // Address exists in the first_time map + // This is the first time updating timestamp + __u64 adjusted_time = adjust_time_to_program_start_time(first_query_time); + // printf("update_addr_times adjusted_time: %lld\n", adjusted_time); + + // Save the adjusted time to addr_times map + __u64 timestamp = adjusted_time; + + // write the updated timestamp back to the map + if (bpf_map__update_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0)) + { + perror("map update failed!"); + return -errno; + } + } + } + return 0; } // 在打印时间时,先将时间调整为相对于程序启动的时间 -int print_time(struct memleak_bpf *skel) { - const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); - - printf("%-16s %12s\n", "AL_ADDR", "AL_Time(s)"); - - // Iterate over the addr_times map to print address and time - for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) { - if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) { - if (errno == ENOENT) { - break; // no more keys, done! - } - perror("map get next key failed!"); - return -errno; - } - - // Read the timestamp for the current address - __u64 timestamp; - if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) { - printf("0x%-16llx %lld\n", curr_key, timestamp); - } - else { - perror("map lookup failed!"); - return -errno; - } - } - return 0; +int print_time(struct memleak_bpf *skel) +{ + const size_t addr_times_key_size = bpf_map__key_size(skel->maps.addr_times); + + printf("%-16s %12s\n", "AL_ADDR", "AL_Time(s)"); + + // Iterate over the addr_times map to print address and time + for (__u64 prev_key = 0, curr_key = 0;; prev_key = curr_key) + { + if (bpf_map__get_next_key(skel->maps.addr_times, &prev_key, &curr_key, addr_times_key_size)) + { + if (errno == ENOENT) + { + break; // no more keys, done! + } + perror("map get next key failed!"); + return -errno; + } + + // Read the timestamp for the current address + __u64 timestamp; + if (bpf_map__lookup_elem(skel->maps.addr_times, &curr_key, addr_times_key_size, ×tamp, sizeof(timestamp), 0) == 0) + { + printf("0x%-16llx %lld\n", curr_key, timestamp); + } + else + { + perror("map lookup failed!"); + return -errno; + } + } + return 0; } -void disable_kernel_tracepoints(struct memleak_bpf *skel) { +void disable_kernel_tracepoints(struct memleak_bpf *skel) +{ bpf_program__set_autoload(skel->progs.memleak__kmalloc, false); bpf_program__set_autoload(skel->progs.memleak__kmalloc_node, false); bpf_program__set_autoload(skel->progs.memleak__kfree, false); @@ -627,19 +751,22 @@ void disable_kernel_tracepoints(struct memleak_bpf *skel) { bpf_program__set_autoload(skel->progs.memleak__mm_page_free, false); } -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) { - return vfprintf(stderr, format, args); -} +// static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) +// { +// return vfprintf(stderr, format, args); +// } -static void sig_handler(int sig) { +static void sig_handler(int sig) +{ exiting = true; - exit(EXIT_SUCCESS); + exit(EXIT_SUCCESS); } -static void setup_signals(void) { - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - signal(SIGALRM, sig_handler); +static void setup_signals(void) +{ + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGALRM, sig_handler); } /* @@ -672,7 +799,8 @@ static char* flags(int flag) return; } */ -static int handle_event_paf(void *ctx, void *data, size_t data_sz) { +static int handle_event_paf(void *ctx, void *data, size_t data_sz) +{ const struct paf_event *e = data; struct tm *tm; char ts[32]; @@ -683,12 +811,13 @@ static int handle_event_paf(void *ctx, void *data, size_t data_sz) { strftime(ts, sizeof(ts), "%H:%M:%S", tm); printf("%-8lu %-8lu %-8lu %-8lu %-8x\n", - e->min, e->low, e->high, e->present, e->flag); + e->min, e->low, e->high, e->present, e->flag); return 0; } -static int handle_event_pr(void *ctx, void *data, size_t data_sz) { +static int handle_event_pr(void *ctx, void *data, size_t data_sz) +{ const struct pr_event *e = data; struct tm *tm; char ts[32]; @@ -699,12 +828,13 @@ static int handle_event_pr(void *ctx, void *data, size_t data_sz) { strftime(ts, sizeof(ts), "%H:%M:%S", tm); printf("%-8lu %-8lu %-8u %-8u %-8u\n", - e->reclaim, e->reclaimed, e->unqueued_dirty, e->congested, e->writeback); + e->reclaim, e->reclaimed, e->unqueued_dirty, e->congested, e->writeback); return 0; } -static int handle_event_procstat(void *ctx, void *data, size_t data_sz) { +static int handle_event_procstat(void *ctx, void *data, size_t data_sz) +{ const struct procstat_event *e = data; struct tm *tm; char ts[32]; @@ -713,15 +843,18 @@ static int handle_event_procstat(void *ctx, void *data, size_t data_sz) { time(&t); tm = localtime(&t); strftime(ts, sizeof(ts), "%H:%M:%S", tm); - if (env.choose_pid) { - if (e->pid == env.choose_pid) { + if (env.choose_pid) + { + if (e->pid == env.choose_pid) + { if (env.rss == true) printf("%-8s %-8d %-8ld %-8ld %-8ld %-8lld %-8lld\n", ts, e->pid, e->vsize, e->Vdata, e->Vstk, e->VPTE, e->vswap); else printf("%-8s %-8d %-8ld %-8lld %-8lld %-8lld\n", ts, e->pid, e->size, e->rssanon, e->rssfile, e->rssshmem); } } - else { + else + { if (env.rss == true) printf("%-8s %-8d %-8ld %-8ld %-8ld %-8lld %-8lld\n", ts, e->pid, e->vsize, e->Vdata, e->Vstk, e->VPTE, e->vswap); else @@ -731,7 +864,8 @@ static int handle_event_procstat(void *ctx, void *data, size_t data_sz) { return 0; } -static int handle_event_sysstat(void *ctx, void *data, size_t data_sz) { +static int handle_event_sysstat(void *ctx, void *data, size_t data_sz) +{ const struct sysstat_event *e = data; struct tm *tm; char ts[32]; @@ -749,119 +883,130 @@ static int handle_event_sysstat(void *ctx, void *data, size_t data_sz) { return 0; } -int attach_uprobes(struct memleak_bpf *skel) { - ATTACH_UPROBE_CHECKED(skel, malloc, malloc_enter); - ATTACH_URETPROBE_CHECKED(skel, malloc, malloc_exit); - ATTACH_UPROBE_CHECKED(skel, free, free_enter); +int attach_uprobes(struct memleak_bpf *skel) +{ + ATTACH_UPROBE_CHECKED(skel, malloc, malloc_enter); + ATTACH_URETPROBE_CHECKED(skel, malloc, malloc_exit); + ATTACH_UPROBE_CHECKED(skel, free, free_enter); - ATTACH_UPROBE_CHECKED(skel, posix_memalign, posix_memalign_enter); - ATTACH_URETPROBE_CHECKED(skel, posix_memalign, posix_memalign_exit); + ATTACH_UPROBE_CHECKED(skel, posix_memalign, posix_memalign_enter); + ATTACH_URETPROBE_CHECKED(skel, posix_memalign, posix_memalign_exit); - ATTACH_UPROBE_CHECKED(skel, calloc, calloc_enter); - ATTACH_URETPROBE_CHECKED(skel, calloc, calloc_exit); + ATTACH_UPROBE_CHECKED(skel, calloc, calloc_enter); + ATTACH_URETPROBE_CHECKED(skel, calloc, calloc_exit); - ATTACH_UPROBE_CHECKED(skel, realloc, realloc_enter); - ATTACH_URETPROBE_CHECKED(skel, realloc, realloc_exit); + ATTACH_UPROBE_CHECKED(skel, realloc, realloc_enter); + ATTACH_URETPROBE_CHECKED(skel, realloc, realloc_exit); - ATTACH_UPROBE_CHECKED(skel, mmap, mmap_enter); - ATTACH_URETPROBE_CHECKED(skel, mmap, mmap_exit); + ATTACH_UPROBE_CHECKED(skel, mmap, mmap_enter); + ATTACH_URETPROBE_CHECKED(skel, mmap, mmap_exit); - ATTACH_UPROBE_CHECKED(skel, memalign, memalign_enter); - ATTACH_URETPROBE_CHECKED(skel, memalign, memalign_exit); + ATTACH_UPROBE_CHECKED(skel, memalign, memalign_enter); + ATTACH_URETPROBE_CHECKED(skel, memalign, memalign_exit); - ATTACH_UPROBE_CHECKED(skel, free, free_enter); - ATTACH_UPROBE_CHECKED(skel, munmap, munmap_enter); + ATTACH_UPROBE_CHECKED(skel, free, free_enter); + ATTACH_UPROBE_CHECKED(skel, munmap, munmap_enter); - // the following probes are intentinally allowed to fail attachment + // the following probes are intentinally allowed to fail attachment - // deprecated in libc.so bionic - ATTACH_UPROBE(skel, valloc, valloc_enter); - ATTACH_URETPROBE(skel, valloc, valloc_exit); + // deprecated in libc.so bionic + ATTACH_UPROBE(skel, valloc, valloc_enter); + ATTACH_URETPROBE(skel, valloc, valloc_exit); - // deprecated in libc.so bionic - ATTACH_UPROBE(skel, pvalloc, pvalloc_enter); - ATTACH_URETPROBE(skel, pvalloc, pvalloc_exit); + // deprecated in libc.so bionic + ATTACH_UPROBE(skel, pvalloc, pvalloc_enter); + ATTACH_URETPROBE(skel, pvalloc, pvalloc_exit); - // added in C11 - ATTACH_UPROBE(skel, aligned_alloc, aligned_alloc_enter); - ATTACH_URETPROBE(skel, aligned_alloc, aligned_alloc_exit); + // added in C11 + ATTACH_UPROBE(skel, aligned_alloc, aligned_alloc_enter); + ATTACH_URETPROBE(skel, aligned_alloc, aligned_alloc_exit); - return 0; + return 0; } - // Functions to process different BPF programs -static int process_paf(struct paf_bpf *skel_paf) { - int err; - struct ring_buffer *rb; +static int process_paf(struct paf_bpf *skel_paf) +{ + int err; + struct ring_buffer *rb; - LOAD_AND_ATTACH_SKELETON(skel_paf, paf); + LOAD_AND_ATTACH_SKELETON(skel_paf, paf); - printf("%-8s %-8s %-8s %-8s %-8s\n", "MIN", "LOW", "HIGH", "PRESENT", "FLAG"); + printf("%-8s %-8s %-8s %-8s %-8s\n", "MIN", "LOW", "HIGH", "PRESENT", "FLAG"); POLL_RING_BUFFER(rb, 1000, err); paf_cleanup: ring_buffer__free(rb); paf_bpf__destroy(skel_paf); - return err; + return err; } -static int process_pr(struct pr_bpf *skel_pr) { - int err; - struct ring_buffer *rb; +static int process_pr(struct pr_bpf *skel_pr) +{ + int err; + struct ring_buffer *rb; - LOAD_AND_ATTACH_SKELETON(skel_pr, pr); + LOAD_AND_ATTACH_SKELETON(skel_pr, pr); - printf("%-8s %-8s %-8s %-8s %-8s\n", "RECLAIM", "RECLAIMED", "UNQUEUE", "CONGESTED", "WRITEBACK"); + printf("%-8s %-8s %-8s %-8s %-8s\n", "RECLAIM", "RECLAIMED", "UNQUEUE", "CONGESTED", "WRITEBACK"); POLL_RING_BUFFER(rb, 1000, err); pr_cleanup: ring_buffer__free(rb); pr_bpf__destroy(skel_pr); - return err; + return err; } -static int process_procstat(struct procstat_bpf *skel_procstat) { - int err; - struct ring_buffer *rb; +static int process_procstat(struct procstat_bpf *skel_procstat) +{ + int err; + struct ring_buffer *rb; - LOAD_AND_ATTACH_SKELETON(skel_procstat, procstat); + LOAD_AND_ATTACH_SKELETON(skel_procstat, procstat); - if (env.rss) { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "VMSIZE", "VMDATA", "VMSTK", "VMPTE", "VMSWAP"); - } else { - printf("%-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "SIZE", "RSSANON", "RSSFILE", "RSSSHMEM"); - } + if (env.rss) + { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "VMSIZE", "VMDATA", "VMSTK", "VMPTE", "VMSWAP"); + } + else + { + printf("%-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "SIZE", "RSSANON", "RSSFILE", "RSSSHMEM"); + } POLL_RING_BUFFER(rb, 1000, err); procstat_cleanup: ring_buffer__free(rb); procstat_bpf__destroy(skel_procstat); - return err; + return err; } -static int process_sysstat(struct sysstat_bpf *skel_sysstat) { - int err; - struct ring_buffer *rb; +static int process_sysstat(struct sysstat_bpf *skel_sysstat) +{ + int err; + struct ring_buffer *rb; - LOAD_AND_ATTACH_SKELETON(skel_sysstat, sysstat); + LOAD_AND_ATTACH_SKELETON(skel_sysstat, sysstat); - if (env.part2) { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "KRECLM", "SLAB", "SRECLM", "SUNRECL", "NFSUNSTB", "WRITEBACKTMP", "KMAP", "UNMAP", "PAGE"); - } else { - printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "CPU", "MEM", "READ", "WRITE", "IOWAIT", "SWAP"); - } - POLL_RING_BUFFER(rb, 1000, err); + if (env.part2) + { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "KRECLM", "SLAB", "SRECLM", "SUNRECL", "NFSUNSTB", "WRITEBACKTMP", "KMAP", "UNMAP", "PAGE"); + } + else + { + printf("%-8s %-8s %-8s %-8s %-8s %-8s %-8s %-8s\n", "TIME", "PID", "CPU", "MEM", "READ", "WRITE", "IOWAIT", "SWAP"); + } + POLL_RING_BUFFER(rb, 1000, err); sysstat_cleanup: ring_buffer__free(rb); sysstat_bpf__destroy(skel_sysstat); - return err; + return err; } -static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { +static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) +{ skel_memleak->rodata->stack_flags = env.kernel_trace ? KERN_STACKID_FLAGS : USER_STACKID_FLAGS; bpf_map__set_value_size(skel_memleak->maps.stack_traces, perf_max_stack_depth * sizeof(__u64)); @@ -871,28 +1016,33 @@ static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { disable_kernel_tracepoints(skel_memleak); int err = memleak_bpf__load(skel_memleak); - if (err) { + if (err) + { fprintf(stderr, "Failed to load BPF skeleton\n"); goto memleak_cleanup; } - if (!env.kernel_trace) { + if (!env.kernel_trace) + { err = attach_uprobes(skel_memleak); - if (err) { + if (err) + { fprintf(stderr, "Failed to attach uprobes\n"); goto memleak_cleanup; } } err = memleak_bpf__attach(skel_memleak); - if (err) { + if (err) + { fprintf(stderr, "Failed to auto-attach BPF skeleton: %d\n", err); goto memleak_cleanup; } g_stacks_size = perf_max_stack_depth * sizeof(*g_stacks); g_stacks = (__u64 *)malloc(g_stacks_size); - if (!g_stacks) { + if (!g_stacks) + { fprintf(stderr, "Failed to allocate memory\n"); err = -1; goto memleak_cleanup; @@ -900,15 +1050,18 @@ static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { memset(g_stacks, 0, g_stacks_size); symbolizer = blaze_symbolizer_new(); - if (!symbolizer) { + if (!symbolizer) + { fprintf(stderr, "Fail to create a symbolizer\n"); err = -1; goto memleak_cleanup; } - for (;;) { + for (;;) + { if (!env.kernel_trace) - if (env.print_time) { + if (env.print_time) + { system("clear"); update_addr_times(skel_memleak); print_time(skel_memleak); @@ -921,13 +1074,16 @@ static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { sleep(1); } - while (!exiting) { + while (!exiting) + { /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { + if (err == -EINTR) + { err = 0; break; } - if (err < 0) { + if (err < 0) + { printf("Error polling perf buffer: %d\n", err); break; } @@ -936,10 +1092,63 @@ static int process_memleak(struct memleak_bpf *skel_memleak, struct env env) { memleak_cleanup: memleak_bpf__destroy(skel_memleak); if (symbolizer) - blaze_symbolizer_free(symbolizer); - if (g_stacks) - free(g_stacks); - if (allocs) - free(allocs); - return err; + blaze_symbolizer_free(symbolizer); + if (g_stacks) + free(g_stacks); + if (allocs) + free(allocs); + return err; +} + +// ================================================== fraginfo==================================================================== +void print_nodes(int fd) { + struct pgdat_info pinfo; + __u64 key = 0, next_key; + printf(" Node ID PGDAT_PTR NR_ZONES \n"); + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { + bpf_map_lookup_elem(fd, &next_key, &pinfo); + printf(" %5d 0x%llx %5d\n", + pinfo.node_id, pinfo.pgdat_ptr, pinfo.nr_zones); + key = next_key; + } +} + +void print_zones(int fd) { + struct zone_info zinfo; + __u64 key = 0, next_key; + printf("%-20s %-20s %-25s %-20s %-20s"," COMM" , "ZONE_PTR" , "ZONE_PFN " , " SUM_PAGES" ,"FACT_PAGES "); + printf("\n"); + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { + bpf_map_lookup_elem(fd, &next_key, &zinfo); + printf(" %-15s 0x%-25llx %-25llu %-20llu %-15llu\n", zinfo.comm, zinfo.zone_ptr, zinfo.zone_start_pfn,zinfo.spanned_pages,zinfo.present_pages); + key = next_key; + } + +} +static int process_fraginfo(struct fraginfo_bpf *skel_fraginfo) +{ + + int err = fraginfo_bpf__load(skel_fraginfo); + if (err) + { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto fraginfo_cleanup; + } + + err = fraginfo_bpf__attach(skel_fraginfo); + if (err) + { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto fraginfo_cleanup; + } + while(1){ + sleep(env.interval); + print_nodes(bpf_map__fd(skel_fraginfo->maps.nodes)); + printf("\n"); + print_zones(bpf_map__fd(skel_fraginfo->maps.zones)); + } + +fraginfo_cleanup: + fraginfo_bpf__destroy(skel_fraginfo); + return -err; } \ No newline at end of file From 84a8de5b6b6294f084c480c771e84351802f166f Mon Sep 17 00:00:00 2001 From: gaoyixiang1 <1739037263@qq.com> Date: Thu, 11 Jul 2024 09:37:23 +0800 Subject: [PATCH 12/12] remove some files Signed-off-by: gaoyixiang1 <1739037263@qq.com> --- .github/workflows/ebpf_frag.yml | 36 ----- .../Memory_Subsystem/fraginfo/Makefile | 131 ------------------ .../fraginfo/src/fraginfo.bpf.c | 76 ---------- .../Memory_Subsystem/fraginfo/src/fraginfo.c | 121 ---------------- .../Memory_Subsystem/fraginfo/src/fraginfo.h | 22 --- 5 files changed, 386 deletions(-) delete mode 100644 .github/workflows/ebpf_frag.yml delete mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile delete mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c delete mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c delete mode 100644 eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h diff --git a/.github/workflows/ebpf_frag.yml b/.github/workflows/ebpf_frag.yml deleted file mode 100644 index b2a6bac03..000000000 --- a/.github/workflows/ebpf_frag.yml +++ /dev/null @@ -1,36 +0,0 @@ - -name: fraginfo - -on: - push: - branches: - - "*" - paths: - - 'eBPF_Supermarket/Memory_Subsystem/fraginfo/**' - - '.github/workflows/ebpf_frag.yml' - pull_request: - branches: - - "*" - paths: - - 'eBPF_Supermarket/Memory_Subsystem/fraginfo/**' - - '.github/workflows/ebpf_frag.yml' - -jobs: - fraginfo-project-build-and-test: - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v3 - - - name: Install dependencies - run: | - sudo apt update - sudo apt install libbpf-dev clang llvm libelf-dev libpcap-dev gcc-multilib build-essential linux-tools-$(uname -r) - git submodule update --init --recursive - - - name: Run fraginfo - continue-on-error: true - run: | - cd eBPF_Supermarket/Memory_Subsystem/fraginfo/ - bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h - make - sudo ./fraginfo -i 5 diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile b/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile deleted file mode 100644 index 2427d210d..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/fraginfo/Makefile +++ /dev/null @@ -1,131 +0,0 @@ - -# Makefile -OUTPUT := .output -CLANG ?= clang - -LIBBPF_SRC := $(abspath ../libbpf/src) -BPFTOOL_SRC := $(abspath ../bpftool/src) -LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) -BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool) -BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool - -ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ - | sed 's/arm.*/arm/' \ - | sed 's/aarch64/arm64/' \ - | sed 's/ppc64le/powerpc/' \ - | sed 's/mips.*/mips/' \ - | sed 's/riscv64/riscv/' \ - | sed 's/loongarch64/loongarch/') -VMDIR := ../vmlinux -VMLINUXSRC := $(VMDIR)/$(ARCH) -VMLINUX := $(VMLINUXSRC)/vmlinux.h -# Use our own libbpf API headers and Linux UAPI headers distributed with -# libbpf to avoid dependency on system-wide headers, which could be missing or -# outdated -INCLUDES := -I$(OUTPUT) -I../../lib/libbpf/include/uapi -I$(dir $(VMLINUX)) -I./include -CFLAGS := -g -Wall -ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) - -APPS = fraginfo - -# Get Clang's default includes on this system. We'll explicitly add these dirs -# to the includes list when compiling with `-target bpf` because otherwise some -# architecture-specific dirs will be "missing" on some architectures/distros - -# headers such as asm/types.h, asm/byteorder.h, asm/socket.h, asm/sockios.h, -# sys/cdefs.h etc. might be missing. -# -# Use '-idirafter': Don't interfere with include mechanics except where the -# build would have failed anyways. -CLANG_BPF_SYS_INCLUDES = $(shell $(CLANG) -v -E - &1 \ - | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') - -ifeq ($(V),1) - Q = - msg = -else - Q = @ - msg = @printf ' %-8s %s%s\n' \ - "$(1)" \ - "$(patsubst $(abspath $(OUTPUT))/%,%,$(2))" \ - "$(if $(3), $(3))"; - MAKEFLAGS += --no-print-directory -endif - -define allow-override - $(if $(or $(findstring environment,$(origin $(1))),\ - $(findstring command line,$(origin $(1)))),,\ - $(eval $(1) = $(2))) -endef - -$(call allow-override,CC,$(CROSS_COMPILE)cc) -$(call allow-override,LD,$(CROSS_COMPILE)ld) - -.PHONY: all -all: deps $(APPS) - -.PHONY: deps -deps: - mkdir -p $(VMLINUXSRC) - bpftool btf dump file /sys/kernel/btf/vmlinux format c > $(VMLINUX) - -.PHONY: clean -clean: - $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) $(APPS) - rm -rf $(VMDIR) - -.PHONY: clean2 -clean2: - $(call msg,CLEAN) - rm -f $(APPS) - rm -f $(OUTPUT)/*.skel.h - rm -f $(OUTPUT)/*.o - rm -rf $(VMDIR) - -$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT): - $(call msg,MKDIR,$@) - $(Q)mkdir -p $@ - -# Build libbpf -$(LIBBPF_OBJ): $(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 $@) \ - INCLUDEDIR= LIBDIR= UAPIDIR= \ - install - -# Build bpftool -$(BPFTOOL): | $(BPFTOOL_OUTPUT) - $(call msg,BPFTOOL,$@) - $(Q)$(MAKE) ARCH= CROSS_COMPILE= OUTPUT=$(BPFTOOL_OUTPUT)/ -C $(BPFTOOL_SRC) bootstrap - -# Build BPF code -$(OUTPUT)/%.bpf.o: src/%.bpf.c $(LIBBPF_OBJ) $(wildcard src/*.h) $(VMLINUX) | $(OUTPUT) $(BPFTOOL) - $(call msg,BPF,$@) - $(Q)$(CLANG) -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) \ - $(INCLUDES) $(CLANG_BPF_SYS_INCLUDES) \ - -c $(filter %.c,$^) -o $(patsubst %.bpf.o,%.tmp.bpf.o,$@) - $(Q)$(BPFTOOL) gen object $@ $(patsubst %.bpf.o,%.tmp.bpf.o,$@) - -# Generate BPF skeletons -$(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT) $(BPFTOOL) - $(call msg,GEN-SKEL,$@) - $(Q)$(BPFTOOL) gen skeleton $< > $@ - -# Build user-space code -$(patsubst %,$(OUTPUT)/%.o,$(APPS)): $(OUTPUT)/%.o: src/%.c $(OUTPUT)/%.skel.h $(wildcard src/*.h) | $(OUTPUT) - $(call msg,CC,$@) - $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ - -# Build application binary -$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) - $(call msg,BINARY,$@) - $(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@ - -# delete failed targets -.DELETE_ON_ERROR: - -# keep intermediate (.skel.h, .bpf.o, etc) targets -.SECONDARY: - -SHELL := /bin/bash diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c deleted file mode 100644 index 45b5c5c54..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.bpf.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "vmlinux.h" -#include -#include -#include -#include "fraginfo.h" - -char LICENSE[] SEC("license") = "Dual BSD/GPL"; - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 102400); - __type(key, u64); - __type(value, struct zone_info); -} zones SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 102400); - __type(key, u64); - __type(value, struct pgdat_info); -} nodes SEC(".maps"); - -static void fill_contig_page_info(struct zone *zone, unsigned int suitable_order, - struct contig_page_info *info) -{ - unsigned int order; - info->free_pages = 0; - info->free_blocks_total = 0; - info->free_blocks_suitable = 0; - for (order = 0; order <= MAX_ORDER; order++) { - unsigned long blocks; - unsigned long nr_free; - nr_free = BPF_CORE_READ(&zone->free_area[order], nr_free); - blocks = nr_free; - info->free_blocks_total += blocks; - info->free_pages += blocks << order; - if (order >= suitable_order) - info->free_blocks_suitable += blocks << (order - suitable_order); - } -} - -SEC("kprobe/get_page_from_freelist") -int BPF_KPROBE(get_page_from_freelist, gfp_t gfp_mask, unsigned int order, int alloc_flags, - const struct alloc_context *ac) -{ - struct pgdat_info node_info = {}; - struct zone_info zone_data = {}; - - struct pglist_data *pgdat; - struct zoneref *zref; - struct zone *z; - int i; - - pgdat = BPF_CORE_READ(ac, preferred_zoneref, zone, zone_pgdat); - node_info.node_id = BPF_CORE_READ(pgdat, node_id); - node_info.nr_zones = BPF_CORE_READ(pgdat, nr_zones); - node_info.pgdat_ptr = (u64)pgdat; - u64 key = (u64)pgdat; - - bpf_map_update_elem(&nodes, &key, &node_info, BPF_ANY); - - for (i = 0; i < __MAX_NR_ZONES; i++) { - zref = &pgdat->node_zonelists[0]._zonerefs[i]; - z = BPF_CORE_READ(zref, zone); - if ((u64)z == 0) break; - zone_data.zone_ptr = (u64)z; - u64 zone_key = (u64)z; - zone_data.zone_start_pfn = BPF_CORE_READ(z, zone_start_pfn); - zone_data.spanned_pages = BPF_CORE_READ(z, spanned_pages); - zone_data.present_pages = BPF_CORE_READ(z, present_pages); - bpf_probe_read_kernel_str(zone_data.comm, sizeof(zone_data.comm), BPF_CORE_READ(z, name)); - bpf_map_update_elem(&zones, &zone_key, &zone_data, BPF_ANY); - } - - return 0; -} diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c deleted file mode 100644 index 71b9fd356..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "fraginfo.skel.h" -#include -#include -#include -#include -#include -#include -#include -#include "fraginfo.h" - -static struct env { - int interval; - int duration; -} env = { - .interval = 1, - .duration = 10, -}; - -const char *argp_program_version = "fraginfo 0.1"; -const char *argp_program_bug_address = ""; -const char argp_program_doc[] = -"Fraginfo BPF program.\n" -"\n" -"USAGE: ./fraginfo [--interval INTERVAL] [--duration DURATION]\n"; - -static const struct argp_option opts[] = { - { "interval", 'i', "INTERVAL", 0, "Print interval in seconds (default 1)"}, - { "duration", 'd', "DURATION", 0, "Total duration in seconds to run (default 10)"}, - {}, -}; - -static error_t parse_arg(int key, char *arg, struct argp_state *state) { - switch (key) { - case 'i': - env.interval = atoi(arg); - break; - case 'd': - env.duration = atoi(arg); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static volatile bool exiting = false; - -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); -} - -void print_nodes(int fd) { - struct pgdat_info pinfo; - __u64 key = 0, next_key; - printf(" Node ID PGDAT_PTR NR_ZONES \n"); - while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { - bpf_map_lookup_elem(fd, &next_key, &pinfo); - printf(" %5d 0x%llx %5d\n", - pinfo.node_id, pinfo.pgdat_ptr, pinfo.nr_zones); - key = next_key; - } -} - -void print_zones(int fd) { - struct zone_info zinfo; - __u64 key = 0, next_key; - printf(" COMM ZONE_PTR ZONE_PFN SUM_PAGES FACT_PAGES \n"); - while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { - bpf_map_lookup_elem(fd, &next_key, &zinfo); - printf(" %s 0x%llx %llu %5llu %llu \n", zinfo.comm, zinfo.zone_ptr, zinfo.zone_start_pfn,zinfo.spanned_pages,zinfo.present_pages); - key = next_key; - } -} - -int main(int argc, char **argv) { - struct fraginfo_bpf *skel; - int err; - - struct argp argp = { opts, parse_arg, NULL, argp_program_doc }; - err = argp_parse(&argp, argc, argv, 0, 0, NULL); - if (err) - return err; - - // libbpf_set_print(libbpf_print_fn); - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); - - skel = fraginfo_bpf__open(); - if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); - return 1; - } - - err = fraginfo_bpf__load(skel); - if (err) { - fprintf(stderr, "Failed to load BPF skeleton\n"); - goto cleanup; - } - - err = fraginfo_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto cleanup; - } - - printf("Tracing... Press Ctrl-C to end.\n"); - - while (!exiting) { - sleep(env.interval); - print_nodes(bpf_map__fd(skel->maps.nodes)); - print_zones(bpf_map__fd(skel->maps.zones)); - } - -cleanup: - fraginfo_bpf__destroy(skel); - return -err; -} \ No newline at end of file diff --git a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h b/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h deleted file mode 100644 index 7041bcfc6..000000000 --- a/eBPF_Supermarket/Memory_Subsystem/fraginfo/src/fraginfo.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef FRAGINFO_H -#define FRAGINFO_H - -#define MAX_ORDER 10 -typedef __u64 u64; - - -struct zone_info { - u64 zone_ptr; - u64 zone_start_pfn; - u64 spanned_pages; - u64 present_pages; - char comm[32]; -}; - -struct pgdat_info { - u64 pgdat_ptr; - int nr_zones; - int node_id; -}; - -#endif