cpu freq limit

声明:以下内容来自于网络,仅收集但并未修正,有几处不妥。因为电脑故障,并未再次查询引述网址。

为什么由此记录:

      因为需要在内核中完成一个限制频率的功能:虽然在init程序启动后,可以限定工作频率,但是有些bug是在kernel initialization阶段产生,此时需要及早地限频;

 

  变频技术是指CPU硬件本身支持在不同的频率下运行,系统在运行过程中可以根据随时可能发生变化的系统负载 情况动态在这些不同的运行频率之间进行切换,从而达到对性能和功耗做到二者兼顾的目的。

整个过程分为两步:

1、mechanism

               “做什么”是指如何根据系统负载的动态变化挑选出 CPU 合适的运行频率

2、policy

               “怎么做”就是要按照选定的运行频率在选定的时间对 CPU 进行设置,使之真正工作在这一频率上。

CPU变频架构(该图有些问题,具体可以参考内核文档)

 

cpufreq 在设计上主要分为以下三个模块:

  • cpufreq 模块(cpufreq module)对如何在底层控制各种不同 CPU 所支持的变频技术以及如何在上层根据系统负载动态选择合适的运行频率进行了封装和抽象,并在二者之间定义了清晰的接口,从而在设计上完成了前文所提到的对 mechanism 与 policy 的分离。
  • 在 cpufreq 模块的底层,各个 CPU 生产厂商只需根据其变频技术的硬件实现和使用方法提供与其 CPU 相关的变频驱动程序(CPU-specific drivers),例如 Intel 需要提供支持 Enhanced SpeedStep 技术的 CPU 驱动程序,而 AMD 则需要提供支持 PowerNow! 技术的 CPU 驱动程序。
  • 在 cpufreq 模块的上层,governor 作为选择合适的目标运行频率的决策者,根据一定的标准在适当的时刻选择出 CPU 适合的运行频率,并通过 cpufreq 模块定义的接口操作底层与 CPU 相关的变频驱动程序,将 CPU 设置运行在选定的运行频率上。

 

  这种设计带来的好处是使得 governor 和 CPU 相关的变频驱动程序的开发可以相互独立进行,并在最大限度上实现代码重用,内核开发人员在编写和试验新的 governor 时不会再陷入到某款特定 CPU 的变频技术的硬件实现细节中去,而 CPU 生产厂商在向 Linux 内核中添加支持其特定的 CPU 变频技术的代码时只需提供一个相对来说简单了很多的驱动程序,而不必考虑在各种不同的应用场景中如何选择合适的运行频率这些复杂的问题。内核中的 cpufreq 子系统通过 sysfs 文件系统向上层应用提供了用户接口,对于系统中的每一个 CPU 而言,其 cpufreq 的 sysfs 用户接口位于 /sys/devices/system/cpu/cpuX/cpufreq/ 目录下,其中 X 代表 processor id。

  虽然 CPU 硬件支持多种不同的运行频率,但是在有些场合下用户可以只选择使用其中的一个子集,这种控制是通过 scaling_max_freq 和 scaling_min_freq 进行的。Governor在选择合适的运行频率时只会在 scaling_max_freq 和 scaling_min_freq 所确定的频率范围内进行选择,这也就是 scaling_available_frequencies 所显示的内容。与 cpuinfo_cur_freq 不同, scaling_cur_freq 返回的是 cpufreq 模块缓存的 CPU 当前运行频率,而不会对 CPU 硬件寄存器进行检查。 scaling_available_governors 会告诉用户当前有哪些 governors 可供用户使用,而 scaling_driver 则会显示该 CPU 所使用的变频驱动程序。 Stats 目录下给出了对 CPU 各种运行频率的使用统计情况,例如 CPU 在各种频率下的运行时间以及在各种频率之间的变频次数。         

 

总共有6种governors: Performance、Powersave、Userspace、Ondemand、Conservative、Interactive。

Cpufreq 作为一个子系统最早被加入到 Linux 内核中时只配备了三个 governors ,分别是performance、powersave 和 userspace。

1、当用户选择使用 performance governor 时,CPU会固定工作在其支持的最高运行频率上;

2、当用户选择使用 powersave governor 时,CPU会固定工作在其支持的最低运行频率上。

