Skip to content

Commit

Permalink
移除了一个子仓库,删除了一些不使用的文件
Browse files Browse the repository at this point in the history
  • Loading branch information
GorilaMond committed Aug 9, 2023
1 parent 70dbb39 commit 2c5d063
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 58 deletions.
1 change: 0 additions & 1 deletion eBPF_Supermarket/Stack_Analyser/FlameGraph
Submodule FlameGraph deleted from d9fcc2
10 changes: 9 additions & 1 deletion eBPF_Supermarket/Stack_Analyser/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# libbpf/stack_analyzer (incomplete)
# 依赖

火焰图绘制程序 `FlameGraph/flamegraph.pl`,需要将该程序放入环境变量PATH中,一种方法:

```shell
sudo cp FlameGraph/flamegraph.pl /usr/bin/
```

# libbpf/stack_analyzer

用于对调用栈进行计数,libbpf版本

Expand Down
169 changes: 114 additions & 55 deletions eBPF_Supermarket/Stack_Analyser/bcc/load_monitor.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
#!/bin/python3
from inspect import stack
import time
from bcc import BPF
import argparse
from signal import signal, SIG_IGN

# arguments
examples = """examples:
./load_monitor.py # monitor system load until Ctrl-C
./load_monitor.py -t 5 # monitor for 5 seconds only
"""


def positive_int(val):
try:
ival = int(val)
Expand All @@ -20,6 +17,7 @@ def positive_int(val):
raise argparse.ArgumentTypeError("must be positive")
return ival


