tracepoint : mm_page_alloc_extfrag
关于本文的前置知识请参考链接
一、tracepoint的format
root@gyx-virtual-machine:/sys/kernel/debug/tracing/events/kmem/mm_page_alloc_extfrag# ls
enable filter format hist id inject trigger
root@gyx-virtual-machine:/sys/kernel/debug/tracing/events/kmem/mm_page_alloc_extfrag# cat format
name: mm_page_alloc_extfrag
ID: 562
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:unsigned long pfn; offset:8; size:8; signed:0;
field:int alloc_order; offset:16; size:4; signed:1;
field:int fallback_order; offset:20; size:4; signed:1;
field:int alloc_migratetype; offset:24; size:4; signed:1;
field:int fallback_migratetype; offset:28; size:4; signed:1;
field:int change_ownership; offset:32; size:4; signed:1;
...
二、tracepoint数据的解析
在linux源码中定义如下:
TRACE_EVENT(mm_page_alloc_extfrag,
TP_PROTO(struct page *page,
int alloc_order, int fallback_order,
int alloc_migratetype, int fallback_migratetype),
TP_ARGS(page,
alloc_order, fallback_order,
alloc_migratetype, fallback_migratetype),
TP_STRUCT__entry(
__field( unsigned long, pfn )
__field( int, alloc_order )
__field( int, fallback_order )
__field( int, alloc_migratetype )
__field( int, fallback_migratetype )
__field( int, change_ownership )
),
TP_fast_assign(
__entry->pfn = page_to_pfn(page);
__entry->alloc_order = alloc_order;
__entry->fallback_order = fallback_order;
__entry->alloc_migratetype = alloc_migratetype;
__entry->fallback_migratetype = fallback_migratetype;
__entry->change_ownership = (alloc_migratetype ==
get_pageblock_migratetype(page));
),
TP_printk("page=%p pfn=0x%lx alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d",
pfn_to_page(__entry->pfn),
__entry->pfn,
__entry->alloc_order,
__entry->fallback_order,
pageblock_order,
__entry->alloc_migratetype,
__entry->fallback_migratetype,
__entry->fallback_order < pageblock_order,
__entry->change_ownership)
);
-
TRACE_EVENT
宏定义用于定义 Linux 内核中的 trace event,它允许在特定事件发生时记录信息。在你的代码中,TRACE_EVENT(mm_page_alloc_extfrag, ...)
定义了一个名为mm_page_alloc_extfrag
的 trace event,记录内存外碎片事件的。 -
TP_PROTO(struct page *page, int alloc_order, int fallback_order, int alloc_migratetype, int fallback_migratetype)
:定义了事件发生时传递的参数类型。TP_PROTO
声明了事件将使用的参数。 -
TP_printk(...)
:定义了事件的打印格式。用于格式化输出事件数据:- pfn 物理页框号
- alloc_order 分配阶数
- fallback_order 从其他迁移类型中迁移页块的分配阶数
- alloc_migratetype 分配时迁移类型
- fallback_migratetype 表示从哪个迁移类型中迁移页块
- change_ownership 所有权是否改变,即如果内存分配请求的迁移类型与页块的迁移类型不匹配,可能需要调整页块的所有权
三、尝试用ebpf提取数据
3.1 思路
挂载上述tracepoint,并且统计每个cpu上的函数调用次数,在加压的环境下进行测试,来统计发生此事件的次数
3.1 程序
#include <uapi/linux/ptrace.h>
#include <linux/mm.h>
#include <linux/gfp.h>
struct data_t {
u64 pfn;
int alloc_order;
int fallback_order;
int alloc_migratetype;
int fallback_migratetype;
int change_ownership;
u64 index;
};
// 定义 perf_event 输出
BPF_PERF_OUTPUT(events);
BPF_HASH(counts_map, u32, u64);
TRACEPOINT_PROBE(kmem, mm_page_alloc_extfrag) {
u32 cpu_id = bpf_get_smp_processor_id(); // 获取当前 CPU ID
u64 *count = counts_map.lookup(&cpu_id);
if (count) {
(*count)++;
} else {
u64 zero = 1;
counts_map.update(&cpu_id, &zero);
}
struct data_t data = {};
data.pfn = args->pfn;
data.alloc_order = args->alloc_order;
data.fallback_order = args->fallback_order;
data.alloc_migratetype = args->alloc_migratetype;
data.fallback_migratetype = args->fallback_migratetype;
data.change_ownership = args->change_ownership;
// 读取当前 CPU 的计数值
u64 *count_updated = counts_map.lookup(&cpu_id);
data.index = count_updated ? *count_updated : 0;
events.perf_submit(args, &data, sizeof(data));
return 0;
}