Skip to content

Commit

Permalink
Merge pull request linuxkerneltravel#633 from nanshuaibo/develop
Browse files Browse the repository at this point in the history
kvm_watcher项目:添加提取kvm page fault指标功能,完善代码
  • Loading branch information
chenamy2017 authored Dec 27, 2023
2 parents 03bdace + 53ff52e commit acadb5f
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 38 deletions.
20 changes: 15 additions & 5 deletions .github/workflows/kvm_watcher.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,24 @@ jobs:
sudo apt install libbpf-dev
sudo apt install linux-tools-$(uname -r)
sudo apt install linux-cloud-tools-$(uname -r)
sudo modprobe kvm
sudo apt-get update && sudo apt-get install -y qemu-kvm
- name: Download Cirros image
run: |
wget http://download.cirros-cloud.net/0.5.1/cirros-0.5.1-x86_64-disk.img
- name: Load KVM module
run: |
sudo modprobe kvm && sudo modprobe kvm-intel
- name: Run QEMU to start VM
run: |
sudo qemu-system-x86_64 -enable-kvm -cpu host -m 2048 -drive file=cirros-0.5.1-x86_64-disk.img,format=qcow2 -boot c -nographic &
- name: Run kvm_watcher
run: |
cd eBPF_Supermarket/kvm_watcher/
make
sudo ./kvm_watcher -w -t 5
sudo ./kvm_watcher -e -t 5 -s
sudo ./kvm_watcher -n -t 5
sudo ./kvm_watcher -d -t 5
sudo ./kvm_watcher -w -t 10
sudo ./kvm_watcher -e -t 10 -s
sudo ./kvm_watcher -n -t 10
sudo ./kvm_watcher -d -t 10
sudo ./kvm_watcher -f -t 10
make clean
2 changes: 1 addition & 1 deletion eBPF_Supermarket/kvm_watcher/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ all: $(APP)
.PHONY: $(APP)
$(APP):
ifeq ($(wildcard ./include/vmlinux.h),)
bpftool btf dump file /sys/kernel/btf/vmlinux format c > ./include/vmlinux.h
bpftool btf dump file /sys/kernel/btf/kvm format c > ./include/vmlinux.h
endif
clang -g -O2 -target bpf -D__TARGET_ARCH_$(ARCH) -I/usr/include/x86_64-linux-gnu -I. -c [email protected] -o [email protected]
bpftool gen skeleton [email protected] > [email protected]
Expand Down
12 changes: 3 additions & 9 deletions eBPF_Supermarket/kvm_watcher/include/kvm_exits.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,15 @@ static int trace_kvm_entry(void *rb) {
bpf_map_delete_elem(&times, &tid);
reason = reas->reason;
count = reas->count;
e = bpf_ringbuf_reserve(rb, sizeof(*e), 0);
if (!e) {
return 0;
}
RESERVE_RINGBUF_ENTRY(rb, e);
e->reason_number = reason;
e->process.pid = pid;
e->duration_ns = duration_ns;
bpf_get_current_comm(&e->process.comm, sizeof(e->process.comm));
e->process.tid = tid;
e->total = ++total;
if (count) {
e->count = count;
} else {
e->count = 1;
}
e->count = count;
e->time = reas->time;
bpf_ringbuf_submit(e, 0);
return 0;
} else {
Expand Down
93 changes: 93 additions & 0 deletions eBPF_Supermarket/kvm_watcher/include/kvm_mmu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2023 The LMP Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// author: [email protected]
//
// Kernel space BPF program used for monitoring data for KVM MMU.

#ifndef __KVM_MMU_H
#define __KVM_MMU_H

#include "kvm_watcher.h"
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, u64);
__type(value, u64);
} pf_delay SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, u64);
__type(value, u32);
} pf_count SEC(".maps");

static int trace_page_fault(struct trace_event_raw_kvm_page_fault *ctx,
pid_t vm_pid) {
CHECK_PID(vm_pid) {
u64 ts = bpf_ktime_get_ns();
u64 addr = ctx->fault_address;
bpf_map_update_elem(&pf_delay, &addr, &ts, BPF_ANY);
}
return 0;
}

