Jemalloc 初始化(二) index2size和size2index解析

前面没有分析完 Jemalloc 初始化,是因为遇到了一个表不得其解,所以停下来分析,这是一个精妙的算法,通过index可以算出size,通过size也可以算出index。

我是从size推算index开始研究的

注释的数是在以下推导的基础上填的
#define    SIZE_CLASSES \
  /* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \
    SC(  0,      3,        3,      0, yes,  3) \ 1-8
    SC(  1,      3,        3,      1, yes,  3) \ 9-16
    SC(  2,      3,        3,      2, yes,  3) \ 17-24
    SC(  3,      3,        3,      3, yes,  3) \ 25-32
                                               \---------------------分割线以下适合用公式
    SC(  4,      5,        3,      1, yes,  3) \ 33-40
    SC(  5,      5,        3,      2, yes,  3) \ 41-48
    SC(  6,      5,        3,      3, yes,  3) \ 49-56
    SC(  7,      5,        3,      4, yes,  3) \ 57-64
                                               \
    SC(  8,      6,        4,      1, yes,  4) \ 65-80 size
    SC(  9,      6,        4,      2, yes,  4) \ 81-96 size
    SC( 10,      6,        4,      3, yes,  4) \ 97-112
    SC( 11,      6,        4,      4, yes,  4) \ 113-128
                                               \
    SC( 12,      7,        5,      1, yes,  5) \ 129-160
    SC( 13,      7,        5,      2, yes,  5) \ 161-192
    SC( 14,      7,        5,      3, yes,  5) \ 193-224
    SC( 15,      7,        5,      4, yes,  5) \ 225-256
                                               \
    SC( 16,      8,        6,      1, yes,  6) \
    SC( 17,      8,        6,      2, yes,  6) \
    SC( 18,      8,        6,      3, yes,  6) \
    SC( 19,      8,        6,      4, yes,  6) \
                                               \
    SC( 20,      9,        7,      1, yes,  7) \
    SC( 21,      9,        7,      2, yes,  7) \
    SC( 22,      9,        7,      3, yes,  7) \
    SC( 23,      9,        7,      4, yes,  7) \
                                               \
    SC( 24,     10,        8,      1, yes,  8) \
    SC( 25,     10,        8,      2, yes,  8) \
    SC( 26,     10,        8,      3, yes,  8) \
    SC( 27,     10,        8,      4, yes,  8) \
                                               \
    SC( 28,     11,        9,      1, yes,  9) \
    SC( 29,     11,        9,      2, yes,  9) \
    SC( 30,     11,        9,      3, yes,  9) \
    SC( 31,     11,        9,      4, yes,  9) \
                                               \
    SC( 32,     12,       10,      1, yes, no) \
    SC( 33,     12,       10,      2, yes, no) \
    SC( 34,     12,       10,      3, yes, no) \
    SC( 35,     12,       10,      4, yes, no) \
                                               \
    SC( 36,     13,       11,      1, yes, no) \ 2^13 + 1,2^13 + 1 + 2^11-1=2^13 + 2^11
    SC( 37,     13,       11,      2, yes, no) \ 2^13 + 2^11 + 1, 2^13 + 2^11 + 1 + 2^11 - 1 = 2^13 + 2*2^11
    SC( 38,     13,       11,      3, yes, no) \ 2^13 + 2*2^11 + 1, 2^13 + 3*2^11
    SC( 39,     13,       11,      4,  no, no) \ 2^13 + 3*2^11 +1, 2^13 + 4*2^11 = 2^14

size2index

LOOKUP_MAXCLASS = 4096,4096以内的size才能直接在这个表里查找,否则就是计算
size2index_tab总数是8 +  4*2 + 4*2*2 + ... + 4*2^6 = 512
const uint8_t size2index_tab[] = {
(1,2,...7)
(8,8, 9,9, ..., 11,11)
(12,12,12,12, ...., 15,15,15,15)
...
(64个28, ..., 64个31)
}

size_t ret = ((size_t)(size2index_tab[(size-1) >> LG_TINY_MIN]));
索引(size-1) >> LG_TINY_MIN = (size-1) >> 3最大不会超过512

/* sizeof(void *) == 2^LG_SIZEOF_PTR. */ 3 = log2(8) 2 = log2(4)
#define LG_SIZEOF_PTR 3

/*
 * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size
 * classes).
 */
#define LG_QUANTUM 3

