mirror of
https://github.com/FeralInteractive/gamemode.git
synced 2025-06-26 17:31:45 +02:00
Add an option for using a different governor for integrated GPUs
This commit adds two new configuration options: igpu_desiredgov and igpu_power_threshold which allow for a different CPU governor when the Intel integrated GPU is under load. This currently only applies to Intel integrated GPUs and not AMD APUs because it uses the Intel RAPL infrastructure for getting power information. If on a platform that without an Intel integrated GPU or where the kernel does not support RAPL, the new options will be ignored and it will fall back to the old behavior. One of the core principals of gamemoded to date has been that, when playing a game, we want to use the "performance" CPU governor to increase CPU performance and prevent CPU-limiting. However, when the integrated GPU is under load, this can be counter-productive because the CPU and GPU share a thermal and power budget. By throwing the CPU governor to "performance" game mode currently makes the CPU frequency management far too aggressive and it burns more power than needed. With a discrete GPU, this is fine because the worst that happens is a bit more fan noise. With an integrated GPU, however, the additional power being burned by the CPU is power not available to the GPU and this can cause the GPU to clock down and lead to significantly worse performance. By using the "powersave" governor instead of the "performance" governor while the integrated GPU is under load, we can save power on the CPU side which lets the GPU clock up higher. On my Razer Blade Stealth 13 with an i7-1065G7, this improves the performance of "Shadow of the Tomb Raider" by around 25-30% according to its internal benchmark mode.
This commit is contained in:
@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "ini.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/inotify.h>
|
||||
@ -50,6 +51,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
/* Default value for the reaper frequency */
|
||||
#define DEFAULT_REAPER_FREQ 5
|
||||
|
||||
#define DEFAULT_IGPU_POWER_THRESHOLD 0.3f
|
||||
|
||||
/* Helper macro for defining the config variable getter */
|
||||
#define DEFINE_CONFIG_GET(name) \
|
||||
long config_get_##name(GameModeConfig *self) \
|
||||
@ -82,6 +85,9 @@ struct GameModeConfig {
|
||||
char defaultgov[CONFIG_VALUE_MAX];
|
||||
char desiredgov[CONFIG_VALUE_MAX];
|
||||
|
||||
char igpu_desiredgov[CONFIG_VALUE_MAX];
|
||||
float igpu_power_threshold;
|
||||
|
||||
char softrealtime[CONFIG_VALUE_MAX];
|
||||
long renice;
|
||||
|
||||
@ -179,6 +185,27 @@ __attribute__((unused)) static bool get_long_value_hex(const char *value_name, c
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a long value from a string
|
||||
*/
|
||||
static bool get_float_value(const char *value_name, const char *value, float *output)
|
||||
{
|
||||
char *end = NULL;
|
||||
float config_value = strtof(value, &end);
|
||||
|
||||
if (errno == ERANGE) {
|
||||
LOG_ERROR("Config: %s overflowed, given [%s]\n", value_name, value);
|
||||
return false;
|
||||
} else if (!(*value != '\0' && end && *end == '\0')) {
|
||||
LOG_ERROR("Config: %s was invalid, given [%s]\n", value_name, value);
|
||||
return false;
|
||||
} else {
|
||||
*output = config_value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple strstr scheck
|
||||
* Could be expanded for wildcard or regex
|
||||
@ -230,6 +257,10 @@ static int inih_handler(void *user, const char *section, const char *name, const
|
||||
valid = get_string_value(value, self->values.defaultgov);
|
||||
} else if (strcmp(name, "desiredgov") == 0) {
|
||||
valid = get_string_value(value, self->values.desiredgov);
|
||||
} else if (strcmp(name, "igpu_desiredgov") == 0) {
|
||||
valid = get_string_value(value, self->values.igpu_desiredgov);
|
||||
} else if (strcmp(name, "igpu_power_threshold") == 0) {
|
||||
valid = get_float_value(name, value, &self->values.igpu_power_threshold);
|
||||
} else if (strcmp(name, "softrealtime") == 0) {
|
||||
valid = get_string_value(value, self->values.softrealtime);
|
||||
} else if (strcmp(name, "renice") == 0) {
|
||||
@ -329,6 +360,7 @@ static void load_config_files(GameModeConfig *self)
|
||||
memset(&self->values, 0, sizeof(self->values));
|
||||
|
||||
/* Set some non-zero defaults */
|
||||
self->values.igpu_power_threshold = DEFAULT_IGPU_POWER_THRESHOLD;
|
||||
self->values.inhibit_screensaver = 1; /* Defaults to on */
|
||||
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 */
|
||||
@ -641,6 +673,35 @@ void config_get_desired_governor(GameModeConfig *self, char governor[CONFIG_VALU
|
||||
memcpy_locked_config(self, governor, self->values.desiredgov, sizeof(self->values.desiredgov));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen iGPU desired governor
|
||||
*/
|
||||
void config_get_igpu_desired_governor(GameModeConfig *self, char governor[CONFIG_VALUE_MAX])
|
||||
{
|
||||
memcpy_locked_config(self,
|
||||
governor,
|
||||
self->values.igpu_desiredgov,
|
||||
sizeof(self->values.igpu_desiredgov));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen iGPU power threshold
|
||||
*/
|
||||
float config_get_igpu_power_threshold(GameModeConfig *self)
|
||||
{
|
||||
float value = 0;
|
||||
memcpy_locked_config(self, &value, &self->values.igpu_power_threshold, sizeof(float));
|
||||
/* Validate the threshold value */
|
||||
if (isnan(value) || value < 0) {
|
||||
LOG_ONCE(ERROR,
|
||||
"Configured iGPU power threshold value '%f' is invalid, ignoring iGPU default "
|
||||
"governor.\n",
|
||||
value);
|
||||
value = FP_INFINITE;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen soft realtime behavior
|
||||
*/
|
||||
|
Reference in New Issue
Block a user