目前的cpu频率越来越高,但实际上大部分场景并不需要cpu一直工作在最高频率。
因为cpu工作频率越高,功耗越大,尤其是对手机等移动设备,更需要降低功耗,
延长手机电池使用时间。
在linux中,通过cpufreq来实现频率的动态调节。


1. 先直观看下cpufreq提供的功能。 



 在/sys/devices/system/cpu/中定义了相关的接口, 

 root:/sys/devices/system/cpu # ll 

 drwxr-xr-x root     root              1970-01-22 03:05 cpu0 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu1 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu2 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu3 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu4 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu5 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu6 

 drwxr-xr-x root     root              2017-01-21 10:26 cpu7 

 drwxr-xr-x root     root              1970-01-22 03:05 cpufreq 

 drwxr-xr-x root     root              1970-01-22 03:05 cpuidle 

 -r--r--r-- root     root         4096 1970-01-22 03:05 kernel_max 

 -r--r--r-- root     root         4096 1970-01-22 03:05 modalias 

 -r--r--r-- root     root         4096 1970-01-22 03:05 offline 

 -r--r--r-- root     root         4096 1970-01-22 03:05 online 

 -r--r--r-- root     root         4096 1970-01-22 03:05 possible 

 drwxr-xr-x root     root              1970-01-22 03:05 power 

 -r--r--r-- root     root         4096 1970-01-22 03:05 present 

 -rw-r--r-- root     root         4096 1970-01-22 03:05 uevent 



 其中cpu0-cpu7 几个目录单独定义了每个cpu core调频信息。 

 cpu0下面的cpufreq里面cpuinfo_XX表示cpu0硬件最大,最小和当前频率, 

 interactive表示调节器用的是interactive模式参数信息,scaling_XX表示调频时 

 软件可以设定的信息。 

 root:/sys/devices/system/cpu/cpu0/cpufreq # ll 

 -r--r--r-- root     root         4096 1970-01-22 03:05 affected_cpus 

 -r-------- root     root         4096 1970-01-22 03:05 cpuinfo_cur_freq 

 -r--r--r-- root     root         4096 1970-01-22 03:05 cpuinfo_max_freq 

 -r--r--r-- root     root         4096 1970-01-22 03:05 cpuinfo_min_freq 

 -r--r--r-- root     root         4096 1970-01-22 03:05 cpuinfo_transition_latency 

 drwxr-xr-x root     root              2017-01-20 12:40 interactive 

 -r--r--r-- root     root         4096 1970-01-22 03:05 related_cpus 

 -r--r--r-- root     root         4096 1970-01-22 03:05 scaling_available_frequencies 

 -r--r--r-- root     root         4096 1970-01-22 03:05 scaling_available_governors 

 -r--r--r-- root     root         4096 1970-01-22 03:05 scaling_cur_freq 

 -r--r--r-- root     root         4096 1970-01-22 03:05 scaling_driver 

 -rw-r--r-- root     root         4096 2017-01-20 12:40 scaling_governor 

 -rw-rw---- system   system       4096 1970-01-22 03:05 scaling_max_freq 

 -rw-rw-r-- system   system       4096 2017-01-20 12:40 scaling_min_freq 

 -rw-r--r-- root     root         4096 1970-01-22 03:05 scaling_setspeed 

 drwxr-xr-x root     root              1970-01-22 03:05 stats 



 2. 内核代码实现 



 代码涉及的数据结构: 



 //调频策略,定义调频时频率信息,具体调节器的选择等信息 

 //每个cpu都有自己的policy,因为不同的cpu能力不同,调频时限制条件也会有差别 

 struct cpufreq_policy { 

/* CPUs sharing clock, require sw coordination */ 

cpumask_var_t 
  cpus; 
 /* Online CPUs only 该policy下online cpus*/ 

cpumask_var_t 
  related_cpus; /* Online + Offline CPUs 该policy所管理的所有cpus*/ 



unsigned int 
  shared_type; /* ACPI: ANY or ALL affected CPUs 

should set cpufreq */ 

unsigned int 
  cpu;    /* cpu nr of CPU managing this policy 管理该policy的cpu编号 */ 

unsigned int 
  last_cpu; /* cpu nr of previous CPU that managed 

  * this policy  上次管理该policy的cpu编号,cpu 热插拔时使用*/ 

struct cpufreq_cpuinfo 
 cpuinfo;/* cpu硬件信息 */ 

//最大、最小、当前频率,软件调频参数信息 

unsigned int 
  min;    /* in kHz */ 

unsigned int 
  max;    /* in kHz */ 

unsigned int 
  cur;    /* in kHz, only needed if cpufreq 

* governors are used */ 

/* 

该变量可以取以下两个值:CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE, 

该变量只有当调频驱动支持setpolicy回调函数的时候有效, 

这时候由驱动根据policy变量的值来决定系统的工作频率或状态。 

如果调频驱动(cpufreq_driver)支持target回调,则频率由相应的governor来决定 

*/ 

unsigned int 
  policy; /* see above */ 

 

/* 

     指向该policy当前使用的cpufreq_governor结构和它的上下文数据,governor是实现该policy的关键所在,调频策略的逻辑由governor实现 

*/ 

struct cpufreq_governor 
 *governor; /* see below */ 

void 
 *governor_data;//其实是每种governor的tunables 

bool 
 governor_enabled; /* governor start/stop flag */ 



/* 

有时在中断上下文中需要更新policy,需要利用该工作队列把实际的工作移到稍后的进程上下文中执行。 

*/ 

struct work_struct 
 update; /* if update_policy() needs to be 

* called, but you're in IRQ context */ 

/* 

有时候因为特殊的原因需要修改policy的参数,比如溫度过高时,最大可允许的运行频率可能会被降低,为了在适当的时候恢复原有的运行参数,需要使用user_policy保存原始的参数(min,max,policy,governor) 

*/ 

struct cpufreq_real_policy 
 user_policy; 



struct list_head        policy_list;//系统使用的policy 列表 

struct kobject 
 kobj; 

struct completion 
 kobj_unregister; 



/* 

* The rules for this semaphore: 

* - Any routine that wants to read from the policy structure will 

*   do a down_read on this semaphore. 

* - Any routine that will write to the policy structure and/or may take away 

*   the policy altogether (eg. CPU hotplug), will hold this lock in write 

*   mode before doing so. 

* 

* Additional rules: 

* - Lock should not be held across 

*     __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); 

*/ 

struct rw_semaphore 
 rwsem; 

 }; 



 //governor:调节器,调节策略的执行者,主要有函数governor实现具体调频工作 

 struct cpufreq_governor { 

char 
 name[CPUFREQ_NAME_LEN]; 

int 
 initialized;//初始化标志 

/* 

指向一个回调函数,CPUFreq Core会在不同的阶段调用该回调函数,用于该governor的启动、停止、初始化、退出动作 

*/ 

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;//所有注册的governor都会利用该字段链接在一个全局链表中,以供系统查询和使用 

struct module 
  *owner; 

 }; 

 关于governor,目前提供了几种不同的实现, 

 performance:cpu一直运行在最高频率; 

 powersave:cpu一直运行在最低频率; 

 ondemand:按需快速动态调整CPU频率,一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率(阙值为 95%) 

 conservative:按需快速动态调整CPU频率,一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率(阙值为 75%) 

 userspace:运行于用户指定的频率 

 interactive:目前Android都是采用此方式,定时计算cpu负载,进行调频处理 



 //调频驱动数据结构,根据不同cpu厂商具体实现,主要用来设定硬件cpu工作频率 

 struct cpufreq_driver { 

char 
 name[CPUFREQ_NAME_LEN];//驱动名 

u8 
 flags;// 



/* needed by all drivers */ 

int 
 (*init) 
 (struct cpufreq_policy *policy);//驱动初始化 

int 
 (*verify) 
 (struct cpufreq_policy *policy);//检查policy的参数是否被驱动支持 



/* 

回调函数,驱动必须实现这两个函数中的其中一个, 

如果不支持通过governor选择合适的运行频率,则实现setpolicy回调函数, 

这样系统只能支持CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE这两种工作策略。 

反之,实现target回调函数,通过target回调设定governor所需要的频率 

*/ 

int 
 (*setpolicy) 
 (struct cpufreq_policy *policy);// 

int 
 (*target) 
 (struct cpufreq_policy *policy, 
 /* Deprecated */ 

unsigned int target_freq, 

unsigned int relation); 

//target或者target_index设定目标频率 

int 
 (*target_index) 
 (struct cpufreq_policy *policy, 

unsigned int index); 



/*获取当前工作频率 */ 

unsigned int 
  (*get) 
 (unsigned int cpu); 



/* optional */ 

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; 

 };




代码中cpufreq.c实现了调频主体框架,cpufreq_governer.c 抽象出来所有governor公共接口,
具体实现由每种governor实现,cpufreq_driver 根据不同芯片实现调频相关的硬件操作。
后续我们以Android采用的interactive来讲解代码流程。