diff --git a/apix-pm-examples/Makefile b/apix-pm-examples/Makefile new file mode 100644 index 0000000..7026374 --- /dev/null +++ b/apix-pm-examples/Makefile @@ -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) diff --git a/apix-pm-examples/README.md b/apix-pm-examples/README.md new file mode 100644 index 0000000..bf571be --- /dev/null +++ b/apix-pm-examples/README.md @@ -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 Set the desired frequency + -v Show the current governor + -g List available governors + -f Set the desired governor + -t List the temperatures of the system + -c Set the critical temperature + -p Set the passive temperature + -u Get the CPU usage + -n Get the number of CPU cores + -d Disable the selected core + -e 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: +``` +~$ . /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. + diff --git a/apix-pm-examples/apix-cpu-sample.c b/apix-pm-examples/apix-cpu-sample.c new file mode 100644 index 0000000..a332ea9 --- /dev/null +++ b/apix-pm-examples/apix-cpu-sample.c @@ -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 +#include +#include +#include + +#include + +/* + * 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 Set the desired frequency \n" + "-v Show the current governor\n" + "-g List available governors\n" + "-f Set the desired governor\n" + "-t List the temperatures of the system\n" + "-c Set the critical temperature in mºC\n" + "-p Set the passive temperature in mºC\n" + "-u Get the CPU usage\n" + "-n Get the number of CPU cores\n" + "-d Disable the selected core\n" + "-e 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; + + +} diff --git a/apix-pm-examples/apix-pm-sample.c b/apix-pm-examples/apix-pm-sample.c new file mode 100644 index 0000000..6352212 --- /dev/null +++ b/apix-pm-examples/apix-pm-sample.c @@ -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 +#include +#include +#include + +#include + +#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); +}