diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c index 79212119b..0ab634eeb 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/bpf/mutrace.bpf.c @@ -33,81 +33,81 @@ struct { } rb SEC(".maps"); static inline struct mu_ctrl *get_mu_ctrl(void) { - struct mu_ctrl *mu_ctrl; - mu_ctrl = bpf_map_lookup_elem(&mu_ctrl_map, &ctrl_key); - if (!mu_ctrl || !mu_ctrl->mu_func) { - return NULL; - } - return mu_ctrl; + struct mu_ctrl *mu_ctrl = bpf_map_lookup_elem(&mu_ctrl_map, &ctrl_key); + return (mu_ctrl && mu_ctrl->mu_func) ? mu_ctrl : NULL; } -/*----------------------------------------------*/ -/* 内核态互斥锁 */ -/*----------------------------------------------*/ +static inline void update_mutex_info(struct mutex_info *info, u64 ts, pid_t pid) { + info->acquire_time = ts; + info->last_owner = pid; + bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); +} + +static inline void init_mutex_info(struct mutex_info *info, u64 lock_addr, u64 ts, pid_t pid) { + info->locked_total = 0; + info->locked_max = 0; + info->contended_total = 0; + info->count = 0; + info->last_owner = pid; + info->acquire_time = ts; + info->ptr = lock_addr; + __builtin_memset(info->last_name, 0, sizeof(info->last_name)); + bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); +} SEC("kprobe/mutex_lock") int BPF_KPROBE(trace_mutex_lock, struct mutex *lock) { - u64 lock_addr = (u64)lock; // 获取锁地址 + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); + u64 lock_addr = (u64)lock; u64 ts = bpf_ktime_get_ns(); struct mutex_info *info = bpf_map_lookup_elem(&kmutex_info_map, &lock_addr); + if (info) { - info->acquire_time = ts; // 保存锁获取时间 + info->acquire_time = ts; } else { - struct mutex_info new_info = { - .locked_total = 0, - .locked_max = 0, - .contended_total = 0, - .count = 0, - .last_owner = 0, - .acquire_time = ts, - .ptr = lock_addr - }; - __builtin_memset(new_info.last_name, 0, sizeof(new_info.last_name)); + struct mutex_info new_info; + init_mutex_info(&new_info, lock_addr, ts, 0); bpf_map_update_elem(&kmutex_info_map, &lock_addr, &new_info, BPF_ANY); } + return 0; } SEC("kprobe/mutex_trylock") int BPF_KPROBE(trace_mutex_trylock, struct mutex *lock) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); int ret = PT_REGS_RC(ctx); - if (ret != 0) { // 成功获取锁 - u64 lock_addr = (u64)lock; // 获取锁地址 + if (ret != 0) { + u64 lock_addr = (u64)lock; u64 ts = bpf_ktime_get_ns(); struct mutex_info *info = bpf_map_lookup_elem(&kmutex_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, - .count = 0, - .last_owner = 0, - .acquire_time = ts, - .ptr = lock_addr - }; - __builtin_memset(new_info.last_name, 0, sizeof(new_info.last_name)); + struct mutex_info new_info; + init_mutex_info(&new_info, lock_addr, ts, 0); bpf_map_update_elem(&kmutex_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 mu_ctrl *mu_ctrl = get_mu_ctrl(); - 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; + if (!mu_ctrl) return 0; + u64 lock_addr = (u64)lock; u64 ts = bpf_ktime_get_ns(); - e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); - if (!e) { - return 0; - } + struct mutex_contention_event *e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); + if (!e) return 0; + + pid_t pid = bpf_get_current_pid_tgid(); + struct task_struct *owner_task, *contender_task; + long owner; + e->contender_pid = pid; e->ptr = lock_addr; bpf_get_current_comm(&e->contender_name, sizeof(e->contender_name)); @@ -115,6 +115,7 @@ int BPF_KPROBE(trace_mutex_lock_slowpath, struct mutex *lock) { 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); @@ -123,89 +124,75 @@ int BPF_KPROBE(trace_mutex_lock_slowpath, struct mutex *lock) { e->owner_pid = 0; __builtin_memset(e->owner_name, 0, sizeof(e->owner_name)); } + struct mutex_info *info = bpf_map_lookup_elem(&kmutex_info_map, &lock_addr); if (info) { u64 contention_start = ts; - info->contended_total += (contention_start - info->acquire_time); // 更新争用时间 - info->count++; // 更新争用次数 + info->contended_total += (contention_start - info->acquire_time); + info->count++; } else { - struct mutex_info new_info = { - .locked_total = 0, - .locked_max = 0, - .contended_total = 0, - .count = 1, // 初始化争用次数 - .last_owner = 0, - .acquire_time = ts, // 初始化获取时间 - .ptr = lock_addr - }; - __builtin_memset(new_info.last_name, 0, sizeof(new_info.last_name)); + struct mutex_info new_info; + init_mutex_info(&new_info, lock_addr, ts, 0); + new_info.count = 1; bpf_map_update_elem(&kmutex_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) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); 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(&kmutex_info_map, &lock_addr); + if (info) { - u64 held_time = ts - info->acquire_time; // 计算锁被持有的时间 - info->locked_total += held_time; // 更新锁被持有的总时间 + u64 held_time = ts - info->acquire_time; + info->locked_total += held_time; if (held_time > info->locked_max) { - info->locked_max = held_time; // 更新锁被持有的最长时间 + info->locked_max = held_time; } - info->last_owner = pid; // 更新最后一次持有该锁的线程ID - bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); // 更新最后一次持有该锁的线程名称 + info->last_owner = pid; + bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); } + return 0; } - - /*----------------------------------------------*/ /* 用户态互斥锁 */ /*----------------------------------------------*/ - - -SEC("uprobe/pthread_mutex_lock") -int BPF_KPROBE(pthread_mutex_lock, void *__mutex) { - u64 pid_tgid = bpf_get_current_pid_tgid(); - pid_t pid = pid_tgid >> 32; - u64 now = bpf_ktime_get_ns(); - +static inline void handle_user_mutex_lock(void *__mutex, u64 now, pid_t pid) { struct mutex_info *info = bpf_map_lookup_elem(&umutex_info_map, &__mutex); if (info) { if (info->acquire_time > 0) { - // 如果 acquire_time 已经被设置,说明锁被争用 info->contended_total += (now - info->acquire_time); - info->count += 1; + info->count++; } - info->acquire_time = now; - info->last_owner = pid; - bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); + update_mutex_info(info, now, pid); } else { - // 初始化 mutex_info - struct mutex_info new_info = { - .locked_total = 0, - .locked_max = 0, - .contended_total = 0, - .count = 0, - .last_owner = pid, - .acquire_time = now, - .ptr = (u64)__mutex, - }; - bpf_get_current_comm(&new_info.last_name, sizeof(new_info.last_name)); + struct mutex_info new_info; + init_mutex_info(&new_info, (u64)__mutex, now, pid); bpf_map_update_elem(&umutex_info_map, &__mutex, &new_info, BPF_ANY); } +} + +SEC("uprobe/pthread_mutex_lock") +int BPF_KPROBE(pthread_mutex_lock, void *__mutex) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); + u64 now = bpf_ktime_get_ns(); + pid_t pid = bpf_get_current_pid_tgid() >> 32; + handle_user_mutex_lock(__mutex, now, pid); return 0; } SEC("uprobe/__pthread_mutex_trylock") int BPF_KPROBE(__pthread_mutex_trylock, void *__mutex) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); u64 pid_tgid = bpf_get_current_pid_tgid(); u64 now = bpf_ktime_get_ns(); struct trylock_info info = { @@ -218,55 +205,32 @@ int BPF_KPROBE(__pthread_mutex_trylock, void *__mutex) { SEC("uretprobe/__pthread_mutex_trylock") int BPF_KRETPROBE(ret_pthread_mutex_trylock, int ret) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); u64 pid_tgid = bpf_get_current_pid_tgid(); struct trylock_info *try_info = bpf_map_lookup_elem(&trylock_map, &pid_tgid); - if (!try_info) { - return 0; - } - void *__mutex = try_info->__mutex; - u64 now = bpf_ktime_get_ns(); + if (!try_info) return 0; + if (ret == 0) { - struct mutex_info *info = bpf_map_lookup_elem(&umutex_info_map, &__mutex); - if (info) { - if (info->acquire_time > 0) { - // 如果 acquire_time 已经被设置,说明锁被争用 - info->contended_total += (now - info->acquire_time); - info->count += 1; - } - info->acquire_time = now; - info->last_owner = pid_tgid >> 32; - bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); - } else { - // 初始化 mutex_info - struct mutex_info new_info = { - .locked_total = 0, - .locked_max = 0, - .contended_total = 0, - .count = 0, - .last_owner = pid_tgid >> 32, - .acquire_time = now, - .ptr = (u64)__mutex, - }; - bpf_get_current_comm(&new_info.last_name, sizeof(new_info.last_name)); - bpf_map_update_elem(&umutex_info_map, &__mutex, &new_info, BPF_ANY); - } + handle_user_mutex_lock(try_info->__mutex, try_info->start_time, pid_tgid >> 32); } bpf_map_delete_elem(&trylock_map, &pid_tgid); return 0; } SEC("uprobe/pthread_mutex_unlock") -int BPF_KPROBE(pthread_mutex_unlock, void *__mutex){ +int BPF_KPROBE(pthread_mutex_unlock, void *__mutex) { + struct mu_ctrl *mu_ctrl = get_mu_ctrl(); u64 now = bpf_ktime_get_ns(); + pid_t pid = bpf_get_current_pid_tgid() >> 32; struct mutex_info *info = bpf_map_lookup_elem(&umutex_info_map, &__mutex); if (info) { - u64 locked_time = now - info->acquire_time; - info->locked_total += locked_time; - if (locked_time > info->locked_max) { - info->locked_max = locked_time; + u64 held_time = now - info->acquire_time; + info->locked_total += held_time; + if (held_time > info->locked_max) { + info->locked_max = held_time; } - info->acquire_time = 0; + info->last_owner = pid; + bpf_get_current_comm(&info->last_name, sizeof(info->last_name)); } return 0; } - diff --git a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c index 59bb2dcb6..806fb55e2 100644 --- a/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c +++ b/eBPF_Supermarket/CPU_Subsystem/cpu_watcher/test/test_cpuwatcher.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,8 @@ static struct env { bool mq_delay_test; bool preempt_test; bool schedule_test; - bool mutrace_test; + bool mutrace_test1; + bool mutrace_test2; } env = { .sar_test = false, .cs_delay_test = false, @@ -27,7 +29,8 @@ static struct env { .mq_delay_test = false, .preempt_test = false, .schedule_test = false, - .mutrace_test = false, + .mutrace_test1 = false, + .mutrace_test2 = false, }; const char argp_program_doc[] ="To test cpu_watcher.\n"; @@ -39,7 +42,8 @@ static const struct argp_option opts[] = { { "mq_delay", 'm', NULL, 0, "To test mq_delay", 0 }, { "preempt_delay", 'p', NULL, 0, "To test preempt_delay", 0 }, { "schedule_delay", 'd', NULL, 0, "To test schedule_delay", 0 }, - { "mu_trace", 'x', NULL, 0, "To test mutrace", 0 }, + { "mu_trace_kernel", 'x', NULL, 0, "To test kernel mutrace", 0 }, + { "mu_trace_user", 'u', NULL, 0, "To test user mutrace", 0 }, { "all", 'a', NULL, 0, "To test all", 0 }, { NULL, 'h', NULL, OPTION_HIDDEN, "show the full help", 0 }, {}, @@ -76,7 +80,10 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) env.schedule_test = true; break; case 'x': - env.mutrace_test = true; + env.mutrace_test1 = true; + break; + case 'u': + env.mutrace_test2 = true; break; case 'h': argp_state_help(state, stderr, ARGP_HELP_STD_HELP); @@ -128,6 +135,43 @@ void input_pid() { printf("\n"); } +void *mutex_test_thread(void *arg) { + pthread_mutex_t *mutex = (pthread_mutex_t *)arg; + uintptr_t mutex_addr = (uintptr_t)mutex; // 获取互斥锁的地址 + + for (int i = 0; i < 10; i++) { + pthread_mutex_lock(mutex); + printf("Thread %ld (mutex address: %lu) acquired the mutex\n", + pthread_self(), (unsigned long)mutex_addr); + usleep(rand() % 1000); + pthread_mutex_unlock(mutex); + printf("Thread %ld (mutex address: %lu) released the mutex\n", + pthread_self(), (unsigned long)mutex_addr); + usleep(rand() % 1000); + } + + return NULL; +} + +void start_mutex_test(int num_threads) { + pthread_mutex_t mutex; + pthread_t *threads = malloc(num_threads * sizeof(pthread_t)); + + pthread_mutex_init(&mutex, NULL); + + for (int i = 0; i < num_threads; i++) { + pthread_create(&threads[i], NULL, mutex_test_thread, &mutex); + } + + for (int i = 0; i < num_threads; i++) { + pthread_join(threads[i], NULL); + } + + pthread_mutex_destroy(&mutex); + free(threads); +} + + int main(int argc, char **argv){ int err; static const struct argp argp = { @@ -197,9 +241,9 @@ int main(int argc, char **argv){ printf("\n"); } - if(env.mutrace_test){ - printf("MUTRACE_TEST----------------------------------------------\n"); - //MUTRACE功能测试逻辑:系统上执行混合压力测试,包括4个顺序读写硬盘线程、4个IO操作线程,持续15秒,观察加压前后的变化。 + if(env.mutrace_test1){ + printf("MUTRACE_KERNEL_TEST----------------------------------------------\n"); + //内核态互斥锁功能测试逻辑:系统上执行混合压力测试,包括4个顺序读写硬盘线程、4个IO操作线程,持续15秒,观察加压前后的变化。 char *argvv[] = { "/usr/bin/stress-ng", "--hdd", "4", "--hdd-opts", "wr-seq,rd-seq", "--io", "4", "--timeout", "15s", "--metrics-brief", NULL }; char *envp[] = { "PATH=/bin", NULL }; printf("MUTRACE功能测试逻辑:系统上执行混合压力测试,包括4个顺序读写硬盘线程、4个IO操作线程和4个UDP网络操作线程,持续15秒,观察加压前后的变化\n"); @@ -209,5 +253,14 @@ int main(int argc, char **argv){ printf("\n"); } + + if(env.mutrace_test2){ + printf("MUTRACE_USER_TEST----------------------------------------------\n"); + printf("测试场景: 创建多个线程,每个线程反复加锁和解锁同一个互斥锁,观察互斥锁的争用情况\n"); + start_mutex_test(10); // 创建10个线程进行互斥锁测试 + printf("测试结束\n"); + printf("\n"); + + } return 0; }