这个governor是最省电模式,即cpu中所有的core都处在最低频率运行。如果是存在cpu hotplug driver的话,那么还可以更加的省电,即只存在一个core是online状态的,关掉其他的core。
废话不多说,直接讲解code:
1、static int __init cpufreq_gov_powersave_init(void)
各个元素含义如下:
1、char name[CPUFREQ_NAME_LEN]:是此governor的name。
2、 int (*governor) (structcpufreq_policy *policy,unsigned int event):是对此governor进行初始化的操作的回调函数。
3、ssize_t (*show_setspeed) (structcpufreq_policy *policy,char *buf):显示当前修改的频率值。
4、int (*store_setspeed) (structcpufreq_policy *policy,unsigned int freq):这个函数只有userspacegovernor使用,是可以对当前的cpu频率进行手动的调整。
5、unsignedint max_transition_latency:最大转换时延,即频率切换所能够忍受的最大延迟。
6、structlist_head governor_list:一个链表,存放的是这个结构体的信息。在各个governor中没有使用到。
7、structmodule *owner:模块的拥有者。
在powersave和performance这两个governor只会对name/governor/owner这三个元素进行设置,由于不需要进行频率的切换,所以也就无需关心频率转换时延和频率的变化了。
我们看看这个结构体在这个governor中是怎样定义的:
设置的一目了然。
现在来看看这个回调函数:cpufreq_governor_powersave了。
code如下:
由于powersave和performance governor仅仅只需对频率进行固定性的设置,所以在这个回调函数中,event是CPUFREQ_GOV_START和CPUFREQ_GOV_LIMITS无关紧要了,本来event是CPUFREQ_GOV_START时,是对这个governor进行初始化工作的,比如频率转换时延的设置,抽样速率的设置(不固定),定时器的初始化,sys接口的设置等等动作,不过这些只有interactive、ondemand和conservative governor才会设置,这是后话。而event为CPUFREQ_GOV_LIMITS时是执行频率的转化操作,通过这个函数实现:
__cpufreq_driver_target(policy, policy->min,CPUFREQ_RELATION_L)
如果event是CPUFREQ_GOV_STOP的话,操作是与event为CPUFREQ_GOV_START相反的操作,如sys接口的卸载,定时器的删除等等操作。现在在poswersave governor中只需要关心这个调节频率的函数__cpufreq_driver_target的工作原理是怎样实现的。
函数的code如下,在cpufreq.c中定义的:
主要是第二个if语句中cpufreq_driver->target(policy,target_freq, relation);它是怎样动作的才是最重要的。
if(cpu_online(policy->cpu) && cpufreq_driver->target)
首先判断当前的cpu是否online状态,即活着,没有plugout,否则也就没有意义了;cpufreq_driver->target这是一个回调函数真正执行具体调频的函数。
那么现在就来看看两个非常重要的结构体:
这个结构体里面的各个元素解释的非常清楚,无需多讲。其实就是与每一个cpu core相关连的policy,即相应的cpu core 采用的governor的限制条件的组合。
下面这个结构体是真实调频driver的使用的结构体,里面包含了很多个回调函数,这些回调函数一些必不可少的会在driver中实现。
执行cpu频率调整的函数,由相应体系结构的cpufrequency具体driver负责。在我的电脑上是使用的driver是:/driver/cpufreq/acpi-cpufreq.c中。你可以到你源码目录下查找。更可靠的方式是在linux电脑上这个目录下查找:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver 出的数据,就是你真正使用的driver了。
我的电脑显示的是:
如在我的电脑上,acpi-coufreq.c中对这个结构体的实现:
讲讲这个结构体中重要的几个元素的含义:
1、verify:是验证工作,目的验证当前的cpu的频率是否在限制范围内。用法如下: cpufreq_driver->verify(policy)
2、target:执行调频动作。
3、bios_limit:在bios中限制的cpu的频率范围。
4、init:初始化工作。
5、resume和suspend在power management中使用。
至此两个最重要的结构体完成了,其实我自己还是有些混乱的。呵呵。。。
继续回到执行调节频率的位置,在powersave governor中: __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L),目的是使所有online状态的cpu处在最低频率运行。这里又涉及到一个有意思的参数relation。
relation只有两种值:CPUFREQ_RELATION_H和CPUFREQ_RELATION_L。
看看kernel的定义:
#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target ,查找大于等于其频率的最小频率*/
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target ,查找小于等于其频率的最大频率*/
这两个参数用的非常的频繁,主要用在cpufreq table中,用来查找合适的频率。当然对于powersave和performance governor是使用不到的。
cpufreq table是一个频率档,cpu的频率可以在这里面进行升降根据当前的cpu load。至于怎么分的,可以
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies,会显示当前电脑分了多少档。
cat /sys/devices/system/cpu/cpu0/cpufreq/stats/trans_table,这是一个统计表格,统计各个频率档使用的次数,
在调整过程中调到此频率的次数(个人理解)。
由于是powersave governor,所以当relation是CPUFREQ_RELATION_L的时候,查找>=policy->min的频率,最后找到的还是最小频率。
对于performance governor与powersave governor是类似的,仅仅做了两处改动:
1、
name修改了。
2、 __cpufreq_driver_target(policy, policy->max,CPUFREQ_RELATION_H);这个调节频率的函数修改。思想是一样,只不过换成了调整为最高频率。
废话不多说,直接讲解code:
1、static int __init cpufreq_gov_powersave_init(void)
static int __init cpufreq_gov_powersave_init(void)
{
return cpufreq_register_governor(&cpufreq_gov_powersave);
}
这是注册powersave governor driver,很简单,直接返回一条注册语句。函数原型是:
int cpufreq_register_governor(struct cpufreq_governor *governor)。
其中,cpufreq_governor结构体的原型如下:struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN];
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;
};
各个元素含义如下:
1、char name[CPUFREQ_NAME_LEN]:是此governor的name。
2、 int (*governor) (structcpufreq_policy *policy,unsigned int event):是对此governor进行初始化的操作的回调函数。
3、ssize_t (*show_setspeed) (structcpufreq_policy *policy,char *buf):显示当前修改的频率值。
4、int (*store_setspeed) (structcpufreq_policy *policy,unsigned int freq):这个函数只有userspacegovernor使用,是可以对当前的cpu频率进行手动的调整。
5、unsignedint max_transition_latency:最大转换时延,即频率切换所能够忍受的最大延迟。
6、structlist_head governor_list:一个链表,存放的是这个结构体的信息。在各个governor中没有使用到。
7、structmodule *owner:模块的拥有者。
在powersave和performance这两个governor只会对name/governor/owner这三个元素进行设置,由于不需要进行频率的切换,所以也就无需关心频率转换时延和频率的变化了。
我们看看这个结构体在这个governor中是怎样定义的:
struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.owner = THIS_MODULE,
};
设置的一目了然。
现在来看看这个回调函数:cpufreq_governor_powersave了。
code如下:
static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
unsigned int event)
{
switch (event) {
case CPUFREQ_GOV_START:
case CPUFREQ_GOV_LIMITS:
pr_debug("setting to %u kHz because of event %u\n",
policy->min, event);
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
break;
default:
break;
}
return 0;
}
由于powersave和performance governor仅仅只需对频率进行固定性的设置,所以在这个回调函数中,event是CPUFREQ_GOV_START和CPUFREQ_GOV_LIMITS无关紧要了,本来event是CPUFREQ_GOV_START时,是对这个governor进行初始化工作的,比如频率转换时延的设置,抽样速率的设置(不固定),定时器的初始化,sys接口的设置等等动作,不过这些只有interactive、ondemand和conservative governor才会设置,这是后话。而event为CPUFREQ_GOV_LIMITS时是执行频率的转化操作,通过这个函数实现:
__cpufreq_driver_target(policy, policy->min,CPUFREQ_RELATION_L)
如果event是CPUFREQ_GOV_STOP的话,操作是与event为CPUFREQ_GOV_START相反的操作,如sys接口的卸载,定时器的删除等等操作。现在在poswersave governor中只需要关心这个调节频率的函数__cpufreq_driver_target的工作原理是怎样实现的。
函数的code如下,在cpufreq.c中定义的:
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
int retval = -EINVAL;
if (cpufreq_disabled())
return -ENODEV;
pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
return retval;
}
主要是第二个if语句中cpufreq_driver->target(policy,target_freq, relation);它是怎样动作的才是最重要的。
if(cpu_online(policy->cpu) && cpufreq_driver->target)
首先判断当前的cpu是否online状态,即活着,没有plugout,否则也就没有意义了;cpufreq_driver->target这是一个回调函数真正执行具体调频的函数。
那么现在就来看看两个非常重要的结构体:
struct cpufreq_policy {
cpumask_var_t cpus; /* CPUs requiring sw coordination */
cpumask_var_t related_cpus; /* CPUs with any coordination */
unsigned int shared_type; /* ANY or ALL affected CPUs
should set cpufreq */
unsigned int cpu; /* cpu nr of registered CPU */
struct cpufreq_cpuinfo cpuinfo;/* see above */
unsigned int min; /* in kHz */
unsigned int max; /* in kHz */
unsigned int cur; /* in kHz, only needed if cpufreq
* governors are used */
unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
struct work_struct update; /* if update_policy() needs to be
* called, but you're in IRQ context */
struct cpufreq_real_policy user_policy;
struct kobject kobj;
struct completion kobj_unregister;
};
这个结构体里面的各个元素解释的非常清楚,无需多讲。其实就是与每一个cpu core相关连的policy,即相应的cpu core 采用的governor的限制条件的组合。
下面这个结构体是真实调频driver的使用的结构体,里面包含了很多个回调函数,这些回调函数一些必不可少的会在driver中实现。
struct cpufreq_driver {
struct module *owner;
char name[CPUFREQ_NAME_LEN];
u8 flags;
/* 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;
};
执行cpu频率调整的函数,由相应体系结构的cpufrequency具体driver负责。在我的电脑上是使用的driver是:/driver/cpufreq/acpi-cpufreq.c中。你可以到你源码目录下查找。更可靠的方式是在linux电脑上这个目录下查找:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver 出的数据,就是你真正使用的driver了。
我的电脑显示的是:
root@samarxie:/sys/devices/system/cpu/cpu0/cpufreq# cat scaling_driver
acpi-cpufreq
这个回调函数是一定定义了的,可以放心使用。如在我的电脑上,acpi-coufreq.c中对这个结构体的实现:
static struct cpufreq_driver acpi_cpufreq_driver = {
.verify = acpi_cpufreq_verify,
.target = acpi_cpufreq_target,
.bios_limit = acpi_processor_get_bios_limit,
.init = acpi_cpufreq_cpu_init,
.exit = acpi_cpufreq_cpu_exit,
.resume = acpi_cpufreq_resume,
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
};
讲讲这个结构体中重要的几个元素的含义:
1、verify:是验证工作,目的验证当前的cpu的频率是否在限制范围内。用法如下: cpufreq_driver->verify(policy)
2、target:执行调频动作。
3、bios_limit:在bios中限制的cpu的频率范围。
4、init:初始化工作。
5、resume和suspend在power management中使用。
至此两个最重要的结构体完成了,其实我自己还是有些混乱的。呵呵。。。
继续回到执行调节频率的位置,在powersave governor中: __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L),目的是使所有online状态的cpu处在最低频率运行。这里又涉及到一个有意思的参数relation。
relation只有两种值:CPUFREQ_RELATION_H和CPUFREQ_RELATION_L。
看看kernel的定义:
#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target ,查找大于等于其频率的最小频率*/
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target ,查找小于等于其频率的最大频率*/
这两个参数用的非常的频繁,主要用在cpufreq table中,用来查找合适的频率。当然对于powersave和performance governor是使用不到的。
cpufreq table是一个频率档,cpu的频率可以在这里面进行升降根据当前的cpu load。至于怎么分的,可以
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies,会显示当前电脑分了多少档。
cat /sys/devices/system/cpu/cpu0/cpufreq/stats/trans_table,这是一个统计表格,统计各个频率档使用的次数,
在调整过程中调到此频率的次数(个人理解)。
由于是powersave governor,所以当relation是CPUFREQ_RELATION_L的时候,查找>=policy->min的频率,最后找到的还是最小频率。
对于performance governor与powersave governor是类似的,仅仅做了两处改动:
1、
struct cpufreq_governor cpufreq_gov_performance = {
.name = "performance",
.governor = cpufreq_governor_performance,
.owner = THIS_MODULE,
};
name修改了。
2、 __cpufreq_driver_target(policy, policy->max,CPUFREQ_RELATION_H);这个调节频率的函数修改。思想是一样,只不过换成了调整为最高频率。
由于第一次发这种帖子,估计有很多不足。原来真的是要自己看懂的写出来和说出来是另外一回事,希望这篇文章不要误导了其他人,如果有,我先说声sorry。~_~.