Browse Source

Added detection for big.LITTLE

Added detection for big.LITTLE aka cpu:s where not all cores have the same frequency like on Intel Alder Lake and newer. The current logic allows a 5% difference in the max frequency due to some reports that those cpu:s doesn't always give back the exact same value (possible due to boosting capability).
Henrik Holst 1 year ago
parent
commit
51ee251efb
1 changed files with 65 additions and 43 deletions
  1. 65 43
      daemon/gamemode-cpu.c

+ 65 - 43
daemon/gamemode-cpu.c

@@ -50,14 +50,14 @@ static int read_small_file (char *path, char **buf, size_t *buflen)
 	FILE *f = fopen(path, "r");
 
 	if (!f) {
-		LOG_ERROR("Couldn't open file at %s (%s), will not apply cpu core parking!\n", path, strerror(errno));
+		LOG_ERROR("Couldn't open file at %s : %s\n", path, strerror(errno));
 		return 0;
 	}
 
 	ssize_t nread = getline(buf, buflen, f);
 
 	if (nread == -1) {
-		LOG_ERROR("Couldn't read file at %s (%s), will not apply cpu core parking!\n", path, strerror(errno));
+		LOG_ERROR("Couldn't read file at %s : %s\n", path, strerror(errno));
 		fclose(f);
 		return 0;
 	}
@@ -75,47 +75,79 @@ static int read_small_file (char *path, char **buf, size_t *buflen)
 static int walk_sysfs (char *cpulist, char **buf, size_t *buflen, GameModeCPUInfo *info)
 {
 	char path[PATH_MAX];
-	unsigned long long max_cache = 0;
+	unsigned long long max_cache = 0, max_freq = 0;
 	long from, to;
 
+	cpu_set_t *freq_cores = CPU_ALLOC(info->num_cpu);
+
 	char *list = cpulist;
 	while ((list = parse_cpulist(list, &from, &to))) {
 		for (long cpu = from; cpu < to + 1; cpu++) {
+			CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->online);
+
+			/* check for L3 cache non-uniformity among the cores */
 			int ret = snprintf(path, PATH_MAX, "/sys/devices/system/cpu/cpu%ld/cache/index3/size", cpu);
-			if (ret < 0 || ret >= PATH_MAX) {
-				LOG_ERROR("snprintf failed, will not apply cpu core parking!\n");
-				return 0;
+
+			if (ret > 0 && ret < PATH_MAX) {
+				if (read_small_file(path, buf, buflen)) {
+					char *endp;
+					unsigned long long cache_size = strtoull (*buf, &endp, 10);
+
+					if (*endp == 'K') {
+						cache_size *= 1024;
+					} else if (*endp == 'M') {
+						cache_size *= 1024 * 1024;
+					} else if (*endp == 'G') {
+						cache_size *= 1024 * 1024 * 1024;
+					} else if (*endp != '\0') {
+						LOG_MSG("cpu L3 cache size (%s) on core #%ld is silly\n", *buf, cpu);
+						cache_size = 0;
+					}
+
+					if (cache_size > max_cache) {
+						max_cache = cache_size;
+						CPU_ZERO_S(CPU_ALLOC_SIZE(info->num_cpu), info->to_keep);
+					}
+
+					if (cache_size == max_cache)
+						CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->to_keep);
+				}
 			}
 
-			if (!read_small_file(path, buf, buflen))
-				return 0;
+			/* check for frequency non-uniformity among the cores */
+			ret = snprintf(path, PATH_MAX, "/sys/devices/system/cpu/cpu%ld/cpufreq/cpuinfo_max_freq", cpu);
 
-			char *endp;
-			unsigned long long cache_size = strtoull (*buf, &endp, 10);
-
-			if (*endp == 'K') {
-				cache_size *= 1024;
-			} else if (*endp == 'M') {
-				cache_size *= 1024 * 1024;
-			} else if (*endp == 'G') {
-				cache_size *= 1024 * 1024 * 1024;
-			} else if (*endp != '\0') {
-				LOG_ERROR("cpu L3 cache size (%s) is silly, will not apply cpu core parking!\n", *buf);
-				return 0;
-			}
+			if (ret > 0 && ret < PATH_MAX) {
+				if (read_small_file(path, buf, buflen)) {
+					unsigned long long freq = strtoull (*buf, NULL, 10);
+					unsigned long long cutoff = (freq * 5) / 100;
 
-			if (cache_size > max_cache) {
-				max_cache = cache_size;
-				CPU_ZERO_S(CPU_ALLOC_SIZE(info->num_cpu), info->to_keep);
-			}
+					if (freq > max_freq) {
+						if (max_freq < freq - cutoff)
+							CPU_ZERO_S(CPU_ALLOC_SIZE(info->num_cpu), freq_cores);
 
-			if (cache_size == max_cache)
-				CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->to_keep);
+						max_freq = freq;
+					}
 
-			CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->online);
+					if (freq - cutoff >= max_freq)
+						CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), freq_cores);
+				}
+			}
 		}
 	}
 