以上两种 governors 都属于静态 governor ,即在使用它们时 CPU 的运行频率不会根据系统运行时负载的变化动态作出调整。这两种 governors 对应的是两种极端的应用场景,使用 performance governor 体现的是对系统高性能的最大追求,而使用 powersave governor 则是对系统低功耗的最大追求。虽然这两种应用需求确实存在,但大多数用户在大部分时间里需要的是更加灵活的变频策略。

  最早的 cpufreq 子系统通过 userspace governor 为用户提供了这种灵活性。

3、使用 userspace governor 时,系统将变频策略的决策权交给了用户态应用程序,并提供了相应的接口供用户态应用程序调节 CPU 运行频率使用。将 userspace 设置为 cpufreq 子系统所使用的 governor 后,我们可以看到与之前相比在/sys/devices/system/cpu/cpuX/cpufreq/ 目录下多出了一个名为 scaling_setspeed 的文件,这正是 userspace governor 所提供的特殊用户接口。用户可以通过向该文件写入任何一个 scaling_available_frequencies 中所支持的运行频率,从而将 CPU 设置在该频率下运行。在使用 userspace governor 时,系统将变频策略的决策权交给了用户态应用程序。该用户态应用程序一般是一个 daemon 程序,每隔一定的时间间隔收集一次系统信息并根据系统的负载情况使用 userspace governor 提供的 scaling_setspeed 接口动态调整 CPU 的运行频率。作为这个 daemon 程序,当时在几个主要的 Linux 发行版中使用的一般是 powersaved 或者 cpuspeed。这两个 daemon 程序一般每隔几秒钟统计一次 CPU 在这个采样周期内的负载情况,并根据统计结果调整 CPU 的运行频率。这种 userspace governor 加用户态 daemon 程序的变频方法虽然为用户提供了一定的灵活性。

  但通过开源社区的广泛使用所得到的意见反馈逐渐暴露了这种方法的两个严重缺陷。

  第一个是性能方面的问题。例 如 powersaved 每隔五秒钟进行一次系统负载情况的采样分析的话,我们可以分析一下在下面给出的应用场景中的用户体验。假设 powersaved 的采样分析刚刚结束,而且由于在刚刚结束的采样周期内系统负载很低,CPU 被设置在最低频率上运行。这时用户如果打开 Firefox® 等对 CPU 运算能力要求相当高的程序的话,powersaved 要在下一个采样点——大约五秒钟之后才有机会观察到这种提高 CPU 运行频率的需求。也就是说,在 Firefox 启动之初的五秒钟内 CPU 的计算能力并没有被充分发挥出来,这无疑会使用户体验大打折扣。

  第二个是系统负载情况的采样分析的准确性问题。将监控系统负载情况并对未来 CPU 的性能需求做出判断的任务交给一个用户态程序完成实际上并不合理,一方面是由于一个用户态程序很难完整的收集到所有需要的信息,因为这些信息大部分都保存 在内核空间;另一方面一个用户态程序如果想要收集这些系统信息,必然需要进行用户态与内核态之间的数据交互,而频繁的用户态与内核态之间的数据交互又会给 系统性能带来负面影响。

 

4、ondemand governor完全在内核空间实现,降频更加激进,更加细粒度的采样间隔。

     第一个问题最直观的解决方案就是降低对系统 负载进行采样分析的时间间隔,这样 powersaved 就能尽早的对系统负载的变化做出及时的响应。 Intel 最新的 Enhanced Speedstep 技术在对 CPU 进行变频设置时耗时已降至 10 微秒;对于第二个问题,既然在用户态对系统的负载情况 进行采集和分析存在这样那样的问题,那么更加合理的做法就是应该将这部分工作交由内核负责。Venkatesh 等人提出并设计实现了一个新的名为 ondemand 的 governor ,它正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的 governor。通过 cpufreq-set 将 ondemand 设置为当前所使用的 governor 之后,在 /sys/devices/system/cpu/cpuX/cpufreq 目录下会出现一个名为 ondemand 的子目录。

  另外比较重要的一个文件是up_threshold ,它表明了系统负载超过什么百分比时 ondemand governor 会自动提高 CPU 的运行频率。在支持 Intel 最新的 Enhanced Speedstep 技术的 CPU 中,在处理器硬件中直接提供了两个 MSR 寄存器(Model Specific Register)供 ondemand governor 采样分析系统负载情况使用。这两个 MSR 寄存器的 名字分别为 IA32_MPERF 和 IA32_APERF[5] ,其中 IA32_MPERF MSR 中的 MPERF 代表 Maximum Performance , IA32_APERF MSR 中的 APERF 代表 Actual Performance 。就像这两个 MSR 的名字一样, IA32_MPERF MSR 寄存器是一个当 CPU 处在 ACPI C0 状态下时按照 CPU 硬件支持的最高运行频率每隔一个时钟周期加一的计数器; IA32_APERF MSR 寄存器是一个当 CPU 处在 ACPI C0 状态下时按照 CPU 硬件当前的实际运行频率每隔一个时钟周期加一的计数器。有了这两个寄存器的存在,再考虑上 CPU 处于 ACPI C0 和处于 ACPI C1、C2、C3 三种状态下的时间比例,也就是 CPU 处于工作状态和休眠状态的时间比例, ondemand governor 就可以准确的计算出 CPU 的负载情况了。

