The operating frequency on the device CPU can scale (change the voltage power supply input) according to system/user needs. When full processor resources are not needed, the system can greatly reduce overall power consumption and operating temperature.
This API allows you to enable and disable the available CPU cores, change their frequencies, and establish the governor on the fly. It also provides access to the current CPU temperature and trip points. In the Digi APIx javadoc documentation you can find a complete list of the available methods in this API.
Unless noted, all CPU API methods require com.digi.android.permission.CPU permission.
If your application does not have com.digi.android.permission.CPU permission, it will not have access to any CPU service feature. |
To work with this API and manage your device CPU, the first step is to instantiate a CPUManager object. To do this, you must provide the application Context.
import android.app.Activity;
import android.os.Bundle;
import com.digi.android.system.cpu.CPUManager;
public class CPUSampleActivity extends Activity {
CPUManager cpuManager;
[...]
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceStace);
// Instantiate the CPU manager object.
cpuManager = new CPUManager(this);
[...]
}
[...]
}
The CPU manager allows you to:
Control CPU cores
The CPUManager allows you to increase and decrease CPU frequencies, display the usage of each core as well as overall CPU usage, and control the CPU cores of your device by enabling and disabling them.
Use the following methods to enable and disable the cores of your device and verify which devices are online or offline.
Method | Description |
---|---|
isCoreEnabled(int) |
Specifies the index of the core to check for enabled/disabled status |
enableCore(int) |
Specifies the index of the core to be enabled |
disableCore(int) |
Specifies the index of the core to be disabled |
These methods may fail for the following reasons:
-
The specified core does not exist, throwing a NoSuchCoreException.
-
An error during configuration or while checking the core status throws a CPUException.
To determine the number of available cores in the device, use the method getNumberOfCores() of the CPUManager class.
CAUTION! It is not possible to disable CPU0 on your device. CPU0 is the default core and must always be running. |
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = new CPUManager(context);
// Get the number of available cores.
int numberOfCores = cpuManager.getNumberOfCores();
System.out.println("Number of cores: " + numberOfCores);
// Check enabled cores.
for (int i = 1; i < numberOfCores; i++) {
boolean coreEnabled = cpuManager.isCoreEnabled(i);
System.out.println("Core " + i + ": " + coreEnabled);
// Enable disabled cores.
if (!coreEnabled) {
System.out.println("Enabling core " + i);
cpuManager.enableCore(i);
}
}
[...]
Monitor CPU usage
Use the following methods to monitor the CPU utilization. The API calculates the percentage of total CPU time (including all cores) and the percentage per each core over a period of time.
Method | Description |
---|---|
getCPUUsage() getCPUUsage(long) |
Returns the total CPU usage as a percentage. This method blocks during 300 milliseconds or the specified time. |
getCoreUsage(int) getCoreUsage(int, long) |
Returns usage of the specified core as a percentage. This method blocks during 300 milliseconds or the specified time. |
getUsage() getUsage(long) |
Returns a list with all CPU usage percentages. Overall CPU usage is at index 0; it is followed by the core usages for the available cores. This method blocks during 300 milliseconds or the specified time. |
CAUTION! Getting CPU usage is a blocking operation. Any of these methods waits until the default interval (300 milliseconds) or the specified interval is reached. |
These methods may fail for the following reasons:
-
The specified core does not exist, throwing a NoSuchCoreException.
-
An error during usage calculation throws a CPUException.
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = ...;
// Get CPU usage in the last minute.
System.out.println("Overall CPU usage: " + cpuManager.getCPUUsage(60 * 1000) + " %");
// Get usage per core.
ArrayList<Float> usages = cpuManager.getUsage();
for (int i = 1; i < usages.size(); i++) {
System.out.println("CPU " + i + " usage: " + usages.get(i));
}
[...]
Configure CPU frequencies
You can obtain a list of available frequencies your device can scale. The API also provides methods to read—and in some cases, change—the current CPU speed and frequency limits.
Method | Description |
---|---|
getAvailableFrequencies() |
Lists the available frequencies (in KHz) the device supports |
getMinFrequency() getMaxFrequency() |
Returns the minimum and maximum operating frequency (in kHz) the CPU supports |
getTransitionLatency() |
Returns the time in nanoseconds it takes the CPU to switch between two frequencies |
getMinScalingFrequency() getMaxScalingFrequency() |
Shows the current "policy limits", the minimum and maximum frequency (kHz) the device may scale the CPU to |
setMinScalingFrequency(int) setMaxScalingFrequency(int) |
Changes the current "policy limits" When setting these frequency limits set the maximum value first, then the minimum. These values must be between the maximum and minimum frequencies returned by getMinFrequency() and getMaxFrequency(). |
getFrequency() |
Returns the current frequency of the CPU as obtained from the hardware, in KHz. This is the frequency the CPU actually runs at |
These methods may fail, throwing a CPUException, if any error occurred while reading or changing the values.
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = ...;
// List supported frequencies.
System.out.println("Available frequencies:");
ArrayList<Integer> availableFreqs = cpuManager.getAvailableFrequencies();
for (Integer f: availableFreqs) {
System.out.println(" " + f);
}
// Min and max supported frequencies.
System.out.println("Min freq: " + cpuManager.getMinFrequency());
System.out.println("Max freq: " + cpuManager.getMaxFrequency());
// Set min and max frequency limits.
cpuManager.setMinScalingFrequency(availableFreqs[0]);
cpuManager.setMaxScalingFrequency(availableFreqs[availableFreqs.size() - 1]);
System.out.println("Min scaling freq: " + cpuManager.getMinScalingFrequency());
System.out.println("Max scaling freq: " + cpuManager.getMaxScalingFrequency());
// Get current CPU speed.
System.out.println("Current freq: " + cpuManager.getFrequency());
[...]
You can perform additional actions depending on the governor you have selected:
-
Userspace governor: The method setFrequency(int) allows you to change the CPU operating frequency to a specific value in kHz, but only within the limits defined by getMinScalingFrequency() and getMaxScalingFrequency().
-
Interactive governor: The method boostPulse() immediately boosts the speed of all CPUs to hispeed_freq (getHiSpeedFreq() of InteractiveGovernor class) for the period of time specified by the boost_pulse_duration property (getBoostPulseDuration() of InteractiveGovernor class).
For more information about governors, see Configure governors. |
Configure governors
A CPU governor controls how the CPU raises and lowers its frequency in response to the demands the user is placing on their device. Governors have a large impact on performance and power save.
Consider the following before selecting a governor:
-
Performance. Consider the trade-offs between more speed and power usage.
-
Power save. Being very battery friendly may correspond to less speed (or sometimes smoothness).
-
Stability. Some governors are unstable and some are rock solid.
-
Smoothness (or Fluidity). Smoothness is not the same as speed; a governor can be fast but not smooth. To test smoothness, scroll pages down/up or open and close apps. More smoothness equates to a better user experience.
Governor types
You can use one of several governor types to configure the CPU, all of which are contained in a enumerator called GovernorType. Each GovernorType is also represented by a class in the API.
Governor | Type | Class | Description |
---|---|---|---|
Performance |
GovernorType.PERFORMANCE |
GovernorPerformance |
Sets the CPU statically to the highest frequency |
Powersave |
GovernorType.POWERSAVE |
GovernorPowerSave |
Sets the CPU statically to the lowest frequency |
Userspace |
GovernorType.USERSPACE |
GovernorUserSpace |
Sets the CPU statically to the user-specified frequencies |
Ondemand |
GovernorType.ONDEMAND |
GovernorOnDemand |
Sets the CPU depending on the current usage. It jumps to max speed when there is load on the CPU. If the CPU load abates, it slowly steps back down through the kernel’s frequency steppings until it settles at the lowest frequency. |
Conservative |
GovernorType.CONSERVATIVE |
GovernorConservative |
Sets the CPU depending on the current usage. It gracefully increases and decreases the CPU speed rather than jumping to the maximum the moment there is load on the CPU. |
Interactive |
GovernorType.INTERACTIVE |
GovernorInteractive |
Sets the CPU depending on the current usage. This governor is more aggressive about scaling the CPU speed up in response to CPU-intensive activity. |
Schedutil |
GovernorType.SCHEDUTIL |
GovernorSchedutil |
Scheduler-driven CPU frequency selection. It uses scheduler-provided CPU utilization information as input for making its decisions. |
To obtain the list of available governor types supported by the CPU, use the getAvaliableGovernorTypes() method of CPUManager.
import com.digi.android.system.cpu.CPUManager;
import com.digi.android.system.cpu.GovernorType;
[...]
// Get the CPU manager.
CPUManager cpuManager = new CPUManager(context);
// Get the available governor types.
ArrayList<GovernorType> governorTypes = cpuManager.getAvailableGovernorTypes();
for (GovernorType type: governorTypes) {
System.out.println(type.getID() + ": " + type.getDescription());
}
[...]
Get and set the CPU governor
You can get and set the current CPU governor using the following methods:
Method | Description |
---|---|
getGovernorType() |
Returns the governor type the CPU is configured with |
getGovernor() |
Returns a Governor object corresponding to the governor that the CPU is configured with |
setGovernorType(GovernorType) |
Configures the CPU with the provided governor type and returns the corresponding Governor object |
If an error occurs during the reading or configuration process these methods may fail, throwing a CPUException.
import com.digi.android.system.cpu.CPUManager;
import com.digi.android.system.cpu.Governor;
import com.digi.android.system.cpu.GovernorType;
[...]
CPUManager cpuManager = ...;
// Get the CPU governor type.
GovernorType governorType = cpuManager.getGovernorType();
System.out.println("Current CPU governor: " + governorType.getID());
// Configure the CPU to use the Powersave governor.
Governor governor = cpuManager.setGovernorType(GovernorType.POWERSAVE);
System.out.println("Configured new CPU governor: " + governor.getGovernorType());
[...]
The getGovernor() and setGovernorType(GovernorType) methods return a Governor object. You can cast this object to the corresponding governor class to access its specific features.
import com.digi.android.system.cpu.CPUManager;
import com.digi.android.system.cpu.Governor;
import com.digi.android.system.cpu.GovernorConservative;
import com.digi.android.system.cpu.GovernorInteractive;
import com.digi.android.system.cpu.GovernorOnDemand;
import com.digi.android.system.cpu.GovernorPerformance;
import com.digi.android.system.cpu.GovernorPowerSave;
import com.digi.android.system.cpu.GovernorSchedutil;
import com.digi.android.system.cpu.GovernorType;
import com.digi.android.system.cpu.GovernorUserSpace;
[...]
CPUManager cpuManager = ...;
// Get the CPU governor type.
Governor governor = cpuManager.getGovernor();
// Cast governor depending on its type.
switch (governor.getGovernorType()) {
case GovernorType.PERFORMANCE:
GovernorPerformance performanceGovernor = (GovernorPerformance)governor;
// TODO Custom implementation.
break;
case GovernorType.POWERSAVE:
GovernorPowerSave powerSaveGovernor = (GovernorPowerSave)governor;
// TODO Custom implementation.
break;
case GovernorType.USERSPACE:
GovernorUserSpace userSpaceGovernor = (GovernorUserSpace)governor;
// TODO Custom implementation.
break;
case GovernorType.ONDEMAND:
GovernorOnDemand onDemandGovernor = (GovernorOnDemand)governor;
// TODO Custom implementation.
break;
case GovernorType.CONSERVATIVE:
GovernorConservative conservativeGovernor = (GovernorConservative)governor;
// TODO Custom implementation.
break;
case GovernorType.INTERACTIVE:
GovernorInteractive interactiveGovernor = (GovernorInteractive)governor;
// TODO Custom implementation.
break;
case GovernorType.SCHEDUTIL:
GovernorSchedutil schedutilGovernor = (GovernorSchedutil)governor;
// TODO Custom implementation.
break;
default:
// TODO Custom implementation.
break;
}
[...]
Configure governor parameters
Some governors are configurable and specify different parameters that can be read and set.
Performance, powersave, and userspace governors do not define any parameter. They just configure the CPU statically to the maximum, minimum, or user-specified frequency respectively when they are selected.
The configurable governors are:
-
Ondemand
-
Conservative
-
Interactive
-
Schedutil
All of them define some common and specific accessible parameters:
Parameter | Method | Description |
---|---|---|
sampling_rate |
getSamplingRate() setSamplingRate(long) |
Represents in microseconds how often the kernel reads CPU usage and determines actions to take depending on frequency |
sampling_rate_min |
getMinSamplingRate() |
Minimum sampling rate. This functionality is not available for kernel 4.14 or higher. In this case the method returns GovernorOndemand.MIN_SAMPLING_RATE. |
up_threshold |
getUpThreshold() setUpThreshold(int) |
Defines what the average CPU usage between the samplings of sampling_rate needs to be for the kernel to make a decision on whether it should increase the frequency |
ignore_nice_load |
isIgnoreNiceLoadEnabled() enableIgnoreNiceLoad() disableIgnoreNiceLoad() |
When disabled (its default), all processes are counted towards the 'CPU utilization' value. When enabled, the processes that are run with a 'nice' value will not count (and thus be ignored) in the overall usage calculation |
sampling_down_factor |
getSamplingDownFactor() setSamplingDownFactor(int) |
Controls the rate at which the kernel makes a decision on when to decrease the frequency while running at top speed |
Parameter | Method | Description |
---|---|---|
sampling_rate |
getSamplingRate() setSamplingRate(long) |
Represents in microseconds how often the kernel reads the CPU usage and determines actions to take based on frequency |
sampling_rate_min |
getMinSamplingRate() |
Minimum sampling rate. This functionality is not available for kernel 4.14 or higher. In this case the method returns GovernorConservative.MIN_SAMPLING_RATE. |
up_threshold |
getUpThreshold() setUpThreshold(int) |
Defines what the average CPU usage between the samplings of sampling_rate needs to be for the kernel to make a decision on whether it should increase the frequency |
ignore_nice_load |
isIgnoreNiceLoadEnabled() enableIgnoreNiceLoad() disableIgnoreNiceLoad() |
When disabled (its default), all processes are counted towards the 'CPU utilization' value. When enabled, the processes that are run with a 'nice' value will not count (and thus be ignored) in the overall usage calculation |
sampling_down_factor |
getSamplingDownFactor() setSamplingDownFactor(int) |
Controls the rate at which the kernel makes a decision on when to decrease the frequency while running at top speed |
down_threshold |
getDownThreshold() setDownThreshold(int) |
Defines what the average CPU usage between the samplings of sampling_rate needs to be for the kernel to make a decision on whether it should decrease the frequency |
freq_step |
getFreqStep() setFreqStep(int) |
Describes by what percentage steps the CPU frequency should be smoothly increased and decreased |
Parameter | Method | Description |
---|---|---|
min_sample_time |
getMinSampleTime() setMinSampleTime(long) |
Represents the minimum amount of microseconds to spend at the current frequency before ramping down |
hispeed_freq |
getHiSpeedFreq() setHiSpeedFreq(int) |
An intermediate "high speed" at which to initially ramp when CPU load hits the value specified in go_hispeed_load |
go_hispeed_freq |
getGoHiSpeedLoad() setGoHiSpeedLoad(int) |
The CPU load at which to ramp to the intermediate "high speed" specified in hispeed_freq |
above_hispeed_delay |
getAboveHiSpeedDelay() setAboveHiSpeedDelay(long) |
Once speed is set to hispeed_freq, time in microseconds to wait before bumping speed higher in response to continued high load |
timer_rate |
getTimerRate() setTimerRate(long) |
Sample rate in microseconds for reevaluating CPU load when the system is not idle |
timer_slack |
getTimerSlack() setTimerSlack(long) |
Maximum additional time in microseconds to defer handling the governor sampling timer beyond timer_rate when running at speeds above the minimum |
boost |
isBoostEnabled() enableBoost() disableBoost() |
When boost is enabled, immediately boosts the speed of all CPUs to at least hispeed_freq until boost is disabled again. When disabled, allows CPU speeds to drop below hispeed_freq to load as usual |
bootspulse_duration |
getBoostPulseDuration() setBoostPulseDuration(long) |
Amount of microseconds to hold CPU speed at hispeed_freq on a boost pulse before allowing speed to drop according to load as usual |
Parameter | Method | Description |
---|---|---|
down_rate_limit_us |
getDownRateLimit() setDownRateLimit(long) |
Amount of microseconds to wait before decreasing the frequency |
up_rate_limit_us |
getUpRateLimit() setUpRateLimit(long) |
Amount of microseconds to wait before increasing the frequency |
import com.digi.android.system.cpu.CPUManager;
import com.digi.android.system.cpu.GovernorType;
import com.digi.android.system.cpu.GovernorInteractive;
[...]
CPUManager cpuManager = ...;
// Set the interactive governor.
GovernorInteractive interactiveGovernor = (GovernorInteractive)cpuManager.setGovernorType(GovernorType.INTERACTIVE);
// Configure the governor.
interactiveGovernor.setMinSampleTime(80000);
interactiveGovernor.setTimerRate(20000);
[...]
// Read some governor parameters.
System.out.println("High speed frequency: " + interactiveGovernor.getHiSpeedFreq());
System.out.println("Boost enabled: " + interactiveGovernor.getBoost());
[...]
Monitor CPU temperature
The CPU manager addresses three concepts related to temperature:
-
Current temperature. The current CPU temperature.
-
Hot temperature. The temperature limit at which system will reduce CPU an GPU frequency to avoid system overheating.
-
Critical temperature. The temperature limit at which system will halt to avoid system damage caused by overheating. This always occurs after reaching hot temperature.
Get CPU temperature
Use the following methods to obtain temperature values:
Parameter | Method |
---|---|
Current temperature |
getCurrentTemperature() |
Hot temperature |
getHotTemperature() |
Critical temperature |
getCriticalTemperature() |
All methods return a float value and may throw a CPUTemperatureException if an error occurs while reading the corresponding temperature value.
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = new CPUManager(context);
// Read the temperature values.
System.out.println("Current temperature: " + cpuManager.getCurrentTemperature());
System.out.println("Hot temperature: " + cpuManager.getHotTemperature());
System.out.println("Critical temperature: " + cpuManager.getCriticalTemperature());
[...]
Control CPU temperature
You can receive notifications about CPU temperature if you subscribe a ICPUTemperatureListener to the CPUManager. Use the registerListener(ICPUTemperatureListener, long) method to register for temperature updates specifying the interval between updates, in milliseconds.
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = new CPUManager(context);
// Create the temperature listener.
MyCPUTemperatureListener myTempListener = ...;
// Register the temperature listener to be notified every 5 seconds.
cpuManager.registerListener(myTempListener, 5000);
[...]
The registered listener class, MyCPUTemperatureListener, must implement the ICPUTemperatureListener interface. This interface defines the onTemperatureUpdate(float) method, which is called when the temperature is updated.
import com.digi.android.system.cpu.ICPUTemperatureListener;
public class MyCPUTemperatureListener implements ICPUTemperatureListener {
@Override
public void onTemperatureUpdate(float temperature) {
// This code will be executed every 5 seconds, the interval configured in the registerListener method.
System.out.println("New temperature value " + temperature);
}
}
To stop the temperature notifications, use the unregisterListener(ICPUTemperatureListener) method to unsubscribe the already registered listener.
[...]
CPUManager cpuManager = ...;
MyCPUTemperatureListener myTempListener = ...;
cpuManager.registerListener(myTempListener, 5000);
[...]
// Remove the temperature listener.
cpuManager.unregisterListener(myTempListener);
[...]
Set CPU temperature trip points
Configure hot and critical temperature values with the following methods:
Parameter | Method |
---|---|
Hot temperature |
setHotTemperature(float) |
Critical temperature |
setCriticalTemperature(float) |
Both require the new value of the trip point to configure as a float and return the configured value.
The configuration of any of these trip points may fail for the following reasons:
-
The hot temperature is equal to or greater than the critical temperature, throwing an IllegalArgumentException.
-
An error occurs while setting the new trip point value, throwing a CPUTemperatureException.
For a ConnectCore 6, the maximum value for the trip points are:
|
import com.digi.android.system.cpu.CPUManager;
[...]
// Get the CPU manager.
CPUManager cpuManager = new CPUManager(context);
// Set the new values of the trip points.
float configuredHotTemp = cpuManager.setHotTemperature(75);
float configuredCriticalTemp = cpuManager.setCriticalTemperature(95);
[...]
CPU management example
Example: CPU management |
---|
The CPU Management Sample Application demonstrates the CPU API. In this example, you can enable and disable the CPU cores, configure frequencies, and select and set up the governor while monitoring the total CPU usage as well as the usage of each core. You can import the example using Digi’s Android Studio plugin. For more information, see Import a Digi sample application. To look at the application source code, go to the GitHub repository. |
CPU temperature example
Example: CPU temperature |
---|
The CPU Temperature Sample Application demonstrates how to manage the CPU temperature. In this example you can read the trip points and configure the sampling rating of the current temperature in ConnectCore 8X. You can import the example using Digi’s Android Studio plugin. For more information, see Import a Digi sample application. To look at the application source code, go to the GitHub repository. |