215 lines
5.3 KiB
C
215 lines
5.3 KiB
C
/*
|
|
* 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);
|
|
}
|