diff --git a/profiles/latency-performance/tuned.conf b/profiles/latency-performance/tuned.conf index 054c554..4cd69a1 100644 --- a/profiles/latency-performance/tuned.conf +++ b/profiles/latency-performance/tuned.conf @@ -6,7 +6,7 @@ summary=Optimize for deterministic performance at the cost of increased power consumption [cpu] -force_latency=1 +force_latency=cstate.id:1|1 governor=performance energy_perf_bias=performance min_perf_pct=100 diff --git a/profiles/sap-hana/tuned.conf b/profiles/sap-hana/tuned.conf index 9afac82..d74250b 100644 --- a/profiles/sap-hana/tuned.conf +++ b/profiles/sap-hana/tuned.conf @@ -7,7 +7,7 @@ summary=Optimize for SAP HANA include=throughput-performance [cpu] -force_latency=70 +force_latency=cstate.id:3|70 [vm] transparent_hugepages=never diff --git a/profiles/virtual-host/tuned.conf b/profiles/virtual-host/tuned.conf index ca493d6..8acb92d 100644 --- a/profiles/virtual-host/tuned.conf +++ b/profiles/virtual-host/tuned.conf @@ -18,4 +18,4 @@ kernel.sched_migration_cost_ns = 5000000 [cpu] # Setting C3 state sleep mode/power savings -force_latency=70 +force_latency=cstate.id:3|70 diff --git a/tuned/plugins/plugin_cpu.py b/tuned/plugins/plugin_cpu.py index 77e9448..04c7b19 100644 --- a/tuned/plugins/plugin_cpu.py +++ b/tuned/plugins/plugin_cpu.py @@ -12,8 +12,7 @@ import procfs log = tuned.logs.get() -# TODO: force_latency -> command -# intel_pstate +cpuidle_states_path = "/sys/devices/system/cpu/cpu0/cpuidle" class CPULatencyPlugin(base.Plugin): """ @@ -210,13 +209,74 @@ class CPULatencyPlugin(base.Plugin): def _instance_unapply_dynamic(self, instance, device): pass + def _str2int(self, s): + try: + return int(s) + except (ValueError, TypeError): + return None + + def _read_cstates_latency(self): + self.cstates_latency = {} + for d in os.listdir(cpuidle_states_path): + cstate_path = cpuidle_states_path + "/%s/" % d + name = self._cmd.read_file(cstate_path + "name", err_ret = None, no_error = True) + latency = self._cmd.read_file(cstate_path + "latency", err_ret = None, no_error = True) + if name is not None and latency is not None: + latency = self._str2int(latency) + if latency is not None: + self.cstates_latency[name.strip()] = latency + + def _get_latency_by_cstate_name(self, name): + log.debug("getting latency for cstate with name '%s'" % name) + if self.cstates_latency is None: + log.debug("reading cstates latency table") + self._read_cstates_latency() + latency = self.cstates_latency.get(name, None) + log.debug("cstate name mapped to latency: %s" % str(latency)) + return latency + + def _get_latency_by_cstate_id(self, lid): + log.debug("getting latency for cstate with ID '%s'" % str(lid)) + lid = self._str2int(lid) + if lid is None: + log.debug("cstate ID is invalid") + return None + latency_path = cpuidle_states_path + "/%s/latency" % ("state%d" % lid) + latency = self._str2int(self._cmd.read_file(latency_path, err_ret = None, no_error = True)) + log.debug("cstate ID mapped to latency: %s" % str(latency)) + return latency + + def _parse_latency(self, latency): + self.cstates_latency = None + latencies = str(latency).split("|") + log.debug("parsing latency") + for latency in latencies: + try: + latency = int(latency) + log.debug("parsed directly specified latency value: %d" % latency) + except ValueError: + if latency[0:10] == "cstate.id:": + latency = self._get_latency_by_cstate_id(latency[10:]) + elif latency[0:12] == "cstate.name:": + latency = self._get_latency_by_cstate_name(latency[12:]) + else: + latency = None + log.debug("invalid latency specified: '%s'" % str(latency)) + if latency is not None: + break + return latency + def _set_latency(self, latency): - latency = int(latency) - if self._has_pm_qos and self._latency != latency: - log.info("setting new cpu latency %d" % latency) - latency_bin = struct.pack("i", latency) - os.write(self._cpu_latency_fd, latency_bin) - self._latency = latency + latency = self._parse_latency(latency) + if self._has_pm_qos: + if latency is None: + log.error("unable to evaluate latency value (probably wrong settings in the 'cpu' section of current profile), disabling PM QoS") + self._has_pm_qos = False + elif self._latency != latency: + log.info("setting new cpu latency %d" % latency) + latency_bin = struct.pack("i", latency) + os.write(self._cpu_latency_fd, latency_bin) + self._latency = latency def _get_available_governors(self, device): return self._cmd.read_file("/sys/devices/system/cpu/%s/cpufreq/scaling_available_governors" % device).strip().split()