• 社区 —频道 春城壹网 七彩云南 一网天下 2019-03-17
  • 陈坤9年之后重回小荧屏 2019-03-17
  • 医院建在“云端”上(聚焦·互联网医院新观察(上)) 2019-03-09
  • 山东十一选五专家杀号 Chinaunix首页 | 论坛 | 山东十一选五专家杀号
    • 博客访问: 1849344
    • 博文数量: 524
    • 博客积分: 11908
    • 博客等级: 上将
    • 技术积分: 5485
    • 用 户 组: 普通用户
    • 注册时间: 2009-04-03 15:50
    文章分类

    全部博文(524)

    文章存档

    2019年(2)

    2013年(4)

    2012年(71)

    2011年(78)

    2010年(58)

    2009年(311)

    分类: LINUX

    2019-03-04 23:12:14

    在Linux中,per-cpu变量用在多处理器系统中,用来为系统中的每个cpu都生成一个变量的副本,以避开多处理器互斥中的加锁问题,另一个是cpu本地的变量可以充分利用cpu的硬件缓存,提高性能。本贴讨论一下Linux内核对per-cpu变量的代码实现。

    1.静态per-cpu变量
    静态per-cpu变量通过DEFINE_PER_CPU和DECLARE_PER_CPU宏在内核源码中定义和声明一个per-cpu变量。这些变量与普通变量的主要区别是放在一个特殊的section里。
    静态percpu变量比较好理解,内核的代码也比较简洁明快。

    相对静态per-cpu变量,还有动态分配的per-cpu变量。普通变量动态分配很简单,用kmalloc或者kzalloc都可以的,其实per- cpu变量的动态分配也是需要利用Linux内核底层的分配函数,页面分配器。从这个角度而言,percpu memory allocator与slab memory allocator是一个层面的东西,都建立在page memory allocator基础之上。不过对于大部分驱动程序员而言,使用kmalloc与kzalloc的机会要远远大于percpu memory allocator。

    为了描述,这里做个定义,CPU0与CPU1变量副本的空间大小完全一样,本贴统称这两个副本空间为副本空间,每个CPU变量副本所在空间为单元空间。
    在内核初始化期间调用的setup_percpu_areas函数中,reserve和dynamic空间大约定义的大小是8KB和12KB,static空间由系统中定义的静态per-cpu变量的多少来决定。

    Linux内核对percpu memory allocator使用了所谓chunk的实现方式,它实现了统一的静态per-cpu和动态per-cpu变量的实现(其实静态per-cpu变量的实 现不需要chunk,但是为了统一,也把它放到chunk的管理体系,就算是大一统吧).

    chunk干什么事呢?chunk是一个管理数据结构,就称之为容器吧??纯淳咛宓氖萁峁够故呛苡斜匾?/span>

    点击(此处)折叠或打开

    1. struct pcpu_chunk {
    2.             struct list_head list; /* linked to pcpu_slot lists */
    3.             int free_size; /* free bytes in the chunk */
    4.             int contig_hint; /* max contiguous size hint */
    5.             void *base_addr; /* base address of this chunk */
    6.             int map_used; /* # of map entries used */
    7.             int map_alloc; /* # of map entries allocated */
    8.             int *map; /* allocation map */
    9.             void *data; /* chunk data */
    10.             bool immutable; /* no [de]population allowed */
    11.             unsigned long populated[]; /* populated bitmap */
    12.     };
    list:用来把chunk链接起来形成链表。每一个链表又都放到pcpu_slot数组中,根据chunk中空闲空间的大小决定放到数组的哪个元素中。
    contig_hint:该chunk所管理的副本空间中空闲空间大小。
    base_addr:简单地说,副本空间首地址。副本空间也是由一个chunk来管,称之为first chunk中,副本空间中的dynamic空间用来给动态per-cpu变量使用
    map_used:为了对chunk所管理的副本空间分配情况的跟踪,用来表示可以管理的个数
    map_alloc:已经分配的小块个数,因为每个分配的小块都是给动态per-cpu使用的,所以其实是已经分配的变量的个数
    map:整数数组,用来表示副本空间分配情况。正数表示该空间空闲,负数就已经分配给一个变量了
    data:指向分配的页数据
    大体上就这些。

    动态分配一个per-cpu变量时,在pcpu_slot空间查找空闲空间可以满足需要的chunk,如果找不到这样的chunk,那么重新分配一个chunk,用kzalloc函数。
    对一个新的chunk都会调用pcpu_get_vm_areas分配VM空间地址:

    点击(此处)折叠或打开

    1. static struct pcpu_chunk *pcpu_create_chunk(void)
    2.     {
    3.             struct pcpu_chunk *chunk;
    4.             struct vm_struct **vms;

    5.             chunk = pcpu_alloc_chunk();
    6.             if (!chunk)
    7.                     return NULL;

    8.             vms = pcpu_get_vm_areas(pcpu_group_offsets, pcpu_group_sizes,
    9.                                     pcpu_nr_groups, pcpu_atom_size, GFP_KERNEL);
    10.             if (!vms) {
    11.                     pcpu_free_chunk(chunk);
    12.                     return NULL;
    13.             }

    14.             chunk->data = vms;
    15.             chunk->base_addr = vms[0]->addr - pcpu_group_offsets[0];
    16.             return chunk;
    17.     } static struct pcpu_chunk *pcpu_create_chunk(void)
    18.     {
    19.             struct pcpu_chunk *chunk;
    20.             struct vm_struct **vms;

    21.             chunk = pcpu_alloc_chunk();
    22.             if (!chunk)
    23.                     return NULL;

    24.             vms = pcpu_get_vm_areas(pcpu_group_offsets, pcpu_group_sizes,
    25.                                     pcpu_nr_groups, pcpu_atom_size, GFP_KERNEL);
    26.             if (!vms) {
    27.                     pcpu_free_chunk(chunk);
    28.                     return NULL;
    29.             }

    30.             chunk->data = vms;
    31.             chunk->base_addr = vms[0]->addr - pcpu_group_offsets[0];
    32.             return chunk;
    33.     }
    pcpu_group_offsets[0]对于非变态的系统都是0.

    所以,动态分配per-cpu变量时,先在chunk所管理的副本空间(在VM区中),然后用到哪个页面就往那个对应的vm上提交物理页面。
    副本空间上实行小额分配,实际上就是有新变量分配,就在副本空间里头找,找到以后看这个vm处的地址有没有被映射到物理地址,没有就提交页面,否则不提 (都提了干吗还提交呢??。?,判断vm处是否提交了物理页面用bit map跟踪,chunk的数据结构中的后两个成员用来干这事。

    OK,分配一个新变量之后,返回给你的是一个vm区中的地址,要让每个cpu访问到自己的vm区,得用内核自己定义的宏,其实核心思想就是用smp_get_processorid等来获得对应cpu变量在变量副本中的偏移地址,然后返回来了。

    要想验证上面说的对不对,可以在内核中打印出alloc_percpu返回的地址,是否在VM区。

    FQA

    访问per-cpu变量为什么要禁止内核抢占?
    这个和进程迁移相关。如果访问per-cpu变量的进程被抢占(如发生中断而重新调度),该进程已经得到自己per-cpu变量副本的偏移地址,当它被恢复执行并有可能迁移到别的CPU上,这时候该偏移地址对新的CPU是无效的。
    per-cpu变量还需要?;ぢ??
    per-cpu 变量虽然能?;け淞勘欢喔鯿ore 访问,但是它并不能?;ね缓诵纳弦觳绞录姆梦?,如ISR,deferred functions。在这样的情况下,同步原语还是需要的。

    ----------------------------------------------------
    struct module 中有个percpu变量,不知道如何用!
    如在load_module 函数实现中:
    ......
            if (pcpuindex) {
                    /* We have a special allocation for this section. */
                    percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
                                             sechdrs[pcpuindex].sh_addralign,
                                             mod->name);
                    if (!percpu) {
                            err = -ENOMEM;
                            goto free_mod;
                    }
                    sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
                    mod->percpu = percpu;        
    ......
    }
    -------------------------------------------------------------------

    ??榈膒er-cpu  section是ELF文件中一个特殊的section,属于data区,??榧釉厥?,会根据系统中CPU个数,将这个 section中的数据复制相应的份数,存放在CORE section区域。这个主要在SMP系统中,不同CPU可以访问??閜er-cpu section中的数据而无需使用CPU间的互斥机制。
    也谈不上什么高级的用法,跟内核中定义的per-cpu变量没有任何区别,只不过平时很少使用到。在??槔锩婕由?/span>
    DEFINE_PER_CPU(int, hea);

    再readelf -S xxx.ko就可以看到这个per-cpu section了。内核因为自己在初始化时对这些静态定义的per-cpu变量进行了复制,??橐蛭挥姓飧鼋锥?,所有由内核??榧釉仄骼赐瓿?。此处讨论仅限于静态定义的per-cpu变量,因为动态分配的话,本身就会产生多个副本空间,这个无论对于内核还是??槎纪耆谎幕?,所以不会有这个问题。
    阅读(1845) | 评论(1) | 转发(0) |
    给主人留下些什么吧!~~

    embededgood2019-03-04 23:12:59

    好文章

    评论热议
    请登录后评论。

    登录 注册

  • 社区 —频道 春城壹网 七彩云南 一网天下 2019-03-17
  • 陈坤9年之后重回小荧屏 2019-03-17
  • 医院建在“云端”上(聚焦·互联网医院新观察(上)) 2019-03-09