cpu核数和内存大小怎么搭配 cpu核数

现代各种处理器采用了许多不同的技术,但从物理结构上,CPU的层次结构却可以被统一的表示如下:
最底层为超线程层,此技术为Intel公司研发,目前在ARM等其他架构处理器中并未采用 。超线程技术充分利用空闲CPU资源,在单一时间内可以让一个物理核心同时处理两个线程的工作 。因此,在开启超线程的4物理核心的机器上,往往可以看到存在有8个逻辑CPU 。
再往上的层次就是物理核心层 。单独的一个物理核心的标志往往是其独占的私有缓存(Cache) 。通常在两级缓存的情况下,每个物理核心独享L1 Cache,L2 Cache则为几个物理核心共享;在三级缓存的情况下,L1与L2为私有,L3为共享 。当然前面说的是通常情况,不能武断地认为二级缓存与三级缓存的情况都是统一的 。
继续往上层走就是处理器层级,多个物理核心可以共享最后一级缓存(LLC),这多个物理核心就被称为是一个Cluster或者Socket 。芯片厂商会把多个物理核心(Core)封装到一个片(Chip)上,主板上会留有插槽,一个插槽可以插一个Chip 。
最上层就到了NUMA的概念了,为了减少对内存总线的访问竞争,可以将CPU分属于不同的Node节点,通常情况下,CPU只访问Node内的memory 。
在不考虑NUMA的情况下,CPU所属层次从高到低可以表示为Cluster —> Core —> Threads 。
了解CPU的层次结构有什么作用呢?
以服务器为例,负载均衡是调度器常要考虑的问题 。负载均衡在进行任务迁移的时候,把任务移动到哪个CPU上是重中之重 。如果开启了超线程,那么移动到超线程层次的兄弟CPU上,被迁移后,原Cache上进程的数据仍然可用,可以说是最优解;如果移动到物理核心层的兄弟CPU上,则LLC上的原先该进程的数据仍然可以被访问到 。可以说,迁移到离原CPU层次更近的兄弟CPU上带来的影响更小 。
以手机等小型设备为例,功耗是核心问题 。尤其是ARM多采用big core和little core的组合结构,即一个Cluster的物理核心是功耗和性能都比较高的CPU,另一个Cluster的物理核心是功耗和性能都比较低的CPU 。这时候任务迁移,除了要考虑层次的兄弟临近关系,还要考虑移动到哪个CPU上可以保证功耗和性能的平衡问题 。
那么,CPU的层次结构在Linux kernel中是如何表示的呢?
我们以ARM64下CPU的初始化开始入手 。ARM64平台下CPU的初始化需要读取DTS(Device Tree Source,设备树)文件 。

cpu核数和内存大小怎么搭配 cpu核数

文章插图
【配套的Linux内核技术教程文档资料】可以私信我【内核】免费获取 。
随意挑选arm64目录下一个处理器的dtsi文件的部分为例:
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu0>;
};
……
};
……
};
cpu0: cpu@20000 {
device_type = "cpu";
compatible = "arm,cortex-a57";
reg = <0x20000>;
enable-method = "psci";
next-level-cache = <&cluster0_l2>;
};
……
cluster0_l2: l2-cache0 {
compatible = "cache";
};
……
};
以上是DTS文件中CPU定义的一个统一的格式 。start_kernel –> setup_arch –> smp_init_cpus 。
smp_init_cpus在系统启动的时候读取DTS文件中CPU信息,获得CPU数量,并调用smp_cpu_setup函数进行possible位图的设置 。
static int __init smp_cpu_setup(int cpu)
{
const struct cpu_operations *ops;
if (init_cpu_ops(cpu))
return -ENODEV;

推荐阅读