【cpu_operations】CPU topology概念(2)
CPU topology除了描述CPU的组成之外,其主要功能,是向kernel调度器提供必要的信息,以便让它合理地分配任务,最终达到性能和功耗之间的平衡。
单核和多核
在英文里面,单核(single-core)和多核(multi-core)多称作uniprocessor和multiprocessor。单独的一个chip(如通常意义上的芯片);一个chip上集成多个核心(如SMP,symmetric multiprocessing);一个核心上实现多个hardware context,以支持多线程(如SMT,Simultaneous multithreading)。
SMP、SMT、NUMA等概念
SMP是将多个功能完全相同的processor集成在一起,它们共享总线、memory等系统资源,这称作SMP(Symmetric Multi-Processing)。
Socket的概念在X86架构上使用尤其多,可以理解为插槽。受限于物理工艺,频率不能无限提高,以及散热因素,在一颗芯片上不能无限的集成晶体管,chiplet技术又让摩尔定律得到延续,多core组成一个未封装的die,芯片厂商会把多个die封装在一个chip上,chip也称作Socket。假设一个插槽有两个Core,那么我在主板上插2个插槽,就是4核系统,插4个插槽,就是8核系统。
大多数操作系统(如Windows、Linux),有进程和线程的概念。进程是程序的运行实例,可以包括很多线程。线程是调度的最小单位。因此有些处理器(Core),可以通过复制硬件寄存器状态等手段,同时执行多个线程,这叫做SMT(Simultanous Multi-Thread)。
NUMA
某些Core之间,独享总线和memory,称作Node。正常情况下,Core只访问Node内的memory,因此可以减轻对总线和memory的带宽需求。但是,有些场景下,Core会不可避免的访问其它Node的memory,这会造成很大的访问延迟。
因此,这种技术称作NUMA(Non-uniform Memory Access),以内存访问的不一致性为代价,减轻对总线和memory的带宽需求。这种结构对进程调度算法的要求较高,尽量减少跨Node的内存访问次数,以提升系统性能。
arm big.LITTLE
随着智能设备的普及,用户对移动设备的性能需求越来越高,相应的就有更多的power消耗,这对设备的电源管理以及散热处理提出了更高的要求。以智能手机为例,必须由高性能CPU来完成的事务,在所有事物里的比重是非常小的,如大型游戏、高清视频播放等。甚至很多用户从来都没有用过。因此arm在2011年推出了big.LITTLE架构,技术的架构包括一个高性能“大”(big)CPU 集群和一个高效率“小”(LITTLE)CPU 集群,它们之间通过一致互联实现连接。在该架构上运行的软件(全局任务调度)可以将正确的应用程序任务调度到正确的CPU上。
如下图所示系统,A57是大核,A53是小核,硬件一致性CCI允许大核和小核之间的数据传输,对软件透明的,如果没有CCI,那么需要使用DDR作为媒介,这样的话就会很慢而且功耗高。大核和小核共享中断控制器GIC-400,所有的core可以相互发送中断。
DynamIQ big.LITTLE
DynamIQ是在big.LITTLE基础上发展出来的概念,big.LITTLE成为DynamIQ的一部分内容。尽管“大”CPU 和“小” CPU 的潜在组合方式保持不变,DynamIQ 却带来了一种可以改变异构处理格局的新型技术架构。它的做法是将大小两个集群合并,从而形成一个兼具大小 CPU、完全集成化的 CPU 集群。DynamIQ允许不同架构的cluster共享L3 cache。
kernel cpu topology重要文件
include/linux/topology.h
CPU topology信息有两个重要的使用场景:一是向用户提供当前的CPU信息(lscpu命令),这是由CPU topology driver实现的;二是向调度器提供CPU core的信息,以便合理的调度任务。
topology.h定义了获取系统CPU topology信息的标准接口。底层的arch-dependent CPU topology会根据平台的特性,实现kernel定义的那些接口。topology.h主要以“#ifndef ... #define”类型的宏定义的形式提供API,其目的是:底层的arch-dependent CPU topology可以重新定义这些宏(在arch目录下的topology.h文件),只要底层有定义,则优先使用底层的,否则就使用Kernel general CPU topology中的默认API,主要包括:
topology_physical_package_id // 用于获取某个CPU的package ID,即socket或者cluster,具体意义依赖于具体平台的实现;
topology_core_id // 用于获取某个CPU的core ID。具体意义依赖于具体的平台实现;
topology_thread_cpumask // 获取和该CPU属于同一个core的所有CPU,通俗的讲,就是姐妹Thread;
topology_core_cpumask // 获取和该CPU属于同一个packet(socket)的所有CPU;
cpu_cpu_mask // 获取该CPU属于同一个Node的所有CPU;
cpu_smt_mask // 用于SMT调度(CONFIG_SCHED_SMT)的一个封装,意义同topology_thread_cpumask
arch/arm64/include/asm/topology.h
对ARM64而言,arch-dependent CPU topology位于“arch/arm64/include/asm/topology.h”和“arch/arm64/kernel/topology.c”中,主要负责ARM64平台相关的topology转换。
drivers\base\topology.c
CPU topology driver位于“drivers\base\topology.c”中,基于“include/linux/topology.h”所提供的API,以sysfs的形式,向用户空间提供获取CPU topology信息的接口,lscpu应用,就是基于该接口实现的。
具体的实现比较简单,sysfs的格式可参考“Documentation\cputopology.txt”,这里不再详细说明。