DPDK在申请内存池时,会对OBJ大小进行重新计算
rte_mempool_create_empty
— rte_mempool_calc_obj_size
—> rte_mempool_calc_obj_size
最终进行重计算的函数是
/*
* Depending on memory configuration on x86 arch, objects addresses are spread
* between channels and ranks in RAM: the pool allocator will add
* padding between objects. This function return the new size of the
* object.
*/
static unsigned int
arch_mem_object_align(unsigned int obj_size)
{
unsigned nrank, nchan;
unsigned new_obj_size;
/* get number of channels */
nchan = rte_memory_get_nchannel();
if (nchan == 0)
nchan = 4;
nrank = rte_memory_get_nrank();
if (nrank == 0)
nrank = 1;
/* process new object size */
new_obj_size = (obj_size + RTE_MEMPOOL_ALIGN_MASK) / RTE_MEMPOOL_ALIGN;
while (get_gcd(new_obj_size, nrank * nchan) != 1)
new_obj_size++;
return new_obj_size * RTE_MEMPOOL_ALIGN;
}
根据注释,此函数是让对象的首地址均匀的落在内存的channels和ranks中(X86平台下)。
对象的首地址均匀分布在channel中可以理解,因为内存通道可以并行访问,同时读写多个对象,提升性能。
然而一个通道中的Ranks是不能并行的,那为什么还要按照均匀分布在Ranks中呢。
因为Rank Interleaving,当一个Rank正在refresh的时候,另一个Rank是可以被访问的,也可以提升对象的读写性能。
因此,以Channel + Rank作为分布的基本单位。
Like this:
chan[0]rank[0]
chan[0]rank[1]
chan[1]rank[0]
chan[1]rank[1]
…
1.获取到当前rank和channel数量
2.对象大小以RTE_MEMPOOL_ALIGN为单位计算,这次CPU一次从缓存写入内存的Size.
RTE_MEMPOOL_ALIGN -->RTE_CACHE_LINE_SIZE 64
3.累加对象大小,直到新的大小与rank*channel最大公约数为1
其中,get_gcd()函数是欧几里得最大公约数算法实现。
/*
* return the greatest common divisor between a and b (fast algorithm)
*
*/
static unsigned get_gcd(unsigned a, unsigned b)
{
unsigned c;
if (0 == a)
return b;
if (0 == b)
return a;
if (a < b) {
c = a;
a = b;
b = c;
}
while (b != 0) {
c = a % b;
a = b;
b = c;
}
return a;
}
两者最大公约数为1,等价于new_obj_size与 rank*chan互质。
当新的对象大小与rank*chan互质时,申请n个对象,每个对象的首地址会在rank * chan上均匀分布。
为什么obj_size与rank*chan互质,则N个对象的首地址会均匀分布呢?
换言之,假设A 与 B 互质,那么 N*A(N为正整数) mod B的结果会是均匀的吗?
举个例子看看
互质数 9 mod 4 = 1, 2 * 9 mod 4 = 2 , 3 * 9 mod 4 = 3, 4 * 9 mod 4 = 0 , 结果 0,1,23
不互质 10 mod 4 = 2 , 2 * 10 mod 4 = 0 , 3 * 10 mod 4 = 2, 4 * 10 mod 4 = 0 结果 0,2
看起来AB两数互质能取所有值[0, B-1],而不互质的数只能取到有限值。
那如何用数学证明呢,暂时我还证不出来,希望有大佬不吝赐教。