统计内存外碎片发生的次数

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;
}

3.2 结果

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值