5、 conservative  :  ondemand governor  的最初实现是在可选的频率范围内调低至下一个可用频率。这种降频策略的主导思想是尽量减小对系统性能的负面影响,从而不会使得系统性能在短时间内迅速降低以影响用户体验。但是在  ondemand governor  的这种最初实现版本在社区发布后,大量用户的使用结果表明这种担心实际上是多余的,  ondemand governor 在降频时对于目标频率的选择完全可以更加激进。因此最新的  ondemand governor  在降频时会在所有可选频率中一次性选择出可以保证  CPU  工作在  80%  以上负荷的频率,当然如果没有任何一个可选频率满足要求的话则会选择  CPU  支持的最低运行频率。大量用户的测试结果表明这种新的算法可以在不影响系统性能的前提下做到更高效的节能。在算法改进后, ondemand governor  的名字并没有改变,而  ondemand governor  最初的实现也保存了下来,并且由于其算法的保守性而得名  conservative 。Ondemand 降频更加激进, conservative 降频比较缓慢保守,事实使用 ondemand 的效果也是比较好的。

   受频率变化影响的其它内核模块:系统在变化CPU主频的时候会调用cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);函数,向挂载在这个通知链上所有的驱动发出一个信号,驱动接收到这个信号则调用相应的处理函数。

 

  一个新的governor必须通过“cpurfreq_register_governor”向CPUfreq核心注册。Cpufreq_governor结构将会传递给CF核心。该结构必须包含入以下的值:g->name唯一的governor名字、g->governor该governor的回调函数、g->owner THIS_MODULEH或者NULL。g->governor回调函数以cpufreq_policy结构和一个无符号事件标志为参数被调用:CPUFREQ_GOV_START: governor要开始对policy->cpu服务;CPUFREQ_GOV_STOP:governor不再为policy->cpu服务;CPUFREQ_GOV_LIMITS:告知对policy->cpu的频率界限更新为policy->min和policy->max。int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table);通过调用本函数,cpuinfo.min_freq和cpuinfo.max值被检测:policy->min,policy->cpuinfo.min_freq被设置为表中的最小频率;policy->max,policy->cpuinfo.max_freq被设置为表中的最大频率。该函数在per-cpu初始化阶段很有用。

  int cpufreq_frequency_table_target(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index);该函数是->target阶段的频率表辅助函数。将target_freq传入该函数,index将会返回频率辅助表的某一项的下标。cpufreq_table[index].frequency包含了新的频率值,cpufreq_table[index].index包含了输入的index值。

  int cpu0_cpufreq_init(struct cpufreq_policy *policy)中将会通过cpufreq_frequency_table_cpuinfo获得/限定最大最小频率,并通过cpufreq_frequency_table_get_attr构建频率表。和时间子系统的关系:因为改变CPU的频率会严重影响虚拟时钟的计数的正确性维护。所以要在CPU频率改变时,更新维护虚拟时钟正确性函数的被调用间隔。比如,如果虚拟计数时钟(sync_virtual_count)原来每隔T秒做一次溢出处理,但是CPU频率升高了,那么T就必须减小,否则会出现溢出,导致虚拟时钟计数溢出。

 

posted on 2014-08-16 09:27  阿加  阅读(1286)  评论(0)    收藏  举报

导航