Merge pull request #104 from mdiluz/more-testing

Add more test coverage
This commit is contained in:
Alex Smith 2019-02-21 14:10:44 +00:00 committed by GitHub
commit d582b580b2
7 changed files with 584 additions and 51 deletions

View File

@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define _GNU_SOURCE
#include "external-helper.h"
#include "logging.h"
#include <linux/limits.h>
@ -45,8 +46,6 @@ int run_external_process(const char *const *exec_args)
{
pid_t p;
int status = 0;
int ret = 0;
int r = -1;
if ((p = fork()) < 0) {
LOG_ERROR("Failed to fork(): %s\n", strerror(errno));
@ -59,23 +58,74 @@ int run_external_process(const char *const *exec_args)
* bindings that these objects are completely constant.
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
*/
if ((r = execv(exec_args[0], (char *const *)exec_args)) != 0) {
if (execv(exec_args[0], (char *const *)exec_args) != 0) {
LOG_ERROR("Failed to execute external process: %s %s\n", exec_args[0], strerror(errno));
exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
} else {
if (waitpid(p, &status, 0) < 0) {
LOG_ERROR("Failed to waitpid(%d): %s\n", (int)p, strerror(errno));
return -1;
}
/* i.e. sigsev */
if (!WIFEXITED(status)) {
LOG_ERROR("Child process '%s' exited abnormally\n", exec_args[0]);
}
}
if ((ret = WEXITSTATUS(status)) != 0) {
if (waitpid(p, &status, 0) < 0) {
LOG_ERROR("Failed to waitpid(%d): %s\n", (int)p, strerror(errno));
return -1;
}
/* i.e. sigsev */
if (!WIFEXITED(status)) {
LOG_ERROR("Child process '%s' exited abnormally\n", exec_args[0]);
} else if (WEXITSTATUS(status) != 0) {
LOG_ERROR("External process failed\n");
return -1;
}
return 0;
}
/**
* Call an external process and get output
*/
int run_external_process_get_output(const char *const *exec_args, char buffer[EXTERNAL_BUFFER_MAX])
{
pid_t p;
int status = 0;
int pipes[2];
if (pipe(pipes) == -1) {
LOG_ERROR("Could not create pipe: %s!\n", strerror(errno));
return -1;
}
if ((p = fork()) < 0) {
LOG_ERROR("Failed to fork(): %s\n", strerror(errno));
return false;
} else if (p == 0) {
/* Send STDOUT to the pipe */
dup2(pipes[1], STDOUT_FILENO);
close(pipes[0]);
close(pipes[1]);
/* Launch the process */
if (execv(exec_args[0], (char *const *)exec_args) != 0) {
LOG_ERROR("Failed to execute external process %s: %s\n", exec_args[0], strerror(errno));
exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
close(pipes[1]);
if (read(pipes[0], buffer, EXTERNAL_BUFFER_MAX) < 0) {
LOG_ERROR("Failed to read from process %s: %s\n", exec_args[0], strerror(errno));
return -1;
}
if (waitpid(p, &status, 0) < 0) {
LOG_ERROR("Failed to waitpid(%d): %s\n", (int)p, strerror(errno));
return -1;
}
/* i.e. sigsev */
if (!WIFEXITED(status)) {
LOG_ERROR("Child process '%s' exited abnormally\n", exec_args[0]);
} else if (WEXITSTATUS(status) != 0) {
LOG_ERROR("External process failed\n");
return -1;
}

View File

@ -31,5 +31,10 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma once
#define EXTERNAL_BUFFER_MAX 1024
/* Run an external process and capture the return value */
int run_external_process(const char *const *exec_args);
/* Run an external process and capture the return value as well as output */
int run_external_process_get_output(const char *const *exec_args, char buffer[EXTERNAL_BUFFER_MAX]);

View File

@ -220,3 +220,46 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply)
return 0;
}
int game_mode_get_gpu(GameModeGPUInfo *info)
{
if (!info)
return 0;
/* Generate the input strings */
char vendor[7];
snprintf(vendor, 7, "0x%04x", (short)info->vendor);
char device[4];
snprintf(device, 4, "%ld", info->device);
char nv_perf_level[4];
snprintf(nv_perf_level, 4, "%ld", info->nv_perf_level);
// Set up our command line to pass to gpuclockctl
// This doesn't need pkexec as get does not need elevated perms
const char *const exec_args[] = {
LIBEXECDIR "/gpuclockctl",
vendor,
device,
"get",
info->vendor == Vendor_NVIDIA ? nv_perf_level : NULL, /* Only use this if Nvidia */
NULL,
};
char buffer[EXTERNAL_BUFFER_MAX] = { 0 };
if (run_external_process_get_output(exec_args, buffer) != 0) {
LOG_ERROR("Failed to call gpuclockctl, could get values!\n");
return -1;
}
int core = 0;
int mem = 0;
if (sscanf(buffer, "%i %i", &core, &mem) != 2) {
LOG_ERROR("Failed to parse gpuclockctl output: %s\n", buffer);
return -1;
}
info->core = core;
info->mem = mem;
return 0;
}

View File

@ -40,7 +40,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/wait.h>
#include <unistd.h>
#include "daemon_config.h"
#include "gamemode_client.h"
#include "governors-query.h"
#include "gpu-control.h"
/* Initial verify step to ensure gamemode isn't already active */
static int verify_gamemode_initial(void)
@ -122,7 +125,7 @@ static int verify_other_client_connected(void)
*/
static int run_basic_client_tests(void)
{
LOG_MSG(" *basic client tests*\n");
LOG_MSG(":: Basic client tests\n");
/* First verify that gamemode is not currently active on the system
* As well as it being currently installed and queryable
@ -150,7 +153,7 @@ static int run_basic_client_tests(void)
if (verify_deactivated() != 0)
return -1;
LOG_MSG(" *passed*\n");
LOG_MSG(":: Passed\n\n");
return 0;
}
@ -163,7 +166,7 @@ static int run_dual_client_tests(void)
int status = 0;
/* Try running some process interop tests */
LOG_MSG(" *dual clients tests*\n");
LOG_MSG(":: Dual client tests\n");
/* Get the current path to this binary */
char mypath[PATH_MAX];
@ -220,13 +223,13 @@ static int run_dual_client_tests(void)
}
/* Give the child a chance to finish */
usleep(10000);
usleep(100000);
// Wait for the child to finish up
int wstatus;
while (waitpid(child, &wstatus, WNOHANG) == 0) {
LOG_MSG(" Waiting for child to quit...\n");
usleep(10000);
LOG_MSG("...Waiting for child to quit...\n");
usleep(100000);
}
/* Verify that gamemode is now innactive */
@ -234,7 +237,341 @@ static int run_dual_client_tests(void)
return -1;
if (status == 0)
LOG_MSG(" *passed*\n");
LOG_MSG(":: Passed\n\n");
return status;
}
/* Check gamemoderun works */
static int run_gamemoderun_and_reaper_tests(struct GameModeConfig *config)
{
int status = 0;
LOG_MSG(":: Gamemoderun and reaper thread tests\n");
/* Fork so that the child can request gamemode */
int child = fork();
if (child == 0) {
/* Close stdout, we don't care if sh prints anything */
fclose(stdout);
/* Preload into sh and then kill it */
if (execl("/usr/bin/gamemoderun", "/usr/bin/gamemoderun", "sh", (char *)NULL) == -1) {
LOG_ERROR("failed to launch gamemoderun with execl: %s\n", strerror(errno));
return -1;
}
}
/* Give the child a chance to reqeust gamemode */
usleep(10000);
/* Check that when we request gamemode, it replies that the other client is connected */
if (verify_other_client_connected() != 0)
status = -1;
/* Send SIGTERM to the child to stop it*/
if (kill(child, SIGTERM) == -1) {
LOG_ERROR("failed to send continue signal to other client: %s\n", strerror(errno));
status = -1;
}
/* Wait for the child to clean up */
int wstatus;
while (waitpid(child, &wstatus, WNOHANG) == 0) {
LOG_MSG("...Waiting for child to quit...\n");
usleep(100000);
}
/* And give gamemode a chance to reap the process */
long freq = config_get_reaper_frequency(config);
LOG_MSG("...Waiting for reaper thread (reaper_frequency set to %ld seconds)...\n", freq);
sleep((unsigned int)freq);
/* Verify that gamemode is now innactive */
if (verify_deactivated() != 0)
return -1;
if (status == 0)
LOG_MSG(":: Passed\n\n");
return status;
}
/* Check the cpu governor setting works */
static int run_cpu_governor_tests(struct GameModeConfig *config)
{
/* get the two config parameters we care about */
char desiredgov[CONFIG_VALUE_MAX] = { 0 };
config_get_desired_governor(config, desiredgov);
if (desiredgov[0] == '\0')
strcpy(desiredgov, "performance");
char defaultgov[CONFIG_VALUE_MAX] = { 0 };
config_get_default_governor(config, defaultgov);
if (desiredgov[0] == '\0') {
const char *currentgov = get_gov_state();
if (currentgov) {
strncpy(desiredgov, currentgov, CONFIG_VALUE_MAX);
} else {
LOG_ERROR(
"Could not get current CPU governor state, this indicates an error! See rest "
"of log.\n");
return -1;
}
}
/* Start gamemode */
gamemode_request_start();
/* Verify the governor is the desired one */
const char *currentgov = get_gov_state();
if (strncmp(currentgov, desiredgov, CONFIG_VALUE_MAX) != 0) {
LOG_ERROR("Govenor was not set to %s (was actually %s)!", desiredgov, currentgov);
gamemode_request_end();
return -1;
}
/* End gamemode */
gamemode_request_end();
/* Verify the governor has been set back */
currentgov = get_gov_state();
if (strncmp(currentgov, defaultgov, CONFIG_VALUE_MAX) != 0) {
LOG_ERROR("Govenor was not set back to %s (was actually %s)!", defaultgov, currentgov);
return -1;
}
return 0;
}
static int run_custom_scripts_tests(struct GameModeConfig *config)
{
int scriptstatus = 0;
/* Grab and test the start scripts */
char startscripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
memset(startscripts, 0, sizeof(startscripts));
config_get_gamemode_start_scripts(config, startscripts);
if (startscripts[0][0] != '\0') {
int i = 0;
while (*startscripts[i] != '\0' && i < CONFIG_LIST_MAX) {
LOG_MSG(":::: Running start script [%s]\n", startscripts[i]);
int ret = system(startscripts[i]);
if (ret == 0)
LOG_MSG(":::: Passed\n");
else {
LOG_MSG(":::: Failed!\n");
scriptstatus = -1;
}
i++;
}
}
/* Grab and test the end scripts */
char endscripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
memset(endscripts, 0, sizeof(endscripts));
config_get_gamemode_end_scripts(config, endscripts);
if (endscripts[0][0] != '\0') {
int i = 0;
while (*endscripts[i] != '\0' && i < CONFIG_LIST_MAX) {
LOG_MSG(":::: Running end script [%s]\n", endscripts[i]);
int ret = system(endscripts[i]);
if (ret == 0)
LOG_MSG(":::: Passed\n");
else {
LOG_MSG(":::: Failed!\n");
scriptstatus = -1;
}
i++;
}
}
/* Specal value for no scripts */
if (endscripts[0][0] == '\0' && startscripts[0][0] == '\0')
return 1;
return scriptstatus;
}
int run_gpu_optimisation_tests(struct GameModeConfig *config)
{
int gpustatus = 0;
/* First check if these are turned on */
char apply[CONFIG_VALUE_MAX];
config_get_apply_gpu_optimisations(config, apply);
if (strlen(apply) == 0) {
/* Special value for disabled */
return 1;
} else if (strncmp(apply, "accept-responsibility", CONFIG_VALUE_MAX) != 0) {
LOG_ERROR(
"apply_gpu_optimisations set to value other than \"accept-responsibility\" (%s), will "
"not apply GPU optimisations!\n",
apply);
return -1;
}
/* Get current GPU values */
GameModeGPUInfo gpuinfo;
gpuinfo.device = config_get_gpu_device(config);
gpuinfo.vendor = config_get_gpu_vendor(config);
if (gpuinfo.vendor == Vendor_NVIDIA)
gpuinfo.nv_perf_level = config_get_nv_perf_level(config);
if (game_mode_get_gpu(&gpuinfo) != 0) {
LOG_ERROR("Could not get current GPU info, see above!\n");
return -1;
}
/* Store the original values */
long original_core = gpuinfo.core;
long original_mem = gpuinfo.mem;
/* Grab the expected values */
long expected_core = 0;
long expected_mem = 0;
switch (gpuinfo.vendor) {
case Vendor_NVIDIA:
expected_core = config_get_nv_core_clock_mhz_offset(config);
expected_mem = config_get_nv_mem_clock_mhz_offset(config);
break;
case Vendor_AMD:
expected_core = config_get_amd_core_clock_percentage(config);
expected_mem = config_get_amd_mem_clock_percentage(config);
break;
default:
LOG_ERROR("Configured for unsupported GPU vendor 0x%04x!\n", (unsigned int)gpuinfo.vendor);
return -1;
}
LOG_MSG("Configured with vendor:0x%04x device:%ld core:%ld mem:%ld (nv_perf_level:%ld)\n",
(unsigned int)gpuinfo.vendor,
gpuinfo.device,
expected_core,
expected_mem,
gpuinfo.nv_perf_level);
/* Start gamemode and check the new values */
gamemode_request_start();
if (game_mode_get_gpu(&gpuinfo) != 0) {
LOG_ERROR("Could not get current GPU info, see above!\n");
gamemode_request_end();
return -1;
}
if (gpuinfo.core != expected_core || gpuinfo.mem != expected_mem) {
LOG_ERROR(
"Current GPU clocks during gamemode do not match requested values!\n"
"\tcore - expected:%ld was:%ld | mem - expected:%ld was:%ld\n",
expected_core,
gpuinfo.core,
expected_mem,
gpuinfo.mem);
gpustatus = -1;
}
/* End gamemode and check the values have returned */
gamemode_request_end();
if (game_mode_get_gpu(&gpuinfo) != 0) {
LOG_ERROR("Could not get current GPU info, see above!\n");
return -1;
}
if (gpuinfo.core != original_core || gpuinfo.mem != original_mem) {
LOG_ERROR(
"Current GPU clocks after gamemode do not matcch original values!\n"
"\tcore - original:%ld was:%ld | mem - original:%ld was:%ld\n",
original_core,
gpuinfo.core,
original_mem,
gpuinfo.mem);
gpustatus = -1;
}
return gpustatus;
}
/**
* game_mode_run_feature_tests runs a set of tests for each current feature (based on the current
* config) returns 0 for success, -1 for failure
*/
static int game_mode_run_feature_tests(struct GameModeConfig *config)
{
int status = 0;
LOG_MSG(":: Feature tests\n");
/* If we reach here, we should assume the basic requests and register functions are working */
/* Does the CPU governor get set properly? */
{
LOG_MSG("::: Verifying CPU governor setting\n");
int cpustatus = run_cpu_governor_tests(config);
if (cpustatus == 0)
LOG_MSG("::: Passed\n");
else {
LOG_MSG("::: Failed!\n");
// Consider the CPU governor feature required
status = 1;
}
}
/* Do custom scripts run? */
{
LOG_MSG("::: Verifying Scripts\n");
int scriptstatus = run_custom_scripts_tests(config);
if (scriptstatus == 1)
LOG_MSG("::: Passed (no scripts configured to run)\n");
else if (scriptstatus == 0)
LOG_MSG("::: Passed\n");
else {
LOG_MSG("::: Failed!\n");
// Any custom scripts should be expected to work
status = 1;
}
}
/* Do GPU optimisations get applied? */
{
LOG_MSG("::: Verifying GPU Optimisations\n");
int gpustatus = run_gpu_optimisation_tests(config);
if (gpustatus == 1)
LOG_MSG("::: Passed (gpu optimisations not configured to run)\n");
else if (gpustatus == 0)
LOG_MSG("::: Passed\n");
else {
LOG_MSG("::: Failed!\n");
// Any custom scripts should be expected to work
status = 1;
}
}
/* Does the screensaver get inhibited? */
/* TODO: Unknown if this is testable, org.freedesktop.ScreenSaver has no query method */
/* Was the process reniced? */
/* Was the scheduling applied? */
/* Were io priorities changed? */
/* Note: These don't get cleared up on un-register, so will have already been applied */
/* TODO */
if (status != -1)
LOG_MSG(":: Passed%s\n\n", status > 0 ? " (with optional failures)" : "");
else
LOG_ERROR(":: Failed!\n");
return status;
}
@ -248,15 +585,39 @@ static int run_dual_client_tests(void)
int game_mode_run_client_tests()
{
int status = 0;
LOG_MSG("Running tests...\n");
LOG_MSG(": Loading config\n");
/* Grab the config */
/* Note: this config may pick up a local gamemode.ini, or the daemon may have one, we may need
* to cope with that */
GameModeConfig *config = config_create();
config_init(config);
LOG_MSG(": Running tests\n\n");
/* Run the basic tests */
if (run_basic_client_tests() != 0)
return -1;
status = -1;
/* Run the dual client tests */
if (run_dual_client_tests() != 0)
return -1;
status = -1;
/* Check gamemoderun and the reaper thread work */
if (run_gamemoderun_and_reaper_tests(config) != 0)
status = -1;
if (status != 0) {
LOG_MSG(": Client tests failed, skipping feature tests\n");
} else {
/* Run the feature tests */
status = game_mode_run_feature_tests(config);
}
if (status >= 0)
LOG_MSG(": All Tests Passed%s!\n", status > 0 ? " (with optional failures)" : "");
else
LOG_MSG(": Tests Failed!\n");
return status;
}

View File

@ -144,3 +144,4 @@ typedef struct GameModeGPUInfo GameModeGPUInfo;
int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info);
void game_mode_free_gpu(GameModeGPUInfo **info);
int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply);
int game_mode_get_gpu(GameModeGPUInfo *info);

View File

@ -36,6 +36,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include "external-helper.h"
#include "gpu-control.h"
/* NV constants */
#define NV_CORE_OFFSET_ATTRIBUTE "GPUGraphicsClockOffset"
#define NV_MEM_OFFSET_ATTRIBUTE "GPUMemoryTransferRateOffset"
#define NV_ATTRIBUTE_FORMAT "[gpu:%ld]/%s[%ld]"
/* AMD constants */
#define AMD_DRM_PATH "/sys/class/drm/card%ld/device/%s"
/* Plausible extras to add:
* Intel support - https://blog.ffwll.ch/2013/03/overclocking-your-intel-gpu-on-linux.html
* AMD - Allow setting fan speed as well
@ -51,32 +59,89 @@ static void print_usage_and_exit(void)
exit(EXIT_FAILURE);
}
static int get_gpu_state_nv(struct GameModeGPUInfo *info)
{
if (info->vendor != Vendor_NVIDIA)
return -1;
if (!getenv("DISPLAY"))
LOG_ERROR("Getting Nvidia parameters requires DISPLAY to be set - will likely fail!\n");
char arg[128] = { 0 };
char buf[EXTERNAL_BUFFER_MAX] = { 0 };
char *end;
/* Set the GPUGraphicsClockOffset parameter */
snprintf(arg,
128,
NV_ATTRIBUTE_FORMAT,
info->device,
NV_CORE_OFFSET_ATTRIBUTE,
info->nv_perf_level);
const char *exec_args_core[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL };
if (run_external_process_get_output(exec_args_core, buf) != 0) {
LOG_ERROR("Failed to set %s!\n", arg);
return -1;
}
info->core = strtol(buf, &end, 10);
if (end == buf) {
LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf);
return -1;
}
/* Set the GPUMemoryTransferRateOffset parameter */
snprintf(arg,
128,
NV_ATTRIBUTE_FORMAT,
info->device,
NV_MEM_OFFSET_ATTRIBUTE,
info->nv_perf_level);
const char *exec_args_mem[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL };
if (run_external_process_get_output(exec_args_mem, buf) != 0) {
LOG_ERROR("Failed to set %s!\n", arg);
return -1;
}
info->mem = strtol(buf, &end, 10);
if (end == buf) {
LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf);
return -1;
}
return 0;
}
/**
* Get the gpu state
* Populates the struct with the GPU info on the system
*/
int get_gpu_state(struct GameModeGPUInfo *info)
static int get_gpu_state_amd(struct GameModeGPUInfo *info)
{
fprintf(stderr, "Fetching GPU state is currently unimplemented!\n");
fprintf(stderr, "Fetching GPU state on AMD is currently unimplemented!\n");
return info != NULL;
}
/**
* Set the gpu state based on input parameters on Nvidia
*/
int set_gpu_state_nv(struct GameModeGPUInfo *info)
static int set_gpu_state_nv(struct GameModeGPUInfo *info)
{
if (info->vendor != Vendor_NVIDIA)
return -1;
// These commands don't technically even need root
if (!getenv("DISPLAY") || !getenv("XAUTHORITY"))
LOG_ERROR(
"Setting Nvidia parameters requires DISPLAY and XAUTHORITY to be set - will likely "
"fail!\n");
/* Set the GPUGraphicsClockOffset parameter */
char core_arg[128];
snprintf(core_arg,
128,
"[gpu:%ld]/GPUGraphicsClockOffset[%ld]=%ld",
NV_ATTRIBUTE_FORMAT "=%ld",
info->device,
NV_CORE_OFFSET_ATTRIBUTE,
info->nv_perf_level,
info->core);
const char *exec_args_core[] = { "/usr/bin/nvidia-settings", "-a", core_arg, NULL };
@ -89,8 +154,9 @@ int set_gpu_state_nv(struct GameModeGPUInfo *info)
char mem_arg[128];
snprintf(mem_arg,
128,
"[gpu:%ld]/GPUMemoryTransferRateOffset[%ld]=%ld",
NV_ATTRIBUTE_FORMAT "=%ld",
info->device,
NV_MEM_OFFSET_ATTRIBUTE,
info->nv_perf_level,
info->mem);
const char *exec_args_mem[] = { "/usr/bin/nvidia-settings", "-a", mem_arg, NULL };
@ -110,9 +176,8 @@ int set_gpu_state_nv(struct GameModeGPUInfo *info)
*/
static int set_gpu_state_amd_file(const char *filename, long device, long value)
{
const char *drm_path = "/sys/class/drm/card%ld/device/%s";
char path[64];
snprintf(path, 64, drm_path, device, filename);
snprintf(path, 64, AMD_DRM_PATH, device, filename);
FILE *file = fopen(path, "w");
if (!file) {
@ -136,11 +201,17 @@ static int set_gpu_state_amd_file(const char *filename, long device, long value)
/**
* Set the gpu state based on input parameters on amd
*/
int set_gpu_state_amd(struct GameModeGPUInfo *info)
static int set_gpu_state_amd(struct GameModeGPUInfo *info)
{
if (info->vendor != Vendor_AMD)
return -1;
/* Must be root to set the state */
if (geteuid() != 0) {
fprintf(stderr, "gpuclockctl must be run as root to set AMD values\n");
print_usage_and_exit();
}
// Set the the core and mem clock speeds using the OverDrive files
if (set_gpu_state_amd_file("pp_sclk_od", info->device, info->core) != 0)
return -1;
@ -191,24 +262,34 @@ static long get_generic_value(const char *val)
*/
int main(int argc, char *argv[])
{
if (argc == 4 && strncmp(argv[3], "get", 3) == 0) {
if (argc >= 4 && strncmp(argv[3], "get", 3) == 0) {
/* Get and verify the vendor and device */
struct GameModeGPUInfo info;
memset(&info, 0, sizeof(info));
info.vendor = get_vendor(argv[1]);
info.device = get_device(argv[2]);
if (info.vendor == Vendor_NVIDIA && argc > 4)
info.nv_perf_level = get_generic_value(argv[4]);
/* Fetch the state and print it out */
get_gpu_state(&info);
switch (info.vendor) {
case Vendor_NVIDIA:
/* Get nvidia power level */
if (get_gpu_state_nv(&info) != 0)
exit(EXIT_FAILURE);
break;
case Vendor_AMD:
if (get_gpu_state_amd(&info) != 0)
exit(EXIT_FAILURE);
break;
default:
printf("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", (short)info.vendor);
break;
}
printf("%ld %ld\n", info.core, info.mem);
} else if (argc >= 6 && argc <= 7 && strncmp(argv[3], "set", 3) == 0) {
/* Must be root to set the state */
if (geteuid() != 0) {
fprintf(stderr, "gpuclockctl must be run as root to set values\n");
print_usage_and_exit();
}
/* Get and verify the vendor and device */
struct GameModeGPUInfo info;
memset(&info, 0, sizeof(info));
@ -217,7 +298,7 @@ int main(int argc, char *argv[])
info.core = get_generic_value(argv[4]);
info.mem = get_generic_value(argv[5]);
if (info.vendor == Vendor_NVIDIA)
if (info.vendor == Vendor_NVIDIA && argc > 6)
info.nv_perf_level = get_generic_value(argv[6]);
printf("gpuclockctl setting core:%ld mem:%ld on device:%ld with vendor 0x%04x\n",

View File

@ -155,16 +155,8 @@ int main(int argc, char *argv[])
exit(EXIT_SUCCESS);
break;
case 't':
if ((status = game_mode_run_client_tests()) == 0) {
LOG_MSG("gamemode tests succeeded\n");
exit(EXIT_SUCCESS);
} else if (status == -1) {
LOG_ERROR("gamemode tests failed\n");
exit(EXIT_FAILURE);
} else {
LOG_ERROR("gamemode test results unknown: %d\n", status);
exit(EXIT_FAILURE);
}
status = game_mode_run_client_tests();
exit(status);
break;
case 'v':
LOG_MSG(VERSION_TEXT);