Compare commits
No commits in common. "c8" and "c10s" have entirely different histories.
1
.fmf/version
Normal file
1
.fmf/version
Normal file
@ -0,0 +1 @@
|
||||
1
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/tuned-2.22.1.tar.gz
|
||||
/tuned-*.tar.gz
|
||||
|
@ -1 +0,0 @@
|
||||
60e206fe73ea537e64141f92b331f65879766f97 SOURCES/tuned-2.22.1.tar.gz
|
@ -1,80 +0,0 @@
|
||||
diff --git a/profiles/cpu-partitioning/script.sh b/profiles/cpu-partitioning/script.sh
|
||||
index ec422ca..cb378b7 100755
|
||||
--- a/profiles/cpu-partitioning/script.sh
|
||||
+++ b/profiles/cpu-partitioning/script.sh
|
||||
@@ -2,6 +2,38 @@
|
||||
|
||||
. /usr/lib/tuned/functions
|
||||
|
||||
+no_balance_cpus_file=$STORAGE/no-balance-cpus.txt
|
||||
+
|
||||
+change_sd_balance_bit()
|
||||
+{
|
||||
+ local set_bit=$1
|
||||
+ local flags_cur=
|
||||
+ local file=
|
||||
+ local cpu=
|
||||
+
|
||||
+ for cpu in $(cat $no_balance_cpus_file); do
|
||||
+ for file in $(find /proc/sys/kernel/sched_domain/cpu$cpu -name flags -print); do
|
||||
+ flags_cur=$(cat $file)
|
||||
+ if [ $set_bit -eq 1 ]; then
|
||||
+ flags_cur=$((flags_cur | 0x1))
|
||||
+ else
|
||||
+ flags_cur=$((flags_cur & 0xfffe))
|
||||
+ fi
|
||||
+ echo $flags_cur > $file
|
||||
+ done
|
||||
+ done
|
||||
+}
|
||||
+
|
||||
+disable_balance_domains()
|
||||
+{
|
||||
+ change_sd_balance_bit 0
|
||||
+}
|
||||
+
|
||||
+enable_balance_domains()
|
||||
+{
|
||||
+ change_sd_balance_bit 1
|
||||
+}
|
||||
+
|
||||
start() {
|
||||
mkdir -p "${TUNED_tmpdir}/etc/systemd"
|
||||
mkdir -p "${TUNED_tmpdir}/usr/lib/dracut/hooks/pre-udev"
|
||||
@@ -9,6 +41,9 @@ start() {
|
||||
cp 00-tuned-pre-udev.sh "${TUNED_tmpdir}/usr/lib/dracut/hooks/pre-udev/"
|
||||
setup_kvm_mod_low_latency
|
||||
disable_ksm
|
||||
+
|
||||
+ echo "$TUNED_no_balance_cores_expanded" | sed 's/,/ /g' > $no_balance_cpus_file
|
||||
+ disable_balance_domains
|
||||
return "$?"
|
||||
}
|
||||
|
||||
@@ -18,6 +53,7 @@ stop() {
|
||||
teardown_kvm_mod_low_latency
|
||||
enable_ksm
|
||||
fi
|
||||
+ enable_balance_domains
|
||||
return "$?"
|
||||
}
|
||||
|
||||
diff --git a/profiles/cpu-partitioning/tuned.conf b/profiles/cpu-partitioning/tuned.conf
|
||||
index 11f03cf..a682c9c 100644
|
||||
--- a/profiles/cpu-partitioning/tuned.conf
|
||||
+++ b/profiles/cpu-partitioning/tuned.conf
|
||||
@@ -35,8 +35,6 @@ no_balance_cores_expanded=${f:cpulist_unpack:${no_balance_cores}}
|
||||
# Fail if isolated_cores contains CPUs which are not online
|
||||
assert2=${f:assertion:isolated_cores contains online CPU(s):${isolated_cores_expanded}:${isolated_cores_online_expanded}}
|
||||
|
||||
-cmd_isolcpus=${f:regex_search_ternary:${no_balance_cores}:\s*[0-9]: isolcpus=${no_balance_cores}:}
|
||||
-
|
||||
[sysfs]
|
||||
/sys/bus/workqueue/devices/writeback/cpumask = ${not_isolated_cpumask}
|
||||
/sys/devices/virtual/workqueue/cpumask = ${not_isolated_cpumask}
|
||||
@@ -62,4 +60,4 @@ priority=10
|
||||
initrd_remove_dir=True
|
||||
initrd_dst_img=tuned-initrd.img
|
||||
initrd_add_dir=${tmpdir}
|
||||
-cmdline_cpu_part=+nohz=on${cmd_isolcpus} nohz_full=${isolated_cores} rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} intel_pstate=disable nosoftlockup
|
||||
+cmdline_cpu_part=+nohz=on nohz_full=${isolated_cores} rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} intel_pstate=disable nosoftlockup
|
@ -1,118 +0,0 @@
|
||||
diff --git a/tuned/consts.py b/tuned/consts.py
|
||||
index 3749363..3b41ed9 100644
|
||||
--- a/tuned/consts.py
|
||||
+++ b/tuned/consts.py
|
||||
@@ -1,4 +1,8 @@
|
||||
import logging
|
||||
+import string
|
||||
+
|
||||
+NAMES_ALLOWED_CHARS = string.ascii_letters + string.digits + " !@'+-.,/:;_$&*()%<=>?#[]{|}^~" + '"'
|
||||
+NAMES_MAX_LENGTH = 4096
|
||||
|
||||
GLOBAL_CONFIG_FILE = "/etc/tuned/tuned-main.conf"
|
||||
ACTIVE_PROFILE_FILE = "/etc/tuned/active_profile"
|
||||
diff --git a/tuned/daemon/controller.py b/tuned/daemon/controller.py
|
||||
index 6a59a1d..94e9022 100644
|
||||
--- a/tuned/daemon/controller.py
|
||||
+++ b/tuned/daemon/controller.py
|
||||
@@ -182,6 +182,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
def switch_profile(self, profile_name, caller = None):
|
||||
if caller == "":
|
||||
return (False, "Unauthorized")
|
||||
+ if not self._cmd.is_valid_name(profile_name):
|
||||
+ return (False, "Invalid profile_name")
|
||||
return self._switch_profile(profile_name, True)
|
||||
|
||||
@exports.export("", "(bs)")
|
||||
@@ -255,8 +257,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
|
||||
@exports.export("s", "(bsss)")
|
||||
def profile_info(self, profile_name, caller = None):
|
||||
- if caller == "":
|
||||
- return tuple(False, "", "", "")
|
||||
+ if caller == "" or not self._cmd.is_valid_name(profile_name):
|
||||
+ return (False, "", "", "")
|
||||
if profile_name is None or profile_name == "":
|
||||
profile_name = self.active_profile()
|
||||
return tuple(self._daemon.profile_loader.profile_locator.get_profile_attrs(profile_name, [consts.PROFILE_ATTR_SUMMARY, consts.PROFILE_ATTR_DESCRIPTION], [""]))
|
||||
@@ -287,7 +289,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
dictionary -- {plugin_name: {parameter_name: default_value}}
|
||||
"""
|
||||
if caller == "":
|
||||
- return False
|
||||
+ return {}
|
||||
plugins = {}
|
||||
for plugin_class in self._daemon.get_all_plugins():
|
||||
plugin_name = plugin_class.__module__.split(".")[-1].split("_", 1)[1]
|
||||
@@ -300,8 +302,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
@exports.export("s","s")
|
||||
def get_plugin_documentation(self, plugin_name, caller = None):
|
||||
"""Return docstring of plugin's class"""
|
||||
- if caller == "":
|
||||
- return False
|
||||
+ if caller == "" or not self._cmd.is_valid_name(plugin_name):
|
||||
+ return ""
|
||||
return self._daemon.get_plugin_documentation(str(plugin_name))
|
||||
|
||||
@exports.export("s","a{ss}")
|
||||
@@ -314,8 +316,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
Return:
|
||||
dictionary -- {parameter_name: hint}
|
||||
"""
|
||||
- if caller == "":
|
||||
- return False
|
||||
+ if caller == "" or not self._cmd.is_valid_name(plugin_name):
|
||||
+ return {}
|
||||
return self._daemon.get_plugin_hints(str(plugin_name))
|
||||
|
||||
@exports.export("s", "b")
|
||||
@@ -328,7 +330,7 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
Return:
|
||||
bool -- True on success
|
||||
"""
|
||||
- if caller == "":
|
||||
+ if caller == "" or not self._cmd.is_valid_name(path):
|
||||
return False
|
||||
if self._daemon._application and self._daemon._application._unix_socket_exporter:
|
||||
self._daemon._application._unix_socket_exporter.register_signal_path(path)
|
||||
@@ -342,6 +344,10 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
def instance_acquire_devices(self, devices, instance_name, caller = None):
|
||||
if caller == "":
|
||||
return (False, "Unauthorized")
|
||||
+ if not self._cmd.is_valid_name(devices):
|
||||
+ return (False, "Invalid devices")
|
||||
+ if not self._cmd.is_valid_name(instance_name):
|
||||
+ return (False, "Invalid instance_name")
|
||||
found = False
|
||||
for instance_target in self._daemon._unit_manager.instances:
|
||||
if instance_target.name == instance_name:
|
||||
@@ -388,6 +394,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
"""
|
||||
if caller == "":
|
||||
return (False, "Unauthorized", [])
|
||||
+ if not self._cmd.is_valid_name(plugin_name):
|
||||
+ return (False, "Invalid plugin_name", [])
|
||||
if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
|
||||
rets = "Plugin '%s' does not exist" % plugin_name
|
||||
log.error(rets)
|
||||
@@ -411,6 +419,8 @@ class Controller(tuned.exports.interfaces.ExportableInterface):
|
||||
"""
|
||||
if caller == "":
|
||||
return (False, "Unauthorized", [])
|
||||
+ if not self._cmd.is_valid_name(instance_name):
|
||||
+ return (False, "Invalid instance_name", [])
|
||||
for instance in self._daemon._unit_manager.instances:
|
||||
if instance.name == instance_name:
|
||||
return (True, "OK", sorted(list(instance.processed_devices)))
|
||||
diff --git a/tuned/utils/commands.py b/tuned/utils/commands.py
|
||||
index ce51fc0..38d95ef 100644
|
||||
--- a/tuned/utils/commands.py
|
||||
+++ b/tuned/utils/commands.py
|
||||
@@ -544,3 +544,7 @@ class commands:
|
||||
import string
|
||||
trans = string.maketrans(source_chars, dest_chars)
|
||||
return text.translate(trans)
|
||||
+
|
||||
+ # Checks if name contains only valid characters and has valid length or is empty string or None
|
||||
+ def is_valid_name(self, name):
|
||||
+ return not name or (all(c in consts.NAMES_ALLOWED_CHARS for c in name) and len(name) <= consts.NAMES_MAX_LENGTH)
|
@ -1,88 +0,0 @@
|
||||
diff --git a/profiles/latency-performance/tuned.conf b/profiles/latency-performance/tuned.conf
|
||||
index 1dec690..e592138 100644
|
||||
--- a/profiles/latency-performance/tuned.conf
|
||||
+++ b/profiles/latency-performance/tuned.conf
|
||||
@@ -35,3 +35,17 @@ vm.dirty_background_ratio=3
|
||||
# 100 tells the kernel to aggressively swap processes out of physical memory
|
||||
# and move them to swap cache
|
||||
vm.swappiness=10
|
||||
+
|
||||
+[scheduler]
|
||||
+runtime=0
|
||||
+# ktune sysctl settings for rhel6 servers, maximizing i/o throughput
|
||||
+#
|
||||
+# Minimal preemption granularity for CPU-bound tasks:
|
||||
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
|
||||
+sched_min_granularity_ns = 3000000
|
||||
+sched_wakeup_granularity_ns = 4000000
|
||||
+
|
||||
+# The total time the scheduler will consider a migrated process
|
||||
+# "cache hot" and thus less likely to be re-migrated
|
||||
+# (system default is 500000, i.e. 0.5 ms)
|
||||
+sched_migration_cost_ns = 5000000
|
||||
diff --git a/profiles/sap-hana/tuned.conf b/profiles/sap-hana/tuned.conf
|
||||
index aeecf53..1b15ea3 100644
|
||||
--- a/profiles/sap-hana/tuned.conf
|
||||
+++ b/profiles/sap-hana/tuned.conf
|
||||
@@ -20,3 +20,8 @@ kernel.numa_balancing = 0
|
||||
vm.dirty_ratio = 40
|
||||
vm.dirty_background_ratio = 10
|
||||
vm.swappiness = 10
|
||||
+
|
||||
+[scheduler]
|
||||
+runtime=0
|
||||
+sched_min_granularity_ns = 3000000
|
||||
+sched_wakeup_granularity_ns = 4000000
|
||||
diff --git a/profiles/throughput-performance/tuned.conf b/profiles/throughput-performance/tuned.conf
|
||||
index e4e832f..3d9c42f 100644
|
||||
--- a/profiles/throughput-performance/tuned.conf
|
||||
+++ b/profiles/throughput-performance/tuned.conf
|
||||
@@ -67,9 +67,33 @@ vm.swappiness=10
|
||||
# on older kernels
|
||||
net.core.somaxconn=>2048
|
||||
|
||||
+[scheduler]
|
||||
+runtime=0
|
||||
+# ktune sysctl settings for rhel6 servers, maximizing i/o throughput
|
||||
+#
|
||||
+# Minimal preemption granularity for CPU-bound tasks:
|
||||
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
|
||||
+sched_min_granularity_ns = 10000000
|
||||
+
|
||||
+# SCHED_OTHER wake-up granularity.
|
||||
+# (default: 1 msec# (1 + ilog(ncpus)), units: nanoseconds)
|
||||
+#
|
||||
+# This option delays the preemption effects of decoupled workloads
|
||||
+# and reduces their over-scheduling. Synchronous workloads will still
|
||||
+# have immediate wakeup/sleep latencies.
|
||||
+sched_wakeup_granularity_ns = 15000000
|
||||
+
|
||||
# Marvell ThunderX
|
||||
[sysctl.thunderx]
|
||||
type=sysctl
|
||||
uname_regex=aarch64
|
||||
cpuinfo_regex=${thunderx_cpuinfo_regex}
|
||||
kernel.numa_balancing=0
|
||||
+
|
||||
+# AMD
|
||||
+[scheduler.amd]
|
||||
+type=scheduler
|
||||
+uname_regex=x86_64
|
||||
+cpuinfo_regex=${amd_cpuinfo_regex}
|
||||
+runtime=0
|
||||
+sched_migration_cost_ns=5000000
|
||||
diff --git a/profiles/virtual-host/tuned.conf b/profiles/virtual-host/tuned.conf
|
||||
index 5301d9f..24d0fb4 100644
|
||||
--- a/profiles/virtual-host/tuned.conf
|
||||
+++ b/profiles/virtual-host/tuned.conf
|
||||
@@ -14,3 +14,10 @@ vm.dirty_background_ratio = 5
|
||||
[cpu]
|
||||
# Setting C3 state sleep mode/power savings
|
||||
force_latency=cstate.id_no_zero:3|70
|
||||
+
|
||||
+[scheduler]
|
||||
+runtime=0
|
||||
+# The total time the scheduler will consider a migrated process
|
||||
+# "cache hot" and thus less likely to be re-migrated
|
||||
+# (system default is 500000, i.e. 0.5 ms)
|
||||
+sched_migration_cost_ns = 5000000
|
@ -1,11 +0,0 @@
|
||||
diff --git a/profiles/postgresql/tuned.conf b/profiles/postgresql/tuned.conf
|
||||
index 88da8e4..4fd3810 100644
|
||||
--- a/profiles/postgresql/tuned.conf
|
||||
+++ b/profiles/postgresql/tuned.conf
|
||||
@@ -55,3 +55,6 @@ sched_min_granularity_ns = 10000000
|
||||
# "cache hot" and thus less likely to be re-migrated
|
||||
# (system default is 500000, i.e. 0.5 ms)
|
||||
sched_migration_cost_ns = 50000000
|
||||
+
|
||||
+[scheduler.amd]
|
||||
+enabled=false
|
@ -1,54 +0,0 @@
|
||||
From 7557cf975282326cdbfe55b7b803d8075ff37cba Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
|
||||
Date: Tue, 12 Mar 2024 20:25:43 +0100
|
||||
Subject: [PATCH] epyc-eda: added new profile for EDA compute workloads on AMD
|
||||
EPYC CPUs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
|
||||
---
|
||||
man/tuned-profiles.7 | 4 ++++
|
||||
profiles/epyc-eda/tuned.conf | 14 ++++++++++++++
|
||||
2 files changed, 18 insertions(+)
|
||||
create mode 100644 profiles/epyc-eda/tuned.conf
|
||||
|
||||
diff --git a/man/tuned-profiles.7 b/man/tuned-profiles.7
|
||||
index 10cad7b..600e8bb 100644
|
||||
--- a/man/tuned-profiles.7
|
||||
+++ b/man/tuned-profiles.7
|
||||
@@ -141,6 +141,10 @@ profiles (e.g. throughput\-performance profile), example:
|
||||
Profile optimized for AWS EC2 instances. It is based on the
|
||||
throughput\-performance profile.
|
||||
|
||||
+.TP
|
||||
+.BI "epyc-eda"
|
||||
+Profile optimized for EDA compute workloads on AMD EPYC CPUs.
|
||||
+
|
||||
.SH "FILES"
|
||||
.nf
|
||||
.I /etc/tuned/*
|
||||
diff --git a/profiles/epyc-eda/tuned.conf b/profiles/epyc-eda/tuned.conf
|
||||
new file mode 100644
|
||||
index 0000000..482d404
|
||||
--- /dev/null
|
||||
+++ b/profiles/epyc-eda/tuned.conf
|
||||
@@ -0,0 +1,14 @@
|
||||
+#
|
||||
+# tuned configuration
|
||||
+#
|
||||
+
|
||||
+[main]
|
||||
+summary=Optimize for EDA compute workloads on AMD EPYC CPUs
|
||||
+description=Configures virtual memory, CPU governors, and network settings for EDA compute workloads.
|
||||
+include=throughput-performance
|
||||
+
|
||||
+# AMD
|
||||
+[scheduler.amd]
|
||||
+type=scheduler
|
||||
+#Allow processes to rapidly move between cores to avoid idle time and maximize CPU usage
|
||||
+sched_migration_cost_ns=10000
|
||||
--
|
||||
2.44.0
|
||||
|
@ -1,28 +0,0 @@
|
||||
From 04ead944fdf640ed986331179e533542efc934c7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Jaroslav=20=C5=A0karvada?= <jskarvad@redhat.com>
|
||||
Date: Mon, 8 Apr 2024 11:03:47 +0200
|
||||
Subject: [PATCH] sap-netweaver: increased vm.max_map_count
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Resolves: RHEL-31757
|
||||
|
||||
Signed-off-by: Jaroslav Škarvada <jskarvad@redhat.com>
|
||||
---
|
||||
profiles/sap-netweaver/tuned.conf | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/profiles/sap-netweaver/tuned.conf b/profiles/sap-netweaver/tuned.conf
|
||||
index a1cfd17..81c4d44 100644
|
||||
--- a/profiles/sap-netweaver/tuned.conf
|
||||
+++ b/profiles/sap-netweaver/tuned.conf
|
||||
@@ -10,4 +10,4 @@ include=throughput-performance
|
||||
kernel.sem = 32000 1024000000 500 32000
|
||||
kernel.shmall = 18446744073692774399
|
||||
kernel.shmmax = 18446744073692774399
|
||||
-vm.max_map_count = 2000000
|
||||
+vm.max_map_count = 2147483647
|
||||
--
|
||||
2.44.0
|
||||
|
@ -1,97 +0,0 @@
|
||||
diff --git a/tuned/plugins/plugin_disk.py b/tuned/plugins/plugin_disk.py
|
||||
index 1438e35..d6feb06 100644
|
||||
--- a/tuned/plugins/plugin_disk.py
|
||||
+++ b/tuned/plugins/plugin_disk.py
|
||||
@@ -100,19 +100,20 @@ class DiskPlugin(hotplug.Plugin):
|
||||
self._devices_supported = True
|
||||
self._use_hdparm = True
|
||||
self._free_devices = set()
|
||||
- self._hdparm_apm_devices = set()
|
||||
+ self._hdparm_apm_device_support = dict()
|
||||
for device in self._hardware_inventory.get_devices("block"):
|
||||
if self._device_is_supported(device):
|
||||
self._free_devices.add(device.sys_name)
|
||||
- if self._use_hdparm and self._is_hdparm_apm_supported(device.sys_name):
|
||||
- self._hdparm_apm_devices.add(device.sys_name)
|
||||
-
|
||||
self._assigned_devices = set()
|
||||
|
||||
def _get_device_objects(self, devices):
|
||||
return [self._hardware_inventory.get_device("block", x) for x in devices]
|
||||
|
||||
def _is_hdparm_apm_supported(self, device):
|
||||
+ if not self._use_hdparm:
|
||||
+ return False
|
||||
+ if device in self._hdparm_apm_device_support:
|
||||
+ return self._hdparm_apm_device_support[device]
|
||||
(rc, out, err_msg) = self._cmd.execute(["hdparm", "-C", "/dev/%s" % device], \
|
||||
no_errors = [errno.ENOENT], return_err=True)
|
||||
if rc == -errno.ENOENT:
|
||||
@@ -122,10 +123,13 @@ class DiskPlugin(hotplug.Plugin):
|
||||
elif rc:
|
||||
log.info("Device '%s' not supported by hdparm" % device)
|
||||
log.debug("(rc: %s, msg: '%s')" % (rc, err_msg))
|
||||
+ self._hdparm_apm_device_support[device] = False
|
||||
return False
|
||||
elif "unknown" in out:
|
||||
log.info("Driver for device '%s' does not support apm command" % device)
|
||||
+ self._hdparm_apm_device_support[device] = False
|
||||
return False
|
||||
+ self._hdparm_apm_device_support[device] = True
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
@@ -232,7 +236,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
return not "standby" in out and not "sleeping" in out
|
||||
|
||||
def _instance_update_dynamic(self, instance, device):
|
||||
- if not device in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
return
|
||||
load = instance._load_monitor.get_device_load(device)
|
||||
if load is None:
|
||||
@@ -315,7 +319,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
# At the moment we support dynamic tuning just for devices compatible with hdparm apm commands
|
||||
# If in future will be added new functionality not connected to this command,
|
||||
# it is needed to change it here
|
||||
- if device not in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
log.info("There is no dynamic tuning available for device '%s' at time" % device)
|
||||
else:
|
||||
super(DiskPlugin, self)._instance_apply_dynamic(instance, device)
|
||||
@@ -350,7 +354,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
|
||||
@command_set("apm", per_device=True)
|
||||
def _set_apm(self, value, device, sim, remove):
|
||||
- if device not in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
if not sim:
|
||||
log.info("apm option is not supported for device '%s'" % device)
|
||||
return None
|
||||
@@ -366,7 +370,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
|
||||
@command_get("apm")
|
||||
def _get_apm(self, device, ignore_missing=False):
|
||||
- if device not in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
if not ignore_missing:
|
||||
log.info("apm option is not supported for device '%s'" % device)
|
||||
return None
|
||||
@@ -390,7 +394,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
|
||||
@command_set("spindown", per_device=True)
|
||||
def _set_spindown(self, value, device, sim, remove):
|
||||
- if device not in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
if not sim:
|
||||
log.info("spindown option is not supported for device '%s'" % device)
|
||||
return None
|
||||
@@ -406,7 +410,7 @@ class DiskPlugin(hotplug.Plugin):
|
||||
|
||||
@command_get("spindown")
|
||||
def _get_spindown(self, device, ignore_missing=False):
|
||||
- if device not in self._hdparm_apm_devices:
|
||||
+ if not self._is_hdparm_apm_supported(device):
|
||||
if not ignore_missing:
|
||||
log.info("spindown option is not supported for device '%s'" % device)
|
||||
return None
|
24
gating.yaml
Normal file
24
gating.yaml
Normal file
@ -0,0 +1,24 @@
|
||||
--- !Policy
|
||||
product_versions:
|
||||
- fedora-*
|
||||
decision_context: bodhi_update_push_testing
|
||||
subject_type: koji_build
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
|
||||
|
||||
#Rawhide
|
||||
--- !Policy
|
||||
product_versions:
|
||||
- fedora-*
|
||||
decision_context: bodhi_update_push_stable
|
||||
subject_type: koji_build
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
|
||||
|
||||
#gating rhel
|
||||
--- !Policy
|
||||
product_versions:
|
||||
- rhel-*
|
||||
decision_context: osci_compose_gate
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/all.functional}
|
6
plans/all.fmf
Normal file
6
plans/all.fmf
Normal file
@ -0,0 +1,6 @@
|
||||
summary: Test plan with all Fedora tests
|
||||
discover:
|
||||
how: fmf
|
||||
url: https://github.com/redhat-performance/tuned.git
|
||||
execute:
|
||||
how: tmt
|
1
sources
Normal file
1
sources
Normal file
@ -0,0 +1 @@
|
||||
SHA512 (tuned-2.25.1.tar.gz) = fa5ac9d818d11b118fb7c26db28993b704f590070edbece570fee1a6c60a1f5f850b711683c45b46f33d9b056a84e43ced2c4c1ee58e9ef3d1fd035a4c1d4de4
|
311
tuned-2.25.1-bootc-kargs.patch
Normal file
311
tuned-2.25.1-bootc-kargs.patch
Normal file
@ -0,0 +1,311 @@
|
||||
From 91cb383ad7339873da3480463061500a308ba825 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= <zacik.pa@gmail.com>
|
||||
Date: Fri, 31 Jan 2025 12:43:08 +0100
|
||||
Subject: [PATCH 1/2] bootloader: Simplify tuning of rpm-ostree kargs
|
||||
|
||||
The bootloader plugin claims that it does not mess
|
||||
with existing kernel parameters; make sure we adhere
|
||||
to that also for rpm-ostree systems:
|
||||
|
||||
1. Only append a new karg if the same key=value pair
|
||||
does not already appear in kernel parameters. If we would
|
||||
duplicate it, it would not be possible to determine which
|
||||
one to delete when unapplying the profile.
|
||||
|
||||
2. Do not delete existing key=value pairs when the profile
|
||||
adds a karg with another value for the key. A single key can
|
||||
appear multiple times in the kernel parameter list with different
|
||||
values.
|
||||
|
||||
Also make sure new kargs are added exactly in the order in which
|
||||
they appear in the profile. This is especially important for kargs
|
||||
related to hugepages.
|
||||
|
||||
Resolves: RHEL-45836
|
||||
---
|
||||
tuned/consts.py | 1 -
|
||||
tuned/plugins/plugin_bootloader.py | 142 +++++++++++------------------
|
||||
2 files changed, 53 insertions(+), 90 deletions(-)
|
||||
|
||||
diff --git a/tuned/consts.py b/tuned/consts.py
|
||||
index 577ad9583..a92c78060 100644
|
||||
--- a/tuned/consts.py
|
||||
+++ b/tuned/consts.py
|
||||
@@ -43,7 +43,6 @@
|
||||
INITRD_IMAGE_DIR = "/boot"
|
||||
BOOT_CMDLINE_TUNED_VAR = "TUNED_BOOT_CMDLINE"
|
||||
BOOT_CMDLINE_INITRD_ADD_VAR = "TUNED_BOOT_INITRD_ADD"
|
||||
-BOOT_CMDLINE_KARGS_DELETED_VAR = "TUNED_BOOT_KARGS_DELETED"
|
||||
BOOT_CMDLINE_FILE = "/etc/tuned/bootcmdline"
|
||||
PETITBOOT_DETECT_DIR = "/sys/firmware/opal"
|
||||
MACHINE_ID_FILE = "/etc/machine-id"
|
||||
diff --git a/tuned/plugins/plugin_bootloader.py b/tuned/plugins/plugin_bootloader.py
|
||||
index 4c66189fb..07a66d265 100644
|
||||
--- a/tuned/plugins/plugin_bootloader.py
|
||||
+++ b/tuned/plugins/plugin_bootloader.py
|
||||
@@ -209,24 +209,6 @@ def _get_config_options(cls):
|
||||
"skip_grub_config": None,
|
||||
}
|
||||
|
||||
- @staticmethod
|
||||
- def _options_to_dict(options, omit=""):
|
||||
- """
|
||||
- Returns dict created from options
|
||||
- e.g.: _options_to_dict("A=A A=B A B=A C=A", "A=B B=A B=B") returns {'A': ['A', None], 'C': ['A']}
|
||||
- """
|
||||
- d = {}
|
||||
- omit = omit.split()
|
||||
- for o in options.split():
|
||||
- if o not in omit:
|
||||
- arr = o.split('=', 1)
|
||||
- d.setdefault(arr[0], []).append(arr[1] if len(arr) > 1 else None)
|
||||
- return d
|
||||
-
|
||||
- @staticmethod
|
||||
- def _dict_to_options(d):
|
||||
- return " ".join([k + "=" + v1 if v1 is not None else k for k, v in d.items() for v1 in v])
|
||||
-
|
||||
def _rpm_ostree_status(self):
|
||||
"""
|
||||
Returns status of rpm-ostree transactions or None if not run on rpm-ostree system
|
||||
@@ -241,68 +223,45 @@ def _rpm_ostree_status(self):
|
||||
return None
|
||||
return splited[1]
|
||||
|
||||
- def _wait_till_idle(self):
|
||||
+ def _wait_till_rpm_ostree_idle(self):
|
||||
+ """Check that rpm-ostree is idle, allowing some waiting time."""
|
||||
sleep_cycles = 10
|
||||
sleep_secs = 1.0
|
||||
- for i in range(sleep_cycles):
|
||||
+ for _ in range(sleep_cycles):
|
||||
if self._rpm_ostree_status() == "idle":
|
||||
return True
|
||||
sleep(sleep_secs)
|
||||
- if self._rpm_ostree_status() == "idle":
|
||||
- return True
|
||||
- return False
|
||||
+ return self._rpm_ostree_status() == "idle"
|
||||
+
|
||||
+ def _get_rpm_ostree_kargs(self):
|
||||
+ """Retrieve the output of rpm-ostree kargs, i.e., current default kernel arguments."""
|
||||
+ if not self._wait_till_rpm_ostree_idle():
|
||||
+ log.error("Error getting rpm-ostree kargs: rpm-ostree is busy")
|
||||
+ return None
|
||||
+ (rc, out, err) = self._cmd.execute(["rpm-ostree", "kargs"], return_err=True)
|
||||
+ if out:
|
||||
+ log.debug("rpm-ostree kargs: %s" % out)
|
||||
+ if rc != 0:
|
||||
+ log.error("Error getting rpm-ostree kargs: %s" % err)
|
||||
+ return None
|
||||
+ return out
|
||||
|
||||
- def _rpm_ostree_kargs(self, append={}, delete={}):
|
||||
+ def _modify_rpm_ostree_kargs(self, delete_kargs=[], append_kargs=[]):
|
||||
"""
|
||||
- Method for appending or deleting rpm-ostree karg
|
||||
- returns None if rpm-ostree not present or is run on not ostree system
|
||||
- or tuple with new kargs, appended kargs and deleted kargs
|
||||
+ Modify (delete and append) kernel arguments in a rpm-ostree system.
|
||||
+ Return a boolean indicating whether the operation was successful.
|
||||
"""
|
||||
- (rc, out, err) = self._cmd.execute(['rpm-ostree', 'kargs'], return_err=True)
|
||||
- log.debug("rpm-ostree output stdout:\n%s\nstderr:\n%s" % (out, err))
|
||||
- if rc != 0:
|
||||
- return None, None, None
|
||||
- kargs = self._options_to_dict(out)
|
||||
-
|
||||
- if not self._wait_till_idle():
|
||||
- log.error("Cannot wait for transaction end")
|
||||
- return None, None, None
|
||||
-
|
||||
- deleted = {}
|
||||
- delete_params = self._dict_to_options(delete).split()
|
||||
- # Deleting kargs, e.g. deleting added kargs by profile
|
||||
- for k, val in delete.items():
|
||||
- for v in val:
|
||||
- kargs[k].remove(v)
|
||||
- deleted[k] = val
|
||||
-
|
||||
- appended = {}
|
||||
- append_params = self._dict_to_options(append).split()
|
||||
- # Appending kargs, e.g. new kargs by profile or restoring kargs replaced by profile
|
||||
- for k, val in append.items():
|
||||
- if kargs.get(k):
|
||||
- # If there is karg that we add with new value we want to delete it
|
||||
- # and store old value for restoring after profile unload
|
||||
- log.debug("adding rpm-ostree kargs %s: %s for delete" % (k, kargs[k]))
|
||||
- deleted.setdefault(k, []).extend(kargs[k])
|
||||
- delete_params.extend([k + "=" + v if v is not None else k for v in kargs[k]])
|
||||
- kargs[k] = []
|
||||
- kargs.setdefault(k, []).extend(val)
|
||||
- appended[k] = val
|
||||
-
|
||||
- if append_params == delete_params:
|
||||
- log.info("skipping rpm-ostree kargs - append == deleting (%s)" % append_params)
|
||||
- return kargs, appended, deleted
|
||||
-
|
||||
- log.info("rpm-ostree kargs - appending: '%s'; deleting: '%s'" % (append_params, delete_params))
|
||||
- (rc, _, err) = self._cmd.execute(['rpm-ostree', 'kargs'] +
|
||||
- ['--append=%s' % v for v in append_params] +
|
||||
- ['--delete=%s' % v for v in delete_params], return_err=True)
|
||||
+ if not self._wait_till_rpm_ostree_idle():
|
||||
+ log.error("Error modifying rpm-ostree kargs: rpm-ostree is busy")
|
||||
+ return False
|
||||
+ (rc, _, err) = self._cmd.execute(
|
||||
+ ["rpm-ostree", "kargs"] +
|
||||
+ ["--delete=%s" % karg for karg in delete_kargs] +
|
||||
+ ["--append=%s" % karg for karg in append_kargs], return_err=True)
|
||||
if rc != 0:
|
||||
- log.error("Something went wrong with rpm-ostree kargs\n%s" % (err))
|
||||
- return self._options_to_dict(out), None, None
|
||||
- else:
|
||||
- return kargs, appended, deleted
|
||||
+ log.error("Error modifying rpm-ostree kargs: %s" % err)
|
||||
+ return False
|
||||
+ return True
|
||||
|
||||
def _get_effective_options(self, options):
|
||||
"""Merge provided options with plugin default options and merge all cmdline.* options."""
|
||||
@@ -368,18 +327,16 @@ def _remove_grub2_tuning(self):
|
||||
log.info("removing initrd image '%s'" % self._initrd_dst_img_val)
|
||||
self._cmd.unlink(self._initrd_dst_img_val)
|
||||
|
||||
- def _get_rpm_ostree_changes(self):
|
||||
+ def _get_appended_rpm_ostree_kargs(self):
|
||||
+ """Return the list of kernel arguments that were appended by this profile (in a rpm-ostree system)."""
|
||||
f = self._cmd.read_file(consts.BOOT_CMDLINE_FILE)
|
||||
appended = re.search(consts.BOOT_CMDLINE_TUNED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
|
||||
- appended = appended[1] if appended else ""
|
||||
- deleted = re.search(consts.BOOT_CMDLINE_KARGS_DELETED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE)
|
||||
- deleted = deleted[1] if deleted else ""
|
||||
- return appended, deleted
|
||||
+ return appended[1].split() if appended else []
|
||||
|
||||
def _remove_rpm_ostree_tuning(self):
|
||||
- appended, deleted = self._get_rpm_ostree_changes()
|
||||
- self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended))
|
||||
- self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""})
|
||||
+ """Remove kernel parameter tuning in a rpm-ostree system."""
|
||||
+ self._modify_rpm_ostree_kargs(delete_kargs=self._get_appended_rpm_ostree_kargs())
|
||||
+ self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: ""})
|
||||
|
||||
def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
|
||||
if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
|
||||
@@ -489,14 +446,22 @@ def _grub2_cfg_patch(self, d):
|
||||
return True
|
||||
|
||||
def _rpm_ostree_update(self):
|
||||
- appended, _ = self._get_rpm_ostree_changes()
|
||||
- _cmdline_dict = self._options_to_dict(self._cmdline_val, appended)
|
||||
- if not _cmdline_dict:
|
||||
- return None
|
||||
- (_, _, d) = self._rpm_ostree_kargs(append=_cmdline_dict)
|
||||
- if d is None:
|
||||
+ """Apply kernel parameter tuning in a rpm-ostree system."""
|
||||
+ if self._get_appended_rpm_ostree_kargs():
|
||||
+ # The kargs are already set in /etc/tuned/bootcmldine,
|
||||
+ # we are likely post-reboot and done.
|
||||
+ return
|
||||
+ profile_kargs = self._cmdline_val.split()
|
||||
+ active_kargs = self._get_rpm_ostree_kargs()
|
||||
+ if active_kargs is None:
|
||||
+ log.error("Not updating kernel arguments, could not read the current ones.")
|
||||
return
|
||||
- self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : self._cmdline_val, consts.BOOT_CMDLINE_KARGS_DELETED_VAR : self._dict_to_options(d)})
|
||||
+ # Only append key=value pairs that do not yet appear in kernel parameters,
|
||||
+ # otherwise we would not be able to restore the cmdline to the previous state
|
||||
+ # via rpm-ostree kargs --delete.
|
||||
+ kargs_to_append = [karg for karg in profile_kargs if karg not in active_kargs.split()]
|
||||
+ if self._modify_rpm_ostree_kargs(append_kargs=kargs_to_append):
|
||||
+ self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)})
|
||||
|
||||
def _grub2_update(self):
|
||||
self._grub2_cfg_patch({consts.GRUB2_TUNED_VAR : self._cmdline_val, consts.GRUB2_TUNED_INITRD_VAR : self._initrd_val})
|
||||
@@ -646,11 +611,10 @@ def _cmdline(self, enabling, value, verify, ignore_missing, instance):
|
||||
v = self._variables.expand(self._cmd.unquote(value))
|
||||
if verify:
|
||||
if self._rpm_ostree:
|
||||
- rpm_ostree_kargs = self._rpm_ostree_kargs()[0]
|
||||
- cmdline = self._dict_to_options(rpm_ostree_kargs)
|
||||
+ cmdline = self._get_rpm_ostree_kargs()
|
||||
else:
|
||||
cmdline = self._cmd.read_file("/proc/cmdline")
|
||||
- if len(cmdline) == 0:
|
||||
+ if cmdline is None or len(cmdline) == 0:
|
||||
return None
|
||||
cmdline_set = set(cmdline.split())
|
||||
value_set = set(v.split())
|
||||
|
||||
From 3e05cb783ee10ea78efb113c54bd2ad7d73a0e2e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= <zacik.pa@gmail.com>
|
||||
Date: Fri, 16 May 2025 15:13:25 +0200
|
||||
Subject: [PATCH 2/2] bootloader: Remove previously appended rpm-ostree kargs
|
||||
|
||||
If TuneD-appended kargs are present and do not match
|
||||
the kargs to be appended, we should remove them. This
|
||||
can happen if there was no profile rollback, e.g.,
|
||||
when using the no-daemon mode.
|
||||
|
||||
Resolves: RHEL-86814
|
||||
---
|
||||
tuned/plugins/plugin_bootloader.py | 24 ++++++++++++++++--------
|
||||
1 file changed, 16 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/tuned/plugins/plugin_bootloader.py b/tuned/plugins/plugin_bootloader.py
|
||||
index 07a66d265..2711e116f 100644
|
||||
--- a/tuned/plugins/plugin_bootloader.py
|
||||
+++ b/tuned/plugins/plugin_bootloader.py
|
||||
@@ -105,7 +105,7 @@ class BootloaderPlugin(base.Plugin):
|
||||
----
|
||||
[main]
|
||||
include=profile_1
|
||||
-
|
||||
+
|
||||
[bootloader]
|
||||
cmdline_profile_2=-quiet
|
||||
----
|
||||
@@ -114,7 +114,7 @@ class BootloaderPlugin(base.Plugin):
|
||||
----
|
||||
[main]
|
||||
include=profile_1
|
||||
-
|
||||
+
|
||||
[bootloader]
|
||||
cmdline_profile_1=-quiet
|
||||
----
|
||||
@@ -447,20 +447,28 @@ def _grub2_cfg_patch(self, d):
|
||||
|
||||
def _rpm_ostree_update(self):
|
||||
"""Apply kernel parameter tuning in a rpm-ostree system."""
|
||||
- if self._get_appended_rpm_ostree_kargs():
|
||||
- # The kargs are already set in /etc/tuned/bootcmldine,
|
||||
- # we are likely post-reboot and done.
|
||||
- return
|
||||
+ appended_kargs = self._get_appended_rpm_ostree_kargs()
|
||||
profile_kargs = self._cmdline_val.split()
|
||||
active_kargs = self._get_rpm_ostree_kargs()
|
||||
if active_kargs is None:
|
||||
log.error("Not updating kernel arguments, could not read the current ones.")
|
||||
return
|
||||
+ # Ignore kargs previously appended by TuneD, these will be removed later.
|
||||
+ non_tuned_kargs = active_kargs.split()
|
||||
+ for karg in appended_kargs:
|
||||
+ non_tuned_kargs.remove(karg)
|
||||
# Only append key=value pairs that do not yet appear in kernel parameters,
|
||||
# otherwise we would not be able to restore the cmdline to the previous state
|
||||
# via rpm-ostree kargs --delete.
|
||||
- kargs_to_append = [karg for karg in profile_kargs if karg not in active_kargs.split()]
|
||||
- if self._modify_rpm_ostree_kargs(append_kargs=kargs_to_append):
|
||||
+ kargs_to_append = [karg for karg in profile_kargs if karg not in non_tuned_kargs]
|
||||
+ if appended_kargs == kargs_to_append:
|
||||
+ # The correct kargs are already set in /etc/tuned/bootcmldine,
|
||||
+ # we are likely post-reboot and done.
|
||||
+ log.info("Kernel arguments already set, not updating.")
|
||||
+ return
|
||||
+ # If there are kargs in /etc/bootcmdline and they do not match
|
||||
+ # the requested ones, there was no rollback, so remove them now.
|
||||
+ if self._modify_rpm_ostree_kargs(delete_kargs=appended_kargs, append_kargs=kargs_to_append):
|
||||
self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)})
|
||||
|
||||
def _grub2_update(self):
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user