Linux动态调频系统CPUFreq之一:概述【转】
转自:https://blog.csdn.net/zhangyongfeiyong/article/details/53506362
随着技术的发展,我们对CPU的处理能力提出了越来越高的需求,芯片厂家也对制造工艺不断地提升。现在的主流PC处理器的主频已经在3GHz左右,就算是智能手机的处理器也已经可以工作在1.5GHz以上,可是我们并不是时时刻刻都需要让CPU工作在最高的主频上,尤其是移动设备和笔记本电脑,大部分时间里,CPU其实工作在轻负载状态下,我们知道:主频越高,功耗也越高。为了节省CPU的功耗和减少发热,我们有必要根据当前CPU的负载状态,动态地提供刚好足够的主频给CPU。在Linux中,内核的开发者定义了一套框架模型来完成这一目的,它就是CPUFreq系统。
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.NET/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
1. sysfs接口
我们先从CPUFreq提供的sysfs接口入手,直观地看看它提供了那些功能。以下是我的电脑输出的结果:
- droidphone@990:~$ cd /sys/devices/system/cpu
- droidphone@990:/sys/devices/system/cpu$ ls
- cpu0 cpu3 cpu6 cpuidle offline power release
- cpu1 cpu4 cpu7 kernel_max online present uevent
- cpu2 cpu5 cpufreq modalias possible probe
droidphone@990:~$ cd /sys/devices/system/cpu
droidphone@990:/sys/devices/system/cpu$ ls
cpu0 cpu3 cpu6 cpuidle offline power release
cpu1 cpu4 cpu7 kernel_max online present uevent
cpu2 cpu5 cpufreq modalias possible probe
所有与CPUFreq相关的sysfs接口都位于:/sys/devices/system/cpu下面,我们可以看到,8个cpu分别建立了一个自己的目录,从cpu0到cpu7,我们再看看offline和online以及present的内容:
- droidphone@990:/sys/devices/system/cpu$ cat online
- 0-7
- droidphone@990:/sys/devices/system/cpu$ cat offline
- 8-15
- droidphone@990:/sys/devices/system/cpu$ cat present
- 0-7
- droidphone@990:/sys/devices/system/cpu$
droidphone@990:/sys/devices/system/cpu$ cat online
0-7
droidphone@990:/sys/devices/system/cpu$ cat offline
8-15
droidphone@990:/sys/devices/system/cpu$ cat present
0-7
droidphone@990:/sys/devices/system/cpu$
online代表目前正在工作的cpu,输出显示编号为0-7这8个cpu在工作,offline代表目前被关掉的cpu,present则表示主板上已经安装的cpu,由输出可以看到,我的主板可以安装16个cpu(因为intel的超线程技术,其实物理上只是8个),第8-15号cpu处于关闭状态(实际上不存在,因为present只有0-7)。
接着往下看:
- droidphone@990:/sys/devices/system/cpu/cpu0$ ls
- cache cpuidle microcode power thermal_throttle uevent
- cpufreq crash_notes node0 subsystem topology
- droidphone@990:/sys/devices/system/cpu/cpu0$ cd cpufreq/
- droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ ls
- affected_cpus related_cpus scaling_max_freq
- bios_limit scaling_available_frequencies scaling_min_freq
- cpuinfo_cur_freq scaling_available_governors scaling_setspeed
- cpuinfo_max_freq scaling_cur_freq stats
- cpuinfo_min_freq scaling_driver
- cpuinfo_transition_latency scaling_governor
- droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$
droidphone@990:/sys/devices/system/cpu/cpu0$ ls
cache cpuidle microcode power thermal_throttle uevent
cpufreq crash_notes node0 subsystem topology
droidphone@990:/sys/devices/system/cpu/cpu0$ cd cpufreq/
droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ ls
affected_cpus related_cpus scaling_max_freq
bios_limit scaling_available_frequencies scaling_min_freq
cpuinfo_cur_freq scaling_available_governors scaling_setspeed
cpuinfo_max_freq scaling_cur_freq stats
cpuinfo_min_freq scaling_driver
cpuinfo_transition_latency scaling_governor
droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$
在我的电脑上,部分的值如下:
cpuinfo_cur_freq: 1600000
cpuinfo_max_freq: 3401000
cpuinfo_min_freq: 1600000
scaling_cur_freq: 1600000
scaling_max_freq: 3401000
scaling_min_freq: 1600000
所以,我的cpu0的最低运行频率是1.6GHz,最高是3.4GHz,目前正在运行的频率是1.6GHz,前缀cpuinfo代表的是cpu硬件上支持的频率,而scaling前缀代表的是可以通过CPUFreq系统用软件进行调节时所支持的频率。cpuinfo_cur_freq代表通过硬件实际上读到的频率值,而scaling_cur_freq则是软件当前的设置值,多数情况下这两个值是一致的,但是也有可能因为硬件的原因,有微小的差异。scaling_available_frequencies会输出当前软件支持的频率值,看看我的cpu支持那些频率:
- droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_available_frequencies
- 3401000 3400000 3000000 2800000 2600000 2400000 2200000 2000000 1800000 1600000
- droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$
droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_available_frequencies
3401000 3400000 3000000 2800000 2600000 2400000 2200000 2000000 1800000 1600000
droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$
Oh,从1.6GHz到3.4GHz,一共支持10挡的频率可供选择。scaling_available_governors则会输出当前可供选择的频率调节策略:
- conservative ondemand userspace powersave performance
conservative ondemand userspace powersave performance
一共有5中策略供我们选择,那么当前系统选用那种策略?让我们看看:
- dong@dong-990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_governor
- ondemand
dong@dong-990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_governor
ondemand
OK,我的系统当前选择ondemand这种策略,这种策略的主要思想是:只要cpu的负载超过某一个阀值,cpu的频率会立刻提升至最高,然后再根据实际情况降到合适的水平。详细的情况我们留在后面的章节中讨论。scaling_driver则会输出当前使用哪一个驱动来设置cpu的工作频率。
当我们选择userspace作为我们的调频governor时,我们可以通过scaling_setspeed手工设置需要的频率。powersave则简单地使用最低的工作频率进行运行,而performance则一直选择最高的频率进行运行。
2. 软件架构
通过上一节的介绍,我们可以大致梳理出CPUFreq系统的构成和工作方式。首先,CPU的硬件特性决定了这个CPU的最高和最低工作频率,所有的频率调整数值都必须在这个范围内,它们用cpuinfo_xxx_freq来表示。然后,我们可以在这个范围内再次定义出一个软件的调节范围,它们用scaling_xxx_freq来表示,同时,根据具体的硬件平台的不同,我们还需要提供一个频率表,这个频率表规定了cpu可以工作的频率值,当然这些频率值必须要在cpuinfo_xxx_freq的范围内。有了这些频率信息,CPUFreq系统就可以根据当前cpu的负载轻重状况,合理地从频率表中选择一个合适的频率供cpu使用,已达到节能的目的。至于如何选择频率表中的频率,这个要由不同的governor来实现,目前的内核版本提供了5种governor供我们选择。选择好适当的频率以后,具体的频率调节工作就交由scaling_driver来完成。CPUFreq系统把一些公共的逻辑和接口代码抽象出来,这些代码与平台无关,也与具体的调频策略无关,内核的文档把它称为CPUFreq Core(/Documents/cpufreq/core.txt)。另外一部分,与实际的调频策略相关的部分被称作cpufreq_policy,cpufreq_policy又是由频率信息和具体的governor组成,governor才是具体策略的实现者,当然governor需要我们提供必要的频率信息,governor的实现最好能做到平台无关,与平台相关的代码用cpufreq_driver表述,它完成实际的频率调节工作。最后,如果其他内核模块需要在频率调节的过程中得到通知消息,则可以通过cpufreq notifiers来完成。由此,我们可以总结出CPUFreq系统的软件结构如下:
3. cpufreq_policy
一种调频策略的各种限制条件的组合称之为policy,代码中用cpufreq_policy这一数据结构来表示:
- struct cpufreq_policy {
- cpumask_var_t cpus;
- cpumask_var_t related_cpus;
- unsigned int shared_type;
- unsigned int cpu;
- unsigned int last_cpu;
- struct cpufreq_cpuinfo cpuinfo;
- unsigned int min; /* in kHz */
- unsigned int max; /* in kHz */
- unsigned int cur;
- unsigned int policy;
- struct cpufreq_governor *governor;
- void *governor_data;
- struct work_struct update;
- struct cpufreq_real_policy user_policy;
- struct kobject kobj;
- struct completion kobj_unregister;
- };
- struct cpufreq_policy {
- cpumask_var_t cpus;
- cpumask_var_t related_cpus;
- unsigned int shared_type;
- unsigned int cpu;
- unsigned int last_cpu;
- struct cpufreq_cpuinfo cpuinfo;
- unsigned int min; /* in kHz */
- unsigned int max; /* in kHz */
- unsigned int cur;
- unsigned int policy;
- struct cpufreq_governor *governor;
- void *governor_data;
- struct work_struct update;
- struct cpufreq_real_policy user_policy;
- struct kobject kobj;
- struct completion kobj_unregister;
- };
其中的各个字段的解释如下:
- cpus和related_cpus 这两个都是cpumask_var_t变量,cpus表示的是这一policy控制之下的所有还出于online状态的cpu,而related_cpus则是online和offline两者的合集。主要是用于多个cpu使用同一种policy的情况,实际上,我们平常见到的大多数系统中都是这种情况:所有的cpu同时使用同一种policy。我们需要related_cpus变量指出这个policy所管理的所有cpu编号。
- cpu和last_cpu 虽然一种policy可以同时用于多个cpu,但是通常一种policy只会由其中的一个cpu进行管理,cpu变量用于记录用于管理该policy的cpu编号,而last_cpu则是上一次管理该policy的cpu编号(因为管理policy的cpu可能会被plug out,这时候就要把管理工作迁移到另一个cpu上)。
- cpuinfo 保存cpu硬件所能支持的最大和最小的频率以及切换延迟信息。
- min/max/cur 该policy下的可使用的最小频率,最大频率和当前频率。
- policy 该变量可以取以下两个值:CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE,该变量只有当调频驱动支持setpolicy回调函数的时候有效,这时候由驱动根据policy变量的值来决定系统的工作频率或状态。如果调频驱动(cpufreq_driver)支持target回调,则频率由相应的governor来决定。
- governor和governor_data 指向该policy当前使用的cpufreq_governor结构和它的上下文数据。governor是实现该policy的关键所在,调频策略的逻辑由governor实现。
- update 有时在中断上下文中需要更新policy,需要利用该工作队列把实际的工作移到稍后的进程上下文中执行。
- user_policy 有时候因为特殊的原因需要修改policy的参数,比如溫度过高时,最大可允许的运行频率可能会被降低,为了在适当的时候恢复原有的运行参数,需要使用user_policy保存原始的参数(min,max,policy,governor)。
- kobj 该policy在sysfs中对应的kobj的对象。
4. cpufreq_governor
所谓的governor,我把它翻译成:调节器。governor负责检测cpu的使用状况,从而在可用的范围中选择一个合适的频率,代码中它用cpufreq_governor结构来表示:
- struct cpufreq_governor {
- char name[CPUFREQ_NAME_LEN];
- int initialized;
- int (*governor) (struct cpufreq_policy *policy,
- unsigned int event);
- ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
- char *buf);
- int (*store_setspeed) (struct cpufreq_policy *policy,
- unsigned int freq);
- unsigned int max_transition_latency; /* HW must be able to switch to
- next freq faster than this value in nano secs or we
- will fallback to performance governor */
- struct list_head governor_list;
- struct module *owner;
- };
- struct cpufreq_governor {
- char name[CPUFREQ_NAME_LEN];
- int initialized;
- int (*governor) (struct cpufreq_policy *policy,
- unsigned int event);
- ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
- char *buf);
- int (*store_setspeed) (struct cpufreq_policy *policy,
- unsigned int freq);
- unsigned int max_transition_latency; /* HW must be able to switch to
- next freq faster than this value in nano secs or we
- will fallback to performance governor */
- struct list_head governor_list;
- struct module *owner;
- };
其中的各个字段的解释如下:
- name 该governor的名字。
- initialized 初始化标志。
- governor 指向一个回调函数,CPUFreq Core会在不同的阶段调用该回调函数,用于该governor的启动、停止、初始化、退出动作。
- list_head 所有注册的governor都会利用该字段链接在一个全局链表中,以供系统查询和使用。
5. cpufreq_driver
上一节提到的gonvernor只是负责计算并提出合适的频率,但是频率的设定工作是平台相关的,这需要cpufreq_driver驱动来完成,cpufreq_driver的结构如下:
- struct cpufreq_driver {
- struct module *owner;
- char name[CPUFREQ_NAME_LEN];
- u8 flags;
- bool have_governor_per_policy;
- /* needed by all drivers */
- int (*init) (struct cpufreq_policy *policy);
- int (*verify) (struct cpufreq_policy *policy);
- /* define one out of two */
- int (*setpolicy) (struct cpufreq_policy *policy);
- int (*target) (struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation);
- /* should be defined, if possible */
- unsigned int (*get) (unsigned int cpu);
- /* optional */
- unsigned int (*getavg) (struct cpufreq_policy *policy,
- unsigned int cpu);
- int (*bios_limit) (int cpu, unsigned int *limit);
- int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy);
- int (*resume) (struct cpufreq_policy *policy);
- struct freq_attr **attr;
- };
- struct cpufreq_driver {
- struct module *owner;
- char name[CPUFREQ_NAME_LEN];
- u8 flags;
- bool have_governor_per_policy;
- /* needed by all drivers */
- int (*init) (struct cpufreq_policy *policy);
- int (*verify) (struct cpufreq_policy *policy);
- /* define one out of two */
- int (*setpolicy) (struct cpufreq_policy *policy);
- int (*target) (struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation);
- /* should be defined, if possible */
- unsigned int (*get) (unsigned int cpu);
- /* optional */
- unsigned int (*getavg) (struct cpufreq_policy *policy,
- unsigned int cpu);
- int (*bios_limit) (int cpu, unsigned int *limit);
- int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy);
- int (*resume) (struct cpufreq_policy *policy);
- struct freq_attr **attr;
- };
相关的字段的意义解释如下:
- name 该频率驱动的名字。
- init 回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数对该驱动进行必要的初始化工作。
- verify 回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数检查policy的参数是否被驱动支持。
- setpolicy/target 回调函数,驱动必须实现这两个函数中的其中一个,如果不支持通过governor选择合适的运行频率,则实现setpolicy回调函数,这样系统只能支持CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE这两种工作策略。反之,实现target回调函数,通过target回调设定governor所需要的频率。
- get 回调函数,用于获取cpu当前的工作频率。
- getavg 回调函数,用于获取cpu当前的平均工作频率。
6. cpufreq notifiers
CPUFreq的通知系统使用了内核的标准通知接口。它对外提供了两个通知事件:policy通知和transition通知。
policy通知用于通知其它模块cpu的policy需要改变,每次policy改变时,该通知链上的回调将会用不同的事件参数被调用3次,分别是:
- CPUFREQ_ADJUST 只要有需要,所有的被通知者可以在此时修改policy的限制信息,比如温控系统可能会修改在大允许运行的频率。
- CPUFREQ_INCOMPATIBLE 只是为了避免硬件错误的情况下,可以在该通知中修改policy的限制信息。
- CPUFREQ_NOTIFY 真正切换policy前,该通知会发往所有的被通知者。
- CPUFREQ_PRECHANGE 调整前的通知。
- CPUFREQ_POSTCHANGE 完成调整后的通知。
- CPUFREQ_RESUMECHANGE
Linux动态调频系统CPUFreq之一:概述【转】的更多相关文章
- Linux动态频率调节系统CPUFreq之三:governor
在上一篇文章中,介绍了cpufreq的core层,core提供了cpufreq系统的初始化,公共数据结构的建立以及对cpufreq中其它子部件提供注册功能.core的最核心功能是对policy的管理, ...
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
上一节中,我们大致地讲解了一下CPUFreq在用户空间的sysfs接口和它的几个重要的数据结构,同时也提到,CPUFreq子系统把一些公共的代码逻辑组织在一起,构成了CPUFreq的核心部分,这些公共 ...
- 深入Linux内核架构——简介与概述
一.内核的任务 纯技术层面上,内核是硬件与软件的之间的一个中间层.作用是将应用程序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址. 从应用程序视角上看,内核可以被认为是一台增强 ...
- linux动态库默认搜索路径设置的三种方法
众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/lib .动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两 ...
- 再探Linux动态链接 -- 关于动态库的基础知识
在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考. 编译时和运行时 纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台 ...
- 技巧:Linux 动态库与静态库制作及使用详解
技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用方法 Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 L ...
- linux动态库加载RPATH, RUNPATH
摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...
- Linux 动态库剖析
进程与 API 动态链接的共享库是 GNU/Linux® 的一个重要方面.该种库允许可执行文件在运行时动态访问外部函数,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用.本文研究了创建和 ...
- linux动态库编译和使用
linux动态库编译和使用详细剖析 引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, ...
随机推荐
- Linux记录-salt-minion安装
python -m SimpleHTTPServer 8888#!/bin/bash sed -i 's/^#//g' /etc/yum.repos.d/centos7.4.repo sed -i ' ...
- Contrast Ratio(Enhanced) (Level AAA)
Contrast ratio between your text and background is at least 7:1 All of your users will benefit from ...
- react暴露webpack配置文件
在react中安装create-react-app脚手架新建项目,但是新建的项目中没有配置文件. webpack的配置文件webpack.base.conf.js隐藏在了node_modules文件夹 ...
- 细说shiro之六:session管理
官网:https://shiro.apache.org/ 我们先来看一下shiro中关于Session和Session Manager的类图. 如上图所示,shiro自己定义了一个新的Session接 ...
- C#中转换函数Convert、Parse、TryParse、(int) 的区别
Convert.Parse.TryParse.(int) 三个函数都是将值转换成整数,但是四者之间各有异同,开发人员可以根据情况选用最合适的.以下解释均经过高人验证,希望对大家有所帮助. 1 (int ...
- 使用js请求Servlet时的路径
项目结构如下: 全是web的html页面 js部分重要代码: function ajaxValidate() { var flag=false; $.ajax({ "url":&q ...
- 二十二、Linux 进程与信号---进程创建
22.1 fork 和 vfork 函数 22.1.1 函数说明 #include <unistd.h> #include <sys/types.h> pid_t fork( ...
- IIS服务器的安全保护措施
转载自:https://www.williamlong.info/archives/118.html 部分内容做了修改. 通过标注Web服务器安全级别以及可用性的安全策略,网络管理员将能够从容地在不同 ...
- JQuery常见事件
##### 事件 onclick 单机事件 ondblclick 双击事件 onmouseover 鼠标穿过 (子盒子独立) onmouseout 鼠标出去 onmouseenter 鼠标进入 (子盒 ...
- vue学习之生命周期和钩子函数
参考文章:Vue2.0 探索之路——生命周期和钩子函数的一些理解 抛出问题: 我们有时候会在几个钩子函数里做一些事情,那么什么时候做,该在哪个函数里做? 生命周期简介 结合代码看el 和 data以及 ...