[L’introduction est en français, le reste du texte en anglais]
L’économie d’énergie a toujours été une préoccupation majeure dans les systèmes embarqués, puisque par définition, ils peuvent avoir des contraintes énergétiques. Bien sûr, aujourd’hui, l’économie d’énergie est toujours au cœur des discussions.
L’économie d’énergie est toujours un ensemble de compromis. En termes de disponibilité du système ou des périphériques, de temps de réveil…
Dans ce blog, nous allons nous pencher sur les multiples façons de réduire la consommation d’énergie d’un Linux embarqué. De plus, pour illustrer mes propos, des résultats de mesures sur i.MX8 seront présentés.
Extinction
We, of course, need to start with the most obvious, but also the most effective in terms of energy saving. If your system does not need to be up all the time, this solution could be very interesting if waiting for the device to boot is not an issue. On a stock constructor distribution, we measure an average boot time of around 16 seconds between power up the board and systemd reached multi-user.target. This target could be considered as the end of boot in a non-graphical system.
Obviously, this system could be modified to reduce the time to boot. There are multiple ways to reduce the time to boot like disable u-boot bootdelay, deactivate console logs, activate U-boot Falcon Mode, optimize kernel and systemd configuration. But this is completely another subject. NXP carried out an optimisation study on an i.MX8, applying most of the optimisations listed earlier, and measure a boot time of 3.8 seconds.
As the i.MX8 is still consuming some current even if it is powered off, the measure was not 0. But we could measure a current saving of 90 % between a powered on system and a powered off system.
Suspend to idle
This standby mode is a pure software implementation and the lightest variant of standby systems. It works by freezing the userspace, suspending all the processes and put peripherals in standby mode. This mode avoids going through another complete boot (bootloader launch, kernel and systemd services initialisation). In this mode, the SoC is still alimented but with a very low workload, it then reduces the global consumption of the system.
On the i.MX8, the kernel was measuring the wake-up time to have a full operational system at around 0.7 seconds.
The measure of the consumption shows a diminution of 12.5 % compare to a powered-on system.
Suspend to ram
This standby mode is saving system state (CPU, memory, …) in RAM. The whole system (CPU, peripherals, bus), except the RAM, is put in standby and low consumption modes. Same as for suspend to idle, the userspace is freezed and avoids relaunching the bootloader, the kernel and systemd services.
The wake-up is controlled via a peripheral like the serial console, a GPIO or a coprocessor for example.
After the wake-up has been triggered, the i.MX8 kernel was measuring around 0.7 seconds to have a full operational system.
For this mode, the consumption is reduced by 50 % of a powered-on system.
Suspend to disk
This standby mode is working like the suspend to ram but instead of saving the system state in RAM, it is saved on disk (eMMC for example). Except for certain peripherals that can remain in standby mode, the entire system is powered off, including the RAM. The mode is then very close to a complete shutdown.
The drawback is that the mode required to relaunch the bootloader to run a fresh instance of the kernel to restore the system status saved before hibernation. This operation takes some time and with some optimisation could lead to 2–3 seconds of wake-up.
As almost all the peripherals are shutdown, the consumption is minimal. We are reaching a reduction by 90 % of a powered-on system
Comparison on an iMX8
As the suspend modes are powering off the devices, the wake-up time could be very influenced by the devices enabled. Since Linux requires powering up all devices, the fewer there are enabled, the shorter the time it takes to get the system up. For example, for the suspend to ram mode, if the USB interface is disabled, the wake-up is decreased to 0.05 seconds.
Here is a little board to summarize the measures:
Suspend mode comparison on an i.MX8 with stock constructor distribution
Reducing consumption via peripherals
On some product, it is impossible to turn down the system for multiple reasons like receiving messages within a short time.
Of course, the first study to reduce the consumption is to look over the peripherals enabled and disable them if there are unneeded.
In this article, we saw that we could activate suspend modes for the whole system, but we could also do it for the peripherals themselves even if not all peripheral’s drivers are supporting it.
On various product, all the peripherals are not required every time. Some could then be powered off when not used.
We could take the example of USB peripherals, where the kernel is not activating dynamic management of alimentation by default. This needs to be activated by writing ‘auto’ in power/control file in sysfs directory of the USB device.
The USB specification states that all USB devices must support power management. Nevertheless, the sad fact is that many devices do not
support it very well. You can suspend them all right, but when you try to resume them they disconnect themselves from the USB bus or
they stop working entirely. This seems to be especially prevalent among printers and scanners, but plenty of other types of device have
the same deficiency. For this reason, by default the kernel disables autosuspend (the ``power/control`` attribute is initialized to ``on``)
for all devices other than hubs. Hubs, at least, appear to be reasonably well-behaved in this regard.
Source : Documentation/driver-api/usb/power-management.rst
To illustrate, moving to this dynamic management of alimentation on a USB modem reduce the energy consumption by 56 % when the device is in suspend mode.
Connectivity devices are very power consuming. To save power, it is recommended to disable them at runtime when unneeded. It is also worth to send burst of data to minimize the time of enable state instead of enabling them each time a short data should be sent if this is possible in the product context.
For example, disabling the Wi-Fi, the Ethernet, and the modem reduced the energy consumption by 52 %.
CPUFREQ
The last solution presented in this blog would be the CPUFREQ configuration. If you have a high level of CPU consumption, it could be interesting to reduce the CPU frequency. This will only have an impact if the CPU load is high as if the CPU load is always low, even if the CPU frequency is high it will not consume more than a low CPU frequency. Here are CPUFREQ configurations available:
The CPUfreq « ondemand » controller adjusts the processor frequency according to the current system load. The load estimate is triggered by the scheduler via the update_util_data->func hook; once triggered, CPUfreq checks the CPU usage statistics over the last period and the governor adjusts the CPU accordingly. The CPU must be able to change frequency very quickly.
The « conservative » CPUfreq governor, like the « ondemand » governor, sets the processor frequency according to current usage. It differs in that it gracefully increases and decreases the processor speed, rather than going to maximum speed as soon as there is a load on the processor. This behaviour is best suited to a battery-powered environment. The governor is set in the same way as the « on demand » governor.
The CPUfreq « powersave » regulator statically sets the CPU to the lowest frequency within the scaling_min_freq and scaling_max_freq limits.
The CPUfreq « performance » regulator statically sets the CPU to the highest frequency within the scaling_min_freq and scaling_max_freq limits.
The « userspace » CPUfreq governor allows the user, or any userspace program running with the « root » UID, to set the processor to a specific frequency by providing a « scaling_setspeed » sysfs file in the CPU-device directory. This value could be set within the scaling_min_freq and scaling_max_freq limits.
The « schedutil » CPUfreq governor is getting the CPU load from the kernel scheduler instead of an average load of the last moments. This is, for the moment, not the best solution for power saving according to lwn.net article.
On a 100% load CPU, we can reduce the energy consumption of 23 % between a CPU max frequency and a CPU min frequency.
Conclusion
As you understand, power saving is highly dependent on the product context. Also, all the modes presented in this article may not be supported by default in constructors BSP’s and will require some customisation of your distribution.