static int trace_direct_page_fault(struct kvm_vcpu *vcpu,
struct kvm_page_fault *fault, void *rb) {
u64 addr;
bpf_probe_read_kernel(&addr, sizeof(u64), &fault->addr);
u64 *ts;
ts = bpf_map_lookup_elem(&pf_delay, &addr);
if (ts) {
u32 *count;
u32 new_count = 1;
u32 error_code;
u64 hva, pfn;
bpf_probe_read_kernel(&error_code, sizeof(u32), &fault->error_code);
bpf_probe_read_kernel(&hva, sizeof(u64), &fault->hva);
bpf_probe_read_kernel(&pfn, sizeof(u64), &fault->pfn);
short memslot_id = BPF_CORE_READ(fault, slot, id);
u64 delay = bpf_ktime_get_ns() - *ts;
bpf_map_delete_elem(&pf_delay, &addr);
struct page_fault_event *e;
RESERVE_RINGBUF_ENTRY(rb, e);
count = bpf_map_lookup_elem(&pf_count, &addr);
if (count) {
(*count)++;
e->count = *count;
bpf_map_update_elem(&pf_count, &addr, count, BPF_ANY);
} else {
e->count = 1;
bpf_map_update_elem(&pf_count, &addr, &new_count, BPF_ANY);
}
e->delay = delay;
e->addr = addr;
e->error_code = error_code;
e->hva = hva;
e->pfn = pfn;
e->memslot_id = memslot_id;
e->process.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->process.comm, sizeof(e->process.comm));
e->time = *ts;
bpf_ringbuf_submit(e, 0);
}
return 0;
}
#endif /* __KVM_MMU_H */
5 changes: 4 additions & 1 deletion eBPF_Supermarket/kvm_watcher/include/kvm_vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static int trace_kvm_halt_poll_ns(struct halt_poll_ns *ctx, void *rb,
e->grow = ctx->grow;
e->old = ctx->old;
e->new = ctx->new;
e->vcpu_id = ctx->vcpu_id;
bpf_get_current_comm(&e->process.comm, sizeof(e->process.comm));
bpf_ringbuf_submit(e, 0);
}
Expand All @@ -89,8 +90,10 @@ static int trace_mark_page_dirty_in_slot(struct kvm *kvm,
gfn_t gfn, void *rb, pid_t vm_pid) {
CHECK_PID(vm_pid) {
u32 flags;
struct kvm_memory_slot *slot;
bpf_probe_read_kernel(&slot, sizeof(memslot), &memslot);
bpf_probe_read_kernel(&flags, sizeof(memslot->flags), &memslot->flags);
if (flags & KVM_MEM_LOG_DIRTY_PAGES) { // 检查memslot是否启用了脏页追踪
if (slot && (flags & KVM_MEM_LOG_DIRTY_PAGES)) { // 检查memslot是否启用了脏页追踪
gfn_t gfnum = gfn;
u32 *count = bpf_map_lookup_elem(&count_dirty_map, &gfnum);
if (count) {
Expand Down
31 changes: 27 additions & 4 deletions eBPF_Supermarket/kvm_watcher/include/kvm_watcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,18 @@
#define TASK_COMM_LEN 16
#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0)

#define PRINT_USAGE_ERR() \
do { \
fprintf(stderr, "Use either the -w, -p, -d, or -e option.\n"); \
argp_usage(state); \
#define PFERR_PRESENT_BIT 0
#define PFERR_WRITE_BIT 1
#define PFERR_USER_BIT 2
#define PFERR_RSVD_BIT 3
#define PFERR_FETCH_BIT 4
#define PFERR_PK_BIT 5
#define PFERR_SGX_BIT 15

#define PRINT_USAGE_ERR() \
do { \
fprintf(stderr, "Use either the -w, -p, -d,-f or -e option.\n"); \
argp_usage(state); \
} while (0)

#define SET_OPTION_AND_CHECK_USAGE(option, value) \
Expand Down Expand Up @@ -68,6 +76,7 @@ struct exit_event {
unsigned long long duration_ns;
int count;
int total;
unsigned long long time;
};

struct ExitReason {
Expand All @@ -87,6 +96,7 @@ struct halt_poll_ns_event {
unsigned int new;
unsigned int old;
unsigned long long time;
unsigned vcpu_id;
};

struct mark_page_dirty_in_slot_event {
Expand All @@ -98,4 +108,17 @@ struct mark_page_dirty_in_slot_event {
unsigned long long gfn;
short slot_id;
};

struct page_fault_event {
struct process process;
unsigned long long time;
unsigned long long delay;
unsigned long long error_code;
unsigned long long addr;
unsigned long long pfn;
unsigned long long hva;
unsigned count;
short memslot_id;
};

#endif /* __KVM_WATCHER_H */
17 changes: 16 additions & 1 deletion eBPF_Supermarket/kvm_watcher/src/kvm_watcher.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <bpf/bpf_tracing.h>
#include "../include/kvm_exits.h"
#include "../include/kvm_vcpu.h"
#include "../include/kvm_mmu.h"
#include "../include/kvm_watcher.h"

char LICENSE[] SEC("license") = "Dual BSD/GPL";
Expand Down Expand Up @@ -56,9 +57,23 @@ int tp_entry(struct exit *ctx) {
trace_kvm_entry(&rb);
return 0;
}

SEC("kprobe/mark_page_dirty_in_slot")
int BPF_KPROBE(kp_mark_page_dirty_in_slot, struct kvm *kvm,
const struct kvm_memory_slot *memslot, gfn_t gfn) {
trace_mark_page_dirty_in_slot(kvm, memslot, gfn, &rb, vm_pid);
return 0;
}
}

SEC("tp/kvm/kvm_page_fault")
int tp_page_fault(struct trace_event_raw_kvm_page_fault *ctx) {
trace_page_fault(ctx, vm_pid);
return 0;
}

SEC("fexit/direct_page_fault")
int BPF_PROG(fexit_direct_page_fault, struct kvm_vcpu *vcpu,
struct kvm_page_fault *fault) {
trace_direct_page_fault(vcpu, fault, &rb);
return 0;
}
Loading

0 comments on commit acadb5f

Please sign in to comment.