24.01.27 최초 작성
page fault가 발생하는지 알아보기handle_mm_fault()를 감지해 프로세스 이름, 주소, 플래그를 출력하는 코드from bcc import BPF
prog = """
#include <linux/sched.h>
#include <linux/mm.h>
BPF_HASH(start, u32);
BPF_PERF_OUTPUT(events);
struct data_t {
u32 pid;
u32 cpu;
char comm[16];
unsigned long address;
unsigned int flags;
}
int kprobe__handle_mm_fault(struct pt_regs *ctx, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, unsigned int flags) {
u32 pid = bpf_get_current_pid_tgid();
u32 cpu = bpf_get_smp_processor_id();
u64 ts = bpf_ktime_get_ns();
struct data_t data = {};
bpf_get_current_comm(&data.comm, sizeof(data.comm));
for (int i = 0; i < sizeof(data.comm); i++) {
if (data.comm[i] == 'p' && data.comm[i + 1] == 'y' && data.comm[i + 2] == 't' && data.comm[i + 3] == 'h' && data.comm[i + 4] == 'o' && data.comm[i + 5] == 'n') {
data.pid = pid;
data.cpu = cpu;
data.address = address;
data.flags = flags;
events.perf_submit(ctx, &data, sizeof(data));
start.update(&pid, &ts);
break;
}
}
return 0;
}
"""
b = BPF(text=prog)
def print_event(cpu, data, size):
event = b["events"].event(data)
print("PID: %d, CPU: %d, Comm: %s, Address: %lx, Flags: %s" % (event.pid, event.cpu, event.comm, event.address, format_flags(event.flags)))
def format_flags(flags):
flags_str = []
if flags & 0x01: flags_str.append("FAULT_FLAG_ALLOW_RETRY")
if flags & 0x02: flags_str.append("FAULT_FLAG_RETRY_NOWAIT")
if flags & 0x04: flags_str.append("FAULT_FLAG_KILLABLE")
if flags & 0x08: flags_str.append("FAULT_FLAG_USER")
if flags & 0x10: flags_str.append("FAULT_FLAG_REMOTE")
if flags & 0x20: flags_str.append("FAULT_FLAG_TRIED")
if flags & 0x40: flags_str.append("FAULT_FLAG_ALLOW_ASYNC")
if flags & 0x80: flags_str.append("FAULT_FLAG_MKWRITE")
if flags & 0x100: flags_str.append("FAULT_FLAG_NO_KILL")
return ", ".join(flags_str)
b["events"].open_perf_buffer(print_event)
print("Tracing handle_mm_fault for python processes... Ctrl-C to end.")
while True:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
exit()
import time
MB = 1 * int(1e6)
blocks = 100
memory_blocks = []
for _ in range(blocks):
memory_blocks.append(bytearray(MB))
print("1GB of memory has been allocated.")
handle_pte_fault()에서 인자로 받은 struct vm_fault의 pgd오프셋 필드를 확인handle_pte_fault()가 없다고 오류 발생handle_pte_fault()를static 지워 다른 소스코드에서 참조할 수 있도록 설정EXPORT_SYMBOL_GPL(handle_pte_fault);입력해 다른 모듈에서도 참조할 수 있도록 설정 from bcc import BPF
bpf_text = """
#include <linux/sched.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
struct data_t {
u32 pid;
u64 cpu;
u64 addr;
u64 pgoff;
char comm[TASK_COMM_LEN];
};
BPF_PERF_OUTPUT(events);
int kprobe__handle_pte_fault(struct pt_regs *ctx, struct vm_fault *vmf) {
struct data_t data = {};
u64 pid_tgid = bpf_get_current_pid_tgid();
data.pid = pid_tgid >> 32;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
if (data.comm[0] == 'p' && data.comm[1] == 'y' && data.comm[2] == 't' && data.comm[3] == 'h' && data.comm[4] == 'o' && data.comm[5] == 'n') {
data.cpu = bpf_get_smp_processor_id();
data.addr = vmf->address;
data.pgoff = vmf->pgoff;
events.perf_submit(ctx, &data, sizeof(data));
}
return 0;
}
"""
bpf = BPF(text=bpf_text)
bpf.attach_kprobe(event="handle_pte_fault", fn_name="kprobe__handle_pte_fault")
def print_event(cpu, data, size):
event = b["events"].event(data)
print(f"CPU: {event.cpu}, PID: {event.pid}, Comm: {event.comm}, Address: {hex(event.addr)}, Pgoff: {event.pgoff}")
b["events"].open_perf_buffer(print_event)
while True:
try:
bpf.perf_buffer_poll()
except KeyboardInterrupt:
exit()