分享

vmalloc size分析

 写意人生 2015-01-07

平台: msm8x25

系统: android 4.1

内核: 3.4.0

原文: http://blog.csdn.net/kris_fei/article/details/17243527


概念

由于系统的连续物理内存有限,这使得非连续物理内存的使用在linux内核中出现,

这叫vmalloc机制。和前者一样,vmalloc机制中的虚拟地址也是连续的。

 

Vmallocinfo

        Vmalloc机制并不是狭义地指使用vmalloc函数分配,其他还有如ioremap, iotable_init等。可以从/proc/vmallocinfo获取到此信息:

#cat /proc/vmallocinfo

0xf3600000-0xf36ff0001044480 binder_mmap+0xb0/0x224 ioremap

………..

0xf6680000-0xf66c1000 266240 kgsl_page_alloc_map_kernel+0x98/0xe8 ioremap

0xf6700000-0xf67ff0001044480 binder_mmap+0xb0/0x224 ioremap

…………….

0xf6f00000-0xf6f41000 266240 kgsl_page_alloc_map_kernel+0x98/0xe8 ioremap

0xf7200000-0xf72ff0001044480 binder_mmap+0xb0/0x224 ioremap

0xfa000000-0xfa001000   4096 iotable_init+0x0/0xb0 phys=c0800000 ioremap

……………..

0xfa105000-0xfa106000   4096 iotable_init+0x0/0xb0 phys=a9800000 ioremap

0xfa200000-0xfa3000001048576 pmd_empty_section_gap+0x0/0x3c ioremap

0xfa300000-0xfa4000001048576 iotable_init+0x0/0xb0 phys=100000 ioremap

0xfa400000-0xfa5000001048576 iotable_init+0x0/0xb0 phys=aa500000 ioremap

0xfa500000-0xfa6000001048576 pmd_empty_section_gap+0x0/0x3c ioremap

0xfa701000-0xfa702000   4096 iotable_init+0x0/0xb0 phys=c0400000 ioremap

…………..

0xfa800000-0xfa9000001048576 pmd_empty_section_gap+0x0/0x3c ioremap

0xfa900000-0xfb60000013631488 iotable_init+0x0/0xb0 phys=ac000000 ioremap

0xfefdc000-0xff000000 147456 pcpu_get_vm_areas+0x0/0x56c vmalloc

 

上面的列数意思依次是:虚拟地址,分配大小,哪个函数分配的,物理地址,分配类型。

后面会提到vmalloc size的划分是按照此info来修改的。

 

分配标志

是否划分到vamlloc区域主要是以下重要的标志来决定的:

File: kernel/include/linux/vmalloc.h

/* bits in flags ofvmalloc's vm_struct below */

#defineVM_IOREMAP    0x00000001     /* ioremap()and friends */

#define VM_ALLOC0x00000002     /* vmalloc() */

#defineVM_MAP             0x00000004     /* vmap()ed pages */

#defineVM_USERMAP    0x00000008     /* suitable forremap_vmalloc_range */

#defineVM_VPAGES       0x00000010     /* buffer for pages was vmalloc'ed */

#defineVM_UNLIST         0x00000020    /* vm_struct is not listed in vmlist */

/* bits [20..32]reserved for arch specific ioremap internals */

Vmallocinfo中的函数,你可以对照源码看一下,在设置flag的时候就会有VM_IOREMAP, VM_ALLOC这些标志。

 

Vmalloc区域

Vmalloc的区域是由两个宏变量来表示: VMALLOC_START,VMALLOC_END.

File: kernel/arch/arm/include/asm/pgtable.h

#defineVMALLOC_OFFSET              (8*1024*1024)

#defineVMALLOC_START                (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))

#defineVMALLOC_END          0xff000000UL

 

VMALLOC_START:看上去会随着high_memory的值变化。

VMALLOC_OFFSET:系统会在low memory和VMALLOC区域留8M,防止访问越界。因此假如理论上vmalloc size有300M,实际可用的也是只有292M。

 

File: kernel/Documentation/arm/memory.txt有给出更好的解释:

VMALLOC_START   VMALLOC_END-1    vmalloc() / ioremap() space. Memory returned byvmalloc/ioremap will be dynamically placed in this region. Machine specificstatic mappings are also located here through iotable_init(). VMALLOC_START isbased upon the value

of the high_memoryvariable, and VMALLOC_END is equal to 0xff000000.

 

下图摘自网络,看下VMALLOC_START和VMALLOC_END的位置。0xc0000000到VMALLOC_START为low memory虚拟地址区域。

        

Vmallocsize计算

 

有了以上知识后我们看下vmalloc size是如何分配的,目前有两种方法,kernel默认分配一个, 以及开机从cmdline分配。

1.     从cmdline分配

File: device/qcom/msm7627a/BoardConfig.mk

BOARD_KERNEL_CMDLINE := androidboot.hardware=qcom loglevel=7vmalloc=200M

