Solaris Slab Allocator–Magazines[2]

原创 2011年01月07日 16:39:00

Thrashing

Wikipedia上的解释:Thrash(computer_science) 。我在这里就暂时叫做"抖动"吧。

首先从我的理解说一下为什么在CPU Layer和Slab Layer之间要有一个Depot Layer。从slab layer拿到的是slab, slab layer和cpu layer都没有把slab切分成magazine的逻辑。还有一点就是我们知道cpu layer中每个magazine中的slots越多(M越大),cache命中率就越高,代价是内存消耗越多。如何确定M的大小,也是放在depot layer来完成的。

现在的逻辑是这样的,depot layer中维护了一个full magazine list和一个empty magazine list。为什么depot不是只维护一个full_magazine_list呢?以cache_cpu[0]为例:

  • 如果当前的magazine是empty的,现在需要分配一个新的object,cache_cpu[0] 就从full magazine list中拿一个full magazine下来作为新的当前magazine,把该full magazine的第一个object分配出去。然后把empty的magazine还给depot layer。
  • 如果当前的magazine是full的,现在application free了一个object, 试想如果只有full_magazine_list的话,我们把新释放的object放在哪里呢?关键在于magazine其实是个逻辑容器,我们需要一个空的逻辑容器来容纳新释放的object。

但是,我们来看这样一种情况:

image

上图的情况就是thrashing。如果当前magazine为empty,需要alloc,于是造成一次cache miss,从depot load一个新的full magazine并还给depot一个empty magazine,然后接着free 两次,造成第二次miss cache,从depot load一个empty magazine并且还给depot一个full magazine。4次alloc/free,2次miss, miss rate=50%

解决的方法是这样的,注意到,在thrashing的时候,要么是用一个full magazine换回一个empty magazine;要么是用一个empty magazine换回一个full magazine。于是我们在cache_cpu中保存两个magazine,current_magazine和previous_magazine。

先paste一下cache_cpu的数据结构:
typedef struct umem_cpu_cache {
     mutex_t     cc_lock;     /* protects this cpu’s local cache */
     uint_t        cc_alloc;    /* allocations from this cpu */
     uint_t        cc_free;     /* frees to this cpu */
     umem_magazine_t    *cc_loaded ;      /* the currently loaded magazine */
     umem_magazine_t    *cc_ploaded;     /* the previously loaded magazine */
     int        cc_rounds ;     /* number of objects in loaded mag */
     int        cc_prounds ;    /* number of objects in previous mag */
     int        cc_magsize;    /* number of rounds in a full mag */
     int        cc_flags;        /* CPU-local copy of cache_flags */
#ifndef _LP64
     char        cc_pad[UMEM_CPU_PAD]; /* for nice alignment (32-bit) */
#endif
} umem_cpu_cache_t;

看分配alloc的算法, 在_umem_cache_alloc中
void * buf;
umem_cpu_cache_t* fmp;
retry:
umem_cpu_cache_t *ccp = UMEM_CPU_CACHE(…); //拿到当前CPU的cache_cpu数据结构
(void) mutex_lock(&ccp->cc_lock);                       //只负责该CPU上的同步
for(;;) {                                                           //其实这里的for是一个简单的状态机的实现
       //情况1:如果当前的magazine不为空
       if(ccp->cc_rounds > 0) {  //如果当前的magazine不为空
           buf = ccp->cc_loaded->mag_round[--ccp->cc_rounds]; //弹出一个object返回
           ccp->cc_alloc++;        //总分配数++
           (void)mutex_unlock(&ccp->cc_lock); //该CPU内共享的数据结构操作完成,解锁
           return (buf);              //返回当前magazine中的一个object
       }
       //情况2: 当前的magazine为空,但是previous magazine不为空
       if(ccp->cc_prounds > 0){  //previous magazine不为空
            umem_cpu_reload(ccp,ccp->cc_ploaded,ccp->cc_prounds); //交换当前magazine和prevous
            continue;                  //使用continue,使其在下次的尝试中落入情况1。
        }

        //情况3: current 和previous magazine都为空
        fmp = umem_depot_alloc(cp,&cp->cache_full); //问depot layer拿一个full magazine
        if(fmp !=NULL){ //如果depot layer 还有 full magazine
              if(ccp->cc_ploaded != NULL){
                    // 将previous empty magazine还给depot empty magazine
                    umem_depot_free(cp,&cp->cache_empty,ccp->cc_ploaded);
               }
               //交换 当前magazine和刚从depot拿到的full magazine
               umem_cpu_reload(ccp,fmp,ccp->cc_magsize);
               continue;            //使用continue,使其在下次的尝试中落入情况1。
        }
        //情况4:如果很不巧,连depot layer都没有full magazine了,拿只好动用slab layer了
        break;
}
(void)mutex_unlock(&ccp->cc_lock);
//下面的代码是处理情况4的…
……

释放的代码是类似的,我就不贴了。下面是原文中用于描述算法的伪代码,贴在这里作为参考。

image

有了这样的防抖动算法,cache的命中率最差也是1/M。而且我觉得这样的思路很经典,也很常用。下一篇笔记介绍在引入magazine layer以后object construction的策略。

 

 

相关文章推荐

Solaris Slab Allocator –Magazines[1]

Overview经典的slab allocator算法在多CPU系统中scalability不是很好,因为它的slab list是一个全局结构,分配和释放的时候需要一个global lock来...

Solaris Slab Allocator–Magazines[3]

Posted on十一月 4, 2008byarrowpig1979Object Construction经典的slab allocator在slab创建的时候给slab中的每个object应用c...

memcached源码分析之内存管理 -- Slab Allocator(2)

Slab Allocator源码分析: 前言:虽然会对slab allocator的所有代码进行注释解说,但是slab allocator的很多代码都是与slab的状态获取相关,那些函数不是我们分析的...

memcached_allocator_slab_langwan

  • 2012年08月22日 16:54
  • 700KB
  • 下载

zz : memcached源码学习-内存管理机制slab allocator

zz : http://blog.csdn.net/tankles/article/details/7027645 前端时间大致浏览了一下memcached的源码,但是并没有对相关的知识...

Memcached内存分配机制—— Slab Allocator

Memcached数据存储方式 Memcached的内存数据存储方式被称为 Slab Allocator(对象缓存分配)。采取的思想可以理解为化整为零。就是将内存进行多层次的拆分,达到对对象和内存...

Slab Allocator内存管理原理

原始出处:http://blog.sina.com.cn/s/blog_72995dcc01018t2t.html Slab Allocator(对象缓存分配) The fun...

memcache学习——内存管理机制slab allocator

大致浏览了一下memcached的源码,但是并没有对相关的知识点进行总结和记录,所以很快就忘了,这次打算将memcached的源码再学习一遍,并进行总结归纳。 memcached模块化设计比较好...

memcached源码学习-内存管理机制slab allocator

前端时间大致浏览了一下memcached的源码,但是并没有对相关的知识点进行总结和记录,所以很快就忘了,这次打算将memcached的源码再学习一遍,并进行总结归纳。     memcached模块...
  • tankles
  • tankles
  • 2011年11月30日 22:01
  • 3112
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Solaris Slab Allocator–Magazines[2]
举报原因:
原因补充:

(最多只允许输入30个字)