一文搞懂linux cpu hotplug

​1. 介绍

Linux 的cpu热插拔是cpu电源管理的一部分,支持系统在负载比较低的时候,拔掉一个cpu,从而省下cpu的静态功耗,并在系统需要时,重新将cpu插上。

另外,在多cpu系统启动、休眠唤醒的过程中也会涉及到non-boot cpu的拔插。

2. 数据结构

cpu hotplug数据结构

3. CPU状态

cpu的状态包括:possible、present、online、active。

  • possible状态的cpu:可理解为存在这个CPU资源,但还没有纳入Kernel的管理范围。
  • present状态的cpu:表示已经被kernel接管。
  • online状态的cpu:表示可以被调度器使用。
  • active状态的cpu:表示可以被迁移migrate。

4. 拔插流程

Linux内核在初始的时候,会创建虚拟总线cpu_subsys,每个cpu调用register_cpu注册时,都会将cpu设备挂在这个总线下。

cpu的拔插是通过操作文件节点online实现的,具体拔插操作如下(以cpu1为例):

  • 拔核操作

echo 0 > /sys/devices/system/cpu/cpu1/online

  • 插核操作

echo 1 > /sys/devices/system/cpu/cpu1/online

CPU的拔插流程可以概括为:

cpu hotplug流程

AP:将要被拔掉的cpu。

BP:处理拔核流程的cpu。

4.1 CPU UP

cpu up流程

  • 颜色的含义:
    • 绿色:系统初始化过程调用。
    • 黄色:BP上做的处理。
    • 橙色:AP上做的处理。
  • Kernel会为每个cpu都创建一个hotplug线程,执行state中定义的状态回调函数,比如teardown/startup。
  • cpu_up的时候依赖底层的具体实现,没有进一步画出cpu_boot后的动作,这后面linux会通过PSCI接口跟ATF通信,然后由ATF跟其他电源管理模块通信,最终由电源管理模块完成上电。

4.2 CPU DOWN

cpu down流程

  • cpu down的流程跟cpu on相反,整个过程很类似;
  • cpuhp拔插核线程创建后,由于should_run为false,所以并没有实质的运行,并处于S状态,在_cpu_down函数中,由__cpuhp_kick_ap函数将should_run置成true,然后wake_up_process cpuhp线程运行在被拔核cpu,然后等待cpuhp运行到指定状态(从CPUHP_ONLINE到CPUHP_TEARDOWN_CPU)的teardown.single调用;
  • cpuhp线程(cpuhp_thread_fun)从CPUHP_ONLINE执行到CPUHP_TEARDOWN_CPU状态,做相关的teardown.single的调用,对于takedown_cpu的调用首先在处理拔核的cpu上运行,会停止每cpu线程,然后通过stop_machine_cpuslocked函数将take_cpu_down任务queue到被拔核的stopper线程上运行,在stop_machine_cpuslocked的__stop_cpus函数中,拔核cpu会通过wait_for_completion(&done.completion)等待被拔核cpu的migrate线程(cpu_stopper_thread)执行完work的回调(muti_cpu_stop,会调用到take_cpu_down),被拔核cpu执行完work的回调后,就会从过cpu_stop_signal_done函数释放信号量(complete(&done->completion)),然后拔核cpu继续运行将被拔核cpu下电;
  • 对于运行在被拔核cpu上的stopper线程(migration)执行take_cpu_down,会先通过执行__cpu_disable将被拔核cpu设为offline,然后从CPUHP_TEARDOWN_CPU运行到CPUHP_AP_OFFLINE状态的teardown.single调用,然后调用stop_machine_park将stopper线程的flag置上KTHREAD_SHOULD_PARK,然后在hotplug线程循环函数smpboot_thread_fn中判断KTHREAD_SHOULD_PARK,然后将stopper线程停下来,然后kthread_parkme里会调用schedule_preempt_disabled schedule出去,然后这时会运行被拔核上的idle线程(或者将其他非rq上的task拉到被拔核cpu执行)。
  • 运行被拔核cpu上的idle线程会通过函数cpu_is_offline判断当前的cpu是否offline,若offline会调用cpuhp_report_idle_dead,然后调用cpuhp_complete_idle_dead,先将state设为CPUHP_AP_IDLE_DEAD,进而complete_ap_thread,这时拔核cpu一直阻塞在takedown_cpu函数中的wait_for_ap_thread,然后拔核cpu执行最后的拔核操作;
  • cpu电的关闭是通过do_idle->cpu_die->cpu_off利用PSCI向ATF发起关闭cpu的请求,然后由ATF跟其他电源管理模块通信,最终在电源管理模块将cpu的电关闭。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值