一、slab相关数据结构


1)slab高速缓存描述符

  1. struct kmem_cache {   
  2.     struct array_cache   *array[NR_CPUS];//为了提高效率,每个cpu都有一个slab空闲对象缓存   
  3. /* 2) Cache tunables. Protected by cache_chain_mutex */   
  4.     unsigned int batchcount;//从本地高速缓存批量移入或移出对象的数目   
  5.     unsigned int limit;//本地高速缓存空闲对象的最大数目   
  6.     unsigned int shared;   
  7.     unsigned int buffer_size;   
  8.     struct kmem_list3 *nodelists[MAX_NUMNODES];//slab高速缓存空闲,部分空闲,无空闲slab的三个链表   
  9.    
  10.     unsigned int flags;     /* constant flags */   
  11.     unsigned int num;//每个slab obj的个数   
  12.     unsigned int gfporder;//每个slab中连续页框的数目   
  13.     gfp_t gfpflags;//分配页框时,传递给伙伴系统的标志   
  14.     size_t colour;//slab使用的颜色个数   
  15.     unsigned int colour_off; //slab的颜色偏移   
  16.     struct kmem_cache *slabp_cache;  //指向存放slab描述符的chache,内部slab此字段为null   
  17.     unsigned int slab_size;//单个slab的大小   
  18.     unsigned int dflags;        /* dynamic flags */   
  19.     //对象创建的构建函数   
  20.     void (*ctor) (void *, struct kmem_cache *, unsigned long);   
  21.     //对象的析构函数   
  22.     void (*dtor) (void *, struct kmem_cache *, unsigned long);   
  23.     const char *name;//slab高速缓存的名称   
  24.     struct list_head next;//通过该字段,将该cachep链接到cachep链表上   
  25. }   

2)slab描述符

  1. struct slab {   
  2.     struct list_head list;  //将slab链接到各个slab链表上面,slabs_full, slabs_paril, slabs_free   
  3.     unsigned long colouroff;//slab中第一个对象的偏移   
  4.     void *s_mem; //slab中第一个对象的地址           
  5.     unsigned int inuse; //有多少对象正在被使用   
  6.     kmem_bufctl_t free; //表明接下来使用哪个空闲对象   
  7.     unsigned short nodeid;//该slab属于哪个内存节点   

slab描述符可能会被存放在两个地方:

外部slab描述符:存放在slab外部,位于cache_size指向的一个普通高速缓存中。

内部slab描述符:存放在slab的内部,位于分配给slab的内存的第一个页框的起始位置。

3)slab队列描述符

  1. struct kmem_list3 {   
  2.     struct list_head slabs_partial; //对象被使用了一部分的slab描述符的链表   
  3.     struct list_head slabs_full;//对象都被占用了的slab描述符的链表   
  4.     struct list_head slabs_free;//只包含空闲对象的slab描述符的链表   
  5.     unsigned long free_objects;//高速缓存中空闲对象的个数   
  6.     unsigned int free_limit;   
  7.     unsigned int colour_next;   /* Per-node cache coloring */   
  8.     spinlock_t list_lock;   
  9.     struct array_cache *shared; //指向所有cpu所共享的一个本地高速缓存 
  10.     struct array_cache **alien; /* on other nodes */   
  11.     unsigned long next_reap;    //由slab的页回收算法使用   
  12.     int free_touched;       //由slab的页回收算法使用   

4)slab对象描述符

  1. typedef unsigned int kmem_bufctl_t; 

每个对象都有一个类型为kmem_bufctl_t的对象描述符,每个slab描述符都有一个kmem_bufctl_t类型的数组来描述slab中的各个对象。其实该描述符记录的是下一个可用的空闲对象,使用了数组的索引来形成一个对象链表而已。对象描述符也分为内部对象描述符和外部对象描述符两种:

slab描述符和slab对象之间的组织图如下图所示:

二、slab的本地对象缓存


Linux2.6为了更好的支持多处理器,减少自旋锁的竞争并更好的利用硬件高速缓存,slab分配器的每个高速缓存都包含一个被称为slab本地高速缓存的每cpu数据结构,该结构由一个指向被释放对象的指针数组组成。这样的话,slab对象的释放和分配就只影响到本地的指针数组,减少了并发性。只有本地数组上溢或者下溢时才会去涉及slab结构。相关数据结构如下:

  1. struct array_cache {   
  2.     unsigned int avail;//本地高速缓存中可用对象的个数,也是空闲数组位置的索引   
  3.     unsigned int limit;//本地高速缓存的大小   
  4.     unsigned int batchcount;//本地高速缓存填充或者清空时使用到的对象个数   
  5.     unsigned int touched;//如果本地高速缓存最近被使用过,置成1   
  6.     spinlock_t lock;   
  7.     void *entry[0];    

同时在多cpu的环境下,还存在着一个共享高速缓存,它的地址被存放在高速缓存描述符的lists.shared字段中,本地共享高速缓存被所有cpu所共享,使得对象从一个本地高速缓存移至另一个高速缓存变的简单。

三、slab内存着色


比如cache line 32 字节,字节0-31一次从内存写入/读取,字节32-63一次从内存写入/读取…..

另外cache对应到内存位置不是任意的

Cache 地址0 对应到 内存地址0 , 32 ,64 ….

Cache 地址1 对应到 内存地址1 , 33 ,65 ….

一个slab大小肯定是整数页,所以起始地址末12位为零, 即都于cache0 对应。然后2个slab的每一个obj大小一样, 所以2个slab每个obj都对应相同的cache line.这样2个位置相同的obj都要频繁访问,比较容易使cache来回刷新,效率降低。

着色就是在第二个slab的起始位置空一个cache line出来,这样2个slab每个obj对应的cache错开一个,这样2个位置相同的obj即使频繁访问,也不会用一个相同cache line。

但是这种方法也是有限的,2个slab里面的obj对象的访问比较随即,不能保证哪两个在一个cache line 里。


相关内容