With the development of technology, we have put forward higher and higher requirements for CPU processing capabilities, and chip manufacturers are constantly improving the manufacturing process. The current mainstream PC Processor frequency is about 3 GHz, and even the smartphone processor can work at GHz or above, however, we do not always need to keep the CPU at the highest clock speed, especially for mobile devices and laptops. Most of the time, the CPU actually works in a light load state. We know: the higher the clock speed, the higher the power consumption. To save CPU power consumption and reduce fever, it is necessary to dynamically provide enough clock speed to the CPU Based on the current CPU load status. In Linux, kernel developers Define a framework model to achieve this goal. It is the cpufreq system.
/*************************************** **************************************** **********************/
Statement: the content of this blog is created at http://blog.csdn.net/droidphone. please refer to it for help. Thank you!
/*************************************** **************************************** **********************/
1. sysfs Interface
Starting with the sysfs interface provided by cpufreq, We can intuitively see what functions it provides. The following are my computer output results:
Droidphone @ 990 :~ $ CD/sys/devices/system/kernel @ 990:/sys/devices/system/CPU $ lscpu0 cpu3 cpu6 cpuidle offline Power Supply cpu4 cpu7 kernel_max online present ueventcpu2 cpu5 cpufreq modalias possible Probe
All sysfs interfaces related to cpufreq are located under/sys/devices/system/CPU. We can see that each of the eight CPUs has its own directory, from cpu0 to cpu7, let's take a look at offline, online, and present:
Droidphone @ 990:/sys/devices/system/CPU $ cat online0-7droidphone @ 990:/sys/devices/system/CPU $ cat offline8-15droidphone @ 990: /sys/devices/system/CPU $ cat present0-7droidphone @ 990:/sys/devices/system/CPU $
Online indicates the CPU currently in operation. The output shows that the 8 CPUs numbered 0-7 are working. Offline indicates the CPU that is currently disabled, and present indicates the CPU that has been installed on the motherboard, from the output, we can see that my motherboard can install 16 CPUs (because of Intel's hyper-threading technology, there are actually eight physical CPUs), and the CPU on the 8-15th is off (actually does not exist, because the present is only 0-7 ).
Next, let's look:
Droidphone @ 990:/sys/devices/system/CPU/cpu0 $ lscache cpuidle microcode power thermal_throttle ueventcpufreq crash_notes node0 subsystem topologydroidphone @ 990: /sys/devices/system/CPU/cpu0 $ CD cpufreq/droidphone @ 990: /sys/devices/system/CPU/cpu0/cpufreq $ lsaffected_cpus related_cpus quota limit scaling_cur_freq quota limit @ 990:/sys/devices/system/CPU/cpu0/cpufreq $
On my computer, some values are as follows:
Cpuinfo_cur_freq: 1600000
Cpuinfo_max_freq: 3401000
Cpuinfo_min_freq: 1600000
Scaling_cur_freq: 1600000
Scaling_max_freq: 3401000
Scaling_min_freq: 1600000
Therefore, the minimum operating frequency of CPU 0 is 1.6 GHz and the maximum operating frequency is 3.4 GHz. Currently, the operating frequency is 1.6 GHz. The prefix cpuinfo indicates the supported frequencies on CPU hardware, the scaling prefix represents the frequency supported by the CPU freq system when it is adjusted using software. Cpuinfo_cur_freq indicates the frequency value actually read by the hardware, while scaling_cur_freq indicates the current setting value of the software. In most cases, these two values are consistent, but they may also be caused by hardware, there are minor differences. Scaling_available_frequencies will output the frequency values supported by the current software. Let's take a look at the frequencies supported by my CPU:
Droidphone @ 990:/sys/devices/system/CPU/cpu0/cpufreq $ cat scaling_available_frequencies 3401000 3400000 3000000 2800000 2600000 2400000 2200000 2000000 droidphone @ 1800000: /sys/devices/system/CPU/cpu0/cpufreq $
Oh, from 3.4 GHz to GHz, a total of 10 frequencies are supported. Scaling_available_governors will output the current available frequency adjustment policy:
Conservative OnDemand userspace powersave Performance
A total of five policies are available for us to choose from. What policy does the current system choose? Let's take a look:
Dong-990:/sys/devices/system/CPU/cpu0/cpufreq $ cat scaling_governorondemand
OK, my system currently chooses the OnDemand policy. The main idea of this policy is: as long as the CPU load exceeds a threshold, the CPU frequency will immediately increase to the highest, then, we can reduce it to a proper level based on the actual situation. The detailed information will be discussed later. Scaling_driver will output which driver is currently used to set the CPU operating frequency.
When we select userspace as our FM Governor, we can manually set the desired frequency through scaling_setspeed. Powersave simply runs at the lowest frequency, while performance always runs at the highest frequency.
2. Software Architecture
Through the introduction in the previous section, we can roughly sort out the composition and working methods of the cpufreq system. First, the hardware features of the CPU determine the maximum and minimum operating frequency of the CPU. All the frequency adjustment values must be within this range. They are expressed by cpuinfo_xxx_freq. Then, we can define a software adjustment range within this range, which is expressed by scaling_xxx_freq. At the same time, we also need to provide a frequency table based on the specific hardware platform, this frequency table specifies the frequency values that can be operated by the CPU. Of course, these frequency values must be within the range of cpuinfo_xxx_freq. With this frequency information, the cpufreq system can select an appropriate frequency from the frequency table for CPU use based on the current CPU load severity, which has achieved the goal of saving energy. As for how to select the frequency in the frequency table, this should be implemented by different governor. The current kernel version provides five types of Governor for us to choose. After the appropriate frequency is selected, the specific frequency adjustment will be done by scaling_driver. The cpufreq system puts some common logic and interfacesCodeAbstract: these codes are irrelevant to the platform and specific frequency modulation policies. The kernel documentation calls them cpufreq.
Core (/documents/cpufreq/core.txt ). In addition, the content related to the actual frequency modulation policy is called cpufreq_policy. cpufreq_policy is composed of frequency information and specific governor, and Governor is the actual implementer of the specific policy, of course, Governor requires us to provide necessary frequency information. The implementation of Governor is best unrelated to the platform. The Code related to the platform is expressed by cpufreq_driver, which completes the actual frequency adjustment. Finally, if other kernel modules need to receive notification messages during frequency adjustment, they can be completed through cpufreq notifiers. Therefore, we can summarize the software structure of the cpufreq system as follows:
3. cpufreq_policy
The combination of various restrictions of a frequency modulation policy is called policy, which is expressed in the cpufreq_policy data structure in the Code:
Struct cpufreq_policy {cpumask_var_t CPUs; cpumask_var_t related_cpus; unsigned int shared_type; unsigned int CPU; unsigned int last_cpu; struct cpufreq_cpuinfo cpuinfo; unsigned int min;/* In kHz */unsigned int Max; /* In kHz */unsigned int cur; unsigned int policy; struct employee * governor; void * governor_data; struct work_struct update; struct cpufreq_real_policy user_policy; struct kobject kobj; struct completion kobj_unregister ;};
The fields are described as follows:
-
- CPUs and related_cpusBoth are cpumask_var_t variables. CPUs indicates all online CPUs under the control of this policy, while related_cpus is a collection of online and offline CPUs. It is mainly used when multiple CPUs use the same policy. In fact, this is the case in most systems: All CPUs use the same policy at the same time. We need the related_cpus variable to indicate all CPU numbers managed by this policy.
-
- CPU and last_cpuAlthough a policy can be used for multiple CPUs at the same time, a policy is usually managed by only one CPU. The CPU variable is used to record the CPU number used to manage the policy, the last_cpu is the number of the CPU used to manage the policy last time (because the CPU used to manage the policy may be plug out, management should be migrated to another CPU at this time ).
-
- CpuinfoSaves the maximum and minimum frequencies supported by CPU hardware, as well as switching latency information.
-
- MIN/max/curThe minimum, maximum, and current frequencies that can be used in this policy.
-
- Policy this variable can take the following two values: cpufreq_policy_powersave and cpufreq_policy_performance. This variable is only valid when the FM driver supports the setpolicy callback function, at this time, the driver determines the operating frequency or status of the system based on the value of the policy variable. If the CPU freq_driver supports target callback, the frequency is determined by the corresponding governor.
- Governor and governor_dataPoint to the cpufreq_governor structure currently used by the Policy and its context data. Governor is the key to implementing this policy, and its logic is implemented by Governor.
-
- UpdateSometimes the policy needs to be updated in the interrupt context. You need to use this work queue to move the actual work to the later process context for execution.
-
- User_policySometimes the policy parameters need to be modified for special reasons. For example, when the duration is too high, the maximum allowable running frequency may be reduced. In order to restore the original running parameters when appropriate, you need to use user_policy to save the original parameters (Min, Max, policy, Governor ).
-
- KobjThis policy corresponds to the kobj object in sysfs.
4. cpufreq_governor
The so-called governor is translated into a regulator. Governor is responsible for detecting CPU usage, so as to select an appropriate frequency in the available range. In the code, it is represented by the cpufreq_governor structure:
Struct detail {char name [cpufreq_name_len]; int initialized; 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 ;};
The fields are described as follows:
- Name: the name of the governor.
- Initialized initialization flag.
- Governor points to a callback function. cpufreq core calls the callback function at different stages for the startup, stop, initialization, and exit actions of the governor.
- All registered governor in list_head will use this field to link to a global linked list for the system to query and use.
5. cpufreq_driver
The gonvernor mentioned in the previous section is only responsible for calculating and proposing appropriate frequencies, but the frequency setting is platform-related. This requires the cpufreq_driver driver to complete. The structure of cpufreq_driver is as follows:
Struct cpufreq_driver {struct module * owner; char name [cpufreq_name_len]; u8 flags; bool metric;/* 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);/* shoshould 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 ;};
The meanings of related fields are as follows:
- NameThe name of the frequency driver.
- InitThe callback function must be implemented. cpufreq core initializes the driver through the callback function.
- VerifyThe callback function must be implemented. cpufreq core checks whether the policy parameter is supported by the driver.
- Setpolicy/TargetThe callback function. The driver must implement one of the two functions. If you cannot select an appropriate running frequency through governor, the setpolicy callback function is implemented, in this way, the system only supports cpufreq_policy_powersave and cpufreq_policy_performance. Otherwise, implement the target callback function and set the frequency required by Governor through the target callback.
- GetThe callback function is used to obtain the current CPU operating frequency.
- GetavgThe callback function is used to obtain the average operating frequency of the CPU.
6. cpufreq notifiers
The cpufreq notification system uses the kernel standard notification interface. It provides two notification events: policy notification and transition notification.
Policy notification is used to notify other modules that the CPU policy needs to be changed. Each time the policy changes, the callback on the notification chain will be called three times with different event parameters, respectively:
- Cpufreq_adjust all notified users can modify the restriction information of the policy as long as they need it. For example, the temperature control system may change the frequency at which the operation is permitted.
- Cpufreq_incompatible is only used to prevent hardware errors. You can modify the policy restriction information in this notification.
- Before cpufreq_policy switches the policy, the notification will be sent to all notified users.
The transition notification chain is used to notify the relevant registrant when the driver adjusts the CPU frequency. When the frequency is adjusted, the notification will send two notification events:
- Notifications before CPU freq_prechange adjustment.
- Notification after CPU freq_postchange is adjusted.
When the frequency is changed because the system enters the suspend, the following notification message is sent: