diff --git a/.github/workflows/libbpf.yml b/.github/workflows/cpu_watcher.yml similarity index 52% rename from .github/workflows/libbpf.yml rename to .github/workflows/cpu_watcher.yml index f2683856a..fc7b25cc6 100644 --- a/.github/workflows/libbpf.yml +++ b/.github/workflows/cpu_watcher.yml @@ -1,18 +1,18 @@ -name: libbpf +name: cpu_watcher on: push: branches: - "*" paths: - - 'eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/**' - - '.github/workflows/libbpf.yml' + - 'eBPF_Supermarket/CPU_Subsystem/cpu_watcher/**' + - '.github/workflows/cpu_watcher.yml' pull_request: branches: - "*" paths: - - 'eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/**' - - '.github/workflows/libbpf.yml' + - 'eBPF_Supermarket/CPU_Subsystem/cpu_watcher/**' + - '.github/workflows/cpu_watcher.yml' jobs: libbpf-project-build-and-test: @@ -26,8 +26,8 @@ jobs: sudo apt install libbpf-dev clang llvm libelf-dev libpcap-dev gcc-multilib build-essential git submodule update --init --recursive - - name: Run cs_delay + - name: Run cpu_watcher run: | - cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay - make cs_delay - sudo ./cs_delay + cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher/ + make cpu_watcher + sudo ./cpu_watcher diff --git a/.github/workflows/system_cpu.yml b/.github/workflows/system_cpu.yml index d0d6390ed..66b3f5726 100644 --- a/.github/workflows/system_cpu.yml +++ b/.github/workflows/system_cpu.yml @@ -104,7 +104,7 @@ jobs: uname -r ./run.sh - libbpf_sar-project-build-and-test: + cpu_watcher-project-build-and-test: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 @@ -115,8 +115,8 @@ jobs: sudo apt install libbpf-dev clang llvm libelf-dev libpcap-dev gcc-multilib build-essential git submodule update --init --recursive - - name: Run libbpf_sar + - name: Run cpu_watcher run: | - cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar - make libbpf_sar - sudo ./libbpf_sar -t 1 + cd eBPF_Supermarket/CPU_Subsystem/cpu_watcher + make cpu_watcher + sudo ./cpu_watcher diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/BCC_cs_delay/cs_delay.c b/eBPF_Supermarket/CPU_Subsystem/BCC_cs_delay/cs_delay.c similarity index 100% rename from eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/BCC_cs_delay/cs_delay.c rename to eBPF_Supermarket/CPU_Subsystem/BCC_cs_delay/cs_delay.c diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/BCC_cs_delay/cs_delay.py b/eBPF_Supermarket/CPU_Subsystem/BCC_cs_delay/cs_delay.py similarity index 100% rename from eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/BCC_cs_delay/cs_delay.py rename to eBPF_Supermarket/CPU_Subsystem/BCC_cs_delay/cs_delay.py diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile similarity index 95% rename from eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/Makefile rename to eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile index 42415728a..99dd4491f 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/Makefile +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/Makefile @@ -19,12 +19,12 @@ # SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) OUTPUT := .output CLANG ?= clang -LIBBPF_SRC := $(abspath ../../../libbpf/src) -BPFTOOL_SRC := $(abspath ../../../bpftool/src) +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 -LIBBLAZESYM_SRC := $(abspath ../../../blazesym/) +LIBBLAZESYM_SRC := $(abspath ../blazesym/) LIBBLAZESYM_INC := $(abspath $(LIBBLAZESYM_SRC)/include) LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym.a) ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ @@ -34,7 +34,7 @@ ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \ | sed 's/mips.*/mips/' \ | sed 's/riscv64/riscv/' \ | sed 's/loongarch64/loongarch/') -VMLINUX := ../../../vmlinux/$(ARCH)/vmlinux.h +VMLINUX := ../vmlinux/$(ARCH)/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 @@ -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 +APPS = cpu_watcher CARGO ?= $(shell which cargo) ifeq ($(strip $(CARGO)),) diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.bpf.c similarity index 68% rename from eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.bpf.c rename to eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.bpf.c index 2d8d8ebd0..bc1fb2aef 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.bpf.c @@ -20,13 +20,29 @@ #include #include #include -#include "libbpf_sar.h" +#include "cpu_watcher.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; const volatile long long unsigned int forks_addr = 0; -// 计数表格,第0项为所统计fork数,第1项为进程切换数,第2项为运行队列长度 +#define PF_IDLE 0x00000002 /* I am an IDLE thread */ +#define PF_KTHREAD 0x00200000 /* I am a kernel thread */ + +/*----------------------------------------------*/ +/* cs_delay相关maps */ +/*----------------------------------------------*/ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, int); + __type(value, u64); +} start SEC(".maps");//记录时间戳; + +/*----------------------------------------------*/ +/* sar相关maps */ +/*----------------------------------------------*/ +// 计数表格,第0项为所统计fork数,第1项为进程切换数, struct { __uint(type, BPF_MAP_TYPE_ARRAY);//基于数组的映射 __uint(max_entries, 3);//countMap 可以存储最多 3 对键值对 @@ -37,10 +53,10 @@ struct { // 记录开始的时间 struct { __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, 1); - __type(key, int); + __uint(max_entries, 4096); + __type(key, pid_t); __type(value, u64); -} start SEC(".maps");//记录时间戳; +} procStartTime SEC(".maps");//记录时间戳; //环形缓冲区; struct { @@ -48,17 +64,6 @@ struct { __uint(max_entries, 256 * 1024); } rb SEC(".maps"); -//cswch_args结构体 -struct cswch_args { - u64 pad; - char prev_comm[16]; - pid_t prev_pid; - int prev_prio; - long prev_state; - char next_comm[16]; - pid_t next_pid; - int next_prio; -}; // 储存运行队列rq的全局变量 struct { @@ -70,17 +75,12 @@ __type(value, struct rq); struct { -__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); -__uint(max_entries, 1); -__type(key, u32); -__type(value, int); + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(max_entries, 1); + __type(key, u32); + __type(value, int); } runqlen SEC(".maps");//多CPU数组 -struct __softirq_info { - u64 pad; - u32 vec; -}; - struct { __uint(type, BPF_MAP_TYPE_PERCPU_HASH); __uint(max_entries, 4096); @@ -111,12 +111,76 @@ __type(key, u32); __type(value, u64); } irq_Last_time SEC(".maps"); -struct __irq_info { - u64 pad; - u32 irq; -}; +// 储存cpu进入空闲的起始时间 +struct { +__uint(type, BPF_MAP_TYPE_ARRAY); +__uint(max_entries, 128); +__type(key, u32); +__type(value, u64); +} idleStart SEC(".maps"); + +// 储存cpu进入空闲的持续时间 +struct { +__uint(type, BPF_MAP_TYPE_ARRAY); +__uint(max_entries, 1); +__type(key, u32); +__type(value, u64); +} idleLastTime SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, u32); + __type(value, u64); +} kt_LastTime SEC(".maps"); + +/*----------------------------------------------*/ +/* cs_delay跟踪函数 */ +/*----------------------------------------------*/ + +SEC("kprobe/schedule") +int BPF_KPROBE(schedule) +{ + u64 t1; + t1 = bpf_ktime_get_ns()/1000; //bpf_ktime_get_ns返回自系统启动以来所经过的时间(以纳秒为单位)。不包括系统挂起的时间。 + int key =0; + bpf_map_update_elem(&start,&key,&t1,BPF_ANY); + return 0; +} +SEC("kretprobe/schedule") +int BPF_KRETPROBE(schedule_exit) +{ + u64 t2 = bpf_ktime_get_ns()/1000; + u64 t1,delay; + int key = 0; + u64 *val = bpf_map_lookup_elem(&start,&key); + if (val != 0) + { + t1 = *val; + delay = t2 - t1; + bpf_map_delete_elem(&start, &key); + }else{ + return 0; + } + + struct event *e; + e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) return 0; + + e->t1=t1;//开始时间 + e->t2=t2;//结束时间 + e->delay=delay;//时间间隔 + + /* 成功地将其提交到用户空间进行后期处理 */ + bpf_ringbuf_submit(e, 0); + + return 0; +} +/*----------------------------------------------*/ +/* sar跟踪函数 */ +/*----------------------------------------------*/ // 统计fork数 SEC("kprobe/finish_task_switch.isra.0") int kprobe__finish_task_switch(struct pt_regs *ctx) @@ -124,7 +188,7 @@ int kprobe__finish_task_switch(struct pt_regs *ctx) u32 key = 0; u64 val, *valp = NULL; unsigned long total_forks; - + if(forks_addr !=0){ valp = (u64 *)forks_addr; bpf_probe_read_kernel(&total_forks, sizeof(unsigned long), valp); @@ -132,12 +196,9 @@ int kprobe__finish_task_switch(struct pt_regs *ctx) val = total_forks; bpf_map_update_elem(&countMap,&key,&val,BPF_ANY); } - return 0; } - - //获取进程切换数; SEC("tracepoint/sched/sched_switch")//静态挂载点 int trace_sched_switch2(struct cswch_args *info) { @@ -146,7 +207,7 @@ int trace_sched_switch2(struct cswch_args *info) { // 只有当上一个进程和下一个进程不相同时才执行以下操作,相同则代表是同一个进程 if (prev != next) { - u32 key = 1; + u32 key = 0; u64 *valp, delta, cur; struct task_struct *ts; @@ -155,7 +216,7 @@ int trace_sched_switch2(struct cswch_args *info) { u64 time = bpf_ktime_get_ns()/1000;//获取当前时间,ms; // Step1: 记录next进程的起始时间 - bpf_map_update_elem(&start,&pid,&time,BPF_ANY);//上传当前时间到start map中 + bpf_map_update_elem(&procStartTime,&pid,&time,BPF_ANY);//上传当前时间到start map中 //procStartTime.update(&pid, &time);//python // Step2: Syscall时间处理 @@ -178,6 +239,25 @@ int trace_sched_switch2(struct cswch_args *info) { return 0; } +SEC("kprobe/finish_task_switch.isra.0") +int BPF_KPROBE(finish_task_switch,struct task_struct *prev){ + pid_t pid=BPF_CORE_READ(prev,pid); + u64 *val, time = bpf_ktime_get_ns(); + u64 delta; + // Step1: 记录内核进程(非IDLE)运行时间 + if ((BPF_CORE_READ(prev,flags) & PF_KTHREAD) && pid!= 0) { + val = bpf_map_lookup_elem(&procStartTime, &pid); + if (val) { + u32 key = 0; + delta = time - *val*1000; + val = bpf_map_lookup_elem(&kt_LastTime, &key); + if (val) *val += delta; + else bpf_map_update_elem(&kt_LastTime, &key, &delta, BPF_ANY); + } + } + return 0; +} + /* SEC("kprobe/finish_task_switch")//动态挂载点 int trace_sched_switch(struct cswch_args *info) { @@ -195,7 +275,7 @@ int trace_sched_switch(struct cswch_args *info) { u64 time = bpf_ktime_get_ns()/1000;//获取当前时间,ms; // Step1: 记录next进程的起始时间 - bpf_map_update_elem(&start,&pid,&time,BPF_ANY);//上传当前时间到start map中 + bpf_map_update_elem(&procStartTime,&pid,&time,BPF_ANY);//上传当前时间到start map中 //procStartTime.update(&pid, &time);//python // Step2: Syscall时间处理 @@ -223,7 +303,7 @@ int trace_sched_switch(struct cswch_args *info) { //统计运行队列长度 SEC("kprobe/update_rq_clock") int kprobe_update_rq_clock(struct pt_regs *ctx){ - u32 key = 2; + u32 key = 0; u32 rqkey = 0; struct rq *p_rq = 0; p_rq = (struct rq *)bpf_map_lookup_elem(&rq_map, &rqkey); @@ -234,7 +314,7 @@ int kprobe_update_rq_clock(struct pt_regs *ctx){ bpf_probe_read_kernel(p_rq, sizeof(struct rq), (void *)PT_REGS_PARM1(ctx)); //使用bpf_probe_read_kernel函数将内核空间中的数据复制到p_rq所指向的内存区域中,以便后续对该数据进行访问和操作。 u64 val = p_rq->nr_running; - bpf_map_update_elem(&countMap,&key,&val,BPF_ANY); + bpf_map_update_elem(&runqlen,&key,&val,BPF_ANY); return 0; } @@ -313,3 +393,30 @@ int trace_irq_handler_exit(struct __irq_info *info) { } +//tracepoint:power_cpu_idle 表征了CPU进入IDLE的状态,比较准确 +SEC("tracepoint/power/cpu_idle") +int trace_cpu_idle(struct idleStruct *pIDLE) { + u64 delta, time = bpf_ktime_get_ns(); + u32 key = pIDLE->cpu_id; + // 按cpuid记录空闲的开始,这十分重要,因为IDLE-0进程可同时运行在两个核上 + + if (pIDLE->state == -1) { + // 结束idle + u64 *valp = bpf_map_lookup_elem(&idleStart,&key); + if (valp && *valp != 0) { + /*找到初始idle时间*/ + delta = time - *valp;//持续空闲时间=当前时间-进入空闲时间; + key = 0; + valp = bpf_map_lookup_elem(&idleLastTime,&key); + if (valp) *valp += delta;//找到持续空闲时间,持续空闲时间更新; + else bpf_map_update_elem(&idleLastTime,&key,&delta,BPF_ANY);//初次记录持续空闲时间; + } + } else { + // 开始idle + u64 val = time; + bpf_map_update_elem(&idleStart,&key,&time,BPF_ANY); + } + return 0; +} + + diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c new file mode 100644 index 000000000..f037d340f --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.c @@ -0,0 +1,427 @@ +// 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: zhangziheng0525@163.com +// +// user-mode code for libbpf sar + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpu_watcher.skel.h" +#include "cpu_watcher.h" + +#define warn(...) fprintf(stderr, __VA_ARGS__) +typedef long long unsigned int u64; +typedef unsigned int u32; +static volatile bool exiting = false;//全局变量,表示程序是否正在退出 + +struct cpu_watcher_bpf *skel;//用于自行加载和运行BPF程序的结构体,由libbpf自动生成并提供与之关联的各种功能接口; +u64 softirq = 0;//初始化softirq; +u64 irqtime = 0;//初始化irq; +u64 idle = 0;//初始化idle; +u64 sched = 0; +u64 proc = 0; +unsigned long ktLastTime = 0; + +// sar 工具的参数设置 +static struct env { + int time; + bool enable_proc; + bool libbpf_sar; + bool cs_delay; + +} env = { + .time = 0, + .enable_proc = false, + .libbpf_sar = false, + .cs_delay = false, +}; + +/*设置传参*/ +const char argp_program_doc[] ="cpu wacher is in use ....\n"; +static const struct argp_option opts[] = { + { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, + {"libbpf_sar", 's', 0,0,"print sar_info (the data of cpu)"}, + {"cs_delay", 'c', 0,0,"print cs_delay (the data of cpu)"}, + { 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 's': + env.libbpf_sar = true; + break; + case 'c': + env.cs_delay = true; + break; + case 'h': + argp_state_help(state, stderr, ARGP_HELP_STD_HELP); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} +static const struct argp argp = { + .options = opts, + .parser = parse_arg, + .doc = argp_program_doc, +}; + + +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); +} + +/*-----------------------------------------------------------------------------------------------------*/ +/* cs_delay处理函数 */ +/*-----------------------------------------------------------------------------------------------------*/ +int count[25]={0};//定义一个count数组,用于汇总schedul()调度时间,以log2(时间间隔)为统计依据; +static int handle_event(void *ctx, void *data,unsigned long data_sz) +{ + const struct event *e = data; + printf("t1:%lu t2:%lu delay:%lu\n",e->t1,e->t2,e->delay); + + int dly=(int)(e->delay),i=0; + while (dly > 1){ + dly /= 2; + i ++; + } + count[i]++;//记录时间间隔次数; + return 0; +} +static int print_hstgram(int i,int max,int per_len) +{ + int cnt=count[i]; + if(per_len==1){ + while(cnt>0){//打印 + printf("*"); + cnt--; + } + } + while(cnt-per_len>=0){//打印 + printf("*"); + cnt-=per_len; + } + printf("\n"); + return per_len; +} +double pow(int n,int k)//实现pow函数 +{ + if (k > 0) + return n * pow(n, k - 1); + else if (k == 0) + return 1; + else + return 1.0 / pow(n, -k); +} +static void histogram() +{ + int log10[15]={0},max=0,per_len=1; + for(int i=0;i<10;i++){//log10(count[i]); + int tmp=count[i],cnt=0; + while (tmp >= 10){ + tmp /= 10; + cnt ++;//幂次 + } + log10[cnt]++; + } + + for(int i=0;i<10;i++){//找log10里的最大值; + if(max0){//pow(10,max); + per_len *=10 ; + max--; + } + + time_t now = time(NULL);// 获取当前时间 + struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 + printf("\nTime : %02d:%02d:%02d \n",localTime->tm_hour, localTime->tm_min, localTime->tm_sec); + printf("%-24s \t%-12s \t%-12s \n","cs_delay","Count","Distribution"); + printf("%d\t=>\t%-8d \t%-12d \t|",0,1,count[0]); + print_hstgram(0,max,per_len); + printf("%d\t=>\t%-8d \t%-12d \t|",2,3,count[1]); + print_hstgram(1,max,per_len); + for(int i=2;i<20;i++){ + printf("%d\t=>\t%-8d \t%-12d \t|",(int)pow(2,i),(int)pow(2,(i+1))-1,count[i]); + print_hstgram(i,max,per_len); + } + printf("per_len = %d\n",per_len); +} + + +/*-----------------------------------------------------------------------------------------------------*/ +/* libbpf_sar处理函数 */ +/*-----------------------------------------------------------------------------------------------------*/ +// 根据符号名称从/proc/kallsyms文件中搜索对应符号地址 +u64 find_ksym(const char* target_symbol) { + FILE *file = fopen("/proc/kallsyms", "r"); + if (file == NULL) { + perror("Failed to open /proc/kallsyms"); + return 1; + } + + char symbol_name[99]; + u64 symbol_address = 0; + + while (fscanf(file, "%llx %*c %s\n", &symbol_address, symbol_name) != EOF) { + if (strcmp(symbol_name, target_symbol) == 0) { + break; + } + } + + fclose(file); + + return symbol_address; +} +/*libbpf_sar处理函数*/ +static int print_all() +{ + + /*proc:*/ + int key_proc = 1;// 设置要查找的键值为0 + int err_proc, fd_proc = bpf_map__fd(skel->maps.countMap);// 获取映射文件描述符 + u64 total_forks;// 用于存储从映射中查找到的值 + err_proc = bpf_map_lookup_elem(fd_proc, &key_proc, &total_forks); // 从映射中查找键为1的值 + if (err_proc < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of total_forks: %d\n", err_proc); + return -1; + } + u64 __proc; + __proc = total_forks - proc;//计算差值; + proc = total_forks; + + /*cswch:*/ + int key_cswch = 0;// 设置要查找的键值为1 + int err_cswch, fd_cswch = bpf_map__fd(skel->maps.countMap);// 获取映射文件描述符 + u64 sched_total;// 用于存储从映射中查找到的值 + err_cswch = bpf_map_lookup_elem(fd_cswch, &key_cswch, &sched_total); // 从映射中查找键为1的值 + if (err_cswch < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of sched_total: %d\n", err_cswch); + return -1; + } + u64 __sched; + __sched = sched_total - sched;//计算差值; + sched = sched_total; + + // /*runqlen:*/ + // int key_runqlen = 0;// 设置要查找的键值为0 + // int err_runqlen, fd_runqlen = bpf_map__fd(skel->maps.runqlen);// 获取映射文件描述符 + // int runqlen;// 用于存储从映射中查找到的值 + // err_runqlen = bpf_map_lookup_elem(fd_runqlen, &key_runqlen, &runqlen); // 从映射中查找键为1的值 + // if (err_runqlen < 0) {//没找到 + // fprintf(stderr, "failed to lookup infos of runqlen: %d\n", err_runqlen); + // return -1; + // } + + /*irqtime:*/ + int key_irqtime = 0;// 设置要查找的键值为0 + int err_irqtime, fd_irqtime = bpf_map__fd(skel->maps.irq_Last_time);// 获取映射文件描述符 + u64 __irqtime;// 用于存储从映射中查找到的值 + __irqtime = irqtime; + err_irqtime = bpf_map_lookup_elem(fd_irqtime, &key_irqtime, &irqtime); // 从映射中查找键为1的值 + if (err_irqtime < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of irqtime: %d\n", err_irqtime); + return -1; + } + u64 dtairqtime = (irqtime - __irqtime); + + /*softirq:*/ + int key_softirq = 0;// 设置要查找的键值为0 + int err_softirq, fd_softirq = bpf_map__fd(skel->maps.softirqLastTime);// 获取映射文件描述符 + u64 __softirq;// 用于存储从映射中查找到的值 + __softirq = softirq; + err_softirq = bpf_map_lookup_elem(fd_softirq, &key_softirq, &softirq); // 从映射中查找键为1的值 + if (err_softirq < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of softirq: %d\n", err_softirq); + return -1; + } + u64 dtasoftirq = (softirq - __softirq); + + /*idle*/ + int key_idle = 0;// 设置要查找的键值为0 + int err_idle, fd_idle = bpf_map__fd(skel->maps.idleLastTime);// 获取映射文件描述符 + u64 __idle;// 用于存储从映射中查找到的值 + __idle = idle; + err_idle = bpf_map_lookup_elem(fd_idle, &key_idle, &idle); // 从映射中查找键为1的值 + if (err_idle < 0) {//没找到 + fprintf(stderr, "failed to lookup infos of idle: %d\n", err_idle); + return -1; + } + u64 dtaidle = (idle - __idle); + + /*kthread*/ + int key_kthread = 0; + int err_kthread, fd_kthread = bpf_map__fd(skel->maps.kt_LastTime); + unsigned long _ktLastTime=0; + _ktLastTime = ktLastTime; + err_kthread = bpf_map_lookup_elem(fd_kthread, &key_kthread,&ktLastTime); + if (err_kthread < 0) { + fprintf(stderr, "failed to lookup infos: %d\n", err_kthread); + return -1; + } + unsigned long dtaKT = ktLastTime -_ktLastTime; + + + + + if(env.enable_proc){ + //判断打印: + time_t now = time(NULL);// 获取当前时间 + struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 + printf("%02d:%02d:%02d %8llu %8llu %8llu %8llu %8llu %8lu\n", + localTime->tm_hour, localTime->tm_min, localTime->tm_sec,__proc,__sched,dtairqtime/1000,dtasoftirq/1000,dtaidle/1000000,dtaKT/1000); + } + else{ + env.enable_proc = true; + } + + return 0; +} + + +int main(int argc, char **argv) +{ + struct ring_buffer *rb = NULL; + int err;//用于存储错误码 + const char* symbol_name = "total_forks"; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + libbpf_set_strict_mode(LIBBPF_STRICT_ALL); + /* 设置libbpf错误和调试信息回调 */ + libbpf_set_print(libbpf_print_fn); + + /* 更干净地处理Ctrl-C + SIGINT:由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 + SIGTERM:请求中止进程,kill命令发送 + */ + signal(SIGINT, sig_handler); //注册一个信号处理函数 sig_handler,用于处理 Ctrl-C 信号(SIGINT) + signal(SIGTERM, sig_handler); + + /* 打开BPF应用程序 */ + skel = cpu_watcher_bpf__open(); + if (!skel) { + fprintf(stderr, "Failed to open BPF skeleton\n"); + return 1; + } + + skel->rodata->forks_addr = (u64)find_ksym(symbol_name); + + /* 加载并验证BPF程序 */ + err = cpu_watcher_bpf__load(skel); + if (err) { + fprintf(stderr, "Failed to load and verify BPF skeleton\n"); + goto cleanup; + } + + /* 附加跟踪点处理程序 */ + err = cpu_watcher_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + + printf("Tracing for Data's... Ctrl-C to end\n"); + + // rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_all, NULL, NULL); + // if (!rb) { + // err = -1; + // fprintf(stderr, "Failed to create ring buffer\n"); + // goto cleanup; + // } + + if(env.libbpf_sar){ + //printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms BpfCnt\n"); + //printf(" time softirq\n"); + printf(" time proc/s cswch/s irqTime/us softirq/us idle/ms kthread/us\n"); + } + else if(env.cs_delay){ + /* 设置环形缓冲区轮询 */ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); //ring_buffer__new() API,允许在不使用额外选项数据结构下指定回调 + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto cleanup; + } + } + /* 处理事件 */ + while (!exiting) { + sleep(1); + if(env.libbpf_sar){ + err = print_all(); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + } + else if(env.cs_delay){ + err = ring_buffer__poll(rb, 1000 /* timeout, s */); + /* Ctrl-C will cause -EINTR */ + if (err == -EINTR) { + err = 0; + break; + } + if (err < 0) { + printf("Error polling perf buffer: %d\n", err); + break; + } + /*打印直方图*/ + histogram(); + } + else { + printf("正在开发中, -c打印cs_delay, -s打印libbpf_sar\n"); + break; + } + } + +/* 卸载BPF程序 */ +cleanup: + /* Clean up */ + if(env.cs_delay) ring_buffer__free(rb);//释放环形缓冲区 + cpu_watcher_bpf__destroy(skel); + + return err < 0 ? -err : 0; +} diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h new file mode 100644 index 000000000..fd9cffb3c --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cpu_watcher.h @@ -0,0 +1,75 @@ +// 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: zhangziheng0525@163.com +// +// eBPF map for libbpf sar + +typedef long long unsigned int u64; +typedef unsigned int u32; + +/*----------------------------------------------*/ +/* cs_delay结构体 */ +/*----------------------------------------------*/ +#ifndef __CS_DELAY_H +#define __CS_DELAY_H +struct event { + long unsigned int t1; + long unsigned int t2; + long unsigned int delay; +}; +#endif /* __CS_DELAY_H */ + +/*----------------------------------------------*/ +/* cswch_args结构体 */ +/*----------------------------------------------*/ +struct cswch_args { + u64 pad; + char prev_comm[16]; + pid_t prev_pid; + int prev_prio; + long prev_state; + char next_comm[16]; + pid_t next_pid; + int next_prio; +}; + +/*----------------------------------------------*/ +/* 软中断结构体 */ +/*----------------------------------------------*/ +struct __softirq_info { + u64 pad; + u32 vec; +}; + +/*----------------------------------------------*/ +/* 硬中断结构体 */ +/*----------------------------------------------*/ +struct __irq_info { + u64 pad; + u32 irq; +}; + +/*----------------------------------------------*/ +/* idlecpu空闲时间所需结构体 */ +/*----------------------------------------------*/ +struct idleStruct { + u64 pad; + int state; + u32 cpu_id; +}; + + + + diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.bpf.c deleted file mode 100644 index 8ec7f2bd3..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.bpf.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "vmlinux.h" -#include //包含了BPF 辅助函数 -#include -#include "cs_delay.h" - -char LICENSE[] SEC("license") = "Dual BSD/GPL"; - -// 定义数组映射 -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, 1); - __type(key, int); - __type(value, u64); -} start SEC(".maps");//记录时间戳; - -struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 256 * 1024); -} rb SEC(".maps");//环形缓冲区; - -SEC("kprobe/schedule") -int BPF_KPROBE(schedule) -{ - u64 t1; - t1 = bpf_ktime_get_ns()/1000; //bpf_ktime_get_ns返回自系统启动以来所经过的时间(以纳秒为单位)。不包括系统挂起的时间。 - int key =0; - bpf_map_update_elem(&start,&key,&t1,BPF_ANY); - - return 0; -} - -SEC("kretprobe/schedule") -int BPF_KRETPROBE(schedule_exit) -{ - u64 t2 = bpf_ktime_get_ns()/1000; - u64 t1,delay; - int key = 0; - u64 *val = bpf_map_lookup_elem(&start,&key); - if (val != 0) - { - t1 = *val; - delay = t2 - t1; - bpf_map_delete_elem(&start, &key); - }else{ - return 0; - } - - - struct event *e; - e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); - if (!e) return 0; - - e->t1=t1;//开始时间 - e->t2=t2;//结束时间 - e->delay=delay;//时间间隔 - - /* 成功地将其提交到用户空间进行后期处理 */ - bpf_ringbuf_submit(e, 0); - - return 0; -} diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.c deleted file mode 100644 index d805dcafe..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - 注意:使用该程序时,将第94行代码注释掉 - 原因:该行代码为了能使程序运行结束,成功提交至Github仓库 -*/ - -#include -//#include //用于对数运算 -#include -#include -#include -#include -#include "cs_delay.skel.h" //包含了 BPF 字节码和相关的管理函数 -#include "cs_delay.h" - -static volatile bool exiting = false; - -int count[25]={0};//定义一个count数组,用于汇总schedul()调度时间,以log2(时间间隔)为统计依据; - -static void sig_handler(int sig) -{ - exiting = true; -} - - -static int handle_event(void *ctx, void *data,unsigned long data_sz) -{ - const struct event *e = data; - printf("t1:%lu t2:%lu delay:%lu\n",e->t1,e->t2,e->delay); - - int dly=(int)(e->delay),i=0; - while (dly > 1){ - dly /= 2; - i ++; - } - count[i]++;//记录时间间隔次数; - return 0; -} -static int print_hstgram(int i,int max,int per_len) -{ - int cnt=count[i]; - if(per_len==1){ - while(cnt>0){//打印 - printf("*"); - cnt--; - } - } - while(cnt-per_len>=0){//打印 - printf("*"); - cnt-=per_len; - } - printf("\n"); - return per_len; -} -double pow(int n,int k)//实现pow函数 -{ - if (k > 0) - return n * pow(n, k - 1); - else if (k == 0) - return 1; - else - return 1.0 / pow(n, -k); -} -static void histogram() -{ - int log10[15]={0},max=0,per_len=1; - for(int i=0;i<10;i++){//log10(count[i]); - int tmp=count[i],cnt=0; - while (tmp >= 10){ - tmp /= 10; - cnt ++;//幂次 - } - log10[cnt]++; - } - - for(int i=0;i<10;i++){//找log10里的最大值; - if(max0){//pow(10,max); - per_len *=10 ; - max--; - } - - printf("\n%-24s \t%-12s \t%-12s \n","cs_delay","Count","Distribution"); - printf("%d\t=>\t%-8d \t%-12d \t|",0,1,count[0]); - print_hstgram(0,max,per_len); - printf("%d\t=>\t%-8d \t%-12d \t|",2,3,count[1]); - print_hstgram(1,max,per_len); - for(int i=2;i<20;i++){ - printf("%d\t=>\t%-8d \t%-12d \t|",(int)pow(2,i),(int)pow(2,(i+1))-1,count[i]); - print_hstgram(i,max,per_len); - } - printf("per_len = %d\n",per_len); -} - - - - -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) -{ - return vfprintf(stderr, format, args); -} - -int main(int argc, char **argv) -{ - struct ring_buffer *rb = NULL; - struct cs_delay_bpf *skel; - int err; - - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - /* 设置libbpf错误和调试信息回调 */ - libbpf_set_print(libbpf_print_fn); - - /* 更干净地处理Ctrl-C - SIGINT:由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 - SIGTERM:请求中止进程,kill命令发送 - */ - signal(SIGINT, sig_handler); //signal设置某一信号的对应动作 - signal(SIGTERM, sig_handler); - - /* 打开BPF应用程序 */ - skel = cs_delay_bpf__open(); - if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); - return 1; - } - - /* 加载并验证BPF程序 */ - err = cs_delay_bpf__load(skel); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto cleanup; - } - - /* 附加跟踪点处理程序 */ - err = cs_delay_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto cleanup; - } - - /* 设置环形缓冲区轮询 */ - rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL); //ring_buffer__new() API,允许在不使用额外选项数据结构下指定回调 - if (!rb) { - err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); - goto cleanup; - } - - /* 处理事件 */ - while (!exiting) { - err = ring_buffer__poll(rb, 100 /* timeout, ms */); //ring_buffer__poll(),轮询打开ringbuf缓冲区。如果有事件,handle_event函数会执行 - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; - } - if (err < 0) { - printf("Error polling perf buffer: %d\n", err); - break; - } - - exiting = true; //使用该程序时,将该行代码注释掉 - - } - /*睡眠*/ - //sleep(99999999); - /*打印直方图*/ - histogram(); -/* 卸载BPF程序 */ -cleanup: - ring_buffer__free(rb); - cs_delay_bpf__destroy(skel); - - return err < 0 ? -err : 0; -} diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.h deleted file mode 100644 index 75ab7feda..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/cs_delay/libbpf_cs_delay/cs_delay.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __CS_DELAY_H -#define __CS_DELAY_H - -struct event { - long unsigned int t1; - long unsigned int t2; - long unsigned int delay; -}; - -#endif /* __CS_DELAY_H */ diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/Makefile b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/Makefile deleted file mode 100644 index 90d57930a..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/Makefile +++ /dev/null @@ -1,155 +0,0 @@ -# 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: zhangziheng0525@163.com -# -# compile the current folder code - -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -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 -LIBBLAZESYM_SRC := $(abspath ../../blazesym/) -LIBBLAZESYM_INC := $(abspath $(LIBBLAZESYM_SRC)/include) -LIBBLAZESYM_OBJ := $(abspath $(OUTPUT)/libblazesym.a) -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/') -VMLINUX := ../../vmlinux/$(ARCH)/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../../../../libbpf/include/uapi -I$(dir $(VMLINUX)) -I$(LIBBLAZESYM_INC) -CFLAGS := -g -Wall -ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS) - -APPS = libbpf_sar - -CARGO ?= $(shell which cargo) -ifeq ($(strip $(CARGO)),) -BZS_APPS := -else -BZS_APPS := profile -APPS += $(BZS_APPS) -# Required by libblazesym -ALL_LDFLAGS += -lrt -ldl -lpthread -lm -endif - -# 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: $(APPS) - -.PHONY: clean -clean: - $(call msg,CLEAN) - $(Q)rm -rf $(OUTPUT) $(APPS) - -$(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 - - -$(LIBBLAZESYM_SRC)/target/release/libblazesym.a:: - $(Q)cd $(LIBBLAZESYM_SRC) && $(CARGO) build --release - -$(LIBBLAZESYM_OBJ): $(LIBBLAZESYM_SRC)/target/release/libblazesym.a | $(OUTPUT) - $(call msg,LIB, $@) - $(Q)cp $(LIBBLAZESYM_SRC)/target/release/libblazesym.a $@ - -# Build BPF code -$(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) \ - $(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)): %.o: %.skel.h - -$(OUTPUT)/%.o: %.c $(wildcard %.h) | $(OUTPUT) - $(call msg,CC,$@) - $(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $(filter %.c,$^) -o $@ - -$(patsubst %,$(OUTPUT)/%.o,$(BZS_APPS)): $(LIBBLAZESYM_OBJ) - -$(BZS_APPS): $(LIBBLAZESYM_OBJ) - -# Build application binary -$(APPS): %: $(OUTPUT)/%.o $(COMMON_OBJ) $(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: \ No newline at end of file diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.c deleted file mode 100644 index bac9c68ac..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.c +++ /dev/null @@ -1,317 +0,0 @@ -// 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: zhangziheng0525@163.com -// -// user-mode code for libbpf sar - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libbpf_sar.skel.h" -#include "libbpf_sar.h" - -#define warn(...) fprintf(stderr, __VA_ARGS__) -typedef long long unsigned int u64; - -static volatile bool exiting = false;//全局变量,表示程序是否正在退出 - -// 长期保存的数值 -static u64 proc = 0; -static u64 sched =0; -static u64 sched2 =0; - -static u64 sum[10] = {};//用于存储要输出的各个数据结果; - -static int line = 0; - -// sar 工具的参数设置 -static struct env { - int time; - bool enable_proc; - //bool enable_sched_prwitch; -} env = { - .time = 0, - .enable_proc = false, - //.enable_sched_prwitch = false, -}; - -const char argp_program_doc[] ="libbpf_sar is a program that simulates sar constructed by libbpf for dynamic CPU indicator monitoring.\n"; - -static const struct argp_option opts[] = { - { "time", 't', "TIME-SEC", 0, "Max Running Time(0 for infinite)" }, - { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help" }, - {}, -}; - -static error_t parse_arg(int key, char *arg, struct argp_state *state) -{ - switch (key) { - case 't': - env.time = strtol(arg, NULL, 10); - if(env.time) alarm(env.time); - break; - case 'h': - argp_state_help(state, stderr, ARGP_HELP_STD_HELP); - break; - default: - return ARGP_ERR_UNKNOWN; - } - - return 0; -} - -static void sig_handler(int sig) -{ - exiting = true; -}//正在退出程序; - -static int print_countMap(struct bpf_map *map) -{ - - - int key = 0;// 设置要查找的键值为1 - int err, fd = bpf_map__fd(map);// 获取映射文件描述符 - u64 total_forks;// 用于存储从映射中查找到的值 - err = bpf_map_lookup_elem(fd, &key, &total_forks); // 从映射中查找键为1的值 - if (err < 0) {//没找到 - fprintf(stderr, "failed to lookup infos of total_forks: %d\n", err); - return -1; - } - - - key = 1;// 设置要查找的键值为1 - u64 sched_total;// 用于存储从映射中查找到的值 - //int err, fd = bpf_map__fd(map);// 获取映射文件描述符 - err = bpf_map_lookup_elem(fd, &key, &sched_total); // 从映射中查找键为1的值 - if (err < 0) {//没找到 - fprintf(stderr, "failed to lookup infos of sched_total: %d\n", err); - return -1; - } - - - key=2; - int runqlen;// 用于存储从映射中查找到的值 - err = bpf_map_lookup_elem(fd, &key, &runqlen); // 从映射中查找键为1的值 - if (err < 0) {//没找到 - fprintf(stderr, "failed to lookup infos of runqlen: %d\n", err); - return -1; - } - - - //proc: - u64 proc_s; - proc_s = total_forks-proc; - proc = total_forks;//统计差值; - - - //cswch: - u64 sched_pr; - sched_pr= sched_total - sched;//计算差值; - sched = sched_total; - - //runqlen: - /*nothing*/ - - //判断打印: - if(env.enable_proc){ - time_t now = time(NULL);// 获取当前时间 - struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 - printf("%02d:%02d:%02d %6lld %6lld %6d\n", - localTime->tm_hour, localTime->tm_min, localTime->tm_sec,proc_s,sched_pr,runqlen); - }else{ // 第一次的数据无法做差,所以不予输出 - env.enable_proc = true; - } - - - /* - //只打印cswch/s - if(env.enable_sched_prwitch){ - u64 sched_pr;//要输出的进程切换次数 - time_t now = time(NULL);// 获取当前时间 - struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 - - sched_pr= sched_total - sched;//计算差值; - sched = sched_total; - - - printf("%02d:%02d:%02d %6lld\n", - localTime->tm_hour, localTime->tm_min, localTime->tm_sec, sched_pr); - }else{ // 第一次的数据无法做差,所以不予输出 - sched = sched_total;//全局变量proc - env.enable_sched_prwitch = true; - } - */ - - //只打印proc - /* - if(env.enable_proc){ - u64 proc_s; - time_t now = time(NULL);// 获取当前时间 - struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 - - line++; - proc_s = total_forks-proc; - sum[0] += proc_s; - proc_s = sum[0]/line; - proc = total_forks; - - printf("%02d:%02d:%02d %6lld\n", - localTime->tm_hour, localTime->tm_min, localTime->tm_sec, proc_s); - }else{ // 第一次的数据无法做差,所以不予输出 - proc = total_forks;//全局变量proc - env.enable_proc = true; - } - */ - - //同时打印proc、cswch/s 失败 - /*if(env.enable_sched_prwitch||env.enable_proc){ - u64 proc_pr;//要输出的新创建的进程数 - u64 sched_pr;//要输出的进程切换次数 - time_t now = time(NULL);// 获取当前时间 - struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 - - - line++; - proc_pr = proc_total-proc; - sum[0] += proc_pr; - proc_pr = sum[0]/line; - proc = proc_total; - - sched_pr= sched_total - sched;//计算差值; - sched = sched_total; - - printf("%02d:%02d:%02d %6lld %6lld\n", - localTime->tm_hour, localTime->tm_min, localTime->tm_sec, proc_pr,sched_pr); - }else{ // 第一次的数据无法做差,所以不予输出 - proc = proc_total;//全局变量proc - env.enable_proc = true; - - sched = sched_total;//全局变量proc - env.enable_sched_prwitch = true; - } - */ - return 0; -} - -static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) -{ - return vfprintf(stderr, format, args); -} - -// 根据符号名称从/proc/kallsyms文件中搜索对应符号地址 -u64 find_ksym(const char* target_symbol) { - FILE *file = fopen("/proc/kallsyms", "r"); - if (file == NULL) { - perror("Failed to open /proc/kallsyms"); - return 1; - } - - char symbol_name[99]; - u64 symbol_address = 0; - - while (fscanf(file, "%llx %*c %s\n", &symbol_address, symbol_name) != EOF) { - if (strcmp(symbol_name, target_symbol) == 0) { - break; - } - } - - fclose(file); - - return symbol_address; -} - -int main(int argc, char **argv) -{ - struct libbpf_sar_bpf *skel; - int err; - const char* symbol_name = "total_forks"; - static const struct argp argp = { - .options = opts, - .parser = parse_arg, - .doc = argp_program_doc, - }; - - err = argp_parse(&argp, argc, argv, 0, NULL, NULL); - if (err) - return err; - - libbpf_set_strict_mode(LIBBPF_STRICT_ALL); - /* 设置libbpf错误和调试信息回调 */ - libbpf_set_print(libbpf_print_fn); - - /* 更干净地处理Ctrl-C - SIGINT:由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 - SIGTERM:请求中止进程,kill命令发送 - */ - signal(SIGINT, sig_handler); //signal设置某一信号的对应动作 - signal(SIGTERM, sig_handler); - signal(SIGALRM, sig_handler); - - /* 打开BPF应用程序 */ - skel = libbpf_sar_bpf__open(); - if (!skel) { - fprintf(stderr, "Failed to open BPF skeleton\n"); - return 1; - } - - skel->rodata->forks_addr = (u64)find_ksym(symbol_name); - - /* 加载并验证BPF程序 */ - err = libbpf_sar_bpf__load(skel); - if (err) { - fprintf(stderr, "Failed to load and verify BPF skeleton\n"); - goto cleanup; - } - - /* 附加跟踪点处理程序 */ - err = libbpf_sar_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); - goto cleanup; - } - - printf("Tracing for Data's... Ctrl-C to end\n"); - - //printf(" time proc/s cswch/s runqlen irqTime/us softirq/us idle/ms kthread/us sysc/ms utime/ms sys/ms BpfCnt\n"); - printf(" time proc/s cswch/s runqlen\n"); - /* 处理事件 */ - while (!exiting) { - sleep(1); - - err = print_countMap(skel->maps.countMap); - /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { - err = 0; - break; - } - if (err < 0) { - break; - } - } - -/* 卸载BPF程序 */ -cleanup: - libbpf_sar_bpf__destroy(skel); - - return err < 0 ? -err : 0; -} diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.h b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.h deleted file mode 100644 index b40e0c273..000000000 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/libbpf_sar/libbpf_sar.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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: zhangziheng0525@163.com -// -// eBPF map for libbpf sar