Page_owner使用分析

目录

背景

原理

page_owner设计思路

Page_owner介绍

Page_owner支持

cmdline开启Page_owner

解析工具

复现问题

分析

Malloc

缺页异常的产生原因

Dmabuf

gpu

其他能够被统计到的堆栈信息

当前统计不到的关键字

参考

小结


背景

在项目中有一部分camera相关的包括camera driver使用大于等于order3的内存分配点,并没有统计到camera provider进程上。所以想通过page_owner,调查一下相机没有统计到的内存申请。

原理

内存页被分配出去前,会走进post_alloc_hook函数,进行一些处理,post_alloc_hook函数会调用set_page_owner函数,完成内存页分配调用栈的保存。

inline void post_alloc_hook(struct page *page, unsigned int order,                                gfp_t gfp_flags)
{
        bool init = !want_init_on_free() && want_init_on_alloc(gfp_flags) &&
                        !should_skip_init(gfp_flags);
        bool zero_tags = init && (gfp_flags & __GFP_ZEROTAGS);
        bool reset_tags = true;
        int i;

        set_page_private(page, 0);
        set_page_refcounted(page);

        arch_alloc_page(page, order);
        debug_pagealloc_map_pages(page, 1 << order);

        /*
         * Page unpoisoning must happen before memory initialization.
         * Otherwise, the poison pattern will be overwritten for __GFP_ZERO
         * allocations and the page unpoisoning code will complain.
         */kernel_unpoison_pages(page, 1 << order);

        /*
         * As memory initialization might be integrated into KASAN,
         * KASAN unpoisoning and memory initializion code must be
         * kept together to avoid discrepancies in behavior.
         *//*
         * If memory tags should be zeroed
         * (which happens only when memory should be initialized as well).
         */if (zero_tags) {
                /* Initialize both memory and memory tags. */for (i = 0; i != 1 << order; ++i)
                        tag_clear_highpage(page + i);

                /* Take note that memory was initialized by the loop above. */init = false;
        }
        if (!should_skip_kasan_unpoison(gfp_flags)) {
                /* Try unpoisoning (or setting tags) and initializing memory. */if (kasan_unpoison_pages(page, order, init)) {
                        /* Take note that memory was initialized by KASAN. */if (kasan_has_integrated_init())
                                init = false;
                        /* Take note that memory tags were set by KASAN. */reset_tags = false;
                } else {
                        /*
                         * KASAN decided to exclude this allocation from being
                         * (un)poisoned due to sampling. Make KASAN skip
                         * poisoning when the allocation is freed.
                         */SetPageSkipKASanPoison(page);
                }
        }
        /*
         * If memory tags have not been set by KASAN, reset the page tags to
         * ensure page_address() dereferencing does not fault.
         */if (reset_tags) {
                for (i = 0; i != 1 << order; ++i)
                        page_kasan_tag_reset(page + i);
        }
        /* If memory is still not initialized, initialize it now. */if (init)
                kernel_init_pages(page, 1 << order);
        /* Propagate __GFP_SKIP_KASAN_POISON to page flags. */if (kasan_hw_tags_enabled() && (gfp_flags & __GFP_SKIP_KASAN_POISON))
                SetPageSkipKASanPoison(page);

        set_page_owner(page, order, gfp_flags);
        page_table_check_alloc(page, order);
}

static inline void set_page_owner(struct page *page,
                        unsigned int order, gfp_t gfp_mask)
{
        if (static_branch_unlikely(&page_owner_inited))
                __set_page_owner(page, order, gfp_mask);
}

noinline void __set_page_owner(struct page *page, unsigned int order,
                                        gfp_t gfp_mask)
{
        struct page_ext *page_ext = lookup_page_ext(page);//获取该page对应的struct page_ext结构体
        depot_stack_handle_t handle;

        if (unlikely(!page_ext))
                return;

        handle = save_stack(gfp_mask);//将该页被分配时的调用栈保存下来
        __set_page_owner_handle(page_ext, handle, order, gfp_mask);
}

page_owner设计思路

