本文专门针对linux内核的CPU主频改换机制和战略的研讨和总结,针对嵌入式linux体系运用中下降功耗的有用办法,暂时想完成的首要的机制有:cpu级,设备驱动级,体系渠道级。办理颗粒度不断递加,构成三驾马车齐驱的局势。
CPU级:首要完成比较简略的在体系处于方针在于频频产生、更高粒度的电源状况改动,首要的完成方法为idle,包含今日的首要想讲的动态主频。
设备驱动级:首要完成对单个设备驱动的办理(suspend,resume等),经过体系监测将搁置的设备,经过从用户态对sys文件目录动态进行单个驱动设备的办理,置于省电形式。
体系渠道级:方针在于办理较大的、十分见的严重电源状况改动,用于削减产品设备在长期的闲暇之后,削减电源耗费 。首要完成方法是依托linux内核所支撑的apm技能,完成整个体系的睡觉/康复(sleep)这几个层次其实并不是彼此独立的,都是彼此穿插的,比方体系渠道级的睡觉不可避免会涉及到cpu的sleep形式和设备驱动的挂起,而动态主频的完成除了cpu自身的支撑也需求外围驱动跟着主频改动做出相应的习惯活动。因而这儿的分级仅仅一种粗规模的,逻辑上的分层。
前段时刻还调研了一下IBM和Monta Vista搞得那套DPM(Dynamic Power Management)机制,看了不少论文和观念,总的感觉便是过分杂乱而且也不是很有用,感觉噱头大过实践成效,(因而这套机制一向还不能进入内核的mainline),言归正传,仍是要点叙述下cpufreq技能。
一、为什么要cpufreq?
关于要不要完成cpufreq技能,我也纠结过,一个原因是:其时对内核怎么供给这么一套动态变频的机制还不了解,只觉得应该十分费事,由于涉及到外围驱动的参数更新,别的一个原因是:在SEP4020这种体量的处理器上跑linux,即便运转在最高频率时的处理才能或许也不是很充裕,我再给它降频还有没有意义?挣扎之后仍是觉得要完成它,我也给自己列了这么几条原因:
1. 尽管cpu在板级中已不是首要的耗电源,可是依然占着无足轻重的方位,功耗机制到最后便是几毫安几毫安的扣了,降频必定能在必定程序上节约功耗那我为什么不选用?
2. 细化功耗办理的颗粒度,为运用程序供给更多的功耗节约机制
3. 对一般的运用,体系能够运转在坚持渠道运作的最低频率,在有处理使命时,变频机制会主动切换到适宜的高主频,而且在使命完毕时重回省电的低主频,这样就处理了我之前的第二个疑问。
SEP4020在运转在88M时板级功耗为:222mA
SEP4020在运转在56M时板级功耗为:190mA,下降14%
SEP4020在运转在32M时板级功耗为:160mA,下降28%
4. 完成的一些作业是咱们一向需求去做可是一向没有动力做的
变频会涉及到许多模块的参数的重新装备,作为cpu原厂,咱们需求把这些参数彻底把握
对这些参数的充沛了解,能对现有体系进行优化,进步全体体系的功率,比方运用发现一些参数仍是过分保存(sdram,nand),咱们的通用装备在体系降为32M时仍能正常作业。
5. 可行性证明没有问题:偶尔看到armkiller同志供给的nand驱动代码中有变频的完成(这儿十分感谢armkiller),网上这方面的文章很少,所以翻阅了linux内核源码中自带的/documentation/cpufreq后,对这种机制大概有必定的了解(linux中的documentaTIon是个好东东),也看到了一些处理器厂商为自己的cpu现已完成了的代码,如sa1100,pxa系列。
二、内核所供给的这种cpufreq技能的机制
1. 意图:
变频技能是指CPU硬件自身支撑在不同的频率下运转,体系在运转过程中能够依据随时或许产生改动的体系负载状况动态在这些不同的运转频率之间进行切换,然后到达对功能和功耗做到二者统筹的意图。
2. 来历:
尽管多个处理器生产厂家都供给了对变频技能的支撑,可是其硬件完成和运用办法必定存在着纤细乃至巨大的不同。这就使得每个处理器生产厂家都需求依照其特别的硬件完成和运用办法向内核中增加代码,然后让自己产品中的变频技能在Linux 中得到支撑和运用。但是,这种内核开发形式所导致的结果是各个厂家的完成代码散落在 Linux 内核代码树的各个角落里,各种不同的完成之间没有任何代码是同享的,这给内核的保护以及将来增加对新的产品的支撑都带来了巨大的开支,并直接导致了 cpufreq 内核子体系的诞生。
3. 办理战略:
Linux内部共有五种对频率的办理战略userspace,conservaTIve,ondemand,powersave 和 performance
performance :CPU会固定作业在其支撑的最高运转频率上;
powersave :CPU会固定作业在其支撑的最低运转频率上。因而这两种 governors 都归于静态 governor ,即在运用它们时 CPU 的运转频率不会依据体系运转时负载的改动动态作出调整。这两种 governors 对应的是两种极点的运用场景,运用 performance governor 表现的是对体系高功能的最大寻求,而运用 powersave governor 则是对体系低功耗的最大寻求。
Userspace:最早的 cpufreq 子体系经过 userspace governor 为用户供给了这种灵活性。体系将变频战略的决议计划权交给了用户态运用程序,并供给了相应的接口供用户态运用程序调理 CPU 运转频率运用。 (能够运用Dominik 等人开发了cpufrequTIls 工具包 )
ondemand :userspace是内核态的检测,功率低。而ondemand正是人们长期以来期望看到的一个彻底在内核态下作业而且能够以愈加细粒度的时刻距离对体系负载状况进行采样剖析的 governor。
conservaTIve : ondemand governor 的开始完成是在可选的频率规模内调低至下一个可用频率。这种降频战略的主导思维是尽量减小对体系功能的负面影响,然后不会使得体系功能在短时刻内敏捷下降以影响用户体会。可是在 ondemand governor 的这种开始完成版别在社区发布后,许多用户的运用结果表明这种忧虑实践上是剩余的, ondemand governor在降频时关于方针频率的挑选彻底能够愈加急进。因而最新的 ondemand governor 在降频时会在一切可选频率中一次性挑选出能够确保 CPU 作业在 80% 以上负荷的频率,当然假如没有任何一个可选频率满足要求的话则会挑选 CPU 支撑的最低运转频率。许多用户的测验结果表明这种新的算法能够在不影响体系功能的前提下做到更高效的节能。在算法改善后, ondemand governor 的姓名并没有改动,而 ondemand governor 开始的完成也保存了下来,而且由于其算法的保存性而得名 conservative 。
Ondemand降频愈加急进,conservative降频比较缓慢保存,现实运用ondemand的作用也是比较好的。
4. Cpufreq在用户态所呈现的接口:
cpuinfo_max_freq cpuinfo_min_freq: 别离给出了 CPU 硬件所支撑的最高运转频率及最低运转频率,
cpuinfo_cur_freq 则会从 CPU 硬件寄存器中读取 CPU 当时所在的运转频率。
Governor在挑选适宜的运转频率时只会在 scaling_max_freq 和 scaling_min_freq 所确认的频率规模内进行挑选
scaling_cur_freq 回来的是 cpufreq 模块缓存的 CPU 当时运转频率,而不会对 CPU 硬件寄存器进行检查。
scaling_available_governors 会告知用户当时有哪些 governors 可供用户运用
scaling_driver 则会显现该 CPU 所运用的变频驱动程序
Scaling_governor 则会显现当时的办理战略,往这个上echo其他类型会有相应的改变。
scaling_setspeed:需将governor类型切换为userspace,才会呈现,往这个文件echo数值,会切换主频
以下是将governor切换为ondemand后生成的ondemand文件夹下呈现的装备文件。(conservative就不说了,禁绝备运用)
sampling_rate:当时运用的采样距离 ,单位:微秒
sampling_rate_min:答应运用的最短采样距离
sampling_rate_max:答应运用的最长采样距离
up_threshold :表明晰体系负载超越什么百分比时 ondemand governor 会主动进步 CPU 的运转频率
ignore_nice_load:ignore_nice_load 文件能够设置为 0 或 1(0 是默认设置)。当这个参数设置为 1 时,任何具有 “nice”值的处理器不计入总处理器利用率。在设置为 0 时,一切处理器都计入利用率。
sampling_down_factor:
5. 运用办法:
cd sys/devices/system/cpu/cpu0/cpufreq/目录
echo 32000 > scaling_min_freq 设置最小作业频率(khz,32000~88000)
//若想运用userspace战略
# echo userspace > scaling_governor切换作业方法为userspace
echo 64000 > scaling_setspeed 设置成想要的作业频率(khz)
//若想运用ondemand战略
# echo ondemand > scaling_governor切换作业方法为ondemand
三、怎么完成?
首要需求干一些杂活,修正kconfig makefile把体系屏蔽的cpufreq翻开,关于咱们来说首要的中心有两部分:
体系相关:首要有cpu,timer(变了频率必定要更新体系timer,不然体系时刻就禁绝了),sdram等。
首要便是完成下面这个结构体:
static struct cpufreq_driver sep4020_driver =
{
.flags = CPUFREQ_STICKY,
.verify = sep4020_verify_speed,
.target = sep4020_target,
.get = sep4020_getspeed,
.init = sep4020_cpu_init,
.name = “SEP4020 Freq”,
};
代码仍是很粗陋,许多细节都没考虑,所以详细的暂时先不讲了,我们能够先参阅pxa和sa1100的完成。
然后便是收频率影响的驱动:
简略的来说便是:体系在改动cpu主频的时分会调用cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);函数,响挂载在这个cpu上一切的驱动宣布一个信号,驱动接收到这个信号则调用相应的处理函数。
这儿把串口部分的完成简化,如下:
#ifdef CONFIG_CPU_FREQ
static int sep4020_serial_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data)
{
// printk(“in the serial cpufreq_transition\n”);
int pmcr_pre;
unsigned long cpu_clk,baud,baudh,baudl;
pmcr_pre = *(volatile unsigned long*)PMU_PMCR_V;
if(pmcr_pre > 0x4000)
cpu_clk = (pmcr_pre-0x4000)*8000000;
else
cpu_clk = (pmcr_pre)*4000000;
baud = cpu_clk/16/115200;
baudh = baud >>8;
baudl = baud&0xff;
*(volatile unsigned char*)UART0_LCR_V |= (0x80);
*(volatile unsigned char*)UART0_DLBL_V = baudl;
*(volatile unsigned char*)UART0_DLBH_V = baudh;
*(volatile unsigned char*)UART0_LCR_V &= ~(0x80);
printk(“in the serial cpufreq_transition\n”);
return 0;
}
static inline int sep4020_serial_cpufreq_register(void)
{
sep4020_serial_freq_transition.notifier_call = sep4020_serial_cpufreq_transition;
return cpufreq_register_notifier(&sep4020_serial_freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
static inline void sep4020_serial_cpufreq_deregister(void)
{
cpufreq_unregister_notifier(&sep4020_serial_freq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
}
#else
#endif
四、作用
在sys下敞开ondeman形式,串上电流表:
1. 板级电流从220mA调至160mA(由于此刻内核检测体系无负载,降频)
2. 履行一个nandflash的复制指令,复制一个5M左右的文件到其他文件夹,
3. 在复制履行时刻在3秒时(我给内核设的扫描周期为2.5秒)体系发现有负载,升频,电流从160mA变为220mA(可见已是体系最高主频)
4. 尔后的复制的整个过程中电流坚持为220mA
5. 在复制完毕后不久(2-3s内),体系电流又跳变至160mA。