Linux动态频率调节系统CPUFreq之一:概述【转】-- 非常好的博客

简介:

转自:http://blog.csdn.net/droidphone/article/details/9346981

 
 
 

随着技术的发展,我们对CPU的处理能力提出了越来越高的需求,芯片厂家也对制造工艺不断地提升。现在的主流PC处理器的主频已经在3GHz左右,就算是智能手机的处理器也已经可以工作在1.5GHz以上,可是我们并不是时时刻刻都需要让CPU工作在最高的主频上,尤其是移动设备和笔记本电脑,大部分时间里,CPU其实工作在轻负载状态下,我们知道:主频越高,功耗也越高。为了节省CPU的功耗和减少发热,我们有必要根据当前CPU的负载状态,动态地提供刚好足够的主频给CPU。在Linux中,内核的开发者定义了一套框架模型来完成这一目的,它就是CPUFreq系统。

/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!
/*****************************************************************************************************/

1.  sysfs接口


 

我们先从CPUFreq提供的sysfs接口入手,直观地看看它提供了那些功能。以下是我的电脑输出的结果:

 

[plain]  view plain copy
 
  1. droidphone@990:~$ cd /sys/devices/system/cpu  
  2. droidphone@990:/sys/devices/system/cpu$ ls  
  3. cpu0  cpu3  cpu6     cpuidle     offline   power    release  
  4. cpu1  cpu4  cpu7     kernel_max  online    present  uevent  
  5. cpu2  cpu5  cpufreq  modalias    possible  probe  

 

所有与CPUFreq相关的sysfs接口都位于:/sys/devices/system/cpu下面,我们可以看到,8个cpu分别建立了一个自己的目录,从cpu0到cpu7,我们再看看offline和online以及present的内容:

 

[plain]  view plain copy
 
  1. droidphone@990:/sys/devices/system/cpu$ cat online  
  2. 0-7  
  3. droidphone@990:/sys/devices/system/cpu$ cat offline  
  4. 8-15  
  5. droidphone@990:/sys/devices/system/cpu$ cat present  
  6. 0-7  
  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)。

 

接着往下看:

 

[plain]  view plain copy
 
  1. droidphone@990:/sys/devices/system/cpu/cpu0$ ls  
  2. cache    cpuidle      microcode  power      thermal_throttle  uevent  
  3. cpufreq  crash_notes  node0      subsystem  topology  
  4. droidphone@990:/sys/devices/system/cpu/cpu0$ cd cpufreq/  
  5. droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ ls  
  6. affected_cpus               related_cpus                   scaling_max_freq  
  7. bios_limit                  scaling_available_frequencies  scaling_min_freq  
  8. cpuinfo_cur_freq            scaling_available_governors    scaling_setspeed  
  9. cpuinfo_max_freq            scaling_cur_freq               stats  
  10. cpuinfo_min_freq            scaling_driver  
  11. cpuinfo_transition_latency  scaling_governor  
  12. 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支持那些频率:

 

[plain]  view plain copy
 
  1. droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_available_frequencies   
  2. 3401000 3400000 3000000 2800000 2600000 2400000 2200000 2000000 1800000 1600000   
  3. droidphone@990:/sys/devices/system/cpu/cpu0/cpufreq$   
Oh,从1.6GHz到3.4GHz,一共支持10挡的频率可供选择。scaling_available_governors则会输出当前可供选择的频率调节策略:

 

 

[plain]  view plain copy
 
  1. conservative ondemand userspace powersave performance  
一共有5中策略供我们选择,那么当前系统选用那种策略?让我们看看:

 

 

[plain]  view plain copy
 
  1. dong@dong-990:/sys/devices/system/cpu/cpu0/cpufreq$ cat scaling_governor  
  2. 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这一数据结构来表示:

 

[cpp]  view plain copy
 
  1. struct cpufreq_policy {  
  2.           
  3.         cpumask_var_t           cpus;     
  4.         cpumask_var_t           related_cpus;   
  5.   
  6.         unsigned int            shared_type;   
  7.                                                   
  8.         unsigned int            cpu;      
  9.         unsigned int            last_cpu;   
  10.                                             
  11.         struct cpufreq_cpuinfo  cpuinfo;  
  12.   
  13.         unsigned int            min;    /* in kHz */  
  14.         unsigned int            max;    /* in kHz */  
  15.         unsigned int            cur;      
  16.                                            
  17.         unsigned int            policy;   
  18.         struct cpufreq_governor *governor;   
  19.         void                    *governor_data;  
  20.   
  21.         struct work_struct      update;   
  22.                                            
  23.   
  24.         struct cpufreq_real_policy      user_policy;  
  25.   
  26.         struct kobject          kobj;  
  27.         struct completion       kobj_unregister;  
  28. };  
其中的各个字段的解释如下:

 

 

  • 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结构来表示:

 

[cpp]  view plain copy
 
  1. struct cpufreq_governor {  
  2.         char    name[CPUFREQ_NAME_LEN];  
  3.         int     initialized;  
  4.         int     (*governor)     (struct cpufreq_policy *policy,  
  5.                                  unsigned int event);  
  6.         ssize_t (*show_setspeed)        (struct cpufreq_policy *policy,  
  7.                                          char *buf);  
  8.         int     (*store_setspeed)       (struct cpufreq_policy *policy,  
  9.                                          unsigned int freq);  
  10.         unsigned int max_transition_latency; /* HW must be able to switch to 
  11.                         next freq faster than this value in nano secs or we 
  12.                         will fallback to performance governor */  
  13.         struct list_head        governor_list;  
  14.         struct module           *owner;  
  15. };  

