I couldn't find any helpful resources about reading hardware performance counters inside the kernel (i mean tracking other processes inside kernel module or driver). But suddenly, i saw a project called
qemu-deterministic-play
which I will give huge credit on this blog post. That project using a function called
perf_event_create_kernel_counter
. This is interesting because we can use perf even in the kernel level. Also, this function has been already used by some other kernel drivers like:
/linux-hwe-5.11-5.11.0/drivers/oprofile/nmi_timer_int.c
/linux-hwe-5.11-5.11.0/kernel/watchdog_hld.c
Actually using this function is very similar to userspace perf tool. So first of all we need to define our performance attributes in a
perf_event_attr
struct. While I'm doing this, i was researching on a how we can track cache misses inside a virtual machine. So my attr struct looks like that:
struct perf_event_attr attr =
{
.type = PERF_TYPE_HW_CACHE,
.size = sizeof(attr),
.exclude_host = 1,
.exclude_user = 0,
.exclude_kernel = 0,
.config = (PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
};
After creating that struct, I used
perf_event_create_kernel_counter
to create kernel counter. Unlike from userspace perf we need to add a overflow handler for that function.
static void kvm_sandbox_perf_overflow_handler(struct perf_event *perf_event,
struct perf_sample_data *data, struct pt_regs *regs)
{
u64 enabled, running, counter;
counter = perf_event_read_value(perf_event, &enabled, &running);
printk("counter: %llx\n", counter);
}
event = perf_event_create_kernel_counter(&attr, -1, current,
kvm_sandbox_perf_overflow_handler, vcpu);
These codes will complete our init phase. After we can create that counter with
perf_event_read_value
function.