文章说明:
-
Linux内核版本:5.0
-
架构:ARM64
-
参考资料及图片来源:《奔跑吧Linux内核》
-
Linux 5.0内核源码注释仓库地址:
1. 前置知识
1.1 CPU管理位图
内核对CPU的管理是通过位图(bitmap)变量来管理的,并且定义了possible、present、online和active这4种状态:
/* 位图类型变量 */
// 表示系统中有多少个可以运行(现在运行或者将来某个时间点运行)的 CPU 内核
#define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask)
// 表示系统中有多少个正处于运行(online)状态的 CPU 内核
#define cpu_online_mask ((const struct cpumask *)&__cpu_online_mask)
// 表示系统中有多少个可处于运行状态的CPU内核,它们不一定都处于运行状态,有的CPU内核可能被热插拔了
#define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask)
// 表示系统中有多少个活跃的 CPU 内核
#define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask)
-
#define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
name[]
:位图类型变量使用一个长整数类型数组name[],每位代表一个CPU。对于64位处理器来说,一个长整数类型数组成员只能表示64个CPU内核。内核配置中有一个宏CONFIG_NR_CPUS为8,那么只需要一个长整数类型数组成员可。struct cpumask
:cpumask数据结构本质上是位图,内核通常使用cpumask的相关接口函数来管理CPU内核数量。
CPU位图的初始化流程如下图所示:
cpu_possible_mask
通过查询系统DTS表或者ACPI表获取系统CPU内核数量cpu_present_mask
等同于cpu_possible_maskcpu_active_mask
是经过使能后的CPU内核数量
1.2 CPU调度域
根据系统的内存和高速缓存的布局,CPU域可分为如下几类:
Linux内核通过数据结构sched_domain_topology_level
来描述CPU的层次关系,简称为SDTL:
// 用于描述 CPU 的层级关系
struct sched_domain_topology_level {
sched_domain_mask_f mask; // 函数指针,用于指定某个 SDTL 的 cpumask 位图
// sd_flags 函数指针里指定了该调度层级的标志位
sched_domain_flags_f sd_flags; // 函数指针,用于指定某个 SDTL 的标志位
int flags;
int numa_level;
struct sd_data data;
#ifdef CONFIG_SCHED_DEBUG
char *name;
#endif
};
另外,内核默认定义了一个数组default_topology[]
来概括CPU物理域的层次结构:
// CPU 拓扑关系,从下往上
static struct sched_domain_topology_level default_topology[] = {
#ifdef CONFIG_SCHED_SMT // 超线程
// cpu_smt_mask() 函数描述了 SMT 层级的 CPU 位图组成方式
{
cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
#endif
#ifdef CONFIG_SCHED_MC // 多核
// cpu_coregroup_mask() 函数描述了 MC 层级的 CPU 位图组成方式
{
cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
#endif // 处理器
// cpu_cpu_mask() 函数描述了 DIE 层级的 CPU 位图组成方式
{
cpu_cpu_mask<