电源管理入门3 CPU热插拔hotplug

2023年 10月 11日 34.8k 0

插图xxx

  之前介绍了电源的开机和关机重启,本小节开始介绍省电的技术,其中最暴力的省电方法就是直接拔核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制定的策略、温控策略等。
  • 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为例):
echo 0 > /sys/devices/system/cpu/cpu1/online //拔核操作

echo 1 > /sys/devices/system/cpu/cpu1/online //插核操作
当操作/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;

ret = strtobool(buf, &val);
if (ret < 0)
return ret;

ret = lock_device_hotplug_sysfs();
if (ret)
return ret;

ret = val ? device_online(dev) : device_offline(dev);
unlock_device_hotplug();
return ret < 0 ? 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),        \
     .mode = VERIFY_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 = {
.name = "cpu",
.dev_name = "cpu",
.match = cpu_subsys_match,
#ifdef CONFIG_HOTPLUG_CPU
.online = cpu_subsys_online,
.offline = cpu_subsys_offline,
#endif
};
cpu_device_down
cpu_down
cpu_down_maps_locked
_cpu_down
cpuhp_down_callbacks

    [CPUHP_TEARDOWN_CPU] = {
            .name                        = "cpu:teardown",
            .startup.single                = NULL,
            .teardown.single        = takedown_cpu,
            .cant_stop                = true,
    },

do_idle状态机会调用arch_cpu_idle_dead--》cpu_die();--》ops->cpu_die(cpu);
psci_cpu_die--》psci_ops.cpu_off(state);--》psci_0_2_cpu_off

__psci_cpu_off(PSCI_0_2_FN_CPU_OFF, state);

之前在XXX中介绍的PSCI协议部分,这里会发送smc指令到ATF

在ATF中同理会处理这些PSCI协议。

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论