扩展page结构体,增加成员变量用于存储该page被分配的调用栈及标志位,然后hook内存页的分配和释放接口,在内存页被分配时,保存调用栈信息,设置标志位;在内存页被释放的时候,清除调用栈信息,清除标志位。然后,通过一个debugfs的接口,将所有读取该接口时刻已经被分配出去的内存页的调用栈信息传递给用户态,并在用户态制作了一个工具,用于统计这些调用栈的信息。

Page_owner介绍

page owner is for the tracking about who allocated each page. It can be used to debug memory leak or to find a memory hogger.

官方介绍如下:

page owner: Tracking about who allocated each page — The Linux Kernel documentation

Page_owner支持

CONFIG_PAGE_OWNER=y 

cmdline开启Page_owner

在BoardConfig.mk文件中,加上对应makefile的修改。

解析工具

page_owner.sh

#!/bin/bash

adb shell 'cat /sys/kernel/debug/page_owner > /data/local/tmp/page_owner_full.txt'

adb pull /data/local/tmp/page_owner_full.txt

grep -v ^PFN page_owner_full.txt > page_owner.txt

./page_owner_sort page_owner.txt sorted_page_owner.txt

复现问题

复现问题后执行:./page_owner.sh

最终生成有三个文件:

page_owner_full.txt

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135260 ns, free_ts 0 ns
PFN 530145 type Unmovable Block 517 type Unmovable Flags 0x4000000000000200(slab|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135468 ns, free_ts 0 ns
PFN 530146 type Unmovable Block 517 type Unmovable Flags 0x4000000000010200(slab|head|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135624 ns, free_ts 0 ns
PFN 530147 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135781 ns, free_ts 0 ns
PFN 530148 type Unmovable Block 517 type Unmovable Flags 0x4000000000010200(slab|head|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135833 ns, free_ts 0 ns
PFN 530149 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135885 ns, free_ts 0 ns
PFN 530150 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135937 ns, free_ts 0 ns
PFN 530151 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136406 ns, free_ts 0 ns
PFN 530152 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136614 ns, free_ts 0 ns
PFN 530153 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136770 ns, free_ts 0 ns
PFN 530154 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136822 ns, free_ts 0 ns
PFN 530155 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136979 ns, free_ts 0 ns
PFN 530156 type Unmovable Block 517 type Unmovable Flags 0x4000000000010200(slab|head|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137031 ns, free_ts 0 ns
PFN 530157 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137083 ns, free_ts 0 ns
PFN 530158 type Unmovable Block 517 type Unmovable Flags 0x4000000000000200(slab|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137135 ns, free_ts 0 ns
PFN 530159 type Unmovable Block 517 type Unmovable Flags 0x4000000000000200(slab|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137343 ns, free_ts 0 ns
PFN 530160 type Unmovable Block 517 type Unmovable Flags 0x4000000000010200(slab|head|zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137395 ns, free_ts 0 ns
PFN 530161 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137552 ns, free_ts 0 ns
PFN 530162 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137604 ns, free_ts 0 ns
PFN 530163 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137864 ns, free_ts 0 ns
PFN 530164 type Unmovable Block 517 type Unmovable Flags 0x4000000000000000(zone=1|kasantag=0x0)
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

page_owner.txt

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135260 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135468 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135624 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135781 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135833 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135885 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43135937 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136406 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136614 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136770 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136822 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43136979 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137031 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137083 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137135 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137343 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137395 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137552 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137604 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137864 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137916 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137916 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138124 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138177 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138229 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138281 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138333 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138541 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138749 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138802 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43138958 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139010 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139062 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139114 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139270 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139322 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139374 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139427 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139427 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139583 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139635 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139687 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139739 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139791 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139843 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139895 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139947 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139999 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43140052 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43140104 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

sorted_page_owner.txt

如下类似内容:
1 times:           
Page allocated via order 9, mask 0x1521c2(__GFP_HIGHMEM|__GFP_IO|__GFP_FS|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_ZERO|__GFP_HARDWALL), pid 2379, tgid 1603 (Preview_2), ts 128125282786 ns, free_ts 75571306063 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 qcom_extend_sys_heap_alloc_largest_available+0x2cc/0xa98 [qcom_dma_heaps]
 system_qcom_sg_buffer_alloc+0xf4/0x380 [qcom_dma_heaps]
 system_heap_allocate+0x90/0x168 [qcom_dma_heaps]
 dma_heap_buffer_alloc+0x5c/0x6c
 cam_mem_util_get_dma_buf+0x2c4/0x718 [camera]                                                                                                                                                                                                              
 cam_mem_mgr_alloc_and_map+0x284/0x7f8 [camera] 
 cam_private_ioctl+0x318/0x274c [camera] 
 __video_do_ioctl+0x298/0x4dc
 video_usercopy+0x43c/0xb38
 video_ioctl2+0x18/0x28
 v4l2_ioctl+0x6c/0x84
 __arm64_sys_ioctl+0xa8/0xe4
 
 
 1 times:
Page allocated via order 0, mask 0x100dc0(GFP_USER|__GFP_ZERO), pid 14313, tgid 1603 (SyncThread), ts 128067784036 ns, free_ts 127389201898 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 qcom_io_pgtable_alloc_page+0xa0/0x1e8 [qcom_iommu_util]
 __arm_lpae_alloc_pages+0x34/0x178 [qcom_iommu_util]
 __arm_lpae_map+0x258/0x4fc [qcom_iommu_util]
 __arm_lpae_map+0x4c4/0x4fc [qcom_iommu_util]
 qcom_arm_lpae_map_pages+0xf4/0x168 [qcom_iommu_util]
 arm_smmu_map_pages+0xd0/0x26c [arm_smmu]
 __iommu_map+0x1d0/0x330
 __iommu_map_sg+0xcc/0x1d4
 iommu_map_sg+0x14/0x20
 cam_smmu_map_buffer_validate+0x744/0x9c8 [camera] 
 cam_smmu_map_user_iova+0x31c/0x5b8 [camera] 
 cam_mem_util_map_hw_va+0x1c8/0x3b4 [camera] 



1 times:
Page allocated via order 0, mask 0x100dc0(GFP_USER|__GFP_ZERO), pid 13119, tgid 30614 (SyncThread), ts 175393672508846 ns, free_ts 175393621807075 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 __get_free_pages+0x1c/0x50
 __pte_alloc_kernel+0x24/0xe4
 __vmap_pages_range_noflush+0x314/0x488
 vmap+0xb8/0x148
 qcom_sg_do_vmap+0x114/0x170 [qcom_dma_heaps]
 qcom_sg_vmap+0x74/0xcc [qcom_dma_heaps]
 dma_buf_vmap+0xc8/0x144
 cam_compat_util_get_dmabuf_va+0x38/0xd8 [camera]
 cam_mem_util_map_cpu_va+0x68/0x114 [camera]
 cam_mem_mgr_alloc_and_map+0x588/0x7f8 [camera]
 cam_private_ioctl+0x318/0x274c [camera]
 __video_do_ioctl+0x298/0x4dc



2 times:
Page allocated via order 0, mask 0x112dc2(GFP_HIGHUSER|__GFP_NOWARN|__GFP_NORETRY|__GFP_ZERO), pid 2191, tgid 1772 (vppservice), ts 6585601582 ns, free_ts 0 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 __iommu_dma_alloc_noncontiguous+0x144/0x404
 iommu_dma_alloc+0xa0/0x324
 dma_alloc_attrs+0xd4/0x108
 fastrpc_buf_alloc+0x1c4/0x4e4 [frpc_adsprpc]
 fastrpc_internal_mmap+0x8c/0x26c [frpc_adsprpc]
 fastrpc_device_ioctl+0x62c/0x24f4 [frpc_adsprpc]
 __arm64_sys_ioctl+0xa8/0xe4
 invoke_syscall+0x58/0x114
 el0_svc_common+0xb4/0xfc
 do_el0_svc+0x2c/0xb8
 el0_svc+0x2c/0xa4
 el0t_64_sync_handler+0x68/0xb4







2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43137916 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43139427 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43140416 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43141718 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43142968 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43143177 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43144479 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43144687 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43145885 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43147239 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43148541 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43149999 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43151406 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43159427 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158

2 times:
Page allocated via order 0, mask 0x0(), pid 1, tgid 1 (swapper/0), ts 43160729 ns, free_ts 0 ns
 register_early_stack+0x34/0x78
 init_page_owner+0x3c/0x2dc
 page_ext_init+0x1c0/0x1d4
 kernel_init_freeable+0xe8/0x158








分析

由于进程组的存在,堆栈信息会表现出多个pid指向同一个tgid,进程组ID是由进程组的首个进程的PID来确定的,这个进程被称为进程组的领头进程(也称为进程组长)

因此pid或者tgid为camera相关的对应堆栈都应被统计为camera内存

el0t_64_sync
    invoke_syscall
        __arm64_sys_ioctl
            dma_heap_ioctl——ion的gralloc、cdsprpc、三方库
                system_heap_allocate
            dma_buf_ioctl
            v4l2_ioctl——ion的cmdbuffer部分、CSLAlloc、ImageBuffer
                video_ioctl2
                    video_usercopy
                        __video_do_ioctl
            kgsl_ioctl——gpu申请
                kgsl_ioctl_gpuobj_alloc
                    gpumem_alloc_entry
            binder_ioctl
            fastrpc_device_ioctl
            dm_ctl_ioctl
            security_file_ioctl
            cvp_unblocked_ioctl——ion libeva.so
            ashmem_ioctl
        __arm64_sys_prctl
            anon_vma_name_alloc
        __arm64_sys_openat
            do_sys_openat2
        __arm64_sys_clone
            kernel_clone

以ps -e|grepcamera.provider返回的14163为例,在pageowner中为进程组,多个tgid为14163的均为provider相关进程。

Page allocated via order 0, mask 0x102dc2(GFP_HIGHUSER|__GFP_NOWARN|__GFP_ZERO), pid 14163, tgid 14163 (binder:14163_2), ts 845516934762555 ns, free_ts 845516934432347 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 __alloc_pages_bulk+0x2f8/0x6a8
 __vmalloc_node_range+0x564/0x808
 dup_task_struct+0x1ac/0x3f8
 copy_process+0x174/0xc3c
 kernel_clone+0xb0/0x488
 __arm64_sys_clone+0x5c/0x8c
 invoke_syscall+0x58/0x114
 el0_svc_common+0xb4/0xfc
 do_el0_svc+0x2c/0xb8
 el0_svc+0x2c/0xa4
 el0t_64_sync_handler+0x68/0xb4
 el0t_64_sync+0x1a0/0x1a4

2 times:
Page allocated via order 0, mask 0x112002(__GFP_HIGHMEM|__GFP_NOWARN|__GFP_NORETRY|__GFP_HARDWALL), pid 15290, tgid 14163 (vendor.qti.came), ts 845529549682750 ns, free_ts 845529494341708 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 kgsl_shmem_fill_page+0x1b4/0x39c [msm_kgsl]
 __traceiter_android_rvh_shmem_get_folio+0x50/0x7c
 shmem_alloc_and_acct_folio+0x30c/0x340
 shmem_get_folio_gfp+0x2ec/0x998
 shmem_read_mapping_page_gfp+0x5c/0xc8
 _kgsl_alloc_pages+0x1cc/0x4c0 [msm_kgsl]
 kgsl_allocate_user+0x190/0x320 [msm_kgsl]
 gpumem_alloc_entry+0xfc/0x43c [msm_kgsl]
 gen7_preemption_context_init+0x58/0x84 [msm_kgsl]
 adreno_drawctxt_create+0x2c4/0x328 [msm_kgsl]
 kgsl_ioctl_drawctxt_create+0x4c/0x134 [msm_kgsl]
 kgsl_ioctl_helper+0x118/0x174 [msm_kgsl]
Charged to memcg provider

2 times:
Page allocated via order 0, mask 0x112002(__GFP_HIGHMEM|__GFP_NOWARN|__GFP_NORETRY|__GFP_HARDWALL), pid 15534, tgid 14163 (MiHalThd0), ts 845530108123325 ns, free_ts 845529497914052 ns
 post_alloc_hook+0x1c0/0x208
 prep_new_page+0x28/0x12c
 get_page_from_freelist+0x1190/0x12b4
 __alloc_pages+0x12c/0x2fc
 kgsl_shmem_fill_page+0x1b4/0x39c [msm_kgsl]
 __traceiter_android_rvh_shmem_get_folio+0x50/0x7c
 shmem_alloc_and_acct_folio+0x30c/0x340
 shmem_get_folio_gfp+0x2ec/0x998
 shmem_read_mapping_page_gfp+0x5c/0xc8
 _kgsl_alloc_pages+0x1cc/0x4c0 [msm_kgsl]
 kgsl_allocate_user+0x190/0x320 [msm_kgsl]
 gpumem_alloc_entry+0xfc/0x43c [msm_kgsl]
 kgsl_ioctl_gpuobj_alloc+0x1c/0xe8 [msm_kgsl]
 kgsl_ioctl_helper+0x118/0x174 [msm_kgsl]
 kgsl_ioctl+0x34/0x9c [msm_kgsl]
 __arm64_sys_ioctl+0xa8/0xe4
Charged to memcg provider

相关pidname介绍:

kworker:负责处理各种内核任务
kswapd:定期扫描系统中的内存页面,将不常用的页面交换到磁盘上,以释放内存空间
vppservice:视频处理相关的任务,例如视频编解码、视频旋转、视频缩放、视频色彩空间转换等
binder:进程间通信进程
AlgoFwkThd
MiHalThd
SyncThread:统服务进程中的一个线程,负责处理与账户同步相关的任务
camera-saver
modprobe:加载和卸载内核模块
CamXBITMLInit:初始化相机硬件和相机驱动程序

Malloc

malloc是用户态函数,申请的是虚拟内存,此时MMU并没有创建虚拟页物理页映射关系。只有当发生缺页异常时才会向内核发出缺页中断去申请物理内存。当malloc一次性能申请小内存(小于128KB),分配的是在堆区(heap),用sbrk()进行对齐生长,而malloc一次性申请大内存(大于128KB时)分配到的是在映射区,而不是在堆区,采用的mmap()系统调用进行映射。

缺页异常的产生原因

缺页异常是在通过虚拟地址去访问物理内存的过程中出现失败时抛出的异常,访问的过程包括几个阶段,首先是通过虚拟地址访问页表转换为物理地址,第二个阶段是通过物理地址访问物理内存,而错误的原因有以下几种:

  1. 第一个阶段出现错误,通过MMU将虚拟地址转换为物理地址时发现不存在映射关系

  2. 第二个阶段出错,通过物理地址访问内存,发现page不在内存当中

  3. 第二个阶段出错,通过物理地址访问内存,发现权限错误

mmap内核态实现函数:ksys_mmap_pgoff

unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
                  unsigned long prot, unsigned long flags,
                  unsigned long fd, unsigned long pgoff)
{
    struct file *file = NULL;
    unsigned long retval;

    // 预处理文件映射
    if (!(flags & MAP_ANONYMOUS)) {
        // 根据 fd 获取映射文件的 struct file 结构
        audit_mmap_fd(fd, flags);
        file = fget(fd);
        if (!file)
            // 这里可以看出如果是匿名映射的话必须要指定 MAP_ANONYMOUS 否则这里就返回错误了
            return -EBADF;
        // 映射文件是否是 hugetlbfs 中的文件,hugetlbfs 中的文件默认由大页支持
        if (is_file_hugepages(file))
            // mmap 进行文件大页映射,len 需要和大页尺寸对齐
            len = ALIGN(len, huge_page_size(hstate_file(file)));
        retval = -EINVAL;
        // 这里可以看出如果想要使用 mmap 对文件进行大页映射,那么映射的文件必须是 hugetlbfs 中的
        // mmap 文件大页映射并不需要指定 MAP_HUGETLB,并且 mmap 不能对普通文件进行大页映射
        if (unlikely(flags & MAP_HUGETLB && !is_file_hugepages(file)))
            goto out_fput;
    } else if (flags & MAP_HUGETLB) {
        // 从这里我们可以看出 MAP_HUGETLB 只能支持 MAP_ANONYMOUS 匿名映射的方式使用 HugePage
        struct user_struct *user = NULL;
        // 内核中的大页池(预先创建)
        struct hstate *hs;
        // 选取指定大页尺寸的大页池(内核中存在不同尺寸的大页池)
        hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
        if (!hs)
            return -EINVAL;
        // 映射长度 len 必须与大页尺寸对齐
        len = ALIGN(len, huge_page_size(hs));
 
        // 在 hugetlbfs 中创建 anon_hugepage 文件,并预留大页内存(禁止其他进程申请)
        file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
                VM_NORESERVE,
                &user, HUGETLB_ANONHUGE_INODE,
                (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
        if (IS_ERR(file))
            return PTR_ERR(file);
    }

    flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
    // 开始内存映射
    retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff);
out_fput:
    if (file)
        // file 引用计数减 1
        fput(file);
    return retval;
}

相关函数接口与堆栈

do_page_fault——缺页中断处理函数arch/arm/mm/fault.c
    handle_mm_fault
ksys_mmap_pgoff——malloc mmap的内核函数
    vm_mmap_pgoff
        do_mmap
            mmap_region
__arm64_sys_mremap——重新映射一个虚拟内存区域
    move_vma
        copy_vma
__arm64_sys_munmap——解除映射一个虚拟内存区域
    __vm_munmap
        do_mas_align_munmap

Dmabuf

申请一个buffer,再创建一个dmabuf 结构体然后将,然后将dmabuf中得指针指向buffer,dmabuf 再传递给一个匿名的inode,获取到一个file,这样file和dmabuf绑定起来,也就和buffer关联上。然后再从进程中分配一个空闲的fd,将fd和file绑定。这样就能通过fd 快速查找到buffer。file 是个全系统的,他和进程无关,但是fd 是每个进程都是自己独立的,所以再跨进程传输时只需要保证fd 和同一个file绑定就可以实现buffer的共享。

相关函数接口与堆栈

/*/mivendor_u_sm8650/kernel_platform/msm-kernel/drivers/dma-buf/*/
dma_heap_ioctl——gralloc、cdsprpc、三方库
    system_heap_allocate
/*/mivendor_u_sm8650/vendor/qcom/opensource/camera-kernel/drivers/cam_req_mgr/*/
v4l2_ioctl——cmdbuffer、CSLAlloc、ImageBuffer
    video_ioctl2
        video_usercopy
            __video_do_ioctl
                cam_private_ioctl
                    cam_mem_mgr_alloc_and_map
                        cam_mem_util_get_dma_buf
                            dma_heap_buffer_alloc
                                system_heap_allocate
/*/mivendor_u_sm8650/vendor/qcom/opensource/eva-kernel/msm/eva/msm_cvp_ioctl.c*/
cvp_unblocked_ioctl——libeva.so
    cvp_ioctl
        msm_cvp_private
            msm_cvp_handle_syscall
                msm_cvp_session_create
                    cvp_comm_set_arp_buffers
                        cvp_allocate_arp_bufs
                            msm_cvp_smem_alloc
                                dma_heap_buffer_alloc
                                    system_heap_allocate

然而在pageowner中使用以上接口过滤出的内存占用远低于实际能够统计到的dmabuf,这是因为以上接口申请的是虚拟内存:

static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
                        unsigned long len,
                        unsigned long fd_flags,
                        unsigned long heap_flags)
{
    struct qcom_sg_buffer *buffer;
    DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
    struct dma_buf *dmabuf;
    int ret;
    //申请的是虚拟内存
    buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    if (!buffer)
        return ERR_PTR(-ENOMEM);
    ret = system_qcom_sg_buffer_alloc(heap, buffer, len, false);
    if (ret)
        goto free_buf_struct;
    buffer->vmperm = mem_buf_vmperm_alloc(&buffer->sg_table);
    if (IS_ERR(buffer->vmperm)) {
        ret = PTR_ERR(buffer->vmperm);
        goto free_sys_heap_mem;
    }
    /* create the dmabuf */
    exp_info.exp_name = dma_heap_get_name(heap);
    exp_info.size = buffer->len;
    exp_info.flags = fd_flags;
    exp_info.priv = buffer;
    dmabuf = qcom_dma_buf_export(&exp_info, &qcom_sg_buf_ops);
    if (IS_ERR(dmabuf)) {
        ret = PTR_ERR(dmabuf);
        goto free_vmperm;
    }
    return dmabuf;
free_vmperm:
    mem_buf_vmperm_release(buffer->vmperm);
free_sys_heap_mem:
    qcom_system_heap_free(buffer);
    return ERR_PTR(ret);
free_buf_struct:
    kfree(buffer);
    return ERR_PTR(ret);
}

以v4l2_ioctl申请imagebuffer为例:

CamxResult ImageBufferManager::InitializeBuffers(
    BufferManagerCreateData* pCreateData)
{
    ImageBuffer* pBuffer = CAMX_NEW ImageBuffer();
    CAMX_ASSERT(NULL != pBuffer);
    if (NULL != pBuffer)
    {
        result = pBuffer->Initialize(m_pBufferManagerName, &m_createData, &m_currentFormat, this,
                                     m_hMemPoolBufMgrHandle);

        if (CamxResultSuccess != result)
        {
            CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] : Failed in initializing ImageBuffer object, result=%s",
                           GetBufferManagerName(), Utils::CamxResultToString(result));
        }
    }
    // Allocate the buffer
    result = pBuffer->Allocate();
    CAMX_ASSERT(CamxResultSuccess == result);\
    if (CamxResultSuccess == result)
    {
        LDLLNode* pNode = static_cast<LDLLNode*>(CAMX_CALLOC(sizeof(LDLLNode)));

        if (NULL != pNode)
        {
            pNode->pData = pBuffer;

            // Add the buffer to the free buffer list
            m_freeBufferList.InsertToTail(pNode);

            CAMX_LOG_VERBOSE(CamxLogGroupMemMgr, "[%s] ImageBuffer %p", GetBufferManagerName(), pBuffer);
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupMemMgr, "[%s] : Failed in allocating Node", GetBufferManagerName());
            result = CamxResultENoMemory;
        }
    }
}
申请的虚拟内存的dmabuf存储在了m_freeBufferList,使用的时候:
IImageBuffer* ImageBufferManager::GetImageBuffer()
{
    LDLLNode*    pNode       = m_freeBufferList.RemoveFromHead();
    pBuffer = static_cast<ImageBuffer*>(pNode->pData);
    CAMX_FREE(pNode);
    pNode = NULL;    
}

实际修改使用dmabuf的例子:

/// @brief Defines the image buffer.
chicommon.h
typedef struct /** @cond */ ChiImage /** @endcond */
{
    UINT32           size;                                   ///< Size of the structure.
    INT              fd[ChiNodeFormatsMaxPlanes];            ///< Maps the buffer to the file descriptor.
    UCHAR*           pAddr[ChiNodeFormatsMaxPlanes];         ///< Pointer to the starting virtual address of the allocated
                                                             ///  buffer.
    CHIHANDLE        pNativeHandle;                          ///< Pointer to the native handle.
} CHIIMAGE;

camxchinodesat.cpp
SatImage ChiSATNode::CvtHandle2Image(CHINODEBUFFERHANDLE hInput)
{
    SatImage::ImageType imageType;
    SatImage::DataType dataType;

    if (hInput->format.format == P010)
    {
        imageType = SatImage::IMAGETYPE_P010;
        dataType = SatImage::DT_16U;
    }
    else if (hInput->format.format == YUV420NV12)
    {
        imageType = SatImage::IMAGETYPE_NV12;
        dataType = SatImage::DT_8U;
    }
    else if (hInput->format.format == YUV420NV21)
    {
        imageType = SatImage::IMAGETYPE_NV21;
        dataType = SatImage::DT_8U;
    }
    else if (hInput->format.format == UBWCTP10)
    {
        imageType = SatImage::IMAGETYPE_UBWC_TP10;
        dataType = SatImage::DT_16U;
    }
    else
    {
        imageType = SatImage::IMAGETYPE_MAX;
        dataType = SatImage::DT_8U;
        MEGVII_LOG_ERROR("unsupported image format: %d", hInput->format.format);
    }

    MEGVII_LOG_VERBOSE("[MEGVII_SAT] image type: %d", hInput->format.format);

    int width = hInput->format.width;
    int height = hInput->format.height;
    int stride = hInput->format.formatParams.yuvFormat[0].planeStride;
    int slice_height = hInput->format.formatParams.yuvFormat[0].sliceHeight;
    if (imageType == SatImage::IMAGETYPE_P010)
    {
        stride /= 2;
    }

    SatImage image(stride, slice_height,
                       hInput->pImageList[0].pAddr[0],
                       hInput->pImageList[0].pAddr[1],
                       NULL,
                       imageType,
                       dataType,
                       SatImage::ROTATION_0);
    image.setImageWH(width, height);

    int imageFd[] = {hInput->pImageList[0].fd[0], hInput->pImageList[0].fd[1]};
    image.setIonFd(imageFd, sizeof(imageFd) / sizeof(int));

    return image;
}

最终以fd指定dmabuf进程操作,因此pageowner中write、read相关的文件操作可能与dmabuf相关。在读写过程中申请物理内存

相关函数接口与堆栈

__arm64_sys_write——写文件时缺页出现的内存申请
    ksys_write
        vfs_write
            __folio_alloc
__arm64_sys_read
    ksys_read
        vfs_read
            f2fs_file_read_iter
            proc_reg_read
                do_read_cache_folio
do_writev——在文件上执行写操作
    do_iter_write
        sock_write_iter
user_path_at_empty——通过文件系统进行文件操作,中途需要添加page
    filename_lookup
        path_lookupat
            walk_component
                lookup_slow
                    __lookup_slow
binder_ioctl——读写时候申请的实际物理内存
    binder_ioctl_write_read

gpu

/vendor/qcom/opensource/graphics-kernel/
相关函数接口与堆栈

kgsl_mem_alloc
    kgsl_ioctl_helper
        kgsl_ioctl_gpuobj_alloc
            gpumem_alloc_entry
kgsl_mem_map
    kgsl_ioctl_helper
        kgsl_ioctl_gpuobj_import

其他能够被统计到的堆栈信息

copy_process:创建进程
__arm64_sys_mprotect——修改内存页属性。设置vma的读写属性和映射方式
    mprotect_fixup
__arm64_sys_execve:用于执行一个新的程序。当该函数被调用时,它会将当前进程的上下文切换到一个新的程序中,新程序的代码将会替换当前进程的代码,并开始执行
v4l2_ioctl
    video_ioctl2
        video_usercopy
            __video_do_ioctl
                v4l_subscribe_event
                    cam_subscribe_event
try_to_free_pages——zram压缩申请的内存
__arm64_sys_prctl——系统调用,用于修改进程的属性
    anon_vma_name_alloc

当前统计不到的关键字


fastrpc_device_ioctl:cdsp的软件接口申请的内存
__arm64_sys_openat:用于打开文件
    do_sys_openat2
        do_filp_open
            path_openat
                vfs_open
                    do_dentry_open
                        chrdev_open
                            v4l2_open
kernel_init_freeable
cam_icp_subdev_open
    cam_icp_mgr_hw_open_u
        cam_icp_mgr_hw_open
v4l2_ioctl
    subdev_ioctl
        video_usercopy
            subdev_do_ioctl_lock
                cam_eeprom_subdev_ioctl
                    cam_eeprom_driver_cmd
cam_compat_util_get_dmabuf_va
    dma_buf_vmap
        qcom_sg_vmap
            qcom_sg_do_vmap
cam_eeprom_driver_cmd——camera驱动自己申请的内存。摄像头驱动程序需要分配内存来初始化pinctrl、传感器核心和EEPROM
cam_sensor_driver_cmd
cam_ois_driver_cmd

参考

brk系统调用:https://zhuanlan.zhihu.com/p/579405096

小结

1. Make sure following parameters in cmdline:

page_pinner=1 stack_depot_disable=off page_owner=on

2. Make sure following configs enabled:

CONFIG_PAGE_PINNER=y

CONFIG_CMA_DEBUG=y

CONFIG_PAGE_OWNER=y

When issue happened, trigger dump, then parse dump by ramparser with following parameters:

--slabinfo --slabsummary --print-pagetracking

后续总结一下更多关于 page_owner的实战内容。

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

repinkply

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值