在定义CONFIG_USE_PERCPU_NUMA_NODE_ID的时候可以通过
static inline int numa_node_id(void)
{
return raw_cpu_read(numa_node);
}
得到当前cpu的numa id
注意这里的numa_node 是一个per_cpu 变量,其定义如下:
DECLARE_PER_CPU(int, numa_node);
例如实际code中通过下面的方式拿到当前cpu的numa id
if (node < 0)
node = numa_node_id();
下来看看为啥raw_cpu_read等得到当前cpu的numa id
#define raw_cpu_read(pcp) __pcpu_size_call_return(raw_cpu_read_, pcp)
继续看看__pcpu_size_call_return
#define __pcpu_size_call_return(stem, variable) \
({ \
typeof(variable) pscr_ret__; \
__verify_pcpu_ptr(&(variable)); \
switch(sizeof(variable)) { \
case 1: pscr_ret__ = stem##1(variable); break; \
case 2: pscr_ret__ = stem##2(variable); break; \
case 4: pscr_ret__ = stem##4(variable); break; \
case 8: pscr_ret__ = stem##8(variable); break; \
default: \
__bad_size_call_parameter(); break; \
} \
pscr_ret__; \
})
这里做完替换后就是raw_cpu_read_4(numa_node)
#ifndef raw_cpu_read_4
#define raw_cpu_read_4(pcp) raw_cpu_generic_read(pcp)
#endif
继续看raw_cpu_generic_read
#define raw_cpu_generic_read(pcp) \
({ \
*raw_cpu_ptr(&(pcp)); \
})
继续看
#define raw_cpu_ptr(ptr) \
({ \
__verify_pcpu_ptr(ptr); \
arch_raw_cpu_ptr(ptr); \
})
这里的核心是arch_raw_cpu_ptr
#ifndef arch_raw_cpu_ptr
#define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
#endif
这里的ptr就是numa_node,因此通过__my_cpu_offset得到当前cpu在numa_node中的offset,就可以得到当前cpu的id
static inline unsigned long __my_cpu_offset(void)
{
unsigned long off;
/*
* We want to allow caching the value, so avoid using volatile and
* instead use a fake stack read to hazard against barrier().
*/
asm("mrs %0, tpidr_el1" : "=r" (off) :
"Q" (*(const unsigned long *)current_stack_pointer));
return off;
}
#define __my_cpu_offset __my_cpu_offset()
这里的通过__my_cpu_offset得到每个cpu对应的offset。
与之对应的是每个cpu的boot的过程中都会调用set_my_cpu_offset来在numa_node中设置offset。
例如这了是cpu 0的
void __init smp_setup_processor_id(void)
{
u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
cpu_logical_map(0) = mpidr;
/*
* clear __my_cpu_offset on boot CPU to avoid hang caused by
* using percpu variable early, for example, lockdep will
* access percpu variable inside lock_release
*/
set_my_cpu_offset(0);
pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
}
下面其其他cpu的
asmlinkage void secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu;
cpu = task_cpu(current);
set_my_cpu_offset(per_cpu_offset(cpu));
}
numa_node_id是得到当前cpu对应的numa id
最新推荐文章于 2024-09-14 16:20:16 发布