您的位置:首页 > 编程语言 > Go语言

powersave/performance governor study

2013-11-27 15:44 411 查看
这个governor是最省电模式,即cpu中所有的core都处在最低频率运行。如果是存在cpu hotplug driver的话,那么还可以更加的省电,即只存在一个core是online状态的,关掉其他的core。

废话不多说,直接讲解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。~_~.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息