之前介绍了电源的**开机**和**关机重启**本小节开始介绍**省电**的技术其中最暴力的省电方法就是直接**拔核hotplug**处理就像需要10个人干活都要吃饭但是现在活少了最节省的方法就是砍掉几个人有点像**裁员**啊。1. 省电技术概览对于省电我们短时间不使用设备的时候可以进行休眠唤醒长时间不使用就直接关机了。在使用设备的时候可以按照当前需要的性能进行调频处理就是CPUFreq和DevFeq当没重度使用或者只运行系统必须进程的时候可以进行CPU休闲(CPUIdle)、CPU热插拔(CPU Hotplug)、CPU隔离(Core Isolate)和动态PM(Runtime PM)。CPUIdle指的是当某个CPU上没有进程可调度的时候可以暂时局部关掉这个CPU的电源从而达到省电的目的当再有进程需要执行的时候再恢复电源。CPU Hotplug指的是我们可以把某个CPU热移除然后系统就不会再往这个CPU上派任务了这个CPU就可以放心地完全关闭电源了当把这个CPU再热插入之后就对这个CPU恢复供电这个CPU就可以正常执行任务了。CPU隔离指的是我们把某个CPU隔离开来系统不再把它作为进程调度的目标这样这个CPU就可以长久地进入Idle状态了达到省电的目的。不过CPU隔离并不是专门的省电机制我们把CPU隔离之后还可以通过set_affinity把进程专门迁移到这个CPU上这个CPU还会继续运行。CPU隔离能达到一种介于CPUIdle和CPU热插拔之间的效果。Runtime PM指的是设备的动态电源管理系统中存在很多设备但是并不是每种设备都在一直使用比如相机可能在大部分时间都不会使用所以我们可以在大部分时间把相机的电源关闭在需用相机的时候再给相机供电。cpu hotplug和idle的区别hotplug是从硬件上拔掉核下电idle只是从软件上进行处理也就是说调度器在idle时只是不去调用但是核还是可见的hotplug直接没这个核了软件完全不可见。省电管理可以达到省电的目的但是也会降低系统的性能包括响应延迟、带宽、吞吐量等。所以内核又提供了一个PM QoS框架QoS是Quality Of Service(服务质量)。PM QoS框架一面向顾客提供接口顾客可以通过这些接口对系统的性能提出要求一面向各种省电机制下发要求省电机制在省电的同时也要满足这些性能要求。PM QoS的顾客包括内核和进程对于内核PM QoS提供了接口函数可以直接调用对于进程PM QoS提供了一些设备文件可以让用户空间进行读写。PM QoS对某一项性能指标的要求叫做一个约束约束分为系统级约束和设备级约束。系统级约束针对的是整个系统的性能要求设备级约束针对的是某个设备的性能要求。整体上电源管理也是策略和机制分离的例如hotplug是一个机制谁去用可以用户App制定的策略、温控策略、系统suspend时需要等。CPUFreq是策略和机制都包含的。2. 热插拔代码介绍cpu的状态包括possible、present、online、active。possible状态的cpu可理解为存在这个CPU资源但还没有纳入Kernel的管理范围。present状态的cpu表示已经被kernel接管。online状态的cpu表示可以被调度器使用。active状态的cpu表示可以被迁移migrate。Linux内核在初始的时候会创建虚拟总线cpu_subsys每个cpu调用register_cpu注册时都会将cpu设备挂在这个总线下。cpu的拔插是通过操作文件节点online实现的具体拔插操作如下以cpu1为例echo0/sys/devices/system/cpu/cpu1/online //拔核操作echo1/sys/devices/system/cpu/cpu1/online //插核操作为什么以cpu1为例?Linux CPU热插拔支持在系统启动后关闭任意一个secondary cpu在ARM架构中CPU0为boot cpu不能被关闭并在需要时重新打开它。当操作/sys/devices/system/cpu/cpu1/online文件的时候会执行drivers/base/core.c中online_store函数static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){bool val;int ret;retstrtobool(buf,val);if(ret0)returnret;retlock_device_hotplug_sysfs();if(ret)returnret;retval ? device_online(dev):device_offline(dev);unlock_device_hotplug();returnret0? ret:count;}static DEVICE_ATTR_RW(online);这块有一个sysfs的知识点就是DEVICE_ATTR_RW(online);声明了这个宏就可以在文件系统里面为这个设备熟悉添加一个文件当向这个文件写入字符串的时候就会调用拼接出来的online_store函数读这个文件的时候就会调用online_show函数#define __ATTR(_name, _mode, _show, _store) { \.attr{.name__stringify(_name),\.modeVERIFY_OCTAL_PERMISSIONS(_mode)},\.show_show,\.store_store,\}#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)#define DEVICE_ATTR_RW(_name) \struct device_attribute dev_attr_##_name __ATTR_RW(_name)在online_store函数中拔核就执行device_offline(dev)函数device_offline中dev-bus-offline(dev);drivers/base/cpu.c中struct bus_type cpu_subsys{.namecpu, .dev_namecpu, .matchcpu_subsys_match,#ifdef CONFIG_HOTPLUG_CPU.onlinecpu_subsys_online, .offlinecpu_subsys_offline,#endif};cpu_device_down cpu_down cpu_down_maps_locked _cpu_down cpuhp_down_callbacks takedown_cpu[CPUHP_TEARDOWN_CPU]{.namecpu:teardown, .startup.singleNULL, .teardown.singletakedown_cpu, .cant_stoptrue,},do_idle状态机会调用arch_cpu_idle_dead cpu_die cpu_die psci_cpu_die psci_ops.cpu_off psci_0_2_cpu_offpsci_0_2_cpu_off会调用__psci_cpu_off(PSCI_0_2_FN_CPU_OFF, state);最终发送smc指令给ATF上面的cpu down流程汇总如下图cpu up流程具体代码自己加log或者打断点看好些。3. ATF中处理之前在[电源管理入门-1关机重启详解](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484601idx1sn4b3e42481f74110d0b5a21e01d95a09dchksmfa52829dcd250b8ba7a691a91759498a2a862510833856e7f07ef2c9315f15c72f8f88413812scene21#wechat_redirect)中介绍的PSCI协议部分这里会发送smc指令到ATF。在ATF中同理,会处理这些PSCI协议这里不详细介绍了。后记本篇文章尝试用markdown进行编写图片用Midjourney生成感觉效果还可以之前每篇文章的排版很费时间。markdown可以只保留最小的一些格式把注意力关注到文章内容本身提高效率才能多写一些文章进行更新。“啥都懂一点啥都不精通干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。后续会继续更新纯干货分析欢迎分享给朋友欢迎评论交流公众号“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io
电源管理入门-3 CPU热插拔hotplug
之前介绍了电源的**开机**和**关机重启**本小节开始介绍**省电**的技术其中最暴力的省电方法就是直接**拔核hotplug**处理就像需要10个人干活都要吃饭但是现在活少了最节省的方法就是砍掉几个人有点像**裁员**啊。1. 省电技术概览对于省电我们短时间不使用设备的时候可以进行休眠唤醒长时间不使用就直接关机了。在使用设备的时候可以按照当前需要的性能进行调频处理就是CPUFreq和DevFeq当没重度使用或者只运行系统必须进程的时候可以进行CPU休闲(CPUIdle)、CPU热插拔(CPU Hotplug)、CPU隔离(Core Isolate)和动态PM(Runtime PM)。CPUIdle指的是当某个CPU上没有进程可调度的时候可以暂时局部关掉这个CPU的电源从而达到省电的目的当再有进程需要执行的时候再恢复电源。CPU Hotplug指的是我们可以把某个CPU热移除然后系统就不会再往这个CPU上派任务了这个CPU就可以放心地完全关闭电源了当把这个CPU再热插入之后就对这个CPU恢复供电这个CPU就可以正常执行任务了。CPU隔离指的是我们把某个CPU隔离开来系统不再把它作为进程调度的目标这样这个CPU就可以长久地进入Idle状态了达到省电的目的。不过CPU隔离并不是专门的省电机制我们把CPU隔离之后还可以通过set_affinity把进程专门迁移到这个CPU上这个CPU还会继续运行。CPU隔离能达到一种介于CPUIdle和CPU热插拔之间的效果。Runtime PM指的是设备的动态电源管理系统中存在很多设备但是并不是每种设备都在一直使用比如相机可能在大部分时间都不会使用所以我们可以在大部分时间把相机的电源关闭在需用相机的时候再给相机供电。cpu hotplug和idle的区别hotplug是从硬件上拔掉核下电idle只是从软件上进行处理也就是说调度器在idle时只是不去调用但是核还是可见的hotplug直接没这个核了软件完全不可见。省电管理可以达到省电的目的但是也会降低系统的性能包括响应延迟、带宽、吞吐量等。所以内核又提供了一个PM QoS框架QoS是Quality Of Service(服务质量)。PM QoS框架一面向顾客提供接口顾客可以通过这些接口对系统的性能提出要求一面向各种省电机制下发要求省电机制在省电的同时也要满足这些性能要求。PM QoS的顾客包括内核和进程对于内核PM QoS提供了接口函数可以直接调用对于进程PM QoS提供了一些设备文件可以让用户空间进行读写。PM QoS对某一项性能指标的要求叫做一个约束约束分为系统级约束和设备级约束。系统级约束针对的是整个系统的性能要求设备级约束针对的是某个设备的性能要求。整体上电源管理也是策略和机制分离的例如hotplug是一个机制谁去用可以用户App制定的策略、温控策略、系统suspend时需要等。CPUFreq是策略和机制都包含的。2. 热插拔代码介绍cpu的状态包括possible、present、online、active。possible状态的cpu可理解为存在这个CPU资源但还没有纳入Kernel的管理范围。present状态的cpu表示已经被kernel接管。online状态的cpu表示可以被调度器使用。active状态的cpu表示可以被迁移migrate。Linux内核在初始的时候会创建虚拟总线cpu_subsys每个cpu调用register_cpu注册时都会将cpu设备挂在这个总线下。cpu的拔插是通过操作文件节点online实现的具体拔插操作如下以cpu1为例echo0/sys/devices/system/cpu/cpu1/online //拔核操作echo1/sys/devices/system/cpu/cpu1/online //插核操作为什么以cpu1为例?Linux CPU热插拔支持在系统启动后关闭任意一个secondary cpu在ARM架构中CPU0为boot cpu不能被关闭并在需要时重新打开它。当操作/sys/devices/system/cpu/cpu1/online文件的时候会执行drivers/base/core.c中online_store函数static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){bool val;int ret;retstrtobool(buf,val);if(ret0)returnret;retlock_device_hotplug_sysfs();if(ret)returnret;retval ? device_online(dev):device_offline(dev);unlock_device_hotplug();returnret0? ret:count;}static DEVICE_ATTR_RW(online);这块有一个sysfs的知识点就是DEVICE_ATTR_RW(online);声明了这个宏就可以在文件系统里面为这个设备熟悉添加一个文件当向这个文件写入字符串的时候就会调用拼接出来的online_store函数读这个文件的时候就会调用online_show函数#define __ATTR(_name, _mode, _show, _store) { \.attr{.name__stringify(_name),\.modeVERIFY_OCTAL_PERMISSIONS(_mode)},\.show_show,\.store_store,\}#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)#define DEVICE_ATTR_RW(_name) \struct device_attribute dev_attr_##_name __ATTR_RW(_name)在online_store函数中拔核就执行device_offline(dev)函数device_offline中dev-bus-offline(dev);drivers/base/cpu.c中struct bus_type cpu_subsys{.namecpu, .dev_namecpu, .matchcpu_subsys_match,#ifdef CONFIG_HOTPLUG_CPU.onlinecpu_subsys_online, .offlinecpu_subsys_offline,#endif};cpu_device_down cpu_down cpu_down_maps_locked _cpu_down cpuhp_down_callbacks takedown_cpu[CPUHP_TEARDOWN_CPU]{.namecpu:teardown, .startup.singleNULL, .teardown.singletakedown_cpu, .cant_stoptrue,},do_idle状态机会调用arch_cpu_idle_dead cpu_die cpu_die psci_cpu_die psci_ops.cpu_off psci_0_2_cpu_offpsci_0_2_cpu_off会调用__psci_cpu_off(PSCI_0_2_FN_CPU_OFF, state);最终发送smc指令给ATF上面的cpu down流程汇总如下图cpu up流程具体代码自己加log或者打断点看好些。3. ATF中处理之前在[电源管理入门-1关机重启详解](http://mp.weixin.qq.com/s?__bizMzUzMDMwNTg2Nwmid2247484601idx1sn4b3e42481f74110d0b5a21e01d95a09dchksmfa52829dcd250b8ba7a691a91759498a2a862510833856e7f07ef2c9315f15c72f8f88413812scene21#wechat_redirect)中介绍的PSCI协议部分这里会发送smc指令到ATF。在ATF中同理,会处理这些PSCI协议这里不详细介绍了。后记本篇文章尝试用markdown进行编写图片用Midjourney生成感觉效果还可以之前每篇文章的排版很费时间。markdown可以只保留最小的一些格式把注意力关注到文章内容本身提高效率才能多写一些文章进行更新。“啥都懂一点啥都不精通干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。后续会继续更新纯干货分析欢迎分享给朋友欢迎评论交流公众号“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io