+	if (CPU_EQUAL_S(CPU_ALLOC_SIZE(info->num_cpu), info->online, info->to_keep) || CPU_COUNT_S(CPU_ALLOC_SIZE(info->num_cpu), info->to_keep) == 0) {
+		LOG_MSG("cpu L3 cache was uniform, this is not a x3D with multiple chiplets\n");
+
+		CPU_FREE(info->to_keep);
+		info->to_keep = freq_cores;
+
+		if (CPU_EQUAL_S(CPU_ALLOC_SIZE(info->num_cpu), info->online, info->to_keep) || CPU_COUNT_S(CPU_ALLOC_SIZE(info->num_cpu), info->to_keep) == 0)
+			LOG_MSG("cpu frequency was uniform, this is not a big.LITTLE type of system\n");
+	} else {
+		CPU_FREE(freq_cores);
+	}
+
 	return 1;
 }
 
@@ -148,9 +180,6 @@ static int walk_string (char *cpulist, char *config_cpulist, GameModeCPUInfo *in
 	return 1;
 }
 
-/**
- * Attempts to identify the current in use CPU information
- */
 int game_mode_initialise_cpu(GameModeConfig *config, GameModeCPUInfo **info)
 {
 	/* Verify input, this is programmer error */
@@ -237,17 +266,16 @@ int game_mode_initialise_cpu(GameModeConfig *config, GameModeCPUInfo **info)
 
 	if (park_or_pin == 0 && CPU_EQUAL_S(CPU_ALLOC_SIZE(new_info->num_cpu), new_info->online, new_info->to_keep)) {
 		game_mode_free_cpu(&new_info);
-		LOG_MSG("cpu L3 cache is uniform, will not apply cpu core parking!\n");
+		LOG_MSG("I can find no reason to perform core parking on this system!\n");
 		goto error_exit;
 	}
 
-	if (CPU_COUNT_S(CPU_ALLOC_SIZE(new_info->num_cpu), new_info->to_keep) == 0) {
+	if (CPU_COUNT_S(CPU_ALLOC_SIZE(new_info->num_cpu), new_info->to_keep) < 4) {
 		game_mode_free_cpu(&new_info);
-		LOG_MSG("logic or config wanted to park/unpin every single cpu core, will not apply cpu core parking/pinning!\n");
+		LOG_MSG("logic or config would result in less than 4 active cores, will not apply cpu core parking/pinning!\n");
 		goto error_exit;
 	}
 
-	/* Give back the new cpu info */
 	*info = new_info;
 
 early_exit:
@@ -289,9 +317,6 @@ static int log_state (char *cpulist, int *pos, const long first, const long last
 	return 1;
 }
 
-/**
- * Park the unwanted cpu cores when gamemode is active
- */
 int game_mode_park_cpu(const GameModeCPUInfo *info)
 {
 	if (!info || info->park_or_pin == 1)
@@ -336,9 +361,6 @@ int game_mode_park_cpu(const GameModeCPUInfo *info)
 	return 0;
 }
 
-/**
- * Restore the parked cpu cores when gamemode is disabled
- */
 int game_mode_unpark_cpu(const GameModeCPUInfo *info)
 {
 	if (!info || info->park_or_pin == 1)
@@ -388,11 +410,12 @@ void game_mode_apply_core_pinning(const GameModeCPUInfo *info, const pid_t clien
 	if (!info || info->park_or_pin == 0)
 		return;
 
+	LOG_MSG("Pinning process...\n");
+
 	if (sched_setaffinity(client, CPU_ALLOC_SIZE(info->num_cpu), info->to_keep) != 0)
 		LOG_ERROR("Failed to pin process: %s\n", strerror(errno));
 }
 
-/* Simply used to free the CPU info object */
 void game_mode_free_cpu(GameModeCPUInfo **info)
 {
 	if (!(*info)) {
@@ -406,4 +429,3 @@ void game_mode_free_cpu(GameModeCPUInfo **info)
 		*info = NULL;
 	}
 }
-