上面的值在build的时候会被赋值给kernel 的cmdline。

开机的时候early_vmalloc()会去读取vmalloc这个值。

File: kernel/arch/arm/mm/mmu.c

static int__init early_vmalloc(char *arg)

{

        /*cmdline中的vmalloc会被解析到vmlloc_reserve中。*/

        unsigned long vmalloc_reserve = memparse(arg, NULL);

        /*小于16M则用16M*/

        if (vmalloc_reserve < SZ_16M) {

                  vmalloc_reserve = SZ_16M;

                  printk(KERN_WARNING

                           "vmalloc area too small, limiting to %luMB\n",

                           vmalloc_reserve >> 20);

        }

        /*大于可用虚拟地址内存则使用可用地址部分再减去32M*/

        if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {

                  vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);

                  printk(KERN_WARNING

                           "vmalloc area is too big, limiting to %luMB\n",

                           vmalloc_reserve >> 20);

        }

        /*计算偏移起始地址。*/

        vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve);

 

        return 0;

}

early_param("vmalloc",early_vmalloc);

 

vmalloc_min会影响arm_lowmem_limit,arm_lowmem_limit其实就是high_memory。因为此过程不是我们要分析的重点,如果有兴趣可分析kernel/arch/arm/mm/mmu.c中的sanity_check_meminfo()函数。

所以,VMALLOC_START受到了hight_memory的影响而发生了变化,最终使得vmalloc size也变化了!

 

2.     开机默认分配:

File: kernel/arch/arm/mm/mmu.c

static void * __initdata vmalloc_min =

        (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);

当cmdline无vmalloc参数传进来的时候,early_vmalloc()函数也不会调用到,vmalloc_min的值就会被默认传进来了,默认是240M。

后面的步骤和方法1一样了!

 

开机log有memory layout 信息:

[    0.000000] [cpuid: 0] Virtual kernelmemory layout:

[    0.000000] [cpuid:0]     vector  : 0xffff0000 - 0xffff1000  (   4 kB)

[    0.000000] [cpuid:0]     fixmap  : 0xfff00000 - 0xfffe0000   (896 kB)

[    0.000000] [cpuid:0]     vmalloc : 0xf3000000 - 0xff000000   ( 192MB)

[    0.000000] [cpuid:0]     lowmem  : 0xc0000000 - 0xf2800000   (808 MB)

[    0.000000] [cpuid:0]     pkmap   : 0xbfe00000 -0xc0000000   (   2 MB)

[    0.000000] [cpuid:0]     modules : 0xbf000000 - 0xbfe00000  (  14 MB)

[    0.000000] [cpuid:0]       .text : 0xc0008000 -0xc0893034   (8749 kB)

[    0.000000] [cpuid:0]       .init : 0xc0894000 -0xc08cdc00   ( 231 kB)

[    0.000000] [cpuid:0]       .data : 0xc08ce000 -0xc09f8eb8   (1196 kB)

[    0.000000] [cpuid:0]        .bss : 0xc0a78eec -0xc0f427a8   (4903 kB)

 

其中看到vmalloc为192MB , cmdline中使用vmllaoc就是200M。

Lowmem为地段内存部分,可见lowmem和vmalloc中间有8M空隙。

 

 

Vmalloc该分配多大?

Linux内核版本从3.2到3.3 默认的vmalloc size由128M 增大到了240M,3.4.0上的

修改Commit信息如下:

To accommodate all static mappings on machines withpossible highmem usage,

the default vmalloc area size is changed to 240 MB sothat VMALLOC_START

is no higher than 0xf0000000 by default.

 

看其意思是因为开机的静态映射增加了,所以要扩大。

另外3.2到3.3版本的一个重大变化是将android引入到主线内核中。我想增大vmalloc

size到240M是基于此考虑吧。当然,各家厂商都也可以基于自己平台来动态修改size的。

 

那么如何判断当前vmalloc size不足呢?

/proc/meminfo中有vmalloc信息:

VmallocTotal:          540672 kB

VmallocUsed:      165268 kB

VmallocChunk:     118788kB

事实上这里的VmallocUsed只是表示已经被真正使用掉的vmalloc区域,但是区域之前

的空隙也就是碎片没有被计算进去。

所以,回到前面说的/proc/vmallocinfo,假设我们的vmalloc size就是200M。那么区域

为0xf3000000- 0xff000000,从vmallocinfo中可以看到,前面大部分虚拟地址空间都用掉了,剩下0xfb600000到0xfefdc000这57M空间,假如申请了64M,那么就会失败了。

 

开机分配使用掉vmalloc之后到底该剩余多少目前没有具体依据,一般来说1GB RAM可以设置为400~600M。

 

 

Ref:

http://www.ibm.com/developerworks/cn/linux/l-33linuxkernel/

http://www./wiki/Common_Problem:_vmalloc_too_small

http://www./docs/4/4.5/Reference_Guide/s2-proc-meminfo.html


2013/11/14

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约