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.

Instantiating the CPUManager
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.

It is not possible to disable CPU0 on your device. CPU0 is the default core and must always be running.
Control CPU cores
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.

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.

Monitor CPU usage
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.

CPU frequencies
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.

Get available governor types
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.

Get and set current governor type
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.

Governor classes
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

Configure governor parameters
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.

Get temperature values
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.

Register temperature updates
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.

ICPUTemperatureListener implementation example, MyCPUTemperatureListener
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.

Unregister temperature updates
[...]

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 8M Mini, the maximum value for the trip points are:

  • Maximum hot temperature value: 85C

  • Maximum critical temperature value: 100C

Set temperature trip points
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

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.

include::../snippets/apix-import-example.adoc GitHub repository.

CPU temperature example

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 8M Mini.

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.