pm: add two examples for the power management API

https://jira.digi.com/browse/DEL-6659

Signed-off-by: Francisco Gil <francisco.gilmartinez@digi.com>
This commit is contained in:
Francisco Gil 2019-07-29 13:27:14 +02:00
parent 844d13fec0
commit 0e94c71cfb
4 changed files with 567 additions and 0 deletions

44
apix-pm-examples/Makefile Normal file
View File

@ -0,0 +1,44 @@
#
# Copyright 2019, Digi International Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
BINARYCPU := apix-cpu-example
BINARYPM := apix-pm-application
BINARIES := $(BINARYCPU) $(BINARYPM)
CFLAGS += -Wall -O0
CFLAGS += $(shell pkg-config --cflags libdigiapix)
LDLIBS += $(shell pkg-config --libs libdigiapix)
.PHONY: all
all: $(BINARIES)
$(BINARYCPU): apix-cpu-sample.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $(BINARYCPU)
$(BINARYPM): apix-pm-sample.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $(BINARYPM)
.PHONY: install
install: $(BINARIES)
install -d $(DESTDIR)/usr/bin
install -m 0755 $^ $(DESTDIR)/usr/bin/
.PHONY: clean
clean:
-rm -f *.o $(BINARIES)

View File

@ -0,0 +1,96 @@
Digi APIX Power Management example Applications
===============================================
Example applications to access and manage CPU functions using the Digi APIX library.
These applications show how to work with different functions and provide different
examples to work with the CPU.
Running the apix-cpu-example application
-----------------------
Once the binary is in the target, launch the application:
```
# ./apix-cpu-example
Example application using libdigiapix CPU support
Usage: apix-cpu-example [options]
-l List available frequencies
-s <frequency> Set the desired frequency
-v Show the current governor
-g List available governors
-f <governor> Set the desired governor
-t List the temperatures of the system
-c <temperature> Set the critical temperature
-p <temperature> Set the passive temperature
-u Get the CPU usage
-n Get the number of CPU cores
-d <core_number> Disable the selected core
-e <core_number> Enable the selected core
Examples:
apix-cpu-example -l
apix-cpu-example -f userspace
apix-cpu-example -t
```
The application needs a valid argument to run, some of the arguments need additional parameters.
Running the apix-pm-application application
-----------------------
Once the binary is in the target, launch the application:
```
# ./apix-pm-application
Example application using libdigiapix power management support.
This application enables counter measurements in the CPU and GPU
in order to reduce the temperature.
Usage: apix-pm-application [options]
-c Apply CPU counter measurements
-g Apply GPU counter measurements
-b Apply CPU & GPU counter measurements
Examples:
apix-pm-application -g
apix-pm-application -b
```
This application enables countermeasures in order to reduce the temperature of the CPU.
If the CPU countermeasures are set, it will select the userspace governor and will set
the minimum frequency in the device in order to reduce the temperature.
If the GPU counter measurements are set, it will reduce the GPU scaler to half of its original value.
Note: Some modules such as CC6UL don't have a GPU.
Compiling the application
-------------------------
This demo can be compiled using a Digi Embedded Yocto based toolchain. Make
sure to source the corresponding toolchain of the platform you are using,
for example, for ConnectCore 6UL:
```
~$ . <DEY-toolchain-path>/environment-setup-cortexa7hf-vfp-neon-dey-linux-gnueabi
~$ make
```
For more information, see the [Digi Embedded Yocto](https://github.com/digi-embedded/meta-digi).
License
-------
Copyright 2019, Digi International Inc.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View File

@ -0,0 +1,213 @@
/*
* Copyright 2019, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libdigiapix/pwr_management.h>
/*
* usage_and_exit() - Show usage information and exit with 'exitval' return
* value
*
* @name: Application name.
* @exitval: The exit code.
*/
static void usage_and_exit(const char *name, int exitval)
{
printf(
"Example application using libdigiapix power management support\n"
"\n"
"Usage: %s [options]\n\n"
"-l List available frequencies\n"
"-s <frequency> Set the desired frequency \n"
"-v Show the current governor\n"
"-g List available governors\n"
"-f <governor> Set the desired governor\n"
"-t List the temperatures of the system\n"
"-c <temperature> Set the critical temperature in mºC\n"
"-p <temperature> Set the passive temperature in mºC\n"
"-u Get the CPU usage\n"
"-n Get the number of CPU cores\n"
"-d <core_number> Disable the selected core\n"
"-e <core_number> Enable the selected core\n"
"\n"
"Examples:\n"
"%s -l\n"
"%s -f userspace\n"
"%s -t\n"
"\n", name, name, name, name);
exit(exitval);
}
/*
* list_available_governors() - Print the available governors
*/
static void list_available_governors()
{
int i;
printf("These are the governors available:\n");
for (i = 0; i < MAX_GOVERNORS; i++) {
for (i = 0; i < GOVERNOR_SIZE; i++) {
if (ldx_cpu_is_governor_available(i) == EXIT_SUCCESS)
printf("\t\t\t%s\n", ldx_cpu_get_governor_string_from_type(i));
}
}
/*
* list_temperatures() - Print the available temperatures
*/
static void list_temperatures()
{
printf("Critical temperature %d mºC\n",
ldx_cpu_get_critical_trip_point());
printf("Passive temperature %d mºC\n",
ldx_cpu_get_passive_trip_point());
printf("Current temperature %d mºC\n",
ldx_cpu_get_current_temp());
}
/*
* list_available_frequencies() - Print the available frequencies
*/
static void list_available_frequencies()
{
int i;
available_frequencies_t freq = ldx_cpu_get_available_freq();
printf("These are the available frequencies:\n");
for (i = 0; i < freq.len; i++) {
printf("\t\t\t%d\n", freq.data[i]);
}
ldx_cpu_free_available_freq(freq);
}
int main(int argc, char *argv[])
{
char *name = basename(argv[0]);
const char *governor;
governor_mode_t governor_mode;
int ret = EXIT_FAILURE;
int frequency, temperature, usage, core, opt;
while ((opt = getopt(argc, argv, "s:f:m:c:d:e:p:gtlunvh ")) > 0) {
switch (opt) {
case 'l':
list_available_frequencies();
ret = EXIT_SUCCESS;
break;
case 's':
frequency = strtoul(optarg, NULL, 10);
if (ldx_cpu_set_scaling_freq(frequency) == EXIT_FAILURE) {
printf("Error setting the scaling frequency to: %d\n", frequency);
} else {
ret = EXIT_SUCCESS;
}
break;
case 'g':
list_available_governors();
break;
case 'v':
governor = ldx_cpu_get_governor_string_from_type(ldx_cpu_get_governor());
if (governor != NULL){
printf("This is the current governor: %s\n", governor);
ret = EXIT_SUCCESS;
} else {
printf("Unable to get the current governor");
}
break;
case 'f':
governor_mode = ldx_cpu_get_governor_type_from_string(optarg);
if (governor_mode == GOVERNOR_INVALID) {
printf("Invalid governor: %s", optarg);
} else {
if (ldx_cpu_set_governor(governor_mode) == EXIT_FAILURE) {
printf("Unable to set governor: %s\n", optarg);
} else {
ret = EXIT_SUCCESS;
}
}
break;
case 't':
list_temperatures();
ret = EXIT_SUCCESS;
break;
case 'c':
temperature = strtoul(optarg, NULL, 10);
if (ldx_cpu_set_critical_trip_point(temperature) == EXIT_FAILURE) {
printf("Unable to set the critical trip point temperature: %d\n", temperature);
} else {
ret = EXIT_SUCCESS;
}
break;
case 'p':
temperature = strtoul(optarg, NULL, 10);
if (ldx_cpu_set_passive_trip_point(temperature) == EXIT_FAILURE)
printf("Unable to set the passive trip point temperature: %d\n", temperature);
else
ret = EXIT_SUCCESS;
break;
case 'u':
usage = ldx_cpu_get_usage();
if (usage == -1) {
printf("Error getting the CPU usage\n");
} else {
printf("The usage of the CPU is: %d %%\n", usage);
ret = EXIT_SUCCESS;
}
break;
case 'n':
core = ldx_cpu_get_number_of_cores();
if (core == -1) {
printf("Error getting the number of cores\n");
} else {
printf("The number of CPU cores is: %d\n", core);
ret = EXIT_SUCCESS;
}
break;
case 'd':
core = strtoul(optarg, NULL, 10);
printf("Disabling core: %d\n", core);
if (ldx_cpu_disable_core(core) == EXIT_FAILURE)
printf("Cannot disable the core with index: %d\n", core);
else
ret = EXIT_SUCCESS;
break;
case 'e':
core = strtoul(optarg, NULL, 10);
printf("Enabling core: %d\n", core);
if (ldx_cpu_enable_core(core) == EXIT_FAILURE)
printf("Cannot enable the core with index: %d\n", core);
else
ret = EXIT_SUCCESS;
break;
case 'h':
default:
usage_and_exit(name, EXIT_FAILURE);
}
}
if (ret == EXIT_FAILURE)
usage_and_exit(name, ret);
return ret;
}

View File

@ -0,0 +1,214 @@
/*
* Copyright 2019, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libdigiapix/pwr_management.h>
#define CPU_SAMPLING_TIME 6
#define MAX_SAMPLES 10
/*
* usage_and_exit() - Show usage information and exit with 'exitval' return
* value
*
* @name: Application name.
* @exitval: The exit code.
*/
static void usage_and_exit(const char *name, int exitval)
{
printf(
"Example application using libdigiapix power management support. \n"
"This application enables counter measurements in the CPU and GPU\n"
"in order to reduce the temperature.\n"
"\n"
"Usage: %s [options]\n\n"
"-c Apply CPU counter measurements \n"
"-g Apply GPU counter measurements \n"
"-b Apply CPU & GPU counter measurements \n"
"\n"
"Examples:\n"
"%s -g\n"
"%s -b\n"
"\n", name, name, name);
exit(exitval);
}
/*
* verify_temperature_reduction() - Print the current temperature during
* CPU_SAMPLING_TIME * MAX_SAMPLES seconds
*
* This function prints the temperature each CPU_SAMPLING_TIME seconds.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE if something fails.
*/
static int verify_temperature_reduction()
{
int i, temperature;
printf("Checking if the temperature is being reduced...\n");
for (i = 0; i < MAX_SAMPLES; i++) {
temperature = ldx_cpu_get_current_temp();
if (temperature == -1) {
printf("Error getting the temperature\n");
return EXIT_FAILURE;
}
printf("Current temperature: %d \n", temperature);
sleep(CPU_SAMPLING_TIME);
}
return EXIT_SUCCESS;
}
/*
* apply_countermeasurements() - Apply counter measurements to reduce the temperature
*
* @gpu: 1 to enable the gpu counter measurements.
* @cpu: 1 to enable the cpu counter measurements.
*
* This function reduces the GPU multiplier to half of its value if
* This function reduces the GPU multiplier to half its value if
* the gpu value is enabled.
*
* This function reduces the CPU frequency to the minimum if the cpu value
* is enabled.
*
* Return: EXIT_SUCCESS on success, EXIT_FAILURE if something fails.
*/
static int apply_countermeasurements(int gpu, int cpu)
{
governor_mode_t governor;
int freq;
int ret = EXIT_SUCCESS;
int gpu_multiplier;
if (gpu) {
gpu_multiplier = ldx_gpu_get_multiplier();
if (gpu_multiplier == -1) {
printf("Error getting the gpu multiplier, verify that your platform has a GPU\n");
ret = EXIT_FAILURE;
goto exit;
}
if (ldx_gpu_set_multiplier(gpu_multiplier / 2) == EXIT_FAILURE) {
printf("Error setting the gpu multiplier to %d\n", gpu_multiplier / 2);
goto exit;
}
}
if (cpu) {
governor = ldx_cpu_get_governor();
if (governor == GOVERNOR_INVALID) {
printf("Error getting governor\n");
ret = EXIT_FAILURE;
goto error;
}
/* Only with the 'userspace' governor can we modify and manage the frequency */
if (ldx_cpu_set_governor(ldx_cpu_get_governor_type_from_string("userspace"))) {
printf("Error setting the 'userspace' governor\n");
ret = EXIT_FAILURE;
goto error;
}
freq = ldx_cpu_get_scaling_freq();
if (freq == -1) {
printf("Error getting the current frequency, restoring the previous governor\n");
ret = EXIT_FAILURE;
goto error;
}
if (ldx_cpu_set_scaling_freq(ldx_cpu_get_min_scaling_freq()) == EXIT_FAILURE) {
printf("Error setting the scaling frequency\n");
ret = EXIT_FAILURE;
goto error;
}
}
ret = verify_temperature_reduction();
if (cpu) {
/* Restore the frequency */
if (ldx_cpu_set_scaling_freq(freq)) {
printf("Error restoring the previous frequency\n");
ret = EXIT_FAILURE;
}
}
error:
/* Restore CPU parameters */
if (cpu) {
if (ldx_cpu_set_governor(governor) == EXIT_FAILURE) {
printf("Error restoring the governor\n");
ret = EXIT_FAILURE;
}
}
/* Restore GPU parameters */
if (gpu) {
if (ldx_gpu_set_multiplier(gpu_multiplier)){
printf("Error restoring the gpu multiplier\n");
ret = EXIT_FAILURE;
}
}
exit:
return ret;
}
int main(int argc, char *argv[])
{
char *name = basename(argv[0]);
int opt;
int cpu = 0;
int gpu = 0;
while ((opt = getopt(argc, argv, "gcbh")) > 0) {
switch (opt) {
case 'g':
gpu = 1;
printf("Applying GPU counter measurements\n");
break;
case 'c':
cpu = 1;
printf("Applying CPU counter measurements\n");
break;
case 'b':
gpu = 1;
cpu = 1;
printf("Applying GPU & CPU counter measurements\n");
break;
case 'h':
default:
usage_and_exit(name, EXIT_FAILURE);
}
}
if (cpu == 1 || gpu == 1){
return apply_countermeasurements(gpu, cpu);
}
usage_and_exit(name, EXIT_FAILURE);
}