diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/mfutex.bpf.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/mfutex.bpf.c index d65926b8e..73080edf5 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/mfutex.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/bpf/mfutex.bpf.c @@ -73,13 +73,18 @@ struct { __uint(max_entries,528 * 10240); } mfutex_rb SEC(".maps"); -// struct { -// __uint(type, BPF_MAP_TYPE_HASH); -// __uint(max_entries, 10240); -// __type(key, struct record_lock_key); -// __type(value, struct per_request); -// } futex_wait_queue SEC(".maps");//记录futex陷入内核 - +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, struct lock_record_key); + __type(value, struct per_request); +} futex_wait_queue SEC(".maps");//记录futex陷入内核 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10240); + __type(key, struct lock_record_key); + __type(value, struct per_request); +} futex_wake_queue SEC(".maps");//记录futex陷入内核 #define MUTEX_FLAG 1 #define RWLOCK_FLAG 2 @@ -280,15 +285,164 @@ int BPF_KPROBE(pthread_mutex_unlock_enter, void *__mutex) // return 0; // } +// SEC("tracepoint/syscall/sys_enter_futex") +// int trace_sys_enter_futex(struct sys_futex_args ctx){ -// /*获取到要加入等待队列的线程,拿到时间*/ -// SEC("kprobe/futex_wait") -// int BPF_KPROBE(trace_futex_wait, -// u32 __user *uaddr, unsigned int flags, -// u32 val, ktime_t *abs_time, u32 bitset) -// { +// } +/*1.将线程加入等待队列,并记录*/ +SEC("kprobe/futex_wait") +int BPF_KPROBE(trace_futex_wait, + u32 *uaddr, unsigned int flags, + u32 val, ktime_t *abs_time, u32 bitset) +{ + struct mfutex_ctrl *mfutex_ctrl = get_mfutex_ctrl(); + if(!mfutex_ctrl) + return 0; + pid_t pid = bpf_get_current_pid_tgid(); + int tgid = bpf_get_current_pid_tgid() >> 32; + if(mfutex_ctrl->target_pid == -1 && mfutex_ctrl->target_tgid == -1)//未指定目标进程或线程 + return 0; + if((mfutex_ctrl->target_pid != -1 && pid!=mfutex_ctrl->target_pid)|| + (mfutex_ctrl->target_tgid != -1 && tgid != mfutex_ctrl->target_tgid))//当前进程或线程非目标进程或线程 + return 0; + u64 lock_ptr = (u64)uaddr; + int cpu = bpf_get_smp_processor_id();//获取当前cpu -// } + /*1.将 单个线程请求信息块 放入 请求等待队列futex_wait_queue*/ + struct per_request per_request = {}; + per_request.pid = pid; + per_request.start_request_time = bpf_ktime_get_ns(); + per_request.cpu_id = cpu; + struct lock_record_key key = {}; + key.lock_ptr = lock_ptr; + key.pid = pid; + bpf_map_update_elem(&futex_wait_queue, &key, &per_request, BPF_ANY); + // bpf_printk("Push_info:pid:%d ,lock_ptr:%lu, cnt:%d\n",per_request.pid,key.lock_ptr,key.cnt); + return 0; +} + +/*2.将线程加入唤醒队列,从等待队列中删除 + *2.1 将执行futex_wake的线程pid与锁地址进行匹配,便于在后面futex_wake_mark找到锁地址 + */ +SEC("kprobe/futex_wake") +int BPF_KPROBE(trace_futex_wake_enter, + u32 *uaddr, unsigned int flags, + int nr_wake, u32 bitset) +{ + struct mfutex_ctrl *mfutex_ctrl = get_mfutex_ctrl(); + if(!mfutex_ctrl) + return 0; + pid_t pid = bpf_get_current_pid_tgid(); + int tgid = bpf_get_current_pid_tgid() >> 32; + + if(mfutex_ctrl->target_pid == -1 && mfutex_ctrl->target_tgid == -1)//未指定目标进程或线程 + return 0; + if((mfutex_ctrl->target_pid != -1 && pid!=mfutex_ctrl->target_pid)|| + (mfutex_ctrl->target_tgid != -1 && tgid != mfutex_ctrl->target_tgid))//当前进程或线程非目标进程或线程 + return 0; + + u64 lock_ptr = (u64)uaddr; + struct proc_flag key={}; + key.pid = pid; + key.flag = FUTEX_FLAG; + bpf_map_update_elem(&proc_unlock, &key, &lock_ptr, BPF_ANY);//将锁地址存在proc_unlock map中 + return 0; +} +/*2.将线程加入唤醒队列,从等待队列中删除 + *2.2 将要被唤醒的线程加入唤醒队列,并从等待队列中删除掉; + */ +SEC("kprobe/futex_wake_mark") +int BPF_KPROBE(trace_futex_wake_mark, struct wake_q_head *wake_q, struct futex_q *q) +{ + struct mfutex_ctrl *mfutex_ctrl = get_mfutex_ctrl(); + if(!mfutex_ctrl) + return 0; + pid_t pid = bpf_get_current_pid_tgid(); + int tgid = bpf_get_current_pid_tgid() >> 32; + + if(mfutex_ctrl->target_pid == -1 && mfutex_ctrl->target_tgid == -1)//未指定目标进程或线程 + return 0; + if((mfutex_ctrl->target_pid != -1 && pid!=mfutex_ctrl->target_pid)|| + (mfutex_ctrl->target_tgid != -1 && tgid != mfutex_ctrl->target_tgid))//当前进程或线程非目标进程或线程 + return 0; + + u64 *lock_ptr; + u64 temp_lock_ptr; + u64 ts = bpf_ktime_get_ns(); + + /*1.找到锁的地址*/ + struct proc_flag proc_flag = {}; + proc_flag.pid = pid; + proc_flag.flag = FUTEX_FLAG; + lock_ptr = bpf_map_lookup_elem(&proc_unlock, &proc_flag); + if(!lock_ptr) return 0; + temp_lock_ptr = *lock_ptr; + + /*2.make key*/ + struct lock_record_key key = {}; + key.lock_ptr = temp_lock_ptr; + key.pid = BPF_CORE_READ(q,task,pid); + + /*3.将线程从等待队列中删除*/ + struct per_request *per_request; + per_request = bpf_map_lookup_elem(&futex_wait_queue, &key); + if(per_request) {//如果等待队列中找到该task 则尝试删除 + bpf_map_delete_elem(&futex_wait_queue, &key); + per_request->start_hold_time = ts; + per_request->wait_delay = ts - per_request->start_hold_time; + }else{//如果没找到,说明该任务陷入阻塞时未记录,则创建per_request + struct per_request new_per_request = {}; + new_per_request.pid = key.pid; + new_per_request.start_hold_time = ts; + per_request = &new_per_request; + } + /*4.将任务放到唤醒队列中*/ + bpf_map_update_elem(&futex_wake_queue, &key, per_request, BPF_ANY); + return 0; +} + +/*2.将线程加入唤醒队列,从等待队列中删除 + *2.1 将执行futex_wake的线程pid与锁地址进行匹配,便于在后面futex_wake_mark找到锁地址 + */ +SEC("kretprobe/futex_wake") +int BPF_KRETPROBE(trace_futex_wake_exit) +{ + struct mfutex_ctrl *mfutex_ctrl = get_mfutex_ctrl(); + if(!mfutex_ctrl) + return 0; + pid_t pid = bpf_get_current_pid_tgid(); + int tgid = bpf_get_current_pid_tgid() >> 32; + + if(mfutex_ctrl->target_pid == -1 && mfutex_ctrl->target_tgid == -1)//未指定目标进程或线程 + return 0; + if((mfutex_ctrl->target_pid != -1 && pid!=mfutex_ctrl->target_pid)|| + (mfutex_ctrl->target_tgid != -1 && tgid != mfutex_ctrl->target_tgid))//当前进程或线程非目标进程或线程 + return 0; + + u64 *lock_ptr; + u64 temp_lock_ptr; + u64 ts = bpf_ktime_get_ns(); + + /*1.找到锁的地址*/ + struct proc_flag proc_flag = {}; + proc_flag.pid = pid; + proc_flag.flag = FUTEX_FLAG; + lock_ptr = bpf_map_lookup_elem(&proc_unlock, &proc_flag); + if(!lock_ptr) return 0; + temp_lock_ptr = *lock_ptr; + bpf_map_delete_elem(&proc_unlock, &proc_flag); + + /*2.传入rb*/ + struct per_lock_event *e; + e = bpf_ringbuf_reserve(&mfutex_rb, sizeof(*e), 0); + if(!e) + return 0; + e->lock_ptr = temp_lock_ptr; + e->start_hold_time = bpf_ktime_get_ns(); + e->type = FUTEX_FLAG; + bpf_ringbuf_submit(e, 0); + return 0; +} \ No newline at end of file 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 101146dbe..0fd459819 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 @@ -27,11 +27,11 @@ #define LAST_ARG (FULL_MAX_ARGS_ARR - ARGSIZE) #define TASK_RUNNING 0x00000000 -// #define MUTEX_FLAG 1 -// #define RWLOCK_FLAG 2 -// #define SPIN_FLAG 3 -// #define RCU_FLAG 4 -// #define FUTEX_FLAG 5 +#define MUTEX_FLAG 1 +#define RWLOCK_FLAG 2 +#define SPIN_FLAG 3 +#define RCU_FLAG 4 +#define FUTEX_FLAG 5 typedef long long unsigned int u64; typedef unsigned int u32; #define MAX_STACK_DEPTH 128 @@ -134,6 +134,7 @@ struct per_request{//每条锁请求信息 u64 start_request_time; u64 start_hold_time; u64 wait_delay; + int cpu_id;//在哪个cpu上阻塞了 }; struct lock_record_key{ @@ -152,6 +153,16 @@ struct per_lock_event{ u64 start_hold_time,last_hold_delay;//持有锁的时间; int cnt;//等待锁+持有锁的数量; }; +struct sys_futex_args { + u64 pad; + int __syscall_nr; + u32 * uaddr; + int op; + u32 val; + const struct __kernel_timespec * utime; + u32 * uaddr2; + u32 val3; +}; // keytime_image struct kt_ctrl{ 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 b185d67b2..6faf1e1e9 100644 --- a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/proc_image.c @@ -534,32 +534,86 @@ static int print_mfutex(void *ctx, void *data,unsigned long data_sz) time_t now = time(NULL);// 获取当前时间 struct tm *localTime = localtime(&now);// 将时间转换为本地时间结构 printf("%02d:%02d:%02d ",localTime->tm_hour, localTime->tm_min, localTime->tm_sec); - printf("%-12s 0x%x %-10d %-16llu %-11llu %-11lu | ",mfutex_type[e->type],e->lock_ptr,e->owner,e->start_hold_time,e->last_owner,e->last_hold_delay); - - int err,record_lock_fd =bpf_map__fd(mfutex_skel->maps.record_lock); - - struct record_lock_key lookup_key = {-1,-1}, next_key; - while(!bpf_map_get_next_key(record_lock_fd, &lookup_key, &next_key)){ - // printf("next_key:%x target_ptr:%x\n",next_key,e->lock_ptr); - if(next_key.lock_ptr != e->lock_ptr) { - lookup_key = next_key; - continue;//不是目标锁,跳过 - } - struct per_request per_request = {}; - err = bpf_map_lookup_elem(record_lock_fd,&next_key,&per_request); - if (err < 0) { - // printf(stderr, "failed to lookup info: %d\n", err); - lookup_key = next_key; - continue;//不是目标锁,跳过 + int type = e->type; + if(type == MUTEX_FLAG){ + printf("%-12s 0x%-8x %-11llu %-11lu %-16llu %-10d\n",mfutex_type[e->type],e->lock_ptr,e->last_owner,e->last_hold_delay,e->start_hold_time,e->owner); + printf("%-81s",""); + int err,record_lock_fd =bpf_map__fd(mfutex_skel->maps.record_lock); + struct record_lock_key lookup_key1 = {-1,-1}, next_key; + while(!bpf_map_get_next_key(record_lock_fd, &lookup_key1, &next_key)){ + // printf("next_key:%x target_ptr:%x\n",next_key,e->lock_ptr); + if(next_key.lock_ptr != e->lock_ptr) { + lookup_key1 = next_key; + continue;//不是目标锁,跳过 + } + struct per_request per_request = {}; + err = bpf_map_lookup_elem(record_lock_fd,&next_key,&per_request); + if (err < 0) { + // printf(stderr, "failed to lookup info: %d\n", err); + lookup_key1 = next_key; + continue;//不是目标锁,跳过 + } + float wait_delay = (e->start_hold_time-per_request.start_request_time)/1000000000.0; + if(wait_delay<=0||wait_delay>=10000) + printf("%d(NULL)|",per_request.pid); + else printf("%d(%ds)|",per_request.pid,((e->start_hold_time-per_request.start_request_time)/1000000000)); + lookup_key1 = next_key; + } + }else if(type == FUTEX_FLAG){ + printf("%-12s 0x%-8x %-11s %-11s %-16llu ",mfutex_type[e->type],e->lock_ptr,"NULL","NULL",e->start_hold_time); + int err,futex_wake_queue_fd =bpf_map__fd(mfutex_skel->maps.futex_wake_queue); + struct lock_record_key lookup_key1 = {-1,-1}, next_key; + while(!bpf_map_get_next_key(futex_wake_queue_fd, &lookup_key1, &next_key)){ + // printf("next_key:%x target_ptr:%x\n",next_key,e->lock_ptr); + if(next_key.lock_ptr != e->lock_ptr) { + lookup_key1 = next_key; + continue;//不是目标锁,跳过 + } + struct per_request per_request = {}; + err = bpf_map_lookup_elem(futex_wake_queue_fd,&next_key,&per_request); + if (err < 0) { + // printf(stderr, "failed to lookup info: %d\n", err); + lookup_key1 = next_key; + continue;//不是目标锁,跳过 + } + + float wait_delay = (e->start_hold_time-per_request.start_request_time)/1000000000.0; + if(wait_delay<=0||wait_delay>=10000) + printf("%d(NULL)| ",per_request.pid); + else printf("%d(%ds)| ",per_request.pid,((e->start_hold_time-per_request.start_request_time)/1000000000)); + err = bpf_map_delete_elem(futex_wake_queue_fd, &next_key); + if (err < 0) { + fprintf(stderr, "failed to cleanup infos: %d\n", err); + return -1; + } + lookup_key1 = next_key; + } + printf("\n%-81s",""); + int err2,futex_wait_queue_fd =bpf_map__fd(mfutex_skel->maps.futex_wait_queue); + struct lock_record_key lookup_key2 = {-1,-1}; + while(!bpf_map_get_next_key(futex_wait_queue_fd, &lookup_key2, &next_key)){ + // printf("next_key:%x target_ptr:%x\n",next_key,e->lock_ptr); + if(next_key.lock_ptr != e->lock_ptr) { + lookup_key2 = next_key; + continue;//不是目标锁,跳过 + } + struct per_request per_request = {}; + err2 = bpf_map_lookup_elem(futex_wait_queue_fd,&next_key,&per_request); + if (err2 < 0) { + // printf(stderr2, "failed to lookup info: %d\n", err2); + lookup_key2 = next_key; + continue;//不是目标锁,跳过 + } + + float wait_delay = (e->start_hold_time-per_request.start_request_time)/1000000000.0; + if(wait_delay<=0||wait_delay>=10000) + printf("%d(NULL)| ",per_request.pid); + else printf("%d(%ds)| ",per_request.pid,((e->start_hold_time-per_request.start_request_time)/1000000000)); + lookup_key2 = next_key; } - float wait_delay = (e->start_hold_time-per_request.start_request_time)/1000000000.0; - if(wait_delay<=0||wait_delay>=10000) - printf("%d(NULL) | ",per_request.pid); - else printf("%d(%ds) | ",per_request.pid,((e->start_hold_time-per_request.start_request_time)/1000000000)); - lookup_key = next_key; + printf("\n"); } printf("\n"); - // struct record_lock_key key; // key.lock_ptr = e->lock_ptr; // key.cnt = 1; @@ -1020,7 +1074,8 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to create mfutex ring buffer\n"); goto cleanup; } - printf("%-8s %-12s %-10s %-10s %-16s %-11s %-11s | %10s\n","TIME","LOCK_TYPE","LOCK_Addr","Holder","HoldTime","Last_Holder","Last_Delay","Wait_Proc"); + printf("============================================ MFutex ============================================\n"); + printf("%-8s %-12s %-10s %-11s %-11s %-16s %-15s\n","TIME","LOCK_TYPE","LOCK_Addr","Last_Holder","Last_Delay","HoldTime","Waker/Waiter"); } if(env.enable_keytime){ diff --git a/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/test/test_futex.c b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/test/test_futex.c new file mode 100644 index 000000000..07519dc5a --- /dev/null +++ b/eBPF_Supermarket/CPU_Subsystem/eBPF_proc_image/test/test_futex.c @@ -0,0 +1,122 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Futex 原子变量 +volatile int futex_var = 0; + +// Futex 系统调用的封装函数 +int futex_wait(volatile int *uaddr, int val) { + return syscall(SYS_futex, uaddr, FUTEX_WAIT, val, NULL, NULL, 0); +} + +int futex_wake(volatile int *uaddr, int num_wake) { + return syscall(SYS_futex, uaddr, FUTEX_WAKE, num_wake, NULL, NULL, 0); +} + +// 等待线程函数 +void* wait_thread(void* arg) { + int thread_id = *(int*)arg; + printf("Thread %d: Waiting on futex...\n", thread_id); + + // 等待 futex_var 为 0 + int ret = futex_wait(&futex_var, 0); + if (ret == -1) { + perror("futex_wait"); + } + + printf("Thread %d: Futex was awakened!\n", thread_id); + + return NULL; +} + +// 唤醒线程函数 +void* wake_thread(void* arg) { + for (int i = 0; i < 10; i++) { + // 模拟一些工作延迟 + sleep(1); + + printf("Wake thread: Waking up thread %d...\n", i + 1); + + // 唤醒一个等待的线程 + futex_var = 1; // 修改 futex_var,允许一个线程继续 + int ret = futex_wake(&futex_var, 1); // 唤醒一个等待的线程 + if (ret == -1) { + perror("futex_wake"); + } else { + printf("Wake thread: Thread %d wake successful!\n", i + 1); + } + + // 重置 futex_var 为 0,确保下一个线程继续等待 + futex_var = 0; + } + + return NULL; +} + +pid_t get_tgid() { + pid_t pid = getpid(); + char path[256]; + snprintf(path, sizeof(path), "/proc/%d/status", pid); + + FILE *fp = fopen(path, "r"); + if (!fp) { + perror("打开 proc/pid/status 文件失败"); + return -1; + } + + char line[256]; + int tgid = -1; + + while (fgets(line, sizeof(line), fp)) { + if (strncmp(line, "Tgid:", 5) == 0) { + sscanf(line, "Tgid: %d", &tgid); + break; + } + } + + fclose(fp); + return tgid; +} + +int main() { + pthread_t wait_threads[10]; + pthread_t wake_thread_id; + pid_t tgid = get_tgid(); + printf("TGID:%d\n", tgid); + printf("lock_addr :0x%-8x\n",&futex_var); + int tmp; + scanf("%d",&tmp); + // 创建等待线程的 ID 数组 + int thread_ids[10]; + for (int i = 0; i < 10; i++) { + thread_ids[i] = i + 1; + } + + // 创建 10 个等待线程 + for (int i = 0; i < 10; i++) { + pthread_create(&wait_threads[i], NULL, wait_thread, &thread_ids[i]); + } + + // 创建唤醒线程 + pthread_create(&wake_thread_id, NULL, wake_thread, NULL); + + // 等待所有等待线程结束 + for (int i = 0; i < 10; i++) { + pthread_join(wait_threads[i], NULL); + } + + // 等待唤醒线程结束 + pthread_join(wake_thread_id, NULL); + + printf("Futex test completed.\n"); + return 0; +} diff --git a/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.bpf.c b/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.bpf.c index f32b27316..3fac61383 100644 --- a/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.bpf.c @@ -145,17 +145,17 @@ __always_inline static void on_sys_exit(u64 time) { } // 进入用户态 -int exit_to_user_mode_prepare() { - // Step1: 记录user开始时间,和当前的in_user状态 - struct task_struct *ts = (struct task_struct *)bpf_get_current_task(); - if (ts->pid != TARGET_PID) return 0; - u64 time = bpf_ktime_get_ns(); +// int exit_to_user_mode_prepare() { +// // Step1: 记录user开始时间,和当前的in_user状态 +// struct task_struct *ts = (struct task_struct *)bpf_get_current_task(); +// if (ts->pid != TARGET_PID) return 0; +// u64 time = bpf_ktime_get_ns(); - on_user_enter(time); - on_sys_exit(time); +// on_user_enter(time); +// on_sys_exit(time); - return 0; -} +// return 0; +// } // 获取进程切换数 int trace_sched_switch(struct cswch_args *info) { diff --git a/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.py b/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.py index 84b2aedda..1d46253bd 100644 --- a/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.py +++ b/eBPF_Supermarket/CPU_Subsystem/old_project/BCC_sar/src/sar/sar_perpro.py @@ -34,7 +34,7 @@ def attach_probe(pid: int): bpf.attach_tracepoint(tp="irq:irq_handler_exit", fn_name="trace_irq_handler_exit") bpf.attach_tracepoint(tp="raw_syscalls:sys_enter", fn_name="trace_sys_enter") # bpf.attach_tracepoint(tp="raw_syscalls:sys_exit", fn_name="trace_sys_exit") - bpf.attach_kprobe(event="exit_to_user_mode_prepare",fn_name="exit_to_user_mode_prepare") + # bpf.attach_kprobe(event="exit_to_user_mode_prepare",fn_name="exit_to_user_mode_prepare") return bpf def perpro_main(args, pid: int):