size2index_compute(size_t size)
    size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ?
            (ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
            : lg_floor((size<<1)-1);
        size的二进制表示最高位1是第几位,x的含义就是grp
    size_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 :
            x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM);
        x = 4是个分界点, x = 4能代表的最大数是5个1,即2^5 - 1 = 31
        即如果size < 32, shift = 0,否则shift = x - 5,32 < size <= 64, shift = 1
    size_t grp = shift << LG_SIZE_CLASS_GROUP;
        如果size = 33~64,x = 6,shift = 1,grp = 2^2
        如果size = 65~128,x = 7,shift = 2,grp = 2 * 2^2
        如果size = 129~256,x = 8,shift = 3,grp = 3 * 2^2
    size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
            ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1;
        size <= 32, lg_delta = 3
        size <= 64,x = 6, lg_delta = 3
        size <= 128, x = 7, lg_delta = 4
        size <= 256, x = 8, lg_delta = 5
    size_t delta_inverse_mask = ZI(-1) << lg_delta;
    size_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
        ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
        size = 64,lg_delta = 3, 减一去掉低(3, 4, 5...)位并右移,只取低2位,3
        size = 65,lg_delta = 4, 减一去掉低(3, 4, 5...)位并右移,只取低2位,0
        ...
    size_t index = NTBINS + grp + mod;
        NTBINS = 0, 实际index = grp + mod
        size = 64,4 + 3 = 7
        size = 65, 8 + 0 = 8, 66, 8 +0 = 8,...,80, 8 + 0 = 8, [65-80] 这16个数共享8这个index
        [81-96]这16个数共享9,[65-128]总共64,分成4组,共享4个index    
        [129-256]有128个数,划分成每份32,也是4组,[129-160]共享12,依次类推

结合上面的表可知各字段的含义
index:表中的索引
lg_grp:size-1的最高位1是第几位,从右往左数,从0开始
lg_delta:2^lg_delta个数共享1个index
ndelta:组内几个偏移单位

通过size可以计算出grp和mod,加和为index

size2index分析结束

下面分析index2size

通过index计算size也有一张表,他里面的size是代表这个index的最大size(结合上面表中添加的注释可以知道)
index2size_tab = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, ...
计算方法((ZU(1)<<lg_grp) + (ZU(ndelta)<<lg_delta)),即2^lg_grp + ndelta * 2^lg_delta
但这是知道lg_grp和lg_delta,以及ndelta的前提下可以快速计算的,通过一个index能不能计算呢

通过index,不查表,也可以计算出grp和mod
因为index的后两位是mod,前面的是grp
size_t reduced_index = index - NTBINS;
size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; 这里的grp是上面的shift
size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
index= 0,grp=0,mod=0
index= 1,grp=0,mod=1
index= 2,grp=0,mod=2
index= 3,grp=0,mod=3

index= 4,grp=1,mod=0
index= 5,grp=1,mod=1
index= 6,grp=1,mod=2
index= 7,grp=1,mod=3

index= 8,grp=2,mod=0
index= 9,grp=2,mod=1
....

size_t grp_size_mask = ~((!!grp)-1);
size_t grp_size = ((ZU(1) << (LG_QUANTUM + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask;
index= 0,grp_size_mask=0x0, grp_size= 0
index= 1,grp_size_mask=0x0, grp_size= 0
index= 2,grp_size_mask=0x0, grp_size= 0
index= 3,grp_size_mask=0x0, grp_size= 0

index= 4,grp_size_mask=0xffffffff, grp_size= 32
index= 5,grp_size_mask=0xffffffff, grp_size= 32
index= 6,grp_size_mask=0xffffffff, grp_size= 32
index= 7,grp_size_mask=0xffffffff, grp_size= 32

index= 8,grp_size_mask=0xffffffff, grp_size= 64
index= 9,grp_size_mask=0xffffffff, grp_size= 64
....

size_t shift = (grp == 0) ? 1 : grp;
size_t lg_delta = shift + (LG_QUANTUM-1);
size_t mod_size = (mod+1) << lg_delta;

index= 0,shift=1, lg_delta=3 , mod_size=8
index= 1,shift=1, lg_delta=3 , mod_size=16
index= 2,shift=1, lg_delta=3 , mod_size=24
index= 3,shift=1, lg_delta=3 , mod_size=32

index= 4,shift=1, lg_delta=3 , mod_size=8
index= 5,shift=1, lg_delta=3 , mod_size=16
index= 6,shift=1, lg_delta=3 , mod_size=24
index= 7,shift=1, lg_delta=3 , mod_size=32

index= 8,shift=2, lg_delta=4 , mod_size=16
index= 9,shift=2, lg_delta=4 , mod_size=32
....

size_t usize = grp_size + mod_size;
index= 0,size=8
index= 1,size=16
index= 2,size=24
index= 3,size=32

index= 4,size=32 + 8=40
index= 5,size=32 + 16 = 48
index= 6,size=32 + 24 = 56
index= 7,size=32 + 32 = 64

index= 8,size=64 + 16 = 80
index= 9,size=64 + 32 = 96
....


还有个函数s2u_compute,他的结果是index2size_lookup的结果,即一个分组的内部分组的最大值
s2u_compute(35584)
size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ?
            (ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1))
            : lg_floor((size<<1)-1); //16
size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1)
    ?  LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; //13
size_t delta = ZU(1) << lg_delta;
size_t delta_mask = delta - 1; //13个1
size_t usize = (size + delta_mask) & ~delta_mask; // 13位对齐,2^13大小对齐
return (usize);

以下面这组数据为例
SC(  4,      5,        3,      1, yes,  3) \ 33-40,33-39都让它变成40(按8字节对齐)
SC(  5,      5,        3,      2, yes,  3) \ 41-48
SC(  6,      5,        3,      3, yes,  3) \ 49-56
SC(  7,      5,        3,      4, yes,  3) \ 57-64

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值