diff --git a/daemon/daemon_config.c b/daemon/daemon_config.c index df24016..69eed10 100644 --- a/daemon/daemon_config.c +++ b/daemon/daemon_config.c @@ -91,7 +91,6 @@ struct GameModeConfig { long gpu_device; long nv_core_clock_mhz_offset; long nv_mem_clock_mhz_offset; - long nv_perf_level; long nv_powermizer_mode; char amd_performance_level[CONFIG_VALUE_MAX]; @@ -257,8 +256,6 @@ static int inih_handler(void *user, const char *section, const char *name, const valid = get_long_value(name, value, &self->values.nv_core_clock_mhz_offset); } else if (strcmp(name, "nv_mem_clock_mhz_offset") == 0) { valid = get_long_value(name, value, &self->values.nv_mem_clock_mhz_offset); - } else if (strcmp(name, "nv_perf_level") == 0) { - valid = get_long_value(name, value, &self->values.nv_perf_level); } else if (strcmp(name, "nv_powermizer_mode") == 0) { valid = get_long_value(name, value, &self->values.nv_powermizer_mode); } else if (strcmp(name, "amd_performance_level") == 0) { @@ -332,8 +329,9 @@ static void load_config_files(GameModeConfig *self) self->values.renice = 4; /* default value of 4 */ self->values.reaper_frequency = DEFAULT_REAPER_FREQ; self->values.gpu_device = -1; /* 0 is a valid device ID so use -1 to indicate no value */ - self->values.nv_perf_level = -1; self->values.nv_powermizer_mode = -1; + self->values.nv_core_clock_mhz_offset = -1; + self->values.nv_mem_clock_mhz_offset = -1; self->values.script_timeout = 10; /* Default to 10 seconds for scripts */ /* @@ -585,7 +583,6 @@ void config_get_apply_gpu_optimisations(GameModeConfig *self, char value[CONFIG_ DEFINE_CONFIG_GET(gpu_device) DEFINE_CONFIG_GET(nv_core_clock_mhz_offset) DEFINE_CONFIG_GET(nv_mem_clock_mhz_offset) -DEFINE_CONFIG_GET(nv_perf_level) DEFINE_CONFIG_GET(nv_powermizer_mode) void config_get_amd_performance_level(GameModeConfig *self, char value[CONFIG_VALUE_MAX]) diff --git a/daemon/daemon_config.h b/daemon/daemon_config.h index d6795f5..538ef10 100644 --- a/daemon/daemon_config.h +++ b/daemon/daemon_config.h @@ -142,7 +142,6 @@ void config_get_apply_gpu_optimisations(GameModeConfig *self, char value[CONFIG_ long config_get_gpu_device(GameModeConfig *self); long config_get_nv_core_clock_mhz_offset(GameModeConfig *self); long config_get_nv_mem_clock_mhz_offset(GameModeConfig *self); -long config_get_nv_perf_level(GameModeConfig *self); long config_get_nv_powermizer_mode(GameModeConfig *self); void config_get_amd_performance_level(GameModeConfig *self, char value[CONFIG_VALUE_MAX]); diff --git a/daemon/gamemode-gpu.c b/daemon/gamemode-gpu.c index f63767c..c7ae96c 100644 --- a/daemon/gamemode-gpu.c +++ b/daemon/gamemode-gpu.c @@ -47,8 +47,6 @@ POSSIBILITY OF SUCH DAMAGE. */ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) { - int status = 0; - /* Verify input, this is programmer error */ if (!info || *info) FATAL_ERROR("Invalid GameModeGPUInfo passed to %s", __func__); @@ -83,33 +81,9 @@ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) } /* Fill in GPU vendor */ - char path[64] = { 0 }; - if (snprintf(path, 64, "/sys/class/drm/card%ld/device/vendor", new_info->device) < 0) { - LOG_ERROR("snprintf failed, will not apply gpu optimisations!\n"); - return -1; - } - FILE *vendor = fopen(path, "r"); - if (!vendor) { - LOG_ERROR("Couldn't open vendor file at %s, will not apply gpu optimisations!\n", path); - return -1; - } - char buff[64]; - if (fgets(buff, 64, vendor) != NULL) { - new_info->vendor = strtol(buff, NULL, 0); - } else { - LOG_ERROR("Coudn't read contents of file %s, will not apply optimisations!\n", path); - return -1; - } - - /* verify GPU vendor */ + new_info->vendor = gamemode_get_gpu_vendor(new_info->device); if (!GPUVendorValid(new_info->vendor)) { - LOG_ERROR("Unknown vendor value (0x%04x) found, cannot apply optimisations!\n", - (unsigned int)new_info->vendor); - LOG_ERROR("Known values are: 0x%04x (NVIDIA) 0x%04x (AMD) 0x%04x (Intel)\n", - Vendor_NVIDIA, - Vendor_AMD, - Vendor_Intel); - free(new_info); + LOG_ERROR("Found invalid vendor, will not apply optimisations!\n"); return -1; } @@ -118,7 +92,6 @@ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) case Vendor_NVIDIA: new_info->nv_core = config_get_nv_core_clock_mhz_offset(config); new_info->nv_mem = config_get_nv_mem_clock_mhz_offset(config); - new_info->nv_perf_level = config_get_nv_perf_level(config); new_info->nv_powermizer_mode = config_get_nv_powermizer_mode(config); /* Reject values over some guessed values @@ -139,18 +112,6 @@ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) return -1; } - /* Sanity check the performance level value as well */ - /* Allow an invalid perf level if we've got the powermizer mode set */ - if (!(new_info->nv_perf_level == -1 && new_info->nv_powermizer_mode != -1) && - (new_info->nv_perf_level < 0 || new_info->nv_perf_level > 16)) { - LOG_ERROR( - "NVIDIA Performance level value likely invalid (%ld), will not apply " - "optimisations!\n", - new_info->nv_perf_level); - free(new_info); - return -1; - } - break; case Vendor_AMD: config_get_amd_performance_level(config, new_info->amd_performance_level); @@ -168,7 +129,7 @@ int game_mode_initialise_gpu(GameModeConfig *config, GameModeGPUInfo **info) /* Give back the new gpu info */ *info = new_info; - return status; + return 0; } /* Simply used to free the GPU info object */ @@ -196,8 +157,6 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info) LOG_MSG("Requesting GPU optimisations on device:%ld\n", info->device); /* Generate the input strings */ - char vendor[7]; - snprintf(vendor, 7, "0x%04x", (short)info->vendor); char device[4]; snprintf(device, 4, "%ld", info->device); @@ -205,8 +164,6 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info) snprintf(nv_core, 8, "%ld", info->nv_core); char nv_mem[8]; snprintf(nv_mem, 8, "%ld", info->nv_mem); - char nv_perf_level[4]; - snprintf(nv_perf_level, 4, "%ld", info->nv_perf_level); char nv_powermizer_mode[4]; snprintf(nv_powermizer_mode, 4, "%ld", info->nv_powermizer_mode); @@ -214,12 +171,10 @@ int game_mode_apply_gpu(const GameModeGPUInfo *info) const char *const exec_args[] = { "/usr/bin/pkexec", LIBEXECDIR "/gpuclockctl", - vendor, device, "set", info->vendor == Vendor_NVIDIA ? nv_core : info->amd_performance_level, info->vendor == Vendor_NVIDIA ? nv_mem : NULL, /* Only use this if Nvidia */ - info->vendor == Vendor_NVIDIA ? nv_perf_level : NULL, /* Only use this if Nvidia */ info->vendor == Vendor_NVIDIA ? nv_powermizer_mode : NULL, /* Only use this if Nvidia */ NULL, }; @@ -238,21 +193,15 @@ int game_mode_get_gpu(GameModeGPUInfo *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, }; diff --git a/daemon/gamemode-tests.c b/daemon/gamemode-tests.c index 57b1746..540311d 100644 --- a/daemon/gamemode-tests.c +++ b/daemon/gamemode-tests.c @@ -456,9 +456,13 @@ int run_gpu_optimisation_tests(struct GameModeConfig *config) char original_amd_performance_level[CONFIG_VALUE_MAX]; strncpy(original_amd_performance_level, gpuinfo->amd_performance_level, CONFIG_VALUE_MAX); - /* account for when powermizer is not set */ + /* account for when settings are not set */ if (expected_nv_powermizer_mode == -1) expected_nv_powermizer_mode = original_nv_powermizer_mode; + if (expected_core == -1) + expected_core = original_nv_core; + if (expected_mem == -1) + expected_mem = original_nv_mem; /* Start gamemode and check the new values */ gamemode_request_start(); diff --git a/daemon/gpu-control.c b/daemon/gpu-control.c new file mode 100644 index 0000000..e665d49 --- /dev/null +++ b/daemon/gpu-control.c @@ -0,0 +1,72 @@ +/* + +Copyright (c) 2017-2018, Feral Interactive +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Feral Interactive nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + */ +#include "gpu-control.h" +#include "logging.h" + +#include + +/* Get the vendor for a device */ +enum GPUVendor gamemode_get_gpu_vendor(long device) +{ + enum GPUVendor vendor = Vendor_Invalid; + + /* Fill in GPU vendor */ + char path[64] = { 0 }; + if (snprintf(path, 64, "/sys/class/drm/card%ld/device/vendor", device) < 0) { + LOG_ERROR("snprintf failed, will not apply gpu optimisations!\n"); + return Vendor_Invalid; + } + FILE *file = fopen(path, "r"); + if (!file) { + LOG_ERROR("Couldn't open vendor file at %s, will not apply gpu optimisations!\n", path); + return Vendor_Invalid; + } + char buff[64]; + if (fgets(buff, 64, file) != NULL) { + vendor = strtol(buff, NULL, 0); + } else { + LOG_ERROR("Coudn't read contents of file %s, will not apply optimisations!\n", path); + return Vendor_Invalid; + } + + /* verify GPU vendor */ + if (!GPUVendorValid(vendor)) { + LOG_ERROR("Unknown vendor value (0x%04x) found, cannot apply optimisations!\n", + (unsigned int)vendor); + LOG_ERROR("Known values are: 0x%04x (NVIDIA) 0x%04x (AMD) 0x%04x (Intel)\n", + Vendor_NVIDIA, + Vendor_AMD, + Vendor_Intel); + return Vendor_Invalid; + } + + return vendor; +} diff --git a/daemon/gpu-control.h b/daemon/gpu-control.h index 325605f..fd9ec21 100644 --- a/daemon/gpu-control.h +++ b/daemon/gpu-control.h @@ -46,8 +46,7 @@ enum GPUVendor { /* Storage for GPU info*/ struct GameModeGPUInfo { long vendor; - long device; /* path to device, ie. /sys/class/drm/card#/ */ - long nv_perf_level; /* The Nvidia Performance Level to adjust */ + long device; /* path to device, ie. /sys/class/drm/card#/ */ long nv_core; /* Nvidia core clock */ long nv_mem; /* Nvidia mem clock */ @@ -55,3 +54,6 @@ struct GameModeGPUInfo { char amd_performance_level[CONFIG_VALUE_MAX]; /* The AMD performance level set to */ }; + +/* Get the vendor for a device */ +enum GPUVendor gamemode_get_gpu_vendor(long device); diff --git a/daemon/gpuclockctl.c b/daemon/gpuclockctl.c index 21f6ad2..832b04e 100644 --- a/daemon/gpuclockctl.c +++ b/daemon/gpuclockctl.c @@ -40,6 +40,8 @@ POSSIBILITY OF SUCH DAMAGE. #define NV_CORE_OFFSET_ATTRIBUTE "GPUGraphicsClockOffset" #define NV_MEM_OFFSET_ATTRIBUTE "GPUMemoryTransferRateOffset" #define NV_POWERMIZER_MODE_ATTRIBUTE "GPUPowerMizerMode" +#define NV_PERFMODES_ATTRIBUTE "GPUPerfModes" +#define NV_PCIDEVICE_ATTRIBUTE "PCIDevice" #define NV_ATTRIBUTE_FORMAT "[gpu:%ld]/%s" #define NV_PERF_LEVEL_FORMAT "[%ld]" @@ -54,14 +56,59 @@ POSSIBILITY OF SUCH DAMAGE. /* Helper to quit with usage */ static const char *usage_text = - "usage: gpuclockctl PCI_ID DEVICE [get] [set CORE MEM [PERF_LEVEL]]]"; + "usage: gpuclockctl DEVICE {arg}\n\t\tget - return current values\n\t\tset [NV_CORE NV_MEM " + "NV_POWERMIZER_MODE | AMD_PERFORMANCE_LEVEL] - set current values"; static void print_usage_and_exit(void) { fprintf(stderr, "%s\n", usage_text); exit(EXIT_FAILURE); } -static int get_gpu_state_nv(struct GameModeGPUInfo *info) +/* Get the nvidia driver index for the current GPU */ +static long get_gpu_index_id_nv(struct GameModeGPUInfo *info) +{ + // Default to using the current device number + long gpu_index = info->device; + + if (info->vendor != Vendor_NVIDIA) + return -1; + + if (!getenv("DISPLAY")) + LOG_ERROR("Getting Nvidia parameters requires DISPLAY to be set - will likely fail!\n"); + long current = 0; + do { + char arg[128] = { 0 }; + char buf[EXTERNAL_BUFFER_MAX] = { 0 }; + char *end; + + /* Get the PCI id parameter */ + snprintf(arg, 128, NV_ATTRIBUTE_FORMAT, current, NV_PCIDEVICE_ATTRIBUTE); + const char *exec_args_core[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL }; + if (run_external_process(exec_args_core, buf, -1) != 0) { + LOG_ERROR("Failed to get %s! Will be defaulting to nvidia gpu index %ld\n", + arg, + gpu_index); + /* Failure just means we've overrun the device list */ + break; + } + + long pcidevice = strtol(buf, &end, 10); + if (end == buf) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf); + break; + } + + if (info->device == pcidevice) { + gpu_index = current; + break; + } + } while (true); + + return gpu_index; +} + +/* Get the max nvidia perf level */ +static long get_max_perf_level_nv(struct GameModeGPUInfo *info) { if (info->vendor != Vendor_NVIDIA) return -1; @@ -69,48 +116,80 @@ static int get_gpu_state_nv(struct GameModeGPUInfo *info) 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 }; + + snprintf(arg, 128, NV_ATTRIBUTE_FORMAT, info->device, NV_PERFMODES_ATTRIBUTE); + const char *exec_args[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL }; + if (run_external_process(exec_args, buf, -1) != 0) { + LOG_ERROR("Failed to get %s!\n", arg); + return -1; + } + + char *ptr = strrchr(buf, ';'); + long level = -1; + if (!ptr || sscanf(ptr, "; perf=%ld", &level) != 1) { + LOG_ERROR( + "Output didn't match expected format, couldn't discern highest perf level from " + "nvidia-settings!\n"); + LOG_ERROR("Output:%s\n", buf); + return -1; + } + + return level; +} + +/* Get the nvidia gpu state */ +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"); + + long perf_level = get_max_perf_level_nv(info); + char arg[128] = { 0 }; char buf[EXTERNAL_BUFFER_MAX] = { 0 }; char *end; - if (info->nv_perf_level != -1) { - /* Get the GPUGraphicsClockOffset parameter */ - snprintf(arg, - 128, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_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(exec_args_core, buf, -1) != 0) { - LOG_ERROR("Failed to get %s!\n", arg); - return -1; - } + /* Get the GPUGraphicsClockOffset parameter */ + snprintf(arg, + 128, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, + info->device, + NV_CORE_OFFSET_ATTRIBUTE, + perf_level); + const char *exec_args_core[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL }; + if (run_external_process(exec_args_core, buf, -1) != 0) { + LOG_ERROR("Failed to get %s!\n", arg); + return -1; + } - info->nv_core = strtol(buf, &end, 10); - if (end == buf) { - LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf); - return -1; - } + info->nv_core = strtol(buf, &end, 10); + if (end == buf) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf); + return -1; + } - /* Get the GPUMemoryTransferRateOffset parameter */ - snprintf(arg, - 128, - NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_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(exec_args_mem, buf, -1) != 0) { - LOG_ERROR("Failed to get %s!\n", arg); - return -1; - } + /* Get the GPUMemoryTransferRateOffset parameter */ + snprintf(arg, + 128, + NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT, + info->device, + NV_MEM_OFFSET_ATTRIBUTE, + perf_level); + const char *exec_args_mem[] = { "/usr/bin/nvidia-settings", "-q", arg, "-t", NULL }; + if (run_external_process(exec_args_mem, buf, -1) != 0) { + LOG_ERROR("Failed to get %s!\n", arg); + return -1; + } - info->nv_mem = strtol(buf, &end, 10); - if (end == buf) { - LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf); - return -1; - } + info->nv_mem = strtol(buf, &end, 10); + if (end == buf) { + LOG_ERROR("Failed to parse output for \"%s\" output was \"%s\"!\n", arg, buf); + return -1; } /* Get the GPUPowerMizerMode parameter */ @@ -135,6 +214,8 @@ static int get_gpu_state_nv(struct GameModeGPUInfo *info) */ static int set_gpu_state_nv(struct GameModeGPUInfo *info) { + int status = 0; + if (info->vendor != Vendor_NVIDIA) return -1; @@ -143,35 +224,39 @@ static int set_gpu_state_nv(struct GameModeGPUInfo *info) "Setting Nvidia parameters requires DISPLAY and XAUTHORITY to be set - will likely " "fail!\n"); + long perf_level = get_max_perf_level_nv(info); + char arg[128] = { 0 }; - if (info->nv_perf_level != -1) { - /* Set the GPUGraphicsClockOffset parameter */ + /* Set the GPUGraphicsClockOffset parameter */ + if (info->nv_core != -1) { snprintf(arg, 128, NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", info->device, NV_CORE_OFFSET_ATTRIBUTE, - info->nv_perf_level, + perf_level, info->nv_core); const char *exec_args_core[] = { "/usr/bin/nvidia-settings", "-a", arg, NULL }; if (run_external_process(exec_args_core, NULL, -1) != 0) { LOG_ERROR("Failed to set %s!\n", arg); - return -1; + status = -1; } + } - /* Set the GPUMemoryTransferRateOffset parameter */ + /* Set the GPUMemoryTransferRateOffset parameter */ + if (info->nv_mem != -1) { snprintf(arg, 128, NV_ATTRIBUTE_FORMAT NV_PERF_LEVEL_FORMAT "=%ld", info->device, NV_MEM_OFFSET_ATTRIBUTE, - info->nv_perf_level, + perf_level, info->nv_mem); const char *exec_args_mem[] = { "/usr/bin/nvidia-settings", "-a", arg, NULL }; if (run_external_process(exec_args_mem, NULL, -1) != 0) { LOG_ERROR("Failed to set %s!\n", arg); - return -1; + status = -1; } } @@ -186,11 +271,11 @@ static int set_gpu_state_nv(struct GameModeGPUInfo *info) const char *exec_args_pm[] = { "/usr/bin/nvidia-settings", "-a", arg, NULL }; if (run_external_process(exec_args_pm, NULL, -1) != 0) { LOG_ERROR("Failed to set %s!\n", arg); - return -1; + status = -1; } } - return 0; + return status; } /** @@ -284,18 +369,6 @@ static int set_gpu_state_amd(struct GameModeGPUInfo *info) return 0; } -/* Helper to get and verify vendor value */ -static long get_vendor(const char *val) -{ - char *end; - long ret = strtol(val, &end, 0); - if (!GPUVendorValid(ret) || end == val) { - LOG_ERROR("Invalid GPU Vendor passed (0x%04x)!\n", (unsigned short)ret); - print_usage_and_exit(); - } - return ret; -} - /* Helper to get and verify device value */ static long get_device(const char *val) { @@ -325,20 +398,21 @@ 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 == 3 && strncmp(argv[2], "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]); + info.device = get_device(argv[1]); + info.vendor = gamemode_get_gpu_vendor(info.device); + + /* Adjust the device number to the gpu index for Nvidia */ + if (info.vendor == Vendor_NVIDIA) + info.device = get_gpu_index_id_nv(&info); /* Fetch the state and print it out */ switch (info.vendor) { case Vendor_NVIDIA: - info.nv_perf_level = -1; - if (argc > 4) - info.nv_perf_level = get_generic_value(argv[4]); - /* Get nvidia power level */ + if (get_gpu_state_nv(&info) != 0) exit(EXIT_FAILURE); printf("%ld %ld %ld\n", info.nv_core, info.nv_mem, info.nv_powermizer_mode); @@ -349,49 +423,49 @@ int main(int argc, char *argv[]) printf("%s\n", info.amd_performance_level); break; default: - printf("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", (short)info.vendor); + LOG_ERROR("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", + (short)info.vendor); break; } - } else if (argc >= 5 && argc <= 8 && strncmp(argv[3], "set", 3) == 0) { + } else if (argc >= 4 && argc <= 7 && strncmp(argv[2], "set", 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]); + info.device = get_device(argv[1]); + info.vendor = gamemode_get_gpu_vendor(info.device); switch (info.vendor) { case Vendor_NVIDIA: - info.nv_core = get_generic_value(argv[4]); - info.nv_mem = get_generic_value(argv[5]); - info.nv_perf_level = -1; - if (argc > 6) - info.nv_perf_level = get_generic_value(argv[6]); + if (argc < 4) { + LOG_ERROR("Must pass at least 4 arguments for nvidia gpu!\n"); + print_usage_and_exit(); + } + info.nv_core = get_generic_value(argv[3]); + info.nv_mem = get_generic_value(argv[4]); + + /* Optional */ info.nv_powermizer_mode = -1; - if (argc > 7) - info.nv_powermizer_mode = get_generic_value(argv[7]); - break; - case Vendor_AMD: - strncpy(info.amd_performance_level, argv[4], CONFIG_VALUE_MAX); - break; - default: - printf("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", (short)info.vendor); - break; - } + if (argc >= 6) + info.nv_powermizer_mode = get_generic_value(argv[5]); - printf("gpuclockctl setting values on device:%ld with vendor 0x%04x", - info.device, - (unsigned short)info.vendor); - - switch (info.vendor) { - case Vendor_NVIDIA: return set_gpu_state_nv(&info); + break; case Vendor_AMD: + if (argc < 3) { + LOG_ERROR("Must pass performance level for AMD gpu!\n"); + print_usage_and_exit(); + } + strncpy(info.amd_performance_level, argv[3], CONFIG_VALUE_MAX); return set_gpu_state_amd(&info); + break; default: - printf("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", (short)info.vendor); + LOG_ERROR("Currently unsupported GPU vendor 0x%04x, doing nothing!\n", + (short)info.vendor); + print_usage_and_exit(); break; } + } else { print_usage_and_exit(); } diff --git a/daemon/meson.build b/daemon/meson.build index e6c3f7d..06cb183 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -3,6 +3,7 @@ common_sources = [ 'logging.c', 'governors-query.c', 'external-helper.c', + 'gpu-control.c', ] daemon_common = static_library( diff --git a/example/gamemode.ini b/example/gamemode.ini index a0ab428..b4a2d6e 100644 --- a/example/gamemode.ini +++ b/example/gamemode.ini @@ -49,12 +49,12 @@ inhibit_screensaver=1 ; Nvidia specific settings ; Requires the coolbits extension activated in nvidia-xconfig ; This corresponds to the desired GPUPowerMizerMode -; Generally "Adaptive"=0 "Prefer Maximum Performance"=1 and "Auto"=2) +; "Adaptive"=0 "Prefer Maximum Performance"=1 and "Auto"=2 +; See NV_CTRL_GPU_POWER_MIZER_MODE and friends in https://github.com/NVIDIA/nvidia-settings/blob/master/src/libXNVCtrl/NVCtrl.h ;nv_powermizer_mode=1 -; This corresponds to the performance level to edit in nvidia-xconfig (usually the highest level - on older cards 1, newer cards can be 4 or higher) -;nv_perf_level=1 -; (these two are Mhz offsets from the baseline, ie. 0 applies no change) +; These will modify the core and mem clocks of the highest perf state in the Nvidia PowerMizer +; They are measured as Mhz offsets from the baseline, 0 will reset values to default, -1 or unset will not modify values ;nv_core_clock_mhz_offset=0 ;nv_mem_clock_mhz_offset=0