parser = argparse.ArgumentParser(
description="Summarize on-CPU time by stack trace",
formatter_class=argparse.RawDescriptionHelpFormatter,
Expand All @@ -31,78 +29,139 @@ def positive_int(val):
code = """
#include <linux/sched.h>
#define LOAD_LIMIT 4
#define MAX_ENTITY 10240
#define avenrun AVENRUN_ADDRULL
typedef struct {
raw_spinlock_t lock;
unsigned int nr_running;
} Rq;
typedef struct {
u64 stackid;
int pid, usid, ksid, o;
char comm[TASK_COMM_LEN];
} TaskData;
BPF_STACK_TRACE(stack_trace, 128);
BPF_HASH(stack_count, u32, u32, 128);
BPF_HASH(pid_data, u32, TaskData);
void kprobe__update_rq_clock(struct pt_regs *ctx) {
Rq rq;
TaskData td;
u32 pid;
int stackid;
bpf_probe_read_kernel(&rq, sizeof(Rq), (void*)PT_REGS_PARM1(ctx));
if(rq.nr_running > LOAD_LIMIT) {
stackid = stack_trace.get_stackid(ctx, 0);
if(stackid < 0) return;
td.stackid = stackid;
stack_count.increment(td.stackid);
BPF_STACK_TRACE(stack_trace, MAX_ENTITY);
BPF_HASH(stack_count, TaskData, u32, MAX_ENTITY);
BPF_ARRAY(load, unsigned long, 1);
void do_stack(struct pt_regs *ctx) {
unsigned long avg_load;
bpf_probe_read_kernel(&avg_load, sizeof(avg_load), (void *)avenrun);
avg_load >>= 11;
int zero = 0;
load.update(&zero, &avg_load);
if(avg_load >= LOAD_LIMIT) {
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
TaskData td = {
.pid = bpf_get_current_pid_tgid() >> 32,
.ksid = stack_trace.get_stackid(ctx, BPF_F_FAST_STACK_CMP),
.usid = stack_trace.get_stackid(ctx, BPF_F_USER_STACK | BPF_F_FAST_STACK_CMP),
.o = 0,
};
bpf_get_current_comm(td.comm, TASK_COMM_LEN);
pid = bpf_get_current_pid_tgid();
pid_data.update(&pid, &td);
stack_count.increment(td);
}
}
"""

from subprocess import Popen, PIPE
p = Popen("sudo cat /proc/kallsyms | grep ' avenrun'", shell=True, stdout=PIPE)
evanrun_addr = "0x" + p.stdout.read().split()[0].decode()
print("get addr of evanrun: ", evanrun_addr)
code = code.replace("AVENRUN_ADDR", evanrun_addr)

# segfault
# import ctypes
# addr = int(evanrun_addr, base=16)
# load = ctypes.cast(addr, ctypes.POINTER(ctypes.c_ulong)).contents

from bcc import BPF, PerfType, PerfSWConfig
bpf = BPF(text=code)
stack_trace = bpf["stack_trace"]
stack_count = bpf["stack_count"]
pid_data = bpf["pid_data"]
bpf.attach_perf_event(ev_type=PerfType.SOFTWARE,
ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_stack",
sample_period=0, sample_freq=99)

load = bpf["load"]


def sig_handle(*_):
bpf.detach_perf_event(ev_type=PerfType.SOFTWARE,
ev_config=PerfSWConfig.CPU_CLOCK)
max_deep = 0
for (k, _) in stackcount:
if(k.usid >= 0):
deep = 0
for _ in bpf["stack_trace"].walk(k.usid):
deep += 1
if max_deep < deep:
max_deep = deep
with open("stack.bpf", "w") as file:
for k, v in stackcount.items():
for (k, v) in stackcount:
file.write("@[\n")
for i in stack_trace.walk(k):
file.write(bpf.ksym(i).decode()+"\n")
file.write("]: %d\n" % v)
if(k.ksid >= 0):
for i in bpf["stack_trace"].walk(k.ksid):
file.write(bpf.ksym(i).decode()+"\n")
else:
file.write("no kernel stack\n")
file.write("-"*16+'\n')
deep = 0
if(k.usid >= 0):
for i in bpf["stack_trace"].walk(k.usid):
file.write(bpf.sym(i, k.pid).decode()+"\n")
deep += 1
else:
file.write("no user stack\n")
deep = 1
file.write('.\n'*(max_deep - deep))
file.write('%s:%d\n'%(k.comm, k.pid))
file.write("]: %d\n\n" % v)
import os
os.system("FlameGraph/stackcollapse-bpftrace.pl stack.bpf | FlameGraph/flamegraph.pl > stack.svg")
os.system(
"FlameGraph/stackcollapse-bpftrace.pl stack.bpf | FlameGraph/flamegraph.pl > stack.svg")
print("\b\bQuit...\n")
exit()


class TaskData:
def __init__(self, a) -> None:
self.pid = a.pid
self.ksid = a.ksid
self.usid = a.usid
self.comm = a.comm.decode()


from signal import signal, SIG_IGN
import time
signal(2, sig_handle)
signal(1, sig_handle)
for _ in range(args.time//5):
time.sleep(5)
stackid = [(v.stackid, k.value) for k, v in pid_data.items()]
stackcount = {k.value: v.value for k, v in stack_count.items()}
piddata = {k.value: v.comm.decode() for k, v in pid_data.items()}
stacktrace = {k: stack_trace.walk(k) for k in stackcount.keys()}
stackid.sort()
timestr = time.strftime("%H:%M:%S")
if (l := len(stackid)) > 0:
for i in range(0, l):
if i == 0 or stackid[i][0] != stackid[i-1][0]:
id = stackid[i][0]
print("_"*60)
for j in stacktrace[id]:
print("%#08x %s" % (j, bpf.ksym(j).decode()))
print("%-10s %-6s %-6s %-16s" %
("stackid", "count", "pid", "comm"))
print("%-10d %-6d" % (id, stackcount[id]))
id = stackid[i][1]
print("%-10s %-6s %-6d %-16s" %
("", "", id, piddata[id]))
start = time.time()
for _ in range(args.time):
load_5 = int(load[0].value)
# print(load_5, end=' ')
if (load_5 < 4):
time.sleep(0.01)
elif (time.time()-start > 10):
time.sleep(1)
stackcount = {TaskData(k): v.value for k,
v in bpf["stack_count"].items()}
stackcount = sorted(stackcount.items(),
key=lambda d: d[1], reverse=False)
timestr = time.strftime("%H:%M:%S")
for d in stackcount:
print("_"*32)
print("%-5d:%16s %d" % (d[0].pid, d[0].comm, d[1]))
if d[0].ksid >= 0:
for j in bpf["stack_trace"].walk(d[0].ksid):
print("\t%#08x %s" % (j, bpf.ksym(j).decode()))
else:
print("\tno kernel stack")
print("\t"+"-"*16)
if d[0].usid >= 0:
for j in bpf["stack_trace"].walk(d[0].usid):
print("\t%#08x %s" % (j, bpf.sym(j, d[0].pid).decode()))
else:
print("\tno user stack")
print("_"*26 + timestr + "_"*26)
print()
start = time.time()
else:
time.sleep(10)

signal(2, SIG_IGN)
signal(1, SIG_IGN)
sig_handle()

8 changes: 7 additions & 1 deletion eBPF_Supermarket/Stack_Analyser/项目开发记录.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,10 @@
- 添加了ctrl-c信号处理功能
- 添加了mmap和munmap采集功能
- 添加io write采集功能,跟踪点为`vfs_write`,为其他文件系统写入文件操作的必经之路
- 需要考虑记录io次数还是io数据量
- 需要考虑记录io次数还是io数据量
2023.8.7
- 找全内存相关跟踪点
- 加入排序功能
- 将vfs read跟踪点加入io模块

0 comments on commit 2c5d063

Please sign in to comment.