Linux SMP 内核源码完整树形分析(ARM64架构,编译前+运行时)
·
第一部分:源码目录树形分析
1.1 编译前源码结构(开发者视角)
这是开发者通过git clone或下载源码包后,在构建主机上看到的目录树。
linux-6.1/ # 内核源码根目录(编译前) │ ├── arch/ # 架构相关代码 │ ├── arm64/ # ARM64架构 │ │ ├── kernel/ │ │ │ ├── smp.c # ARM64 SMP初始化 │ │ │ ├── smp_spin_table.c # 自旋表启动方式 │ │ │ ├── smp_psci.c # PSCI固件启动 │ │ │ ├── head.S # 内核入口汇编 │ │ │ ├── process.c # 进程切换 │ │ │ └── setup.c # 架构初始化 │ │ ├── mm/ │ │ │ ├── init.c # ARM64内存初始化 │ │ │ ├── fault.c # 缺页异常 │ │ │ └── cache.S # 缓存操作 │ │ ├── include/asm/ │ │ │ ├── smp.h # 架构SMP头文件 │ │ │ ├── atomic.h # 原子操作 │ │ │ ├── spinlock.h # 自旋锁 │ │ │ └── mmu.h # MMU相关 │ │ ├── Kconfig # ARM64配置选项 │ │ └── Makefile │ ├── x86/ # x86架构(对比参考) │ │ └── kernel/smp.c │ └── Kconfig # 顶层架构选择 │ ├── kernel/ # 核心子系统 │ ├── sched/ # 调度器 │ │ ├── core.c # 核心调度逻辑(__schedule) │ │ ├── fair.c # CFS完全公平调度类 │ │ ├── rt.c # 实时调度类 │ │ ├── deadline.c # 限期调度类 │ │ ├── idle.c # 空闲调度类 │ │ ├── stop_task.c # 停止任务调度类 │ │ ├── topology.c # 调度域拓扑 │ │ ├── loadavg.c # 负载计算 │ │ ├── cpupri.c # CPU优先级管理 │ │ ├── cpudeadline.c # CPU限期管理 │ │ ├── smp.h # 调度内部SMP接口 │ │ ├── stats.c # 调度统计 │ │ └── debug.c # 调度调试 │ ├── smp.c # 通用SMP函数 │ │ ├── smp_call_function_single() # 单CPU函数调用 │ │ ├── smp_call_function_many() # 多CPU函数调用 │ │ ├── on_each_cpu() # 每个CPU执行 │ │ └── flush_smp_call_function_queue() # IPI队列处理 │ ├── softirq.c # 软中断 │ ├── stop_machine.c # 停止所有CPU │ ├── cpu.c # CPU热插拔 │ ├── irq/ │ │ ├── irqdesc.c # 中断描述符 │ │ ├── manage.c # 中断管理 │ │ └── affinity.c # 中断亲和性 │ ├── fork.c # 进程创建(copy_process) │ ├── exit.c # 进程退出 │ └── sched/ │ └── core.c │ ├── mm/ # 内存管理 │ ├── page_alloc.c # 页分配器 │ ├── slub.c # SLUB分配器 │ ├── vmalloc.c # 虚拟内存分配 │ ├── memory.c # 内存管理核心 │ └── hugetlb.c # 大页管理 │ ├── include/ # 内核头文件 │ ├── linux/ │ │ ├── smp.h # SMP API定义 │ │ │ ├── get_cpu()/put_cpu() │ │ │ ├── smp_processor_id() │ │ │ ├── on_each_cpu() │ │ │ └── smp_call_function() │ │ ├── sched.h # 调度器头文件 │ │ │ ├── task_struct # 进程描述符 │ │ │ ├── sched_class # 调度类结构 │ │ │ └── rq # 运行队列 │ │ ├── percpu.h # per-CPU变量 │ │ ├── cpus.h # CPU掩码操作 │ │ ├── atomic.h # 原子操作 │ │ └── spinlock.h # 自旋锁 │ └── asm/ # 架构头文件(链接到arch/arm64/include/asm) │ └── smp.h │ ├── init/ # 内核初始化 │ ├── main.c # start_kernel()入口 │ └── Kconfig # CONFIG_SMP配置 │ ├── drivers/ # 设备驱动 │ ├── base/ │ │ └── cpu.c # CPU设备模型 │ ├── irqchip/ # 中断控制器驱动 │ │ └── irq-gic-v3.c # GICv3驱动 │ └── net/ # 网络驱动 │ └── dev.c │ ├── fs/ # 文件系统 │ ├── ext4/ # ext4文件系统 │ ├── fat/ # FAT文件系统 │ └── proc/ # proc文件系统 │ └── stat.c # /proc/stat │ ├── lib/ # 通用库函数 │ ├── smp_processor_id.c # smp_processor_id()调试 │ └── locking/ # 锁实现 │ ├── scripts/ # 配置/编译脚本 │ ├── kconfig/ # Kconfig解析 │ └── Makefile.* # 编译规则 │ ├── tools/ # 用户态工具 │ ├── perf/ # perf性能分析工具 │ └── trace/ # 追踪工具 │ ├── Documentation/ # 内核文档 │ ├── scheduler/sched-domains.txt # 调度域文档 │ └── core-api/smp_processor_id.rst │ ├── virt/ # 虚拟化 │ └── kvm/ # KVM虚拟化 │ └── arm64/ # ARM64 KVM支持 │ ├── Kconfig # 顶层配置菜单 ├── Makefile # 顶层Makefile └── README # 说明文件
1.2 运行时系统结构(目标机视角)
这是内核编译安装后,在ARM64目标系统(如树莓派、RK3588开发板)上看到的目录结构。
/ # 根文件系统 │ ├── boot/ # 内核启动文件 │ ├── vmlinuz-6.1.0-arm64 # 压缩内核镜像 │ ├── System.map-6.1.0-arm64 # 内核符号表(地址→函数名) │ ├── config-6.1.0-arm64 # 内核编译配置 │ └── dtbs/ # 设备树二进制文件 │ └── rockchip/ │ └── rk3588-evb.dtb │ ├── lib/ # 库文件 │ └── modules/ # 内核模块目录 │ └── 6.1.0-arm64/ # 每个内核版本一个子目录 │ ├── kernel/ # .ko模块文件 │ │ ├── drivers/ │ │ │ ├── mmc/ # MMC驱动模块 │ │ │ ├── net/ # 网卡驱动模块 │ │ │ └── usb/ # USB驱动模块 │ │ ├── fs/ │ │ │ ├── ext4.ko │ │ │ └── vfat.ko │ │ └── net/ │ │ └── ipv6.ko │ ├── modules.dep # 模块依赖关系 │ ├── modules.alias # 模块别名 │ ├── modules.symbols # 模块符号表 │ └── build/ # 符号链接 → 源码目录 │ ├── usr/ # 用户程序 │ └── src/ # 源码目录(可选) │ └── linux-6.1.0/ # 通常不存在,需手动安装 │ ├── proc/ # proc文件系统(内核接口) │ ├── cpuinfo # CPU信息 │ ├── stat # 系统统计 │ ├── interrupts # 中断分布 │ ├── softirqs # 软中断统计 │ ├── schedstat # 调度器统计 │ ├── [pid]/ # 每个进程目录 │ │ ├── stat # 进程状态 │ │ └── task/ # 线程信息 │ └── self/ │ └── task/ │ ├── sys/ # sysfs文件系统 │ └── devices/ │ └── system/ │ └── cpu/ # CPU设备信息 │ ├── cpu0/ # CPU0设备目录 │ ├── cpu1/ │ ├── present # 在线CPU掩码 │ ├── possible # 可能CPU掩码 │ ├── offline # 离线CPU │ └── kernel_max # 最大CPU编号 │ ├── dev/ # 设备文件 │ ├── mmcblk0/ # eMMC块设备 │ └── ttyS0/ # 串口设备 │ └── etc/ # 配置文件 └── modprobe.d/ # 模块配置
1.3 关键文件依赖关系图
┌─────────────────────────────────────────┐ │ 编译前: arch/arm64/kernel/head.S │ │ _text (入口点) │ └───────────────────┬─────────────────────┘ │ ▼ ┌─────────────────────────────────────────┐ │ init/main.c │ │ start_kernel() │ └───────────────────┬─────────────────────┘ │ ┌───────────────────────────┼───────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ │ arch/arm64/kernel/ │ │ kernel/sched/core.c │ │ mm/page_alloc.c │ │ smp.c │ │ scheduler_tick() │ │ 内存初始化 │ │ smp_init_cpus() │ │ │ │ │ └───────────┬───────────┘ └───────────┬───────────┘ └───────────────────────┘ │ │ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ arch/arm64/kernel/ │ │ kernel/sched/fair.c │ │ smp_spin_table.c │ │ trigger_load_balance()│ │ smp_psci.c │ │ │ └───────────┬───────────┘ └───────────┬───────────┘ │ │ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ kernel/smp.c │ │ kernel/sched/core.c │ │ smp_call_function_*() │ │ pick_next_task() │ └───────────────────────┘ └───────────────────────┘
第二部分:数据结构树形分析
2.1 核心数据结构层次图
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ SMP 核心数据结构 │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ struct task_struct (include/linux/sched.h) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ 进程描述符(每个任务一个) │ │ │ │ │ ├──────────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ volatile long state; // 进程状态 (TASK_RUNNING等) │ │ │ │ │ │ int prio, static_prio, normal_prio; // 优先级 (0-139) │ │ │ │ │ │ unsigned int policy; // 调度策略 (SCHED_NORMAL等) │ │ │ │ │ │ struct sched_class *sched_class; // 调度类指针 │ │ │ │ │ │ struct sched_entity se; // CFS调度实体 │ │ │ │ │ │ struct sched_rt_entity rt; // RT调度实体 │ │ │ │ │ │ struct sched_dl_entity dl; // DL调度实体 │ │ │ │ │ │ int cpu; // 当前运行的CPU │ │ │ │ │ │ int on_cpu; // 是否正在CPU上运行 │ │ │ │ │ │ int on_rq; // 是否在运行队列中 │ │ │ │ │ │ cpumask_t cpus_allowed; // CPU亲和性掩码 │ │ │ │ │ │ unsigned int migration_disabled; // 迁移禁用标志 │ │ │ │ │ │ struct list_head tasks; // 全局任务链表 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ struct rq (kernel/sched/sched.h) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ 运行队列(per-CPU变量) │ │ │ │ │ ├──────────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ unsigned int nr_running; // 运行队列中的任务数 │ │ │ │ │ │ struct cfs_rq cfs; // CFS运行队列 │ │ │ │ │ │ struct rt_rq rt; // RT运行队列 │ │ │ │ │ │ struct dl_rq dl; // DL运行队列 │ │ │ │ │ │ struct task_struct *curr; // 当前运行的任务 │ │ │ │ │ │ struct task_struct *idle; // 空闲任务 │ │ │ │ │ │ int cpu; // 所属CPU │ │ │ │ │ │ int online; // CPU是否在线 │ │ │ │ │ │ #ifdef CONFIG_SMP │ │ │ │ │ │ struct sched_domain *sd; // 调度域 │ │ │ │ │ │ int active_balance; // 主动均衡标志 │ │ │ │ │ │ int push_cpu; // 推送目标CPU │ │ │ │ │ │ struct task_struct *migration_thread; // 迁移线程 │ │ │ │ │ │ struct list_head migration_queue; // 迁移请求队列 │ │ │ │ │ │ u64 nr_switches; // 上下文切换次数 │ │ │ │ │ │ u64 nr_load_updates; // 负载更新次数 │ │ │ │ │ │ raw_spinlock_t lock; // 队列锁 │ │ │ │ │ │ #endif │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ struct sched_class (kernel/sched/sched.h) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ 调度类(多态调度,链表组织) │ │ │ │ │ ├──────────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ void (*enqueue_task)(struct rq *rq, struct task_struct *p); │ │ │ │ │ │ void (*dequeue_task)(struct rq *rq, struct task_struct *p); │ │ │ │ │ │ void (*yield_task)(struct rq *rq); │ │ │ │ │ │ void (*check_preempt_curr)(struct rq *rq, struct task_struct *p); │ │ │ │ │ │ struct task_struct *(*pick_next_task)(struct rq *rq); │ │ │ │ │ │ void (*task_tick)(struct rq *rq, struct task_struct *p, int queued); │ │ │ │ │ │ #ifdef CONFIG_SMP │ │ │ │ │ │ unsigned long (*load_balance)(struct rq *this_rq, ...); │ │ │ │ │ │ int (*move_one_task)(struct rq *this_rq, ...); │ │ │ │ │ │ #endif │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ struct sched_domain (kernel/sched/sched.h) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ 调度域(CPU分组,树形组织) │ │ │ │ │ ├──────────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ struct sched_domain *parent; // 父域 │ │ │ │ │ │ struct sched_domain *child; // 子域 │ │ │ │ │ │ struct sched_group *groups; // 调度组 │ │ │ │ │ │ cpumask_t span; // 包含的CPU掩码 │ │ │ │ │ │ unsigned long min_interval; // 最小负载均衡间隔 │ │ │ │ │ │ unsigned long max_interval; // 最大负载均衡间隔 │ │ │ │ │ │ unsigned int busy_factor; // 忙碌因子 │ │ │ │ │ │ unsigned int imbalance_pct; // 不平衡百分比阈值 │ │ │ │ │ │ unsigned int cache_nice_tries; // 缓存亲和性尝试次数 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ struct smp_operations (arch/arm64/include/asm/smp.h) │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ SMP操作集(ARM64架构相关) │ │ │ │ │ ├──────────────────────────────────────────────────────────────────────────┤ │ │ │ │ │ void (*smp_init_cpus)(void); // 初始化CPU映射 │ │ │ │ │ │ void (*smp_prepare_cpus)(unsigned int); // 准备启动secondary CPU │ │ │ │ │ │ void (*smp_secondary_init)(unsigned int); // secondary CPU初始化 │ │ │ │ │ │ int (*smp_boot_secondary)(unsigned int, struct task_struct*); │ │ │ │ │ │ #ifdef CONFIG_HOTPLUG_CPU │ │ │ │ │ │ int (*cpu_kill)(unsigned int); // 关闭CPU │ │ │ │ │ │ void (*cpu_die)(unsigned int); │ │ │ │ │ │ int (*cpu_disable)(unsigned int); │ │ │ │ │ │ #endif │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
2.2 per-CPU变量机制
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ per-CPU 变量存储布局 │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 声明方式(编译前源码): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ DEFINE_PER_CPU(type, name); // 定义per-CPU变量 │ │ │ │ DECLARE_PER_CPU(type, name); // 声明 │ │ │ │ get_cpu_var(name); // 获取当前CPU的变量(禁用抢占) │ │ │ │ put_cpu_var(name); // 完成操作,重新启用抢占 │ │ │ │ per_cpu(name, cpu); // 获取指定CPU的变量 │ │ │ │ this_cpu_ptr(name); // 获取当前CPU指针 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 运行时内存布局(ARM64,NR_CPUS=4): │ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ 内核数据段 │ │ │ │ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │ │ │ │ │ CPU0 变量 │ CPU1 变量 │ CPU2 变量 │ CPU3 变量 │ ← per-CPU区域 │ │ │ │ │ 副本 │ 副本 │ 副本 │ 副本 │ │ │ │ │ └─────────────┴─────────────┴─────────────┴─────────────┘ │ │ │ │ ▲ ▲ ▲ ▲ │ │ │ │ │ │ │ │ │ │ │ │ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │ │ │ │ │ CPU0 │ │ CPU1 │ │ CPU2 │ │ CPU3 │ │ │ │ │ │ 寄存器 │ │ 寄存器 │ │ 寄存器 │ │ 寄存器 │ │ │ │ │ │ SP_EL0 │ │ SP_EL0 │ │ SP_EL0 │ │ SP_EL0 │ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 典型per-CPU变量(源码中定义): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ DEFINE_PER_CPU(struct rq, runqueues); // kernel/sched/core.c │ │ │ │ DEFINE_PER_CPU(struct task_struct *, curr_task); // kernel/sched/core.c │ │ │ │ DEFINE_PER_CPU(struct softnet_data, softnet_data); // net/core/dev.c │ │ │ │ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases); // kernel/time/hrtimer.c│ │ │ │ DEFINE_PER_CPU(struct tick_device, tick_cpu_device); // kernel/time/tick-common.c│ │ │ │ DEFINE_PER_CPU(struct mm_struct *, idle_mm); // arch/arm64/mm/mm.h │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
第三部分:算法计算树形分析
3.1 负载均衡算法树
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 负载均衡算法层次图 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 负载均衡触发点(运行时): │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ 1. 周期性触发: scheduler_tick() → trigger_load_balance() → raise_softirq() │ │
│ │ 2. 进程唤醒: try_to_wake_up() → wake_balance() → select_task_rq() │ │
│ │ 3. 空闲均衡: idle_balance() → 空闲CPU从其他CPU拉取任务 │ │
│ │ 4. 主动均衡: active_load_balance() → 迁移线程处理 │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ 负载计算:load = weight * nr_running │ │
│ │ │ │
│ │ weight计算(CFS,kernel/sched/sched.h): │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ const int sched_prio_to_weight[40] = { │ │ │
│ │ │ /* -20 */ 88761, 71755, 56483, 46273, 36291, │ │ │
│ │ │ /* -15 */ 29154, 23254, 18705, 14949, 11916, │ │ │
│ │ │ /* -10 */ 9548, 7620, 6100, 4904, 3906, │ │ │
│ │ │ /* -5 */ 3121, 2501, 1991, 1586, 1277, │ │ │
│ │ │ /* 0 */ 1024, 820, 655, 526, 423, │ │ │
│ │ │ /* 5 */ 335, 272, 215, 172, 137, │ │ │
│ │ │ /* 10 */ 110, 87, 70, 56, 45, │ │ │
│ │ │ /* 15 */ 36, 29, 23, 18, 15 │ │ │
│ │ │ }; │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ find_busiest_queue() (kernel/sched/fair.c) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 算法:遍历调度域内所有CPU的运行队列 │ │ │
│ │ │ 1. 跳过空闲队列 (nr_running == 0) │ │ │
│ │ │ 2. 计算每个队列的 load = load_avg / nr_running │ │ │
│ │ │ 3. 找出 load 最大的队列 │ │ │
│ │ │ 4. 检查负载差是否超过 imbalance_pct 阈值 │ │ │
│ │ │ 5. 如果超过阈值,返回该队列;否则返回NULL │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ move_tasks() (kernel/sched/fair.c) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 算法:从最忙队列迁移任务到当前队列 │ │ │
│ │ │ │ │ │
│ │ │ while (当前队列负荷 < 目标负荷) { │ │ │
│ │ │ // 1. 选择可迁移任务 │ │ │
│ │ │ task = pick_next_task_from_busiest_queue(); │ │ │
│ │ │ │ │ │
│ │ │ // 2. 检查亲和性 │ │ │
│ │ │ if (!cpumask_test_cpu(this_cpu, &task->cpus_allowed)) │ │ │
│ │ │ continue; // 不能迁移到此CPU │ │ │
│ │ │ │ │ │
│ │ │ // 3. 执行迁移 │ │ │
│ │ │ dequeue_task(busiest_rq, task); │ │ │
│ │ │ enqueue_task(this_rq, task); │ │ │
│ │ │ │ │ │
│ │ │ // 4. 更新负荷统计 │ │ │
│ │ │ update_load(); │ │ │
│ │ │ } │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
3.2 调度域层级算法(ARM64示例)
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 调度域层级(ARM64 big.LITTLE 配置) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 硬件布局(如RK3588:4xA76 + 4xA55): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ Cluster 0 (性能核) Cluster 1 (能效核) │ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ │ │ A76-0 A76-1 │ │ A55-0 A55-1 │ │ │ │ │ │ A76-2 A76-3 │ │ A55-2 A55-3 │ │ │ │ │ │ L3 Cache │ │ L3 Cache │ │ │ │ │ └─────────────────────┘ └─────────────────────┘ │ │ │ │ │ │ │ │ │ │ └───────────┬───────────────┘ │ │ │ │ │ │ │ │ │ DSU互联 (DynamIQ) │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 调度域层级(内核构建时由arch/arm64/kernel/topology.c初始化): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ 层级0: MC (Multi-Core) - 单个Cluster内 │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ │ │ │ │ Cluster0 MC域 │ │ Cluster1 MC域 │ │ │ │ │ │ │ │ CPU0,CPU1,CPU2,CPU3│ │ CPU4,CPU5,CPU6,CPU7│ │ │ │ │ │ │ │ 均衡: 积极 │ │ 均衡: 积极 │ │ │ │ │ │ │ └─────────────────────┘ └─────────────────────┘ │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ 层级1: DIE - 整个SoC │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ DIE域: 所有CPU (0-7) │ │ │ │ │ │ │ 均衡: 保守(跨Cluster迁移开销大) │ │ │ │ │ │ │ 阈值: imbalance_pct = 125% (允许25%不平衡) │ │ │ │ │ │ │ 额外策略: 优先在相同Cluster内均衡 │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
第四部分:数据流程文字图树形分析
4.1 进程唤醒数据流(try_to_wake_up)
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ try_to_wake_up() 数据流 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ 输入: task_struct *p (被唤醒的进程) │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Step 1: 检查任务状态 (kernel/sched/core.c) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ if (task->state == TASK_RUNNING) return 1; // 已经在运行 │ │ │
│ │ │ if (task->state & TASK_NORMAL) { │ │ │
│ │ │ // 继续唤醒流程 │ │ │
│ │ │ } │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Step 2: 选择目标CPU (select_task_rq) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ if (task->cpus_allowed 有限制) { │ │ │
│ │ │ target_cpu = cpumask_any_and(&task->cpus_allowed, cpu_online_mask);│ │ │
│ │ │ } else { │ │ │
│ │ │ // 优先使用上次运行的CPU (缓存亲和性) │ │ │
│ │ │ target_cpu = task->wake_cpu; │ │ │
│ │ │ // 如果上次运行的CPU负载过高,选择负载最低的CPU │ │ │
│ │ │ if (cpu_load(target_cpu) > threshold) { │ │ │
│ │ │ target_cpu = find_idlest_cpu(); │ │ │
│ │ │ } │ │ │
│ │ │ } │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Step 3: 获取目标CPU的运行队列锁 │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ rq = cpu_rq(target_cpu); │ │ │
│ │ │ raw_spin_lock_irqsave(&rq->lock, flags); │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Step 4: 激活任务 (activate_task → enqueue_task) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ // 根据调度类调用不同的enqueue函数 │ │ │
│ │ │ p->sched_class->enqueue_task(rq, p, flags); │ │ │
│ │ │ │ │ │
│ │ │ // CFS调度类 (kernel/sched/fair.c): │ │ │
│ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ place_entity(cfs_rq, se, flags); // 设置vruntime │ │ │ │
│ │ │ │ __enqueue_entity(cfs_rq, se); // 插入红黑树 │ │ │ │
│ │ │ │ account_entity_enqueue(cfs_rq, se); // 更新负载统计 │ │ │ │
│ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ rq->nr_running++; │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Step 5: 检查是否需要抢占当前进程 │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ check_preempt_curr(rq, p, flags); │ │ │
│ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ if (p->sched_class->prio > rq->curr->sched_class->prio) { │ │ │ │
│ │ │ │ resched_curr(rq); // 设置 TIF_NEED_RESCHED 标志 │ │ │ │
│ │ │ │ } │ │ │ │
│ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ 输出: 成功唤醒返回 1 │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
4.2 负载均衡触发数据流
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ 负载均衡触发数据流 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ 时钟中断路径(运行时): │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ arch/arm64/kernel/time.c │ │
│ │ timer_interrupt() │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ kernel/time/tick-common.c │ │
│ │ tick_handle_periodic() │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ kernel/time/timer.c │ │
│ │ update_process_times() │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ kernel/sched/core.c │ │
│ │ scheduler_tick() │ │
│ │ │ │ │
│ │ ├─► curr->sched_class->task_tick(rq, curr, 0) // 更新任务时间片 │ │
│ │ │ │ │
│ │ └─► trigger_load_balance(rq) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ raise_softirq(SCHED_SOFTIRQ) // 触发调度软中断 │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 软中断路径: │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ kernel/sched/core.c │ │
│ │ run_rebalance_domains() [软中断处理函数] │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ kernel/sched/fair.c │ │
│ │ rebalance_domains(this_cpu, idle) │ │
│ │ │ │ │
│ │ ├─► for_each_domain(cpu, sd) { // 遍历所有调度域 │ │
│ │ │ load_balance(cpu, rq, sd, idle, &balance); │ │
│ │ │ } │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ load_balance() // 核心负载均衡函数 │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 负载均衡核心(kernel/sched/fair.c): │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ load_balance(): │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 1. find_busiest_group() // 找出最忙调度组 │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► update_sd_lb_stats() // 更新组内负载统计 │ │ │
│ │ │ └─► 找出平均负载最高的组 │ │ │
│ │ │ │ │ │
│ │ │ 2. find_busiest_queue() // 找出最忙CPU队列 │ │ │
│ │ │ │ │ │ │
│ │ │ └─► 遍历组内CPU,找出负载最高的 │ │ │
│ │ │ │ │ │
│ │ │ 3. move_tasks() // 迁移任务 │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► 遍历任务(从高优先级到低优先级) │ │ │
│ │ │ ├─► 检查亲和性限制 (cpus_allowed) │ │ │
│ │ │ ├─► 检查迁移代价 │ │ │
│ │ │ └─► 执行迁移: detach_task() + attach_task() │ │ │
│ │ │ │ │ │
│ │ │ 4. 如果迁移失败且调度域允许主动均衡 → 触发主动均衡 │ │ │
│ │ │ └─► 设置 active_balance 标志,唤醒 migration_thread │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
第五部分:调度器运用树形分析
5.1 调度器类优先级层次
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 调度器类优先级层次 │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 优先级从高到低(kernel/sched/sched.h中的调度类链表顺序): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ stop_sched_class (最高优先级) │ │ │ │ │ │ ├─ 用于 stop_machine() 机制 │ │ │ │ │ │ ├─ 执行时停止所有其他任务 │ │ │ │ │ │ └─ 用于CPU热插拔、ftrace等 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ dl_sched_class (Deadline调度) │ │ │ │ │ │ ├─ SCHED_DEADLINE 策略 │ │ │ │ │ │ ├─ 任务有明确的截止时间要求 │ │ │ │ │ │ └─ 使用 CBS (Constant Bandwidth Server) 算法 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ rt_sched_class (实时调度) │ │ │ │ │ │ ├─ SCHED_FIFO: 先入先出,运行直到主动让出 │ │ │ │ │ │ ├─ SCHED_RR: 时间片轮转 │ │ │ │ │ │ ├─ 优先级范围 0-99 (数字越大优先级越高) │ │ │ │ │ │ └─ 使用优先级位图快速查找 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ fair_sched_class (CFS完全公平调度) │ │ │ │ │ │ ├─ SCHED_NORMAL: 普通进程 │ │ │ │ │ │ ├─ SCHED_BATCH: 批处理进程 │ │ │ │ │ │ ├─ SCHED_IDLE: 空闲优先级 │ │ │ │ │ │ ├─ 使用红黑树管理运行队列 │ │ │ │ │ │ └─ 基于 vruntime 选择下一个任务 │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │ │ │ │ idle_sched_class (空闲调度) │ │ │ │ │ │ ├─ 没有其他任务时运行 │ │ │ │ │ │ ├─ 执行 idle 任务 (CPU idle loop) │ │ │ │ │ │ └─ 触发 CPU 省电模式 (WFI/WFE on ARM64) │ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 调度类链表定义(kernel/sched/core.c): │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ static const struct sched_class * const sched_class_highest = │ │ │ │ &stop_sched_class, │ │ │ │ &dl_sched_class, │ │ │ │ &rt_sched_class, │ │ │ │ &fair_sched_class, │ │ │ │ &idle_sched_class, │ │ │ │ }; │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
5.2 pick_next_task() 核心逻辑
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ pick_next_task() 程序流程图 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ pick_next_task(struct rq *rq, struct task_struct *prev) │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ // 优化1: 如果队列中只有CFS任务,直接调用公平调度类 │ │
│ │ if (likely(rq->nr_running == rq->cfs.h_nr_running)) { │ │
│ │ p = fair_sched_class.pick_next_task(rq); │ │
│ │ if (likely(p != RETRY_TASK)) return p; │ │
│ │ } │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ // 通用路径:按优先级遍历所有调度类 │ │
│ │ for_each_class(class) { │ │
│ │ p = class->pick_next_task(rq); │ │
│ │ if (p) return p; │ │
│ │ } │ │
│ │ // 理论上一定会返回idle任务,所以不会返回NULL │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ fair_sched_class.pick_next_task() 实现 (kernel/sched/fair.c) │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ pick_next_task_fair(): │ │ │
│ │ │ ┌────────────────────────────────────────────────────────────────────┐ │ │ │
│ │ │ │ 1. 从当前运行队列的cfs_rq中获取最左边的红黑树节点 │ │ │ │
│ │ │ │ se = pick_next_entity(cfs_rq); │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ 2. 如果存在组调度(group scheduling),处理嵌套cfs_rq │ │ │ │
│ │ │ │ while (se && se->my_q) { │ │ │ │
│ │ │ │ se = pick_next_entity(se->my_q); │ │ │ │
│ │ │ │ } │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ 3. 返回对应的task_struct │ │ │ │
│ │ │ │ return task_of(se); │ │ │ │
│ │ │ └────────────────────────────────────────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
第六部分:关键函数树形分析
6.1 核心调度函数调用树
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 关键函数调用树 │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ schedule() (kernel/sched/core.c) │ │ │ │ │ └─► __schedule(false) │ │ │ │ │ ├─► preempt_disable() // 关闭抢占 │ │ │ │ │ ├─► raw_spin_lock_irq(&rq->lock) // 获取运行队列锁 │ │ │ │ │ ├─► update_rq_clock(rq) // 更新队列时钟 │ │ │ │ │ ├─► pick_next_task(rq, prev, &rf) // 选择下一个任务 │ │ │ │ │ │ │ ├─► fair_sched_class.pick_next_task() │ │ │ │ └─► pick_next_task_fair() │ │ │ │ └─► pick_next_entity() │ │ │ │ └─► __pick_first_entity() // 红黑树最左节点 │ │ │ │ │ │ │ ├─► rt_sched_class.pick_next_task() │ │ │ │ └─► pick_next_task_rt() │ │ │ │ └─► 优先级位图查找 │ │ │ │ │ │ │ └─► idle_sched_class.pick_next_task() │ │ │ └─► pick_next_task_idle() // 返回 idle 任务 │ │ │ │ │ ├─► context_switch(rq, prev, next, &rf) // 上下文切换 │ │ │ │ │ │ │ ├─► switch_mm_irqs_off(&prev->mm, &next->mm, next) // 切换内存空间 │ │ │ │ │ │ │ ├─► switch_to(prev, next, prev) // 切换CPU寄存器 │ │ │ │ └─► arch/arm64/kernel/entry.S: __switch_to() │ │ │ │ │ │ │ └─► finish_task_switch(prev) // 清理前一个任务 │ │ │ │ │ └─► raw_spin_unlock_irq(&rq->lock) // 释放锁 │ │ │ │ │ └─► preempt_enable() // 重新启用抢占 │ │ │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ try_to_wake_up() (kernel/sched/core.c) │ │ │ │ │ └─► ttwu_queue(p, cpu) │ │ │ │ │ ├─► ttwu_queue_remote(p, cpu) // 跨CPU唤醒 │ │ │ └─► smp_send_reschedule(cpu) // 发送IPI │ │ │ │ │ └─► ttwu_do_activate() // 同CPU唤醒 │ │ │ │ │ ├─► activate_task() │ │ │ └─► enqueue_task() │ │ │ └─► p->sched_class->enqueue_task() │ │ │ │ │ └─► ttwu_do_wakeup() │ │ └─► check_preempt_curr() │ │ └─► resched_curr() // 设置 TIF_NEED_RESCHED │ │ │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ load_balance() (kernel/sched/fair.c) [SMP专用] │ │ │ │ │ ├─► find_busiest_group() │ │ │ └─► update_sd_lb_stats() // 更新调度域统计 │ │ │ │ │ ├─► find_busiest_queue() │ │ │ └─► 遍历组内CPU,计算负载 │ │ │ │ │ ├─► move_tasks() │ │ │ ├─► detach_tasks() // 从源队列移除任务 │ │ │ └─► attach_tasks() // 添加到目标队列 │ │ │ │ │ └─► active_load_balance() // 迁移失败时的主动均衡 │ │ └─► stop_one_cpu_nowait() // 使用stop类迁移任务 │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
6.2 SMP启动流程(ARM64)
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ ARM64 SMP 启动流程图 │
├─────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ Boot ROM → ATF (ARM Trusted Firmware) → Bootloader → Kernel entry │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ CPU0 (主核) 启动流程: │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ arch/arm64/kernel/head.S │ │ │
│ │ │ _text (入口点) │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► 设置页表、使能MMU │ │ │
│ │ │ └─► 跳转到 start_kernel │ │ │
│ │ │ │ │ │
│ │ │ init/main.c │ │ │
│ │ │ start_kernel() │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► setup_arch() // arch/arm64/kernel/setup.c │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ └─► smp_init_cpus() // 探测CPU数量 │ │ │
│ │ │ │ └─► of_parse_and_init_cpus() // 从设备树读取 │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► smp_prepare_cpus() // 准备启动secondary CPU │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ └─► 根据启动方式选择: │ │ │
│ │ │ │ ├─► smp_spin_table_ops (自旋表) │ │ │
│ │ │ │ └─► smp_psci_ops (PSCI固件) │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► rest_init() │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ├─► kernel_thread(kernel_init, ...) // 创建init进程 │ │ │
│ │ │ │ └─► cpu_startup_entry(CPUHP_ONLINE) // 进入idle循环 │ │ │
│ │ │ │ │ │ │
│ │ │ └─► smp_init() // 正式启动secondary CPU │ │ │
│ │ │ │ │ │ │
│ │ │ └─► for_each_present_cpu(cpu) { │ │ │
│ │ │ cpu_up(cpu); │ │ │
│ │ │ } │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────────┐ │
│ │ CPU1...n (从核) 启动流程: │ │
│ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 1. CPU0 通过 PSCI 或 自旋表 发送启动信号 │ │ │
│ │ │ │ │ │ │
│ │ │ ▼ │ │ │
│ │ │ 2. arch/arm64/kernel/head.S: secondary_startup() │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► 等待 pen_release == cpu_id (自旋表方式) │ │ │
│ │ │ └─► 跳转到 secondary_startup_kernel() │ │ │
│ │ │ │ │ │
│ │ │ 3. arch/arm64/kernel/smp.c: smp_secondary_init(cpu) │ │ │
│ │ │ │ │ │ │
│ │ │ └─► 设置 pen_release = -1 (通知CPU0完成) │ │ │
│ │ │ │ │ │
│ │ │ 4. start_secondary() │ │ │
│ │ │ │ │ │ │
│ │ │ ├─► cpu_init() // 初始化CPU寄存器 │ │ │
│ │ │ ├─► 初始化 per-CPU 数据 │ │ │
│ │ │ ├─► 设置 current 指向 idle 任务 │ │ │
│ │ │ ├─► notify_cpu_starting(cpu) // 通知其他子系统 │ │ │
│ │ │ ├─► set_cpu_online(cpu, true) // 标记CPU在线 │ │ │
│ │ │ └─► cpu_startup_entry(CPUHP_ONLINE) // 进入 idle 循环 │ │ │
│ │ └──────────────────────────────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────┘
第七部分:调试流程树形分析
7.1 运行时调试接口
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 运行时调试接口(目标系统) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ /proc 接口: │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ /proc/cpuinfo # CPU信息,包括processor、CPU part等 │ │ │ │ /proc/stat # CPU时间统计(user, system, idle等) │ │ │ │ /proc/interrupts # 中断分布(每个CPU的IRQ计数) │ │ │ │ /proc/softirqs # 软中断分布 │ │ │ │ /proc/schedstat # 调度器统计信息 │ │ │ │ /proc/[pid]/stat # 单个进程状态(包含运行的CPU) │ │ │ │ /proc/[pid]/task/ # 进程的线程信息 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ /sys 接口: │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ /sys/devices/system/cpu/ # CPU设备目录 │ │ │ │ ├── cpu0/... # CPU0相关信息 │ │ │ │ ├── cpu1/... │ │ │ │ ├── present # 当前在线的CPU掩码 │ │ │ │ ├── possible # 可能存在的CPU掩码 │ │ │ │ ├── offline # 离线的CPU(可写,用于热插拔) │ │ │ │ └── kernel_max # 最大CPU编号 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 命令行工具: │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ taskset -p [mask] [pid] # 设置进程CPU亲和性 │ │ │ │ chrt -f [prio] [pid] # 设置实时优先级 │ │ │ │ mpstat -P ALL 1 # 查看各CPU使用率 │ │ │ │ top (按1查看各CPU) # 实时监控 │ │ │ │ perf stat -e sched:* ./app # 调度事件跟踪 │ │ │ │ trace-cmd record -e sched* # 调度器追踪 │ │ │ │ echo 0 > /sys/devices/system/cpu/cpu1/online # CPU热插拔(下线) │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
7.2 常见SMP问题调试决策树
┌─────────────────────────────────────────────────────────────────────────────────────┐ │ 常见SMP问题调试决策树(ARM64) │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ 问题: 某个CPU占用率100%,系统响应慢 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Step 1: 确认问题CPU │ │ │ │ $ top -1 │ │ │ │ $ mpstat -P ALL 1 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌─────────────────┼─────────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 用户态进程 │ │ 内核线程 │ │ 软中断 │ │ │ │ 占用高 │ │ 占用高 │ │ 占用高 │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ $ perf top │ │ $ ps -eLf │ │ $ cat/proc/ │ │ │ │ -C [cpu] │ │ 查看ksoftirqd│ │ softirqs │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ 问题: 锁竞争严重,性能下降 │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Step 1: 分析锁等待 │ │ │ │ $ perf lock record -a sleep 10 │ │ │ │ $ perf lock report │ │ │ │ │ │ │ │ Step 2: 查看自旋锁统计(需要内核配置CONFIG_LOCK_STAT) │ │ │ │ $ cat /proc/lock_stat │ │ │ │ │ │ │ │ Step 3: 使用lockdep检测死锁(需要内核配置CONFIG_LOCKDEP) │ │ │ │ # 查看 /proc/lockdep_chain │ │ │ │ # 查看 /proc/lockdep_stats │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ ├─────────────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ 问题: 负载不均衡,某些CPU空闲而其他忙碌(big.LITTLE架构常见) │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌────────────────────────────────────────────────────────────────────────────────┐ │ │ │ Step 1: 查看调度域配置 │ │ │ │ $ cat /proc/sys/kernel/sched_domain/cpu*/domain*/flags │ │ │ │ │ │ │ │ Step 2: 查看EAS(能量感知调度)状态 │ │ │ │ $ cat /proc/sys/kernel/sched_energy_aware │ │ │ │ │ │ │ │ Step 3: 调整负载均衡参数 │ │ │ │ # 减少负载均衡间隔 │ │ │ │ echo 1 > /proc/sys/kernel/sched_min_interval │ │ │ │ │ │ │ │ # 允许更激进的任务迁移 │ │ │ │ echo 1 > /proc/sys/kernel/sched_migration_cost_ns │ │ │ │ │ │ │ │ Step 4: 使用trace-cmd追踪负载均衡 │ │ │ │ $ trace-cmd record -e sched:sched_migrate_task -e sched:sched_balance* │ │ │ └────────────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────────────┘
第八部分:总结对比表
| 分析维度 | 编译前(源码树) | 运行时(目标系统) |
|---|---|---|
| 源码位置 | 开发者下载的 linux-6.1/ 目录 |
/lib/modules/$(uname -r)/build/(符号链接) |
| 头文件 | include/linux/*.h, arch/arm64/include/asm/*.h |
/usr/include/linux/(用户态头文件,不同) |
| 核心数据结构定义 | include/linux/sched.h, kernel/sched/sched.h |
只能通过 /proc 和 /sys 查看运行时状态 |
| 函数实现 | kernel/sched/core.c, kernel/sched/fair.c 等 |
只能通过 System.map 查看地址,无法查看源码 |
| 调试接口 | CONFIG_DEBUG_* 编译选项,printk() |
/proc/*, /sys/*, perf, trace-cmd |
| 修改方式 | 编辑源码 → 重新编译 → 安装新内核 | 只能修改 /proc/sys/kernel/sched_* 运行时参数 |
核心要点:
-
编译前:开发者分析
arch/arm64/kernel/smp.c、kernel/sched/等源码文件 -
运行时:系统管理员使用
mpstat -P ALL、taskset、/proc/interrupts等工具 -
不要混淆:
/usr/src/linux通常不存在,需要手动安装linux-source包
更多推荐


所有评论(0)