在 BiscuitOS / Linux 上使用 kmem_cache_create() 创建缓存时,需要根据分配的对象的大小从 Buddy 分配器中获得空闲页来组成 slab page.
例如:
struct kmem_cache *file_cachep = kmem_cache_create("File",sizeof(struct file),0,0,NULL);
内核通过 sizeof(struct file) 计算的值将从 Buddy 中获得的空闲页,然后将空闲页分成大小为 sizeof(struct file) 的 object.
储存这些 object 的 page 称为 slab page.本帖用于讨论一个 slab page 的大小.
内核根据 object 的 size 来计算 slab page 的大小,
1. 如果 object 的 size 很小,那么一个 slab page 就由一个 page 组成
2. 如果 object 的 size 很大,那么一个 slab page 可能有两个或多个 page 组成.
Slab page 的大小计算如下:
1. 在 slub 中一个 slab page 中规定最小的 object 数量为 slub_min_objects,其值可以为零,
当 slub_min_objects 为零的时候,内核根据 cpu 的数量来进行赋值,其计算公式如下:
slub_min_objects = 4 * (fls(nr_cpu_ids) + 1)
其中函数 fls() 的作用是求参数的最高位的位数,如
fls(00001100B) = 4
fls(00001000B) = 4
fls(00010000B) = 5
fls() 的作用类似于向下除的效果.
nr_cpu_ids 为系统 cpu 的个数.
于是我们可以得出以下结论:
(1) 在单 CPU 的体系中 slub_min_objects 为 8
(2) 在双 CPU 的体系中 slub_min_objects 为 12
(3) 在四 CPU 的体系中 slub_min_objects 为 16
2. 一个 slab page 最大 objects 数量为 max_objects,其计算如下:
max_objects = (PAGE_SIZE << slub_max_order) / size;
max_objects = min(min_objects,max_objects);
上述表达式中 slub_max_order 为 3,其含义为最大的 slab_page 为 2^3,也就是 一个最大的 slab_page 可由 8 page 构成.
size 为 object 的 size.
3. 获得上面两个值之后,内核进行 slab order 的计算,其过程如下:
(1) 对一个 page 构成的 slab page 进行检测,如果在这种情况下, objects 的数量大于 slab page 规定的最大 object 的数量
那么内核直接从 Buddy 分配器中获得最大 object 时的 page. 代码如下:
if ((PAGE_SIZE << min_order) / size > MAX_OBJS_PER_PAGE)
return get_order(size * MAX_OBJS_PER_PAGE) - 1;
(2) 内核计算 object 的 size 对应的最小 order,其计算如下:
order = fls(min_objects * size - 1) - PAGE_SHIFT;
通过上面对 min_objects 的计算,可以获得 object 的最小 order 如下表:
object_size
|
min_object = 8
|
min_object = 12
|
min_object = 16
|
|
8
|
-6
|
-5
|
-5
|
|
16
|
-5
|
-4
|
-4
|
|
32
|
-4
|
-3
|
-3
|
|
64
|
-3
|
-2
|
-2
|
|
128
|
-2
|
-1
|
-1
|
|
256
|
-1
|
0
|
0
|
|
512
|
0
|
1
|
1
|
|
1024
|
1
|
2
|
2
|
|
2048
|
2
|
3
|
3
|
|
4096
|
3
|
4
|
4
|
|
8096
|
4
|
5
|
5
|
|
通过上面表的计算,我们可以看出不同的 object size 的 slab page 的最小 order 不同,由于 order 最小为 0,所以最最小 order 进行处理
order = max(min_order,fls(min_objects * size - 1) - PAGE_SHIFT);
(3) 获得最小 order 之后,就从最小 order 开始遍历,只要满足一个 slab page 中,浪费部分小于 1/16 就可以进行分配.因为 object size 大小不同,
而 page 则按 PAGE_SIZE 进行对齐,所以无法避免一定的浪费,但内核规定只要浪费不超过 1/16 就可以进行分配.所以代码如下:
for (order = max(min_order , fls(min_objects * size - 1) - PAGE_SHIFT) ; order <= max_order; order++) {
unsigned long slab_size = PAGE_SIZE << order;
if (slab_size < min_objects * size)
continue;
rem = slab_size % size;
if (rem <= slab_size / fract_leftover)
break;
}
(4) 通过上面的计算之后获得最小 slab page 的 order,接着就可以从 Buddy 中获得对应的 page 来构成 slab page.
阅读(2657) | 评论(0) | 转发(0) |