powersave/performance governor study

这个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。~_~.

猜你喜欢

转载自blog.csdn.net/wuming_422103632/article/details/16983911