CPU频率调节模式以及降频方法简介

在kernel中实现了两个driver,一个负责控制开关CPU的核数,叫做hot-plug驱动,另一个负责调整CPU的频率,叫做DVFS驱动。kernel中的driver会根据系统的负载,自动调整使用几个CPU和调整CPU频率。如果负载高了,提高频率,或者多开几个核,或者开大核。如果负载降下去了,就可以关大核,关核,降频。

以下是两个知名手机厂商开源的config配置文档:

60 CONFIG_CPU_FREQ=y                                                | 446 CONFIG_CPU_FREQ=y
 61 CONFIG_CPU_FREQ_STAT_DETAILS=y                                   | 447 CONFIG_CPU_FREQ_STAT=y
 62 CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y                        | 448 CONFIG_CPU_FREQ_STAT_DETAILS=y
 63 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y                                | 449 # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
 64 CONFIG_CPU_FREQ_GOV_POWERSAVE=y                                  | 450 # CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set                                        
 65 CONFIG_CPU_FREQ_GOV_USERSPACE=y                                  | 451 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 66 CONFIG_CPU_FREQ_GOV_ONDEMAND=y  
 
 # CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
 67 CONFIG_NET=y                                                     | 453 # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
 68 CONFIG_PACKET=y                                                  | 454 CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y
 69 CONFIG_UNIX=y                                                    | 455 # CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
 70 CONFIG_XFRM_MIGRATE=y                                            | 456 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 71 CONFIG_NET_KEY=y                                                 | 457 # CONFIG_CPU_FREQ_GOV_USERSPACE is not set
 72 CONFIG_INET=y                                                    | 458 # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
 73 CONFIG_IP_MULTICAST=y                                            | 459 CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
 74 CONFIG_IP_ADVANCED_ROUTER=y                                      | 460 # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 75 CONFIG_IP_MULTIPLE_TABLES=y                                      | 461 # CONFIG_CPUFREQ_DT is not set
在adb shell命令下,和cpu频率相关的目录:
/sys/devices/system/cpu/cpuX, X表示cpu number.
:/sys/devices/system/cpu/cpu0/cpufreq # ls
affected_cpus              related_cpus                  scaling_governor
cpuinfo_cur_freq           scaling_available_frequencies scaling_max_freq
cpuinfo_max_freq           scaling_available_governors   scaling_min_freq
cpuinfo_min_freq           scaling_cur_freq              scaling_setspeed
cpuinfo_transition_latency scaling_driver                stats

这些文件节点的读写属性:

cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400);
 936 cpufreq_freq_attr_ro(cpuinfo_min_freq);
 937 cpufreq_freq_attr_ro(cpuinfo_max_freq);
 938 cpufreq_freq_attr_ro(cpuinfo_transition_latency);
 939 cpufreq_freq_attr_ro(scaling_available_governors);
 940 cpufreq_freq_attr_ro(scaling_driver);
 941 cpufreq_freq_attr_ro(scaling_cur_freq);
 942 cpufreq_freq_attr_ro(bios_limit);
 943 cpufreq_freq_attr_ro(related_cpus);
 944 cpufreq_freq_attr_ro(affected_cpus);
 945 cpufreq_freq_attr_rw(scaling_min_freq);
 946 cpufreq_freq_attr_rw(scaling_max_freq);                                                                                                                                                   
 947 cpufreq_freq_attr_rw(scaling_governor);
 948 cpufreq_freq_attr_rw(scaling_setspeed);
 
cpuinfo_cur_freq: 当前cpu正在运行的工作频率
cpuinfo_max_freq:该文件指定了处理器能够运行的最高工作频率 (单位: 千赫兹)
cpuinfo_min_freq :该文件指定了处理器能够运行的最低工作频率 (单位: 千赫兹)
cpuinfo_transition_latency:该文件定义了处理器在两个不同频率之间切换时所需要的时间  (单位: 纳秒)
scaling_available_frequencies:所有支持的主频率列表  (单位: 千赫兹)
scaling_available_governors:该文件显示当前内核中支持的所有cpufreq governor类型
scaling_cur_freq:被governor和cpufreq核决定的当前CPU工作频率。该频率是内核认为该CPU当前运行的主频率
scaling_driver:该文件显示该CPU正在使用何种cpufreq driver
scaling_governor:通过echo命令,能够改变当前处理器的governor类型
scaling_max_freq:显示当前policy的上下限  (单位: 千赫兹)需要注意的是,当改变cpu policy时,需要首先设置scaling_max_freq, 然后才是scaling_min_freq

scaling_setspeed:如果用户选择了“userspace” governor, 那么可以设置cpu工作主频率到某一个指定值。只需要这个值在scaling_min_freq 和 scaling_max_freq之间即可。

工作模式:cat scaling_available_governors
:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_available_governors
ondemand userspace powersave interactive performance
CPU的频率调节模式:
1. Performance.  不考虑耗电,只用最高频率。
2. Interactive.  直接上最高频率,然后看CPU负荷慢慢降低。
3. Powersave.    通常以最低频率运行,流畅度会受影响,一般不会用这个吧!
4. Userspace.    可以在用户空间手动调节频率。
5. Ondemand.    定期检查负载,根据负载来调节频率。