其中的各个字段的解释如下:

 

 

  • name    该governor的名字。
  • initialized    初始化标志。
  • governor    指向一个回调函数,CPUFreq Core会在不同的阶段调用该回调函数,用于该governor的启动、停止、初始化、退出动作。
  • list_head    所有注册的governor都会利用该字段链接在一个全局链表中,以供系统查询和使用。

 

5.  cpufreq_driver


 

上一节提到的gonvernor只是负责计算并提出合适的频率,但是频率的设定工作是平台相关的,这需要cpufreq_driver驱动来完成,cpufreq_driver的结构如下:

 

[cpp]  view plain copy
 
  1. struct cpufreq_driver {  
  2.         struct module           *owner;  
  3.         char                    name[CPUFREQ_NAME_LEN];  
  4.         u8                      flags;  
  5.        
  6.         bool                    have_governor_per_policy;  
  7.   
  8.         /* needed by all drivers */  
  9.         int     (*init)         (struct cpufreq_policy *policy);  
  10.         int     (*verify)       (struct cpufreq_policy *policy);  
  11.   
  12.         /* define one out of two */  
  13.         int     (*setpolicy)    (struct cpufreq_policy *policy);  
  14.         int     (*target)       (struct cpufreq_policy *policy,  
  15.                                  unsigned int target_freq,  
  16.                                  unsigned int relation);  
  17.   
  18.         /* should be defined, if possible */  
  19.         unsigned int    (*get)  (unsigned int cpu);  
  20.   
  21.         /* optional */  
  22.         unsigned int (*getavg)  (struct cpufreq_policy *policy,  
  23.                                  unsigned int cpu);  
  24.         int     (*bios_limit)   (int cpu, unsigned int *limit);  
  25.   
  26.         int     (*exit)         (struct cpufreq_policy *policy);  
  27.         int     (*suspend)      (struct cpufreq_policy *policy);  
  28.         int     (*resume)       (struct cpufreq_policy *policy);  
  29.         struct freq_attr        **attr;  
  30. };  

相关的字段的意义解释如下:

 

 

  • 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前,该通知会发往所有的被通知者。
transition通知链用于在驱动实施调整cpu的频率时,用于通知相关的注册者。每次调整频率时,该通知会发出两次通知事件:
  • CPUFREQ_PRECHANGE    调整前的通知。
  • CPUFREQ_POSTCHANGE    完成调整后的通知。
当检测到因系统进入suspend而造成频率被改变时,以下通知消息会被发出:
  • CPUFREQ_RESUMECHANGE

 


版权声明:本文为博主原创文章,未经博主允许不得转载。










本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/4834051.html,如需转载请自行联系原作者


相关文章
|
3天前
|
Ubuntu 安全 Linux
《Linux 简易速速上手小册》第1章: Linux 系统基础(2024 最新版)
《Linux 简易速速上手小册》第1章: Linux 系统基础(2024 最新版)
36 1
|
11天前
|
资源调度 JavaScript 搜索推荐
Linux系统之部署envlinks极简个人导航页
【4月更文挑战第11天】Linux系统之部署envlinks极简个人导航页
52 2
|
13天前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
69 0
|
13天前
|
安全 网络协议 Linux
Linux网络名称空间概述
Linux网络名称空间是操作系统级别的一种虚拟化技术🔄,它允许创建隔离的网络环境🌐,使得每个环境拥有自己独立的网络资源,如IP地址📍、路由表🗺️、防火墙规则🔥等。这种技术是Linux内核功能的一部分,为不同的用户空间进程提供了一种创建和使用独立网络协议栈的方式。本文旨在全方面、多维度解释Linux网络名称空间的概念、必要性和作用。
Linux网络名称空间概述
|
13天前
|
监控 Unix Linux
Linux操作系统调优相关工具(四)查看Network运行状态 和系统整体运行状态
Linux操作系统调优相关工具(四)查看Network运行状态 和系统整体运行状态
28 0
|
20天前
|
存储 前端开发 Linux
Linux系统之部署ToDoList任务管理工具
【4月更文挑战第1天】Linux系统之部署ToDoList任务管理工具
63 1
|
22天前
|
存储 传感器 运维
linux系统资源统计工具
【4月更文挑战第1天】Linux系统监控工具如dstat、htop、glances、vmstat、top、iostat、mpstat、sar和atop,用于跟踪CPU、内存、磁盘I/O、网络和进程性能。这些工具提供实时、交互式和历史数据分析,助力管理员优化系统性能和故障排查。例如,dstat是vmstat等工具的增强版,htop提供彩色界面的进程管理,而atop则结合了多种功能并记录历史数据。
28 5
linux系统资源统计工具
|
11天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
31 6
|
21天前
|
Ubuntu 架构师 Java
Linux系统常用命令非常详细建议收藏
Linux系统常用命令非常详细建议收藏
49 0
|
2天前
|
Linux Perl
Linux系统替换字符串常用命令
请注意,`sed`命令可以非常强大,可以根据不同的需求使用不同的选项和正则表达式来进行更复杂的字符串替换操作。
16 0