当前位置: 移动技术网 > 科技>操作系统>Linux > 【原创】Linux cpufreq framework

【原创】Linux cpufreq framework

2019年08月21日  | 移动技术网科技  | 我要评论

背景

  • read the fucking source code! --by 鲁迅
  • a picture is worth a thousand words. --by 高尔基

说明:

  1. kernel版本:4.14
  2. arm64处理器
  3. 使用工具:source insight 3.5, visio

1. 介绍

  • cpufreq子系统负责在运行时对cpu频率和电压的动态调整,以达到性能和功耗的平衡,它也叫dvfs(dynamic voltage frequency scaling)
  • dvfs原理:cmos电路中功耗与电压的平方成正比,与频率也成正比。此外,频率越高,性能也越强,相应的能耗就增大了,所以tradeoff依旧是一门艺术。
  • cpufreq framework类似于cpuidle framework,提供机制(cpufreq driver)与策略(cpufreq governor),此外提供了cpufreq core来对机制和策略进行管理。

2. 框架

主要代码路径:
driver/cpufreq/cpufreq.c
include/linux/cpufreq.h
drivers/cpufreq/cpufreq_userspace.c

先上框架图:

粗一看与cpuidle framework的图很像,但是有些差别如下:

  • 用户层与cpufreq framework的交互,主要是通过sysfs,这个可以在/sys下看到很多文件,而kernel module也可以使用某些接口来回调它;
  • 系统只允许有一个platform drivers,为全局变量cpufreq_drivercpufreq core通过它去回调驱动;
  • 驱动与硬件的交互,通过如set_clk_rate/regulator_set_voltage等接口去设置cpu的时钟和电压,而不再是cpu_ops
  • 有一个全局的governor链表cpufreq_governor_list,可以通过查找链表来选择合适的governor

3. 数据结构

核心的数据结构有三个:

  • struct cpufreq_policy:用于描述不同的policy,涉及到频率表、cpuinfo等各种信息,并且每个policy都会指向某个governor
  • struct cpufreq_governor:用于对policy的管理;
  • struct cpufreq_driver:用于描述具体的驱动程序;
    如下图:

4. 流程

4.1 cpufreq_driver注册

仔细观察上图中struct cpufreq_driver结构体,你会发现它与传统的设备模型中的驱动结构不一致,它并没有内嵌struct bus_typestruct device_driver类型,这就决定了它不属于“device<--->bus<--->driver”这种模型。
事实上,cpufreq_driver是一个全局的变量,不属于任何一个拓扑的结构。它的注册从cpufreq_register_driver开始。
流程如下图:

4.2 governor注册

接口为:cpufreq_register_governor,这个操作实在是太简单了,添加到全局链表即可,完事!
顺带提一句吧,还有一个接口cpufreq_register_notifier,这个用于通知机制,具体不再深入分析了。

4.3 sysfs访问

cpufreq core会在/sys目录下创建相应的节点,如下图所示:

用户态可以通过cat/echo命令来读取/设置相应的值。

对应结构体如下:

static struct attribute *default_attrs[] = {
    &cpuinfo_min_freq.attr,
    &cpuinfo_max_freq.attr,
    &cpuinfo_transition_latency.attr,
    &scaling_min_freq.attr,
    &scaling_max_freq.attr,
    &affected_cpus.attr,
    &related_cpus.attr,
    &scaling_governor.attr,
    &scaling_driver.attr,
    &scaling_available_governors.attr,
    &scaling_setspeed.attr,
    null
};

各个字段含义如下:

  • affected_cpus:需要软件调整频率的cpu列表;
  • related_cpus:需要软件或硬件来调整频率的cpu列表;
  • cpuinfo_max_freq:cpu能够支持的最高频率(khz);
  • cpuinfo_min_freq:cpu能够支持的最小频率(khz);
  • cpuinfo_transition_latency:cpu频率切换时的时间开销(ns);
  • scaling_available_governors:内核中支持的governor
  • scaling_driver:硬件驱动,比如cpufreq-dt
  • scaling_cur_freq:cpu工作频率;
  • scaling_max_freq:当前policy的频率上限;
  • scaling_min_freq:当前policy的频率下限;
  • scaling_governor:cpu调频策略,可以修改;
  • scaling_setspeed:设置cpu运行频率;
    如下图:

sysfs回调下来后,会进入xxx_store/xxx_show函数来进行具体的设置,至于设置的流程大体与cpufreq_driver注册图中类似,不再深入分析了。

驱动的实现变成了实现struct cpufreq_driver函数指针中的函数,并注册即可。目前的驱动开发大抵如此,变成了一道填空题,当然我们也需要去了解背后的原理。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网