分享

slab分配器简明分析

 ShangShujie 2012-04-26
这还是暑假之前写的总结... 这几天一个kernel群里老有人问关于slab方面的问题... 所以就在这里把些的总结贴一下... 献丑了...

Slab Allocator 逻辑结构如下图所示:
cache_slab.png
如图,主要结构包括 cache 以及 slabs。故相应的数据结构有 cache 描述符和 slab 描述符。
cache 描述符
          struct kmem_cache_s {
               /* full, partial first, then free */
               struct list_head         slabs_full;
               struct list_head         slabs_partial;
               struct list_head         slabs_free;
               unsigned int             objsize;
            unsigned int         flags;     /* constant flags */
            unsigned int         num;       /* # of objs per slab */
            spinlock_t           spinlock;
      #ifdef CONFIG_SMP
            unsigned int         batchcount;
      #endif
            unsigned int         gfporder;
            unsigned int         gfpflags;
            size_t               colour;         /* cache colouring range */
            unsigned int         colour_off;     /* colour offset */
            unsigned int         colour_next; /* cache colouring */
            kmem_cache_t               *slabp_cache;
            unsigned int         growing;
            unsigned int         dflags;         /* dynamic flags */
            /* constructor func */
            void (*ctor)(void *, kmem_cache_t *, unsigned long);
            /* de-constructor func */
            void (*dtor)(void *, kmem_cache_t *, unsigned long);
            unsigned long        failures;
            char           name[CACHE_NAMELEN];
            struct list_head     next;
      #ifdef CONFIG_SMP
            cpucache_t           *cpudata[NR_CPUS];
      #endif
      #if STATS
            unsigned long        num_active;
            unsigned long        num_allocations;
            unsigned long        high_mark;
            unsigned long        grown;
            unsigned long        reaped;
            unsigned long              errors;
      #ifdef CONFIG_SMP
            atomic_t       allochit;
            atomic_t       allocmiss;
            atomic_t       freehit;
            atomic_t       freemiss;
      #endif
      #endif
};
各个字段含义如下:
slab_*                  保存slabs的链表,如上图,full、partial和empty。
objsize                 装入缓存器中的每个”对象”的大小。
flags                   决定当处理这个缓存器时,分配器的部分行为。见8.1.2
num                     每个slab包含的”对象”的数量
  spinlock             保护这个结构的自旋锁,防止并发访问
  batchcount           决定对于每个CPU的缓存器,一次所分配的”对象”的数量
  gfporder             表示slab的页面的数量。每slab有2^gfporder个页面。因为这
                       是伙伴分配器所提供的分配大小。
  gfpflags             保存当调用伙伴分配器分配页面时所用到GFP标识。
  colour               每个slab会尽可能的将”对象”保存到不同的高速缓存行。缓存器着色
                       会在8.1.5节深入讨论。
  colour_off           保持slabs对齐到的字节数。例如,对于size-X缓存器里的slab会对齐到
                       L1高速缓存。
  colour_next          下一个要使用的颜色行。当这个值达到colour时就会反绕到0。
  growing              设置这个标识可以表示这个缓存器的大小是否增加了。如果增加了,
                       则在内存紧张时,选择它来获取空闲的slabs的可能性会更小。
  dflags               在缓存器存在期间会改变的动态标识。
  ctor                 一个复杂的”对象”可以可选的提供一个构造函数来初始化每个新
                       的”对象”。这是指向那个函数的指针,而且可以是NULL。
  dtor                 析构函数的指针,可以是NULL。
  failure              在代码中不在使用这个字段,因此都初始化为0。
  name                 每个缓存器的名称
  next                 缓存器链表上的下一个缓存器。
  cpudata              每CPU数据,指向描述一小组可用”对象”的管理结构。
  num_active           在缓存器中当前活跃的”对象”的数量
  num_allocations      在缓存器中已经分配了的”对象”的数量的总数。
  high_mark            num_active能够达到的最大的值
  grown                kmem_cache_grow()被调用的次数
  reaped               缓存器被释放的次数
  allochit             分配时,从每CPU缓存中分配”对象”的次数
  allocmiss            与allochit相反
  freehit              将”对象”释放到每CPU缓存中的次数
  freemiss             与freehit相反。
  这个结构相当的大,Slab Allocator中对每种”对象”都有一个对应的cache。每个cache管理
  多个slab。Slab才是真正存放”对象”的地方。管理这些”对象”的结构就是slab描述符。
  Slab 描述符

  typedef struct slab_s {
        struct list_head    list;
        unsigned long       colouroff;
        void           *s_mem;          /* including colour offset */
        unsigned int        inuse;           /* num of objs active in slab */
        kmem_bufctl_t             free;
  } slab_t;
  各个字段含义如下:
  list                 此 slab 所属于的链表。这个字段是在缓存器中的 slab_full 或者
                       slab_patial 或者 slab_free 上。
  colouroff            这是离在 slab 中的第一个”对象”的基址的着色偏移值。                          第一个对象的
                     地址是 s_mem + colouroff。
  s_mem              给出在 slab 中第一个”对象”的起始地址。
  inuse              在 slab 中的活跃”对象”的个数。
  free               存储空闲”对象”的 bufctls 数组。参见 8.2.3 中的详细介绍。
  这个结构仅仅是用来管理”对象”的,在创建 slab 时需要分配存放”对象”的内存,所需内存
  从 buddy allocator 中申请,内存大小为其所属 cache 中 gfporder 指定。显然,所申请的内
  存是连续的 2^cachep->gfporder 个页面。Slab 描述符可以存放在这个所分配的内存起始
  处,也可以放在另外的地方。如图:
slab_pos1.png
slab_pos.png
通用缓存器组
  typedef struct cache_sizes {
       size_t         cs_size;
       kmem_cache_t       *cs_cachep;
       kmem_cache_t       *cs_dmacachep;
  } cache_sizes_t;
  各字段含义如下:
  cs_size              这个通用缓存器的大小
  cs_cachep            用于在普通内存中分配”对象”的缓存器指针
  cs_dmacachep         用于在 DMA 内存中分配”对象”的缓存器指针
  在系统中静态定义了这个类型的一个数组,其主要为大小不定的一些通用结构分配内存。
  例如,如过 Slab 描述符的位置是 Off_Slab,则这个 Slab 描述符以及其后的 kmem_bufctl_t[]
  就放在这个通用缓存器组中的某一个缓存器里。
下面所要将到的数据结构是针对 SMP 系统进行优化所用到的数据结构:
每 CPU cache
  typedef struct cpucache_s {
        unsigned int avail;
        unsigned int limit;
  } cpucache_t;
  avail      在这个 cpucache 上空闲”对象”的数量。
  limit      可以存在的空闲”对象”的总数。
  每个 CPU 都有一个对应的小的本地 cache,这个 cache 并不是上面所提到的 cache 描述符。
  这个 cache 仅仅是特定于某个 cache 描述符所管理的”对象”的数组。如 mm_struct 相关
  的 cache 描述符所管理的”对象”就是 mm_struct 类型的,则这个 CPU 的本地 cache 就是
  mm_struct 类型的数组。在为某 CPU 分配 cpucache_t 结构时,除了分配 cpucache_t 结构
  所需要的内存外,也分配 limit*sizeof(void *)字节的内存。当然,它们是连续的。
  如代码所示:
             ccnew = kmalloc(sizeof(void*)*limit+
                       sizeof(cpucache_t), GFP_KERNEL);
  ccnew 就是 cpucache_t *类型。
  因此 cpucache_t 结构后面就是 limit 个 void 类型的指针。                 所以 avail 还有一个作用就是作
  为空闲”对象”的索引。如在从这个 CPU 本地 cache 分配一个”对象”时就有如下代码:
             obj = cc_entry(cc)[--cc->avail];
  其中:
             #define cc_entry(cpucache) \
                  ((void **)(((cpucache_t*)(cpucache))+1))
  这个代码就可以解释上面所说的一切。
  更新每 CPU cache 信息所用到的数据结构

  typedef struct ccupdate_struct_s
  {
        kmem_cache_t *cachep;
        cpucache_t *new[NR_CPUS];
  } ccupdate_struct_t;
  cachep 是正在被更新的缓存器的指针,new 是系统中每个 CPU 的 cpucache 描述符的数组。
  当然仅有在 SMP 系统上设置 SMP 选项时才可用。
  在每 CPU cache 信息改变之后,在更新每个 CPU cache 信息时就不需要考虑并发性带来
  的一致性问题,因为每个 CPU 只为从对应的 ccpudata_struct_t->new[ID]中获取新信息来
  更新自己本地的 cache。这样就不需要用自旋锁来保护。

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多