对于这项飞思卡尔的实现:
默认使用了performance,不过freescale在boot完成后改成了interactive.
device/fsl/tek_mx6/init.rc:
on property:sys.boot_completed=1
# Set default CPU frequency governor
# Set timer 40ms, min sample 60ms,hispeed at cpufreq MAX freq in freq_table at load 40%
    write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor interactive
最终可通过scaling_governor文件查看。


工作频率:
当前支持的cpu调节模式可通过 scaling_available_frequencies 查看。
:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_available_frequencies
1092000 988000 858000 793000 637000 494000 364000 221000

相关的数据结构:
kernel-4.4$ vi ./include/linux/cpufreq.h +59
struct cpufreq_policy {
	/* CPUs sharing clock, require sw coordination */
	cpumask_var_t		cpus;	/* Online CPUs only */
	cpumask_var_t		related_cpus; /* Online + Offline CPUs */
	cpumask_var_t		real_cpus; /* Related and present */

	unsigned int		shared_type; /* ACPI: ANY or ALL affected CPUs
						should set cpufreq */
	unsigned int		cpu;    /* cpu managing this policy, must be online */

	struct clk		*clk;
	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		restore_freq; /* = policy->cur before transition */
	unsigned int		suspend_freq; /* freq to set during suspend */

	unsigned int		policy; /* see above */
	unsigned int		last_policy; /* policy before unplug */
	struct cpufreq_governor	*governor; /* see below */
	void			*governor_data;
	bool			governor_enabled; /* governor start/stop flag */
	char			last_governor[CPUFREQ_NAME_LEN]; /* last governor used */

	struct work_struct	update; /* if update_policy() needs to be
					 * called, but you're in IRQ context */

	struct cpufreq_user_policy user_policy;
	struct cpufreq_frequency_table	*freq_table;

	struct list_head        policy_list;
	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;


	/*
	 * Fast switch flags:
	 * - fast_switch_possible should be set by the driver if it can
	 *   guarantee that frequency can be changed on any CPU sharing the
	 *   policy and that the change will affect all of the policy CPUs then.
	 * - fast_switch_enabled is to be set by governors that support fast
	 *   freqnency switching with the help of cpufreq_enable_fast_switch().
	 */
	bool                    fast_switch_possible;
	bool                    fast_switch_enabled;

	/* Cached frequency lookup from cpufreq_driver_resolve_freq. */
	unsigned int cached_target_freq;
	int cached_resolved_idx;

	/* Synchronization for frequency transitions */
	bool			transition_ongoing; /* Tracks transition status */
	spinlock_t		transition_lock;
	wait_queue_head_t	transition_wait;
	struct task_struct	*transition_task; /* Task which is doing the transition */

	/* cpufreq-stats */
	struct cpufreq_stats	*stats;

	/* For cpufreq driver's internal use */
	void			*driver_data;
};
根据平台以及默认的最大频率来选择对应的频率列表。
所以降频有两种方法:
1. 直接编译静态修改频率列表。
2. 通过scaling_max_freq文件动态写入。


/ # cat /proc/cpufreq/cpufreq_ptpod_freq_volt
cat /proc/cpufreq/cpufreq_ptpod_freq_volt
[0] = { .cpufreq_khz = 1092000, .cpufreq_volt = 119375, .cpufreq_volt_org = 125000, },
[1] = { .cpufreq_khz = 988000,  .cpufreq_volt = 114375, .cpufreq_volt_org = 121875, },
[2] = { .cpufreq_khz = 858000,  .cpufreq_volt = 108125, .cpufreq_volt_org = 118750, },
[3] = { .cpufreq_khz = 793000,  .cpufreq_volt = 105000, .cpufreq_volt_org = 115000, },
[4] = { .cpufreq_khz = 637000,  .cpufreq_volt = 101250, .cpufreq_volt_org = 110000, },
[5] = { .cpufreq_khz = 494000,  .cpufreq_volt = 101250, .cpufreq_volt_org = 105000, },
[6] = { .cpufreq_khz = 364000,  .cpufreq_volt = 101250, .cpufreq_volt_org = 100000, },
[7] = { .cpufreq_khz = 221000,  .cpufreq_volt = 101250, .cpufreq_volt_org = 95000, },
/ # cat proc/cpufreq/cpufreq_oppidx
cat proc/cpufreq/cpufreq_oppidx
[MT_CPU_DVFS_LITTLE/0]
cpufreq_oppidx = 1
        OP(1092000, 119375),
        OP(988000, 114375),
        OP(858000, 108125),
        OP(793000, 105000),
        OP(637000, 101250),
        OP(494000, 101250),
        OP(364000, 101250),
        OP(221000, 101250),

猜你喜欢

转载自blog.csdn.net/good123_2014/article/details/79531133