Skip to content

Commit

Permalink
Stack_Analyzer: fix bug and arrange code (linuxkerneltravel#634)
Browse files Browse the repository at this point in the history
* format and comment

Signed-off-by: LiuLingze <[email protected]>

* arrange code

Signed-off-by: LiuLingze <[email protected]>

* fix no precision bug of io enhancement

Signed-off-by: LiuLingze <[email protected]>

* fix segment fault

Signed-off-by: LiuLingze <[email protected]>

* fix bug for changed api

Signed-off-by: LiuLingze <[email protected]>

* A new version more simple for C/S architechture

Separate the target run logic from the stack collection class.
Take advantage of the C++ feature definitions in the eBPF program header
file to simplify the code with macro.
Add a sub-function queue to control the use of multiple sub-functions at
the same time.
Renaming symbols makes the code easier to understand.
Removed the code that implemented the visualization capability.

Signed-off-by: LiuLingze <[email protected]>

* update action

Signed-off-by: LiuLingze <[email protected]>

* update macro

Signed-off-by: LiuLingze <[email protected]>

* add filter self ability and filter kthread ability

Signed-off-by: LiuLingze <[email protected]>

* update using of api

Signed-off-by: LiuLingze <[email protected]>

* fix segment fault

Signed-off-by: LiuLingze <[email protected]>

---------

Signed-off-by: LiuLingze <[email protected]>
  • Loading branch information
GorilaMond authored Dec 27, 2023
1 parent b4a1f19 commit ae4d827
Show file tree
Hide file tree
Showing 10 changed files with 875 additions and 1,197 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/ebpf_stack_analyser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ jobs:
run: |
cd eBPF_Supermarket/Stack_Analyser/libbpf
make
sudo ./stack_analyzer on-cpu 10
sudo ./stack_analyzer mem 10 -l
sudo ./stack_analyzer on-cpu off-cpu mem io ra -t 5
bcc-project-build-and-test:
Expand Down
74 changes: 30 additions & 44 deletions eBPF_Supermarket/Stack_Analyser/libbpf/bpf/io_count.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,72 +21,63 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#include "stack_analyzer.h"
#include "sa_ebpf.h"
#include "task.h"


//定义的哈希表以及堆栈跟踪对象
// BPF_HASH(psid_count, psid, u64);
BPF_STACK_TRACE(stack_trace); //记录了相应的函数内核栈以及用户栈的使用次数
BPF_HASH(pid_tgid, u32, u32);
BPF_HASH(pid_comm, u32, comm);
BPF_HASH(psid_count, psid, io_tuple);
DeclareCommonMaps(io_tuple);
DeclareCommonVar();
int apid = 0;

const char LICENSE[] SEC("license") = "GPL";

int apid = 0;
bool u = false, k = false, cot = false;
__u64 min = 0, max = 0;

static int do_stack(struct trace_event_raw_sys_enter *ctx)
{
// u64 td = bpf_get_current_pid_tgid();
// u32 pid = td >> 32;

struct task_struct* curr = (struct task_struct*)bpf_get_current_task();//利用bpf_get_current_task()获得当前的进程tsk
u32 pid = get_task_ns_pid(curr); //利用帮助函数获得当前进程的pid

if ((apid >= 0 && pid != apid) || !pid)
struct task_struct* curr = (struct task_struct*)bpf_get_current_task(); //利用bpf_get_current_task()获得当前的进程tsk
ignoreKthread(curr);
u32 pid = get_task_ns_pid(curr); //利用帮助函数获得当前进程的pid
if ((apid >= 0 && pid != apid) || !pid || pid == self_pid)
return 0;

u64 len = (u64)BPF_CORE_READ(ctx, args[3]); //从当前ctx中读取64位的值,并保存在len中,
u64 len = BPF_CORE_READ(ctx, args[2]); //从当前ctx中读取64位的值,并保存在len中
bpf_printk("%llu", len);
if (len <= min || len > max)
return 0;

// u32 tgid = td;
u32 tgid = get_task_ns_tgid(curr); //利用帮助函数获取进程的tgid
bpf_map_update_elem(&pid_tgid, &pid, &tgid, BPF_ANY); //将pid_tgid表中的pid选项更新为tgid,若没有该表项,则创建
comm *p = bpf_map_lookup_elem(&pid_comm, &pid); //p指向pid_comm哈希表中的pid表项对应的value
if (!p) //如果p不为空,获取当前进程名保存至name中,如果pid_comm当中不存在pid name项,则更新
u32 tgid = get_task_ns_tgid(curr); //利用帮助函数获取进程的tgid
bpf_map_update_elem(&pid_tgid, &pid, &tgid, BPF_ANY); //将pid_tgid表中的pid选项更新为tgid,若没有该表项,则创建
comm *p = bpf_map_lookup_elem(&pid_comm, &pid); //p指向pid_comm哈希表中的pid表项对应的value
if (!p) //如果p不为空,获取当前进程名保存至name中,如果pid_comm当中不存在pid name项,则更新
{
comm name;
bpf_get_current_comm(&name, COMM_LEN);
bpf_map_update_elem(&pid_comm, &pid, &name, BPF_NOEXIST);
}
psid apsid = {
.pid = pid,
.usid = u ? USER_STACK : -1, //u存在,则USER_STACK
.ksid = k ? KERNEL_STACK : -1, //K存在,则KERNEL_STACK
.usid = u ? USER_STACK : -1, //u存在,则USER_STACK
.ksid = k ? KERNEL_STACK : -1, //K存在,则KERNEL_STACK
};

// record time delta
io_tuple *d = bpf_map_lookup_elem(&psid_count, &apsid); //count指向psid_count表当中的apsid表项,即size
io_tuple *d = bpf_map_lookup_elem(&psid_count, &apsid); //count指向psid_count表当中的apsid表项,即size

if(!d){
io_tuple it = {.count = 1, .size = len};
bpf_map_update_elem(&psid_count, &apsid, &it, BPF_NOEXIST);
return 0;
}
if(!d) {
io_tuple nd = {.count = 1, .size = len};
bpf_map_update_elem(&psid_count, &apsid, &nd, BPF_NOEXIST);
} else {
d->count++;
d->size += len;

return 0;
}
return 0;
}

#define io_sec_tp(name) \
SEC("tracepoint/syscalls/sys_enter_" #name) \
SEC("tp/syscalls/sys_enter_" #name) \
int prog_t_##name(struct trace_event_raw_sys_enter *ctx) { return do_stack(ctx); }

io_sec_tp(write);
io_sec_tp(read);
io_sec_tp(recvfrom);
io_sec_tp(sendto);

// tracepoint:syscalls:sys_exit_select
// tracepoint:syscalls:sys_enter_poll
// tracepoint:syscalls:sys_enter_epoll_wait
Expand All @@ -99,9 +90,4 @@ static int do_stack(struct trace_event_raw_sys_enter *ctx)
// tracepoint/syscalls/sys_enter_sendto 发送数据

//2. 执行程序 int prog_t_##name(struct trace_event_raw_sys_enter *ctx) { return do_stack(ctx); }
//最终调用上面的do_stack函数

io_sec_tp(write);
io_sec_tp(read);
io_sec_tp(recvfrom);
io_sec_tp(sendto);
//最终调用上面的do_stack函数
49 changes: 25 additions & 24 deletions eBPF_Supermarket/Stack_Analyser/libbpf/bpf/mem_count.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,41 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#include "stack_analyzer.h"
#include "sa_ebpf.h"
#include "task.h"

//定义的哈希表以及堆栈跟踪对象
BPF_HASH(psid_count, psid, u64); //记录对应进程申请的总内存空间大小
BPF_STACK_TRACE(stack_trace);
BPF_HASH(pid_tgid, u32, u32);
BPF_HASH(pid_comm, u32, comm);
DeclareCommonMaps(u64);
DeclareCommonVar();

/// @brief 内存信息的键,唯一标识一块被分配的内存
/// @note o为可初始化的填充对齐成员,贴合bpf verifier要求
typedef struct {
__u64 addr;
__u32 pid, o;
} piddr;

/// @brief 内存分配信息,可溯源的一次内存分配
/// @note o为可初始化的填充对齐成员,贴合bpf verifier要求
typedef struct {
__u64 size;
__u32 usid, o;
} mem_info;

BPF_HASH(pid_size, u32, u64); //记录了对应进程使用malloc,calloc等函数申请内存的大小
BPF_HASH(piddr_meminfo, piddr, mem_info); //记录了每次申请的内存空间的起始地址等信息

const char LICENSE[] SEC("license") = "GPL";

bool u = false, k = false;
int apid = 0;
__u64 min = 0, max = 0;

int gen_alloc_enter(size_t size)
{
// bpf_printk("malloc_enter");
// record data
if (size <= min || size > max)
return 0;
// u64 pt = bpf_get_current_pid_tgid();
// u32 pid = pt >> 32;
// u32 tgid = pt;
struct task_struct *curr = (struct task_struct *)bpf_get_current_task(); //利用bpf_get_current_task()获得当前的进程tsk
ignoreKthread(curr);
u32 pid = get_task_ns_pid(curr); // also kernel pid, but attached ns pid on kernel pid, invaild!
if(pid == self_pid)
return 0;
u32 tgid = get_task_ns_tgid(curr); //利用帮助函数获得当前进程的tgid
bpf_map_update_elem(&pid_tgid, &pid, &tgid, BPF_ANY); //更新pid_tgid哈希表中的pid项目为tgid,如果该项不存在,则创建该表项
comm *p = bpf_map_lookup_elem(&pid_comm, &pid); //p指向pid_comm哈希表中的pid表项对应的value
Expand All @@ -62,7 +68,7 @@ int gen_alloc_enter(size_t size)
}

// record size
//size为挂载点传递的值
//size为挂载点传递的值
return bpf_map_update_elem(&pid_size, &pid, &size, BPF_ANY); //更新pid_size哈希表的pid项对应的值为size,如果不存在该项,则创建
}

Expand Down Expand Up @@ -93,10 +99,6 @@ int gen_alloc_exit(struct pt_regs *ctx) //
void *addr = (void *)PT_REGS_RC(ctx); //从 struct pt_regs ctx 中提取函数的返回值
if (!addr)
return 0;
// bpf_printk("malloc_exit");
// get size
// u32 pid = bpf_get_current_pid_tgid() >> 32;
// struct task_struct* curr = ;
u32 pid = get_task_ns_pid((struct task_struct*)bpf_get_current_task());//通过bpf_get_current_task函数得到当前进程的tsk。再通过get_task_ns_pid得到该进程的pid
u64 *size = bpf_map_lookup_elem(&pid_size, &pid); //size指向pid_size哈希表pid对应的值
if (!size) //size不存在
Expand All @@ -108,17 +110,16 @@ int gen_alloc_exit(struct pt_regs *ctx) //
.usid = u ? USER_STACK : -1,
.ksid = k ? KERNEL_STACK: -1,
};
u64 *count = bpf_map_lookup_elem(&psid_count, &apsid);//count指向psid_count表apsid对应的值
if (!count) //如果count为空,若表的apsid表项不存在,则更新psid_count表的apsid为size
u64 *count = bpf_map_lookup_elem(&psid_count, &apsid); //count指向psid_count表apsid对应的值

if (!count) //如果count为空,若表的apsid表项不存在,则更新psid_count表的apsid为size
bpf_map_update_elem(&psid_count, &apsid, size, BPF_NOEXIST);
else
(*count) += *size; //psid_count表apsid对应的值+=pid_size哈希表pid对应的值


// record pid_addr-info
piddr a = {
.addr = (u64)addr, //函数的返回值
.addr = (u64)addr, //函数的返回值
.pid = pid,
.o = 0,
};
Expand Down
24 changes: 10 additions & 14 deletions eBPF_Supermarket/Stack_Analyser/libbpf/bpf/off_cpu_count.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,31 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#include "stack_analyzer.h"
#include "sa_ebpf.h"
#include "task.h"

BPF_HASH(psid_count, psid, u32); //记录了进程的运行总时间
BPF_HASH(start, u32, u64); //记录进程运行的起始时间
BPF_STACK_TRACE(stack_trace);
BPF_HASH(pid_tgid, u32, u32);
BPF_HASH(pid_comm, u32, comm);

const char LICENSE[] SEC("license") = "GPL";
DeclareCommonMaps(u32);
DeclareCommonVar();

int apid = 0;
bool u = false, k = false;
__u64 min = 0, max = 0;
BPF_HASH(start, u32, u64); //记录进程运行的起始时间

const char LICENSE[] SEC("license") = "GPL";

SEC("kprobe/finish_task_switch.isra.0") //动态挂载点finish_task_switch.isra.0
int BPF_KPROBE(do_stack, struct task_struct *curr)
{
// u32 pid = BPF_CORE_READ(curr, pid);
u32 pid = get_task_ns_pid(curr); //利用帮助函数获取当前进程tsk的pid

if ((apid >= 0 && pid == apid) || (apid < 0 && pid))
ignoreKthread(curr);
if ((apid >= 0 && pid == apid) || (apid < 0 && pid && pid != self_pid))
{
// record next start time
// record curr block time
u64 ts = bpf_ktime_get_ns(); //ts=当前的时间戳(ns)
bpf_map_update_elem(&start, &pid, &ts, BPF_NOEXIST); //如果start表中不存在pid对应的时间,则就创建pid-->ts
}

// calculate time delta
// calculate time delta, next ready to run
struct task_struct *next = (struct task_struct *)bpf_get_current_task();//next指向当前的结构体
// pid = BPF_CORE_READ(next, pid);
pid = get_task_ns_pid(next); //利用帮助函数获取next指向的tsk的pid
Expand Down
21 changes: 8 additions & 13 deletions eBPF_Supermarket/Stack_Analyser/libbpf/bpf/on_cpu_count.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,15 @@
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#include "stack_analyzer.h"
#include "sa_ebpf.h"
#include "task.h"

const char LICENSE[] SEC("license") = "GPL";

BPF_STACK_TRACE(stack_trace);
BPF_HASH(pid_tgid, u32, u32);
BPF_HASH(psid_count, psid, u32); //记录了内核栈以及用户栈的使用次数
BPF_HASH(pid_comm, u32, comm);

bool u = false, k = false;
__u64 min = 0, max = 0;
DeclareCommonMaps(u32);
DeclareCommonVar();
unsigned long *load_a = NULL;


SEC("perf_event") //挂载点为perf_event
int do_stack(void *ctx)
{
Expand All @@ -44,13 +39,13 @@ int do_stack(void *ctx)
bpf_printk("%lu %lu", load, min); //输出load 以及min
if (load < min || load > max)
return 0;

// record data
struct task_struct *curr = (void *)bpf_get_current_task(); //curr指向当前进程的tsk
u32 pid = BPF_CORE_READ(curr, pid); //pid保存当前进程的pid
if (!pid)
ignoreKthread(curr); // 忽略内核线程
u32 pid = get_task_ns_pid(curr); //pid保存当前进程的pid,是cgroup pid 对应的level 0 pid
if (!pid || pid == self_pid)
return 0;
u32 tgid = BPF_CORE_READ(curr, tgid); //tgid保存当前进程的tgid
u32 tgid = get_task_ns_tgid(curr); //tgid保存当前进程的tgid
bpf_map_update_elem(&pid_tgid, &pid, &tgid, BPF_ANY); //更新pid_tgid表中的pid表项
comm *p = bpf_map_lookup_elem(&pid_comm, &pid); //p指向pid_comm中的Pid对应的值
if (!p)
Expand Down
Loading

0 comments on commit ae4d827

Please sign in to comment.