gpt4 book ai didi

linux - linux内核中的大尺寸kmalloc kmalloc

转载 作者:太空宇宙 更新时间:2023-11-04 09:14:59 26 4
gpt4 key购买 nike

我正在查看 Linux 版本 4.9.31

还有一个slab和slub的kmalloc()函数

下面是include/linux/slab.h的kmalloc()函数

static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
if (!(flags & GFP_DMA)) {
int index = kmalloc_index(size);

if (!index)
return ZERO_SIZE_PTR;

return kmem_cache_alloc_trace(kmalloc_caches[index],
flags, size);
}
#endif
}
return __kmalloc(size, flags);
}

在上面的代码中,当 __builtin_constant_p(size) 为真时调用 kmalloc_large()。

第一个问题。__builtin_constant_p(size) 和kmalloc_large() 之间有什么关系? kmalloc_large() 不应该在运行时而不是编译时调用吗?

下面是mm/slab.c的__kmalloc()和__do_kmalloc()

static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
unsigned long caller)
{
struct kmem_cache *cachep;
void *ret;

cachep = kmalloc_slab(size, flags);
if (unlikely(ZERO_OR_NULL_PTR(cachep)))
return cachep;
ret = slab_alloc(cachep, flags, caller);

kasan_kmalloc(cachep, ret, size, flags);
trace_kmalloc(caller, ret,
size, cachep->size, flags);

return ret;
}

void *__kmalloc(size_t size, gfp_t flags)
{
return __do_kmalloc(size, flags, _RET_IP_);
}

下面是mm/slub.c的__kmalloc()

void *__kmalloc(size_t size, gfp_t flags)
{
struct kmem_cache *s;
void *ret;

if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
return kmalloc_large(size, flags);

s = kmalloc_slab(size, flags);

if (unlikely(ZERO_OR_NULL_PTR(s)))
return s;

ret = slab_alloc(s, flags, _RET_IP_);

trace_kmalloc(_RET_IP_, ret, size, s->size, flags);

kasan_kmalloc(s, ret, size, flags);

return ret;
}

第二个问题。为什么 slub __kmalloc() 检查“size > KMALLOC_MAX_CACHE_SIZE”并在运行时调用 kmalloc_large()?

最佳答案

你的两个问题实际上是单个问题的一部分:

What is __builtin_constant_p(size)?

Operator __builtin_constant_p 是特定于 gcc 的扩展,它检查其参数是否可以在编译时 求值。例如,如果您调用

p = kmalloc(100, GFP_KERNEL);

然后运算符返回 true。

但是用

size_t size = 100;
p = kmalloc(size, GFP_KERNEL);

运算符返回 false*。

通过知道某些函数的参数在编译时已知,可以在编译时检查它,并执行一些优化。

if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)

虽然 size > KMALLOC_MAX_CACHE_SIZE 在这里似乎是运行时检查,但实际上是编译时检查,因为外部条件保证 size 在编译时已知。有了这些知识,编译器可以优化内部分支,如果它是假的(如果分支为真,编译器可以优化其他分支)。

例如,

p = kmalloc(100000, GFP_KERNEL);

会被编译成

kmalloc_large(100000, GFP_KERNEL);

p = kmalloc(100, GFP_KERNEL);

会被编译成

__kmalloc(100, GFP_KERNEL);

但是

size_t size = 100000;
p = kmalloc(size, GFP_KERNEL);

会被编译成

size_t size = 100000;
__kmalloc(size, GFP_KERNEL);

因为编译器无法在编译时预测分支。

“回退”函数 __kmalloc 的实现在任何地方检查其参数,以防无法执行编译时检查。


*- 在我最近的测试中,编译器实际上并没有尝试预测直接用常量赋值的 size 变量的值。但这可能会在未来的 gcc 版本中改变。

关于linux - linux内核中的大尺寸kmalloc kmalloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48946903/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com