diff --git a/Makefile b/Makefile
index e10d5f2c3..075306161 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ REV=$(shell git describe --long --tags --match='v*' --always --dirty)
# Upstream tuned daemon variables
TUNED_REPO:=https://github.com/redhat-performance/tuned.git
-TUNED_COMMIT:=850368d2f89681725e9bd5eb2dfb44ad2226bc73
+TUNED_COMMIT:=954bc4624db8fb345e9fb264ee2ac09d1736105a
TUNED_DIR:=daemon
# API-related variables
diff --git a/assets/tuned/daemon/com.redhat.tuned.policy b/assets/tuned/daemon/com.redhat.tuned.policy
index 824ae0c80..8bee088b8 100644
--- a/assets/tuned/daemon/com.redhat.tuned.policy
+++ b/assets/tuned/daemon/com.redhat.tuned.policy
@@ -227,4 +227,24 @@
+
+ Get list of active TuneD plugin instances
+ Authentication is required to get list of active TuneD plugin instances
+
+ yes
+ yes
+ yes
+
+
+
+
+ Get list of devices assigned to the instance
+ Authentication is required to get list of devices assigned to the instance
+
+ yes
+ yes
+ yes
+
+
+
diff --git a/assets/tuned/daemon/man/tuned-adm.8 b/assets/tuned/daemon/man/tuned-adm.8
index 4ede4f363..f29966d3e 100644
--- a/assets/tuned/daemon/man/tuned-adm.8
+++ b/assets/tuned/daemon/man/tuned-adm.8
@@ -24,7 +24,7 @@
tuned\-adm - command line tool for switching between different tuning profiles
.SH SYNOPSIS
.B tuned\-adm
-.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend ]
+.RB [ list " | " active " | " "profile \fI[profile]\fP..." " | " "profile_info \fI[profile]\fP..." " | " off " | " auto_profile " | " profile_mode " | " "verify \fI[\-i | \-\-ignore\-missing]\fP" " | " recommend " | " "instance_acquire_devices \fIdevices\fP \fIinstance\fP" " | " "get_instances \fI[plugin]\fP" " | " "instance_get_devices \fIinstance\fP" ]
.SH DESCRIPTION
This command line utility allows you to switch between user definable tuning
@@ -110,6 +110,23 @@ Enable automatic profile selection mode, switch to the recommended profile.
.B profile_mode
Show current profile selection mode.
+.TP
+.B "instance_acquire_devices \fIdevices\fP \fIinstance\fP"
+Move all provided \fIdevices\fP under the given plugin \fIinstance\fP. The plugin
+instance is identified using its name from the TuneD profile.
+
+The devices are specified using a comma-separated list. When moving a set of CPUs,
+it is possible to use the cpulist syntax by including the 'cpulist:' prefix.
+For instance, 'cpulist:0,2-4' will move the devices cpu0, cpu1, cpu2, and cpu4.
+
+.TP
+.B "get_instances \fI[plugin]\fP"
+List active instances of a given plugin or all active instances if no plugin is specified.
+
+.TP
+.B "instance_get_devices \fIinstance\fP"
+List devices currently assigned to a given instance.
+
.TP
.B off
Unload tunings.
diff --git a/assets/tuned/daemon/profiles/cpu-partitioning/tuned.conf b/assets/tuned/daemon/profiles/cpu-partitioning/tuned.conf
index 979e40bfa..11f03cfbc 100644
--- a/assets/tuned/daemon/profiles/cpu-partitioning/tuned.conf
+++ b/assets/tuned/daemon/profiles/cpu-partitioning/tuned.conf
@@ -37,12 +37,6 @@ assert2=${f:assertion:isolated_cores contains online CPU(s):${isolated_cores_exp
cmd_isolcpus=${f:regex_search_ternary:${no_balance_cores}:\s*[0-9]: isolcpus=${no_balance_cores}:}
-[sysctl]
-kernel.hung_task_timeout_secs = 600
-kernel.nmi_watchdog = 0
-vm.stat_interval = 10
-kernel.timer_migration = 0
-
[sysfs]
/sys/bus/workqueue/devices/writeback/cpumask = ${not_isolated_cpumask}
/sys/devices/virtual/workqueue/cpumask = ${not_isolated_cpumask}
diff --git a/assets/tuned/daemon/profiles/functions b/assets/tuned/daemon/profiles/functions
index bfd3d57a2..9dd3bd91b 100644
--- a/assets/tuned/daemon/profiles/functions
+++ b/assets/tuned/daemon/profiles/functions
@@ -566,7 +566,7 @@ disable_ksm()
die "failed to create $KSM_MASK_FILE"
fi
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
- systemctl cat -- $KSM_SERVICES &> /dev/null || return
+ systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
systemctl --now --quiet mask $KSM_SERVICES
# Unmerge all shared pages
test -f $KSM_RUN_PATH && echo 2 > $KSM_RUN_PATH
@@ -578,7 +578,7 @@ enable_ksm()
{
if [ -f $KSM_MASK_FILE ]; then
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
- systemctl cat -- $KSM_SERVICES &> /dev/null || return
+ systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
if systemctl --quiet unmask $KSM_SERVICES; then
rm -f $KSM_MASK_FILE
fi
diff --git a/assets/tuned/daemon/profiles/network-latency/tuned.conf b/assets/tuned/daemon/profiles/network-latency/tuned.conf
index 05df96bd0..99df160da 100644
--- a/assets/tuned/daemon/profiles/network-latency/tuned.conf
+++ b/assets/tuned/daemon/profiles/network-latency/tuned.conf
@@ -14,6 +14,12 @@ net.core.busy_read=50
net.core.busy_poll=50
net.ipv4.tcp_fastopen=3
kernel.numa_balancing=0
+kernel.hung_task_timeout_secs = 600
+kernel.nmi_watchdog = 0
+vm.stat_interval = 10
+kernel.timer_migration = 0
[bootloader]
-cmdline_network_latency=skew_tick=1
+cmdline_network_latency=skew_tick=1 tsc=reliable rcupdate.rcu_normal_after_boot=1
+
+[rtentsk]
diff --git a/assets/tuned/daemon/profiles/realtime-virtual-guest/tuned.conf b/assets/tuned/daemon/profiles/realtime-virtual-guest/tuned.conf
index a381f4136..01c3ae163 100644
--- a/assets/tuned/daemon/profiles/realtime-virtual-guest/tuned.conf
+++ b/assets/tuned/daemon/profiles/realtime-virtual-guest/tuned.conf
@@ -38,11 +38,6 @@ group.ktimersoftd=0:f:3:*:^\[ktimersoftd
ps_blacklist=^\[ksoftirqd;^\[ktimers;^\[rcuc;^\[rcub;^\[ktimersoftd
-[sysfs]
-# Perform lockless check for timer softirq on isolated CPUs.
-#
-/sys/kernel/ktimer_lockless_check = 1
-
[script]
script=${i:PROFILE_DIR}/script.sh
diff --git a/assets/tuned/daemon/profiles/realtime-virtual-host/tuned.conf b/assets/tuned/daemon/profiles/realtime-virtual-host/tuned.conf
index b0e8846cc..be8d2dfc4 100644
--- a/assets/tuned/daemon/profiles/realtime-virtual-host/tuned.conf
+++ b/assets/tuned/daemon/profiles/realtime-virtual-host/tuned.conf
@@ -51,10 +51,6 @@ ps_blacklist=^\[ksoftirqd;^\[ktimers;^\[rcuc;^\[rcub;^\[ktimersoftd;pmd;PMD;^DPD
# 2: stop ksmd, unmerge all pages
/sys/kernel/mm/ksm/run = 2
-# Perform lockless check for timer softirq on isolated CPUs.
-#
-/sys/kernel/ktimer_lockless_check = 1
-
[script]
script=${i:PROFILE_DIR}/script.sh
diff --git a/assets/tuned/daemon/profiles/realtime/tuned.conf b/assets/tuned/daemon/profiles/realtime/tuned.conf
index 196ed01be..218402887 100644
--- a/assets/tuned/daemon/profiles/realtime/tuned.conf
+++ b/assets/tuned/daemon/profiles/realtime/tuned.conf
@@ -39,11 +39,7 @@ managed_irq=${f:regex_search_ternary:${isolate_managed_irq}:\b[y,Y,1,t,T]\b:mana
channels=combined ${f:check_net_queue_count:${netdev_queue_count}}
[sysctl]
-kernel.hung_task_timeout_secs = 600
-kernel.nmi_watchdog = 0
kernel.sched_rt_runtime_us = -1
-vm.stat_interval = 10
-kernel.timer_migration = 0
[sysfs]
/sys/bus/workqueue/devices/writeback/cpumask = ${not_isolated_cpumask}
@@ -52,7 +48,7 @@ kernel.timer_migration = 0
/sys/devices/system/machinecheck/machinecheck*/ignore_ce = 1
[bootloader]
-cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} intel_pstate=disable nosoftlockup tsc=reliable
+cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} intel_pstate=disable nosoftlockup
[irqbalance]
banned_cpus=${isolated_cores}
@@ -62,5 +58,3 @@ script = ${i:PROFILE_DIR}/script.sh
[scheduler]
isolated_cores=${isolated_cores}
-
-[rtentsk]
diff --git a/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/main.fmf b/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/main.fmf
index 7fdcf23e4..9139f75de 100644
--- a/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/main.fmf
+++ b/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/main.fmf
@@ -8,3 +8,5 @@ relevancy: |
distro = rhel-4, rhel-5, rhel-6: False
summary: Test for BZ#1688371 (Program tuned tried to access /dev/mem between)
framework: beakerlib
+require:
+ - library(tuned/basic)
diff --git a/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/runtest.sh b/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/runtest.sh
index c80eff953..cdb221246 100755
--- a/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/Program-tuned-tried-to-access-dev-mem-between/runtest.sh
@@ -24,6 +24,9 @@ rlJournalStart
rlAssertRpm $PACKAGE
rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory"
rlRun "pushd $TmpDir"
+ rlImport "tuned/basic"
+
+ tunedDisableSystemdRateLimitingStart
rlServiceStop "tuned"
# systemd can have some issues with quick restarts sometimes
sleep 1
@@ -36,6 +39,7 @@ rlJournalStart
rlPhaseEnd
rlPhaseStartCleanup
+ tunedDisableSystemdRateLimitingEnd
rlRun "popd"
rlRun "rm -r $TmpDir" 0 "Removing tmp directory"
rlServiceRestore "tuned"
diff --git a/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/main.fmf b/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/main.fmf
index 313fd21aa..60e71b872 100644
--- a/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/main.fmf
+++ b/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/main.fmf
@@ -8,3 +8,8 @@ relevancy: |
distro = rhel-4, rhel-5, rhel-6: False
summary: Test for BZ#1663412 (TuneD takes too long to reload/start when \"ulimit)
framework: beakerlib
+require:
+ - library(tuned/basic)
+recommend:
+ - psmisc
+ - tuned
diff --git a/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/runtest.sh b/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/runtest.sh
index 906bf8794..327f3fb79 100755
--- a/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/Tuned-takes-too-long-to-reload-start-when-ulimit/runtest.sh
@@ -22,6 +22,8 @@ PACKAGE="tuned"
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
+ rlImport "tuned/basic"
+ tunedDisableSystemdRateLimitingStart
rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory"
rlRun "pushd $TmpDir"
rlServiceStop "tuned"
@@ -41,6 +43,11 @@ rlJournalStart
rlRun "popd"
rlRun "rm -r $TmpDir" 0 "Removing tmp directory"
+ killall tuned
+ rlRun "sleep 3"
+ killall tuned
+
+ tunedDisableSystemdRateLimitingEnd
rlFileRestore
rlServiceRestore "tuned"
rlPhaseEnd
diff --git a/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/main.fmf b/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/main.fmf
index eb283d265..e869e106f 100644
--- a/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/main.fmf
+++ b/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/main.fmf
@@ -7,7 +7,8 @@ contact:
component:
- tuned
require:
-- tuned
+ - tuned
+ - library(tuned/basic)
duration: 5m
extra-task: /CoreOS/tuned/Regression/bz1798183-RFE-support-post-loaded-profile
framework: beakerlib
diff --git a/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/runtest.sh b/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/runtest.sh
index 2e7d8d727..5b871c79a 100755
--- a/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/runtest.sh
@@ -61,6 +61,8 @@ function wait_for_tuned_stop()
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
+ rlImport "tuned/basic"
+ tunedDisableSystemdRateLimitingStart
rlRun "for PYTHON in $PYTHON_CHECK; do \$PYTHON --version 2>/dev/null && break; done" 0 "Detect python"
rlRun "rlFileBackup --clean $PROFILE_DIR"
rlRun "cp -r parent $PROFILE_DIR"
@@ -259,6 +261,7 @@ rlJournalStart
rlPhaseEnd
rlPhaseStartCleanup
+ tunedDisableSystemdRateLimitingEnd
rlRun "popd"
rlRun "rm -r $TmpDir" 0 "Removing tmp directory"
rlRun "rlFileRestore"
diff --git a/assets/tuned/daemon/tests/beakerlib/error-messages/main.fmf b/assets/tuned/daemon/tests/beakerlib/error-messages/main.fmf
index e36ebb365..0ca7a3fe4 100644
--- a/assets/tuned/daemon/tests/beakerlib/error-messages/main.fmf
+++ b/assets/tuned/daemon/tests/beakerlib/error-messages/main.fmf
@@ -8,3 +8,5 @@ relevancy: |
distro = rhel-4, rhel-5: False
summary: Test for BZ#1416712 (TuneD logs error message if)
framework: beakerlib
+require:
+ - library(tuned/basic)
diff --git a/assets/tuned/daemon/tests/beakerlib/error-messages/runtest.sh b/assets/tuned/daemon/tests/beakerlib/error-messages/runtest.sh
index 752c949b8..12b352956 100755
--- a/assets/tuned/daemon/tests/beakerlib/error-messages/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/error-messages/runtest.sh
@@ -23,30 +23,32 @@ rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
rlImport "tuned/basic"
+ tunedDisableSystemdRateLimitingStart
rlServiceStart "tuned"
tunedProfileBackup
rlPhaseEnd
rlPhaseStartTest "Test of profile balanced"
- rlRun "cat /usr/lib/tuned/balanced/tuned.conf | grep alpm="
- echo > /var/log/tuned/tuned.log
- rlRun "tuned-adm profile balanced"
- rlRun "tuned-adm active | grep balanced"
- rlRun "cat /var/log/tuned/tuned.log | grep -v 'ERROR tuned.utils.commands: Reading /sys/class/scsi_host/host0/link_power_management_policy'"
- rlRun "cat /var/log/tuned/tuned.log | grep -v 'WARNING tuned.plugins.plugin_scsi_host: ALPM control file'"
+ rlRun "cat /usr/lib/tuned/balanced/tuned.conf | grep alpm="
+ echo > /var/log/tuned/tuned.log
+ rlRun "tuned-adm profile balanced"
+ rlRun "tuned-adm active | grep balanced"
+ rlRun "cat /var/log/tuned/tuned.log | grep -v 'ERROR tuned.utils.commands: Reading /sys/class/scsi_host/host0/link_power_management_policy'"
+ rlRun "cat /var/log/tuned/tuned.log | grep -v 'WARNING tuned.plugins.plugin_scsi_host: ALPM control file'"
rlPhaseEnd
rlPhaseStartTest "Test of profile powersave"
- rlRun "cat /usr/lib/tuned/powersave/tuned.conf | grep alpm="
- echo > /var/log/tuned/tuned.log
- rlRun "tuned-adm profile powersave"
- rlRun "tuned-adm active | grep powersave"
- rlRun "cat /var/log/tuned/tuned.log | grep -v 'ERROR tuned.utils.commands: Reading /sys/class/scsi_host/host0/link_power_management_policy'"
- rlRun "cat /var/log/tuned/tuned.log | grep -v 'WARNING tuned.plugins.plugin_scsi_host: ALPM control file'"
+ rlRun "cat /usr/lib/tuned/powersave/tuned.conf | grep alpm="
+ echo > /var/log/tuned/tuned.log
+ rlRun "tuned-adm profile powersave"
+ rlRun "tuned-adm active | grep powersave"
+ rlRun "cat /var/log/tuned/tuned.log | grep -v 'ERROR tuned.utils.commands: Reading /sys/class/scsi_host/host0/link_power_management_policy'"
+ rlRun "cat /var/log/tuned/tuned.log | grep -v 'WARNING tuned.plugins.plugin_scsi_host: ALPM control file'"
rlPhaseEnd
rlPhaseStartCleanup
- tunedProfileRestore
+ tunedDisableSystemdRateLimitingEnd
+ tunedProfileRestore
rlPhaseEnd
rlJournalPrintText
rlJournalEnd
diff --git a/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/main.fmf b/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/main.fmf
index 550b40833..dd048bbaa 100644
--- a/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/main.fmf
+++ b/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/main.fmf
@@ -8,3 +8,5 @@ relevancy: |
distro < rhel-7.3: False
summary: Check functionality of tuned-adm tool.
framework: beakerlib
+require:
+ - library(tuned/basic)
diff --git a/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/runtest.sh b/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/runtest.sh
index 922fd5bdf..d5bf50f0e 100755
--- a/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/tuned-adm-functionality/runtest.sh
@@ -25,6 +25,7 @@ rlJournalStart
rlAssertRpm $PACKAGE
rlImport "tuned/basic"
tunedProfileBackup
+ tunedDisableSystemdRateLimitingStart
rlPhaseEnd
rlPhaseStartTest "Test tuned-adm LIST"
@@ -82,6 +83,7 @@ rlJournalStart
rlPhaseEnd
rlPhaseStartCleanup
+ tunedDisableSystemdRateLimitingEnd
tunedProfileRestore
rlServiceRestore "tuned"
rlPhaseEnd
diff --git a/assets/tuned/daemon/tests/beakerlib/variables-support-in-profiles/runtest.sh b/assets/tuned/daemon/tests/beakerlib/variables-support-in-profiles/runtest.sh
index b3000b98a..155c75965 100755
--- a/assets/tuned/daemon/tests/beakerlib/variables-support-in-profiles/runtest.sh
+++ b/assets/tuned/daemon/tests/beakerlib/variables-support-in-profiles/runtest.sh
@@ -22,11 +22,8 @@ PACKAGE="tuned"
rlJournalStart
rlPhaseStartSetup
rlAssertRpm $PACKAGE
- rlFileBackup --clean /etc/systemd/system.conf.d
- rlRun "mkdir -p /etc/systemd/system.conf.d"
- rlRun "echo -e '[Manager]\nDefaultStartLimitInterval=0' > /etc/systemd/system.conf.d/tuned.conf" 0 "Disable systemd rate limiting"
- rlRun "systemctl daemon-reload"
rlImport "tuned/basic"
+ rlRun "tunedDisableSystemdRateLimitingStart"
rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory"
rlRun "pushd $TmpDir"
rlServiceStart "tuned"
@@ -56,6 +53,7 @@ vm.swappiness = \${SWAPPINESS2}
rlPhaseStartCleanup
rlRun "sysctl vm.swappiness=$OLD_SWAPPINESS"
+ tunedDisableSystemdRateLimitingEnd
rlFileRestore
tunedProfileRestore
rlServiceRestore "tuned"
diff --git a/assets/tuned/daemon/tests/unit/plugins/test_base.py b/assets/tuned/daemon/tests/unit/plugins/test_base.py
index fdbf6cf4e..9fe77900c 100644
--- a/assets/tuned/daemon/tests/unit/plugins/test_base.py
+++ b/assets/tuned/daemon/tests/unit/plugins/test_base.py
@@ -211,7 +211,7 @@ def _get_config_options(self):
return {'size':'S','device_setting':'101'}
@decorators.command_set('size')
- def _set_size(self, new_size, sim):
+ def _set_size(self, new_size, sim, remove):
self._size = new_size
return new_size
@@ -220,7 +220,7 @@ def _get_size(self):
return self._size
@decorators.command_set('device_setting',per_device = True)
- def _set_device_setting(self,value,device,sim):
+ def _set_device_setting(self,value,device,sim,remove):
device.setting = value
return device.setting
diff --git a/assets/tuned/daemon/tuned-adm.py b/assets/tuned/daemon/tuned-adm.py
index fcf19e214..712e7da98 100755
--- a/assets/tuned/daemon/tuned-adm.py
+++ b/assets/tuned/daemon/tuned-adm.py
@@ -97,6 +97,19 @@ def check_log_level(value):
parser_profile_mode = subparsers.add_parser("profile_mode", help="show current profile selection mode")
parser_profile_mode.set_defaults(action="profile_mode")
+ parser_instance_acquire_devices = subparsers.add_parser("instance_acquire_devices", help="acquire devices from other instances and assign them to the given instance")
+ parser_instance_acquire_devices.set_defaults(action="instance_acquire_devices")
+ parser_instance_acquire_devices.add_argument("devices", metavar="devices", type=str, help="comma-separated list of device names; may use the cpulist syntax if prefixed with 'cpulist:'")
+ parser_instance_acquire_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance which should acquire the devices")
+
+ parser_get_instances = subparsers.add_parser("get_instances", help="list active instances of a given plugin or all active instances if no plugin is specified")
+ parser_get_instances.set_defaults(action="get_instances")
+ parser_get_instances.add_argument("plugin_name", metavar="plugin_name", type=str, nargs="?", default="", help="name of the plugin to restrict the list of instances to")
+
+ parser_instance_get_devices = subparsers.add_parser("instance_get_devices", help="list devices assigned to a given instance")
+ parser_instance_get_devices.set_defaults(action="instance_get_devices")
+ parser_instance_get_devices.add_argument("instance", metavar="instance", type=str, help="name of the plugin instance")
+
args = parser.parse_args(sys.argv[1:])
options = vars(args)
diff --git a/assets/tuned/daemon/tuned-gui.glade b/assets/tuned/daemon/tuned-gui.glade
index 6409663e7..d56bd328c 100644
--- a/assets/tuned/daemon/tuned-gui.glade
+++ b/assets/tuned/daemon/tuned-gui.glade
@@ -134,6 +134,137 @@
buttonCancel1
+
+
False
dialog
@@ -230,6 +361,99 @@
buttonCloseAddPlugin
+
+ False
+ dialog
+
+
+ False
+ vertical
+ 2
+
+
+ False
+ end
+
+
+ gtk-add
+ True
+ True
+ True
+ True
+ 0.40999999642372131
+ 0.60000002384185791
+ bottom
+
+
+ False
+ True
+ 0
+
+
+
+
+ gtk-cancel
+ True
+ True
+ True
+ True
+
+
+ False
+ True
+ 1
+
+
+
+
+ False
+ True
+ end
+ 0
+
+
+
+
+ True
+ False
+ vertical
+
+
+ True
+ False
+ Choose plugin value to add:
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+
+
+ False
+ True
+ 1
+
+
+
+
+ False
+ True
+ 1
+
+
+
+
+
+ button1
+ button2
+
+
False
dialog
@@ -1561,6 +1785,8 @@
False
+ 600
+ 500
@@ -1601,7 +1827,7 @@
- False
+ True
True
1
diff --git a/assets/tuned/daemon/tuned-gui.py b/assets/tuned/daemon/tuned-gui.py
index 4826d6ff1..da591e78b 100755
--- a/assets/tuned/daemon/tuned-gui.py
+++ b/assets/tuned/daemon/tuned-gui.py
@@ -41,7 +41,7 @@
"to be installed.")
try:
- from gi.repository import Gtk, GObject
+ from gi.repository import Gtk, GObject, GLib
except ImportError:
raise ImportError("Gtk3 backend requires pygobject to be installed.")
@@ -116,8 +116,8 @@ def __init__(self):
self.builder = Gtk.Builder()
try:
self.builder.add_from_file(GLADEUI)
- except GObject.GError as e:
- print("Error loading '%s'" % GLADEUI, file=sys.stderr)
+ except GLib.GError as e:
+ print("Error loading '%s', error: '%s'" % (GLADEUI, e), file=sys.stderr)
sys.exit(1)
#
@@ -249,14 +249,14 @@ def data_for_listbox_summary_of_active_profile(self):
self.manager.get_profile(self.controller.active_profile())
else:
self.active_profile = None
- self._gobj('summaryProfileName').set_text(self.active_profile.name)
+ try:
+ self._gobj('summaryProfileName').set_text(self.active_profile.name)
+ except AttributeError:
+ self.error_dialog('No active profile set', '')
try:
self._gobj('summaryIncludedProfileName').set_text(self.active_profile.options['include'
])
- except:
-
- # keyerror probably
-
+ except (AttributeError, KeyError):
self._gobj('summaryIncludedProfileName').set_text('None')
row = Gtk.ListBoxRow()
@@ -275,32 +275,33 @@ def data_for_listbox_summary_of_active_profile(self):
self._gobj('listboxSummaryOfActiveProfile').add(sep)
sep.show()
- for u in self.active_profile.units:
- row = Gtk.ListBoxRow()
- hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
- spacing=0)
- hbox.set_homogeneous(True)
- row.add(hbox)
- label = Gtk.Label()
- label.set_markup(u)
- label.set_justify(Gtk.Justification.LEFT)
- hbox.pack_start(label, False, True, 1)
-
- grid = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
- spacing=0)
- grid.set_homogeneous(True)
- for o in self.active_profile.units[u].options:
- label_option = Gtk.Label()
- label_option.set_markup(o + ' = ' + ''
- + self.active_profile.units[u].options[o]
- + '')
- grid.pack_start(label_option, False, True, 0)
-
- hbox.pack_start(grid, False, True, 0)
- self._gobj('listboxSummaryOfActiveProfile').add(row)
- separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
- self._gobj('listboxSummaryOfActiveProfile').add(separator)
- separator.show()
+ if self.active_profile:
+ for u in self.active_profile.units:
+ row = Gtk.ListBoxRow()
+ hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL,
+ spacing=0)
+ hbox.set_homogeneous(True)
+ row.add(hbox)
+ label = Gtk.Label()
+ label.set_markup(u)
+ label.set_justify(Gtk.Justification.LEFT)
+ hbox.pack_start(label, False, True, 1)
+
+ grid = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
+ spacing=0)
+ grid.set_homogeneous(True)
+ for o in self.active_profile.units[u].options:
+ label_option = Gtk.Label()
+ label_option.set_markup(o + ' = ' + ''
+ + self.active_profile.units[u].options[o]
+ + '')
+ grid.pack_start(label_option, False, True, 0)
+
+ hbox.pack_start(grid, False, True, 0)
+ self._gobj('listboxSummaryOfActiveProfile').add(row)
+ separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL)
+ self._gobj('listboxSummaryOfActiveProfile').add(separator)
+ separator.show()
self._gobj('listboxSummaryOfActiveProfile').show_all()
@@ -411,8 +412,8 @@ def execute_add_plugin_to_notebook(self, button):
self._gobj('notebookPlugins').append_page_menu(
self.treeview_for_data(
config_options, plugin),
- Gtk.Label(plugin),
- Gtk.Label(plugin)
+ Gtk.Label(label = plugin),
+ Gtk.Label(label = plugin)
)
self._gobj('notebookPlugins').show_all()
@@ -445,7 +446,7 @@ def execute_apply_window_profile_editor_raw(self, data):
self.manager.set_raw_profile(profile_name,
text_buffer.get_text(start, end, True))
except Exception:
- self.error_dialog('Error while parsing raw configuration')
+ self.error_dialog('Error while parsing raw configuration', '')
return
self.error_dialog('Profile Editor will be closed.',
@@ -629,7 +630,7 @@ def execute_update_profile(self, data):
for (name, unit) in list(profile.units.items()):
self._gobj('notebookPlugins').append_page_menu(self.treeview_for_data(unit.options, unit.name),
- Gtk.Label(unit.name), Gtk.Label(unit.name))
+ Gtk.Label(label = unit.name), Gtk.Label(label = unit.name))
self._gobj('notebookPlugins').show_all()
self._gobj('windowProfileEditor').show()
@@ -639,11 +640,11 @@ def treeview_for_data(self, data, plugin_name):
"""
treestore = Gtk.ListStore(GObject.TYPE_STRING,
- GObject.TYPE_STRING)
+ GObject.TYPE_STRING)
for (option, value) in list(data.items()):
treestore.append([str(value), option])
- treeview = Gtk.TreeView(treestore)
+ treeview = Gtk.TreeView(model = treestore)
renderer = Gtk.CellRendererText()
column_option = Gtk.TreeViewColumn('Option', renderer, text=0)
column_value = Gtk.TreeViewColumn('Value', renderer, text=1)
@@ -694,7 +695,7 @@ def execute_change_profile(self, button):
def execute_switch_tuned(self, switch, data):
"""
- Suported switch_tuned_start_stop and switch_tuned_startup_start_stop.
+ Supported switch_tuned_start_stop and switch_tuned_startup_start_stop.
"""
if switch == self._gobj('switchTunedStartStop'):
@@ -798,8 +799,8 @@ def on_treeview_click(self, treeview, event):
if event.button == 3:
popup = Gtk.Menu()
- popup.append(Gtk.MenuItem('add'))
- popup.append(Gtk.MenuItem('delete'))
+ popup.append(Gtk.MenuItem(label = 'add'))
+ popup.append(Gtk.MenuItem(label = 'delete'))
time = event.time
self._gobj('menuAddPluginValue').popup(
None,
@@ -818,6 +819,70 @@ def liststore_contains_item(liststore, item):
return True
return False
+ def add_plugin_value_to_treeview(self, action):
+ notebook_plugins = self._gobj('notebookPlugins')
+ current_plugin = \
+ notebook_plugins.get_tab_label(notebook_plugins.get_nth_page(notebook_plugins.get_current_page())).get_text()
+ current_plugin_options = \
+ self.plugin_loader.plugins.get(current_plugin)
+ curent_plugin_values_model = \
+ notebook_plugins.get_nth_page(notebook_plugins.get_current_page()).get_model()
+
+ treestore_plugins_values = Gtk.ListStore(GObject.TYPE_STRING)
+
+ for (vl_name, vl_val) in current_plugin_options.items():
+ if not self.liststore_contains_item(curent_plugin_values_model,
+ vl_name):
+ treestore_plugins_values.append([vl_name])
+
+ dialog_add_plugin_value = \
+ self.builder.get_object('dialogAddPluginValue')
+ dialog_add_plugin_value.connect('destroy', lambda d: \
+ dialog_add_plugin_value.hide())
+ combobox = self.builder.get_object('comboboxPluginsValues')
+ combobox.set_model(treestore_plugins_values)
+
+ response = dialog_add_plugin_value.run()
+ dialog_add_plugin_value.hide()
+
+ if response == 1:
+ active = combobox.get_active_text()
+ curent_plugin_values_model.append([current_plugin_options.get(active),
+ active])
+ return True
+ return False
+
+ def add_custom_plugin_value_to_treeview(self, action):
+ notebook_plugins = self._gobj('notebookPlugins')
+ curent_plugin_values_model = \
+ notebook_plugins.get_nth_page(notebook_plugins.get_current_page()).get_model()
+
+ dialog_add_custom_plugin_value = \
+ self.builder.get_object('dialogAddCustomPluginValue')
+ text = self.builder.get_object('entry2')
+ dialog_add_custom_plugin_value.connect('destroy', lambda d: \
+ dialog_add_custom_plugin_value.hide())
+
+ response = dialog_add_custom_plugin_value.run()
+ dialog_add_custom_plugin_value.hide()
+
+ if response == 1:
+ curent_plugin_values_model.append(['', text.get_text()])
+ return True
+ return False
+
+ def delete_plugin_value_to_treeview(self, action):
+ notebook_plugins = self._gobj('notebookPlugins')
+ curent_plugin_values_tree = \
+ notebook_plugins.get_nth_page(notebook_plugins.get_current_page())
+
+ (model, iter) = \
+ curent_plugin_values_tree.get_selection().get_selected()
+ if model is None or iter is None:
+ return False
+ model.remove(iter)
+ return True
+
def _start_tuned(self):
self._su_execute(['service', 'tuned', 'start'])
time.sleep(10)
diff --git a/assets/tuned/daemon/tuned.spec b/assets/tuned/daemon/tuned.spec
index 8550abfd8..8889199fe 100644
--- a/assets/tuned/daemon/tuned.spec
+++ b/assets/tuned/daemon/tuned.spec
@@ -44,9 +44,9 @@
Summary: A dynamic adaptive system tuning daemon
Name: tuned
-Version: 2.20.0
+Version: 2.21.0
Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist}
-License: GPLv2+
+License: GPL-2.0-or-later AND CC-BY-SA-3.0
Source0: https://github.com/redhat-performance/%{name}/archive/v%{version}%{?prerel2}/%{name}-%{version}%{?prerel2}.tar.gz
URL: http://www.tuned-project.org/
BuildArch: noarch
@@ -557,6 +557,28 @@ fi
%{_mandir}/man7/tuned-profiles-openshift.7*
%changelog
+* Tue Aug 29 2023 Jaroslav Škarvada - 2.21.0-1
+- new release
+ - rebased tuned to latest upstream
+ related: rhbz#2182117
+ - api: fixed stop method not to require any parameter
+ resolves: rhbz#2235637
+
+* Sun Aug 20 2023 Jaroslav Škarvada - 2.21.0-0.1.rc1
+- new release
+ - rebased tuned to latest upstream
+ resolves: rhbz#2182117
+ - plugin_scheduler: fix perf fd leaks
+ resolves: rhbz#2173938
+ - allow skipping rollback when restarting TuneD or switching profile
+ resolves: rhbz#2203142
+ - function_calc_isolated_cores: no errors for offline CPUs
+ resolves: rhbz#2217015
+ - sap-hana: new profile sap-hana-kvm-guest
+ resolves: rhbz#2173740
+ - serialized SIGHUP handler to prevent possible bootcmdline corruption
+ resolves: rhbz#2215298
+
* Fri Feb 17 2023 Jaroslav Škarvada - 2.20.0-1
- new release
- rebased tuned to latest upstream
diff --git a/assets/tuned/daemon/tuned/admin/admin.py b/assets/tuned/daemon/tuned/admin/admin.py
index 89edf77d7..b9ef94b94 100644
--- a/assets/tuned/daemon/tuned/admin/admin.py
+++ b/assets/tuned/daemon/tuned/admin/admin.py
@@ -439,3 +439,39 @@ def _action_dbus_list_plugins(self, verbose=False):
def _action_list_plugins(self, verbose=False):
print("Not supported in no_daemon mode.")
return False
+
+ def _action_dbus_instance_acquire_devices(self, devices, instance):
+ (ret, msg) = self._controller.instance_acquire_devices(devices, instance)
+ if not ret:
+ self._error("Unable to acquire devices: %s" % msg)
+ return self._controller.exit(ret)
+
+ def _action_instance_acquire_devices(self, devices, instance):
+ print("Not supported in no_daemon mode.")
+ return False
+
+ def _action_dbus_get_instances(self, plugin_name):
+ (ret, msg, pairs) = self._controller.get_instances(plugin_name)
+ if not ret:
+ self._error("Unable to list instances: %s" % msg)
+ return self._controller.exit(False)
+ for instance, plugin in pairs:
+ print("%s (%s)" % (instance, plugin))
+ return self._controller.exit(True)
+
+ def _action_get_instances(self, plugin_name):
+ print("Not supported in no_daemon mode.")
+ return False
+
+ def _action_dbus_instance_get_devices(self, instance):
+ (ret, msg, devices) = self._controller.instance_get_devices(instance)
+ if not ret:
+ self._error("Unable to list devices: %s" % msg)
+ return self._controller.exit(False)
+ for device in devices:
+ print(device)
+ return self._controller.exit(True)
+
+ def _action_instance_get_devices(self, instance):
+ print("Not supported in no_daemon mode.")
+ return False
diff --git a/assets/tuned/daemon/tuned/admin/dbus_controller.py b/assets/tuned/daemon/tuned/admin/dbus_controller.py
index 4d22cb0a5..22c8b8d3b 100644
--- a/assets/tuned/daemon/tuned/admin/dbus_controller.py
+++ b/assets/tuned/daemon/tuned/admin/dbus_controller.py
@@ -163,6 +163,15 @@ def get_plugin_hints(self, plugin_name):
"""
return self._call("get_plugin_hints", plugin_name)
+ def instance_acquire_devices(self, devices, instance):
+ return self._call("instance_acquire_devices", devices, instance)
+
+ def get_instances(self, plugin_name):
+ return self._call("get_instances", plugin_name)
+
+ def instance_get_devices(self, instance):
+ return self._call("instance_get_devices", instance)
+
def exit(self, ret):
self.set_action(None)
self._ret = ret
diff --git a/assets/tuned/daemon/tuned/consts.py b/assets/tuned/daemon/tuned/consts.py
index cd112e65f..b7fb21545 100644
--- a/assets/tuned/daemon/tuned/consts.py
+++ b/assets/tuned/daemon/tuned/consts.py
@@ -79,7 +79,7 @@
FUNCTION_PREFIX = "function_"
# prefix for exported environment variables when calling scripts
ENV_PREFIX = "TUNED_"
-ROLLBACK_NOT_ON_EXIT = 0
+ROLLBACK_NONE = 0
ROLLBACK_SOFT = 1
ROLLBACK_FULL = 2
diff --git a/assets/tuned/daemon/tuned/daemon/application.py b/assets/tuned/daemon/tuned/daemon/application.py
index 5f203b113..fe12a65a3 100644
--- a/assets/tuned/daemon/tuned/daemon/application.py
+++ b/assets/tuned/daemon/tuned/daemon/application.py
@@ -67,7 +67,7 @@ def handler_wrapper(_signal_number, _frame):
signal.signal(signal_number, handler_wrapper)
def _init_signals(self):
- self._handle_signal(signal.SIGHUP, self._controller.reload)
+ self._handle_signal(signal.SIGHUP, self._controller.sighup)
self._handle_signal(signal.SIGINT, self._controller.terminate)
self._handle_signal(signal.SIGTERM, self._controller.terminate)
diff --git a/assets/tuned/daemon/tuned/daemon/controller.py b/assets/tuned/daemon/tuned/daemon/controller.py
index 1c7582d28..6a59a1d86 100644
--- a/assets/tuned/daemon/tuned/daemon/controller.py
+++ b/assets/tuned/daemon/tuned/daemon/controller.py
@@ -70,6 +70,12 @@ def run(self):
def terminate(self):
self._terminate.set()
+ def sighup(self):
+ if not self._daemon._sighup_processing.is_set():
+ self._daemon._sighup_processing.set()
+ if not self.reload():
+ self._daemon._sighup_processing.clear()
+
@exports.signal("sbs")
def profile_changed(self, profile_name, result, errstr):
pass
@@ -116,10 +122,7 @@ def start(self, caller = None):
return False
return self._daemon.start()
- @exports.export("", "b")
- def stop(self, caller = None, profile_switch = False):
- if caller == "":
- return False
+ def _stop(self, profile_switch = False):
if not self._daemon.is_running():
res = True
else:
@@ -127,12 +130,18 @@ def stop(self, caller = None, profile_switch = False):
self._timer_store.cancel_all()
return res
+ @exports.export("", "b")
+ def stop(self, caller = None):
+ if caller == "":
+ return False
+ return self._stop(profile_switch = False)
+
@exports.export("", "b")
def reload(self, caller = None):
if caller == "":
return False
if self._daemon.is_running():
- stop_ok = self.stop(profile_switch = True)
+ stop_ok = self._stop(profile_switch = True)
if not stop_ok:
return False
try:
@@ -364,3 +373,47 @@ def instance_acquire_devices(self, devices, instance_name, caller = None):
log.info(rets)
return (False, rets)
return (True, "OK")
+
+ @exports.export("s", "(bsa(ss))")
+ def get_instances(self, plugin_name, caller = None):
+ """Return a list of active instances of a plugin or all active instances
+
+ Parameters:
+ plugin_name -- name of the plugin or an empty string
+
+ Return:
+ bool -- True on success
+ string -- error message or "OK"
+ list of string pairs -- [(instance_name, plugin_name)]
+ """
+ if caller == "":
+ return (False, "Unauthorized", [])
+ if plugin_name != "" and plugin_name not in self.get_all_plugins().keys():
+ rets = "Plugin '%s' does not exist" % plugin_name
+ log.error(rets)
+ return (False, rets, [])
+ instances = filter(lambda instance: instance.active, self._daemon._unit_manager.instances)
+ if plugin_name != "":
+ instances = filter(lambda instance: instance.plugin.name == plugin_name, instances)
+ return (True, "OK", list(map(lambda instance: (instance.name, instance.plugin.name), instances)))
+
+ @exports.export("s", "(bsas)")
+ def instance_get_devices(self, instance_name, caller = None):
+ """Return a list of devices assigned to an instance
+
+ Parameters:
+ instance_name -- name of the instance
+
+ Return:
+ bool -- True on success
+ string -- error message or "OK"
+ list of strings -- device names
+ """
+ if caller == "":
+ return (False, "Unauthorized", [])
+ for instance in self._daemon._unit_manager.instances:
+ if instance.name == instance_name:
+ return (True, "OK", sorted(list(instance.processed_devices)))
+ rets = "Instance '%s' not found" % instance_name
+ log.error(rets)
+ return (False, rets, [])
diff --git a/assets/tuned/daemon/tuned/daemon/daemon.py b/assets/tuned/daemon/tuned/daemon/daemon.py
index 2b3ecfa47..81582d05d 100644
--- a/assets/tuned/daemon/tuned/daemon/daemon.py
+++ b/assets/tuned/daemon/tuned/daemon/daemon.py
@@ -59,6 +59,8 @@ def _init_threads(self):
self._terminate_profile_switch = threading.Event()
# Flag which is set if there is no operation in progress
self._not_used = threading.Event()
+ # Flag which is set if SIGHUP is being processed
+ self._sighup_processing = threading.Event()
self._not_used.set()
self._profile_applied = threading.Event()
@@ -203,6 +205,7 @@ def _thread_code(self):
exports.start()
profile_names = " ".join(self._active_profiles)
self._notify_profile_changed(profile_names, True, "OK")
+ self._sighup_processing.clear()
if self._daemon:
# In python 2 interpreter with applied patch for rhbz#917709 we need to periodically
@@ -231,7 +234,7 @@ def _thread_code(self):
# if terminating due to profile switch
if self._terminate_profile_switch.is_set():
- full_rollback = consts.ROLLBACK_FULL
+ rollback = consts.ROLLBACK_FULL
else:
# Assume only soft rollback is needed. Soft rollback means reverting all
# non-persistent tunings applied by a plugin instance. In contrast to full
@@ -241,21 +244,21 @@ def _thread_code(self):
# perform full cleanup. If the system is not shutting down, it means that TuneD
# was explicitly stopped by the user and in such case do the full cleanup. On
# systems without systemd, full cleanup is never performed.
- full_rollback = consts.ROLLBACK_SOFT
+ rollback = consts.ROLLBACK_SOFT
if not self._full_rollback_required():
log.info("terminating TuneD due to system shutdown / reboot")
elif self._rollback == "not_on_exit":
# no rollback on TuneD exit whatsoever
- full_rollback = consts.ROLLBACK_NOT_ON_EXIT
+ rollback = consts.ROLLBACK_NONE
log.info("terminating TuneD and not rolling back any changes due to '%s' option in '%s'" % (consts.CFG_ROLLBACK, consts.GLOBAL_CONFIG_FILE))
else:
if self._daemon:
log.info("terminating TuneD, rolling back all changes")
- full_rollback = consts.ROLLBACK_FULL
+ rollback = consts.ROLLBACK_FULL
else:
log.info("terminating TuneD in one-shot mode")
if self._daemon:
- self._unit_manager.stop_tuning(full_rollback)
+ self._unit_manager.stop_tuning(rollback)
self._unit_manager.destroy_all()
def _save_active_profile(self, profile_names, manual):
diff --git a/assets/tuned/daemon/tuned/gtk/gui_plugin_loader.py b/assets/tuned/daemon/tuned/gtk/gui_plugin_loader.py
index 309b3129b..507750bee 100644
--- a/assets/tuned/daemon/tuned/gtk/gui_plugin_loader.py
+++ b/assets/tuned/daemon/tuned/gtk/gui_plugin_loader.py
@@ -40,7 +40,7 @@
class GuiPluginLoader():
'''
- Class for scan, import and load actual avaible plugins.
+ Class for scan, import and load actual variable plugins.
'''
def __init__(self):
@@ -53,7 +53,7 @@ def __init__(self):
self._prefix = 'plugin_'
self._sufix = '.py'
self._dbus_controller = DBusController(consts.DBUS_BUS,
- consts.DBUS_INTERFACE, consts.DBUS_OBJECT
+ consts.DBUS_INTERFACE, consts.DBUS_OBJECT
)
self._get_plugins()
diff --git a/assets/tuned/daemon/tuned/plugins/base.py b/assets/tuned/daemon/tuned/plugins/base.py
index 47a346828..9ec902a9c 100644
--- a/assets/tuned/daemon/tuned/plugins/base.py
+++ b/assets/tuned/daemon/tuned/plugins/base.py
@@ -212,7 +212,7 @@ def _instance_pre_static(self, instance, enabling):
def _instance_post_static(self, instance, enabling):
pass
- def _call_device_script(self, instance, script, op, devices, full_rollback = consts.ROLLBACK_SOFT):
+ def _call_device_script(self, instance, script, op, devices, rollback = consts.ROLLBACK_SOFT):
if script is None:
return None
if len(devices) == 0:
@@ -228,7 +228,7 @@ def _call_device_script(self, instance, script, op, devices, full_rollback = con
environ = os.environ
environ.update(self._variables.get_env())
arguments = [op]
- if full_rollback == consts.ROLLBACK_FULL:
+ if rollback == consts.ROLLBACK_FULL:
arguments.append("full_rollback")
arguments.append(dev)
log.info("calling script '%s' with arguments '%s'" % (script, str(arguments)))
@@ -298,11 +298,11 @@ def instance_update_tuning(self, instance):
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._run_for_each_device(instance, self._instance_update_dynamic, instance.processed_devices.copy())
- def instance_unapply_tuning(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def instance_unapply_tuning(self, instance, rollback = consts.ROLLBACK_SOFT):
"""
Remove all tunings applied by the plugin instance.
"""
- if full_rollback == consts.ROLLBACK_NOT_ON_EXIT:
+ if rollback == consts.ROLLBACK_NONE:
return
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
@@ -310,11 +310,11 @@ def instance_unapply_tuning(self, instance, full_rollback = consts.ROLLBACK_SOFT
if instance.has_static_tuning:
self._call_device_script(instance, instance.script_post,
"unapply", instance.processed_devices,
- full_rollback = full_rollback)
+ rollback = rollback)
self._instance_pre_static(instance, False)
- self._instance_unapply_static(instance, full_rollback)
+ self._instance_unapply_static(instance, rollback)
self._instance_post_static(instance, False)
- self._call_device_script(instance, instance.script_pre, "unapply", instance.processed_devices, full_rollback = full_rollback)
+ self._call_device_script(instance, instance.script_pre, "unapply", instance.processed_devices, rollback = rollback)
def _instance_apply_static(self, instance):
self._execute_all_non_device_commands(instance)
@@ -328,7 +328,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
self._cleanup_all_device_commands(instance,
instance.processed_devices)
self._cleanup_all_non_device_commands(instance)
@@ -506,7 +506,7 @@ def _execute_device_command(self, instance, command, device, new_value):
else:
new_value = self._check_and_save_value(instance, command, device, new_value)
if new_value is not None:
- command["set"](new_value, device, sim = False)
+ command["set"](new_value, device, sim = False, remove = False)
def _execute_non_device_command(self, instance, command, new_value):
if command["custom"] is not None:
@@ -514,7 +514,7 @@ def _execute_non_device_command(self, instance, command, new_value):
else:
new_value = self._check_and_save_value(instance, command, None, new_value)
if new_value is not None:
- command["set"](new_value, sim = False)
+ command["set"](new_value, sim = False, remove = False)
def _norm_value(self, value):
v = self._cmd.unquote(str(value))
@@ -576,7 +576,7 @@ def _verify_device_command(self, instance, command, device, new_value, ignore_mi
new_value = self._process_assignment_modifiers(new_value, current_value)
if new_value is None:
return None
- new_value = command["set"](new_value, device, True)
+ new_value = command["set"](new_value, device, True, False)
return self._verify_value(command["name"], new_value, current_value, ignore_missing, device)
def _verify_non_device_command(self, instance, command, new_value, ignore_missing):
@@ -586,7 +586,7 @@ def _verify_non_device_command(self, instance, command, new_value, ignore_missin
new_value = self._process_assignment_modifiers(new_value, current_value)
if new_value is None:
return None
- new_value = command["set"](new_value, True)
+ new_value = command["set"](new_value, True, False)
return self._verify_value(command["name"], new_value, current_value, ignore_missing)
def _cleanup_all_non_device_commands(self, instance):
@@ -594,19 +594,19 @@ def _cleanup_all_non_device_commands(self, instance):
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
self._cleanup_non_device_command(instance, command)
- def _cleanup_all_device_commands(self, instance, devices):
+ def _cleanup_all_device_commands(self, instance, devices, remove = False):
for command in reversed([command for command in list(self._commands.values()) if command["per_device"]]):
if (instance.options.get(command["name"], None) is not None) or (command["name"] in self._options_used_by_dynamic):
for device in devices:
- self._cleanup_device_command(instance, command, device)
+ self._cleanup_device_command(instance, command, device, remove)
- def _cleanup_device_command(self, instance, command, device):
+ def _cleanup_device_command(self, instance, command, device, remove = False):
if command["custom"] is not None:
command["custom"](False, None, device, False, False)
else:
old_value = self._storage_get(instance, command, device)
if old_value is not None:
- command["set"](old_value, device, sim = False)
+ command["set"](old_value, device, sim = False, remove = remove)
self._storage_unset(instance, command, device)
def _cleanup_non_device_command(self, instance, command):
@@ -615,5 +615,5 @@ def _cleanup_non_device_command(self, instance, command):
else:
old_value = self._storage_get(instance, command)
if old_value is not None:
- command["set"](old_value, sim = False)
+ command["set"](old_value, sim = False, remove = False)
self._storage_unset(instance, command)
diff --git a/assets/tuned/daemon/tuned/plugins/hotplug.py b/assets/tuned/daemon/tuned/plugins/hotplug.py
index 5c6548009..9e392a704 100644
--- a/assets/tuned/daemon/tuned/plugins/hotplug.py
+++ b/assets/tuned/daemon/tuned/plugins/hotplug.py
@@ -109,4 +109,4 @@ def _added_device_apply_tuning(self, instance, device_name):
def _removed_device_unapply_tuning(self, instance, device_name):
if instance.has_dynamic_tuning and self._global_cfg.get(consts.CFG_DYNAMIC_TUNING, consts.CFG_DEF_DYNAMIC_TUNING):
self._instance_unapply_dynamic(instance, device_name)
- self._cleanup_all_device_commands(instance, [device_name])
+ self._cleanup_all_device_commands(instance, [device_name], remove = True)
diff --git a/assets/tuned/daemon/tuned/plugins/instance/instance.py b/assets/tuned/daemon/tuned/plugins/instance/instance.py
index f57b861fc..1e286729d 100644
--- a/assets/tuned/daemon/tuned/plugins/instance/instance.py
+++ b/assets/tuned/daemon/tuned/plugins/instance/instance.py
@@ -85,8 +85,8 @@ def verify_tuning(self, ignore_missing):
def update_tuning(self):
self._plugin.instance_update_tuning(self)
- def unapply_tuning(self, full_rollback = consts.ROLLBACK_SOFT):
- self._plugin.instance_unapply_tuning(self, full_rollback)
+ def unapply_tuning(self, rollback = consts.ROLLBACK_SOFT):
+ self._plugin.instance_unapply_tuning(self, rollback)
def destroy(self):
self.unapply_tuning()
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_audio.py b/assets/tuned/daemon/tuned/plugins/plugin_audio.py
index 5a94e3c89..eee932cb9 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_audio.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_audio.py
@@ -4,6 +4,7 @@
from tuned.utils.commands import commands
import os
+import errno
import struct
import glob
@@ -73,7 +74,7 @@ def _reset_controller_path(self, device):
return "/sys/module/%s/parameters/power_save_controller" % device
@command_set("timeout", per_device = True)
- def _set_timeout(self, value, device, sim):
+ def _set_timeout(self, value, device, sim, remove):
try:
timeout = int(value)
except ValueError:
@@ -82,7 +83,8 @@ def _set_timeout(self, value, device, sim):
if timeout >= 0:
sys_file = self._timeout_path(device)
if not sim:
- cmd.write_to_file(sys_file, "%d" % timeout)
+ cmd.write_to_file(sys_file, "%d" % timeout, \
+ no_error = [errno.ENOENT] if remove else False)
return timeout
else:
return None
@@ -96,12 +98,13 @@ def _get_timeout(self, device, ignore_missing=False):
return None
@command_set("reset_controller", per_device = True)
- def _set_reset_controller(self, value, device, sim):
+ def _set_reset_controller(self, value, device, sim, remove):
v = cmd.get_bool(value)
sys_file = self._reset_controller_path(device)
if os.path.exists(sys_file):
if not sim:
- cmd.write_to_file(sys_file, v)
+ cmd.write_to_file(sys_file, v, \
+ no_error = [errno.ENOENT] if remove else False)
return v
return None
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_bootloader.py b/assets/tuned/daemon/tuned/plugins/plugin_bootloader.py
index 89fd0f2f4..13f13432d 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_bootloader.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_bootloader.py
@@ -373,7 +373,7 @@ def _remove_grub2_tuning(self):
log.info("cannot find grub.cfg to patch")
return
for f in self._grub2_cfg_file_names:
- self._cmd.add_modify_option_in_file(f, {"set\s+" + consts.GRUB2_TUNED_VAR : "", "set\s+" + consts.GRUB2_TUNED_INITRD_VAR : ""}, add = False)
+ self._cmd.add_modify_option_in_file(f, {r"set\s+" + consts.GRUB2_TUNED_VAR : "", r"set\s+" + consts.GRUB2_TUNED_INITRD_VAR : ""}, add = False)
if self._initrd_dst_img_val is not None:
log.info("removing initrd image '%s'" % self._initrd_dst_img_val)
self._cmd.unlink(self._initrd_dst_img_val)
@@ -391,8 +391,8 @@ def _remove_rpm_ostree_tuning(self):
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: ""})
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
- if full_rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
+ if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val:
if self._rpm_ostree:
log.info("removing rpm-ostree tuning previously added by Tuned")
self._remove_rpm_ostree_tuning()
@@ -403,9 +403,9 @@ def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOF
def _grub2_cfg_unpatch(self, grub2_cfg):
log.debug("unpatching grub.cfg")
- cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_VAR + "\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
+ cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_VAR + "\\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
grub2_cfg = re.sub(r" *\$" + consts.GRUB2_TUNED_VAR, "", cfg, flags = re.MULTILINE)
- cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_INITRD_VAR + "\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
+ cfg = re.sub(r"^\s*set\s+" + consts.GRUB2_TUNED_INITRD_VAR + "\\s*=.*\n", "", grub2_cfg, flags = re.MULTILINE)
grub2_cfg = re.sub(r" *\$" + consts.GRUB2_TUNED_INITRD_VAR, "", cfg, flags = re.MULTILINE)
cfg = re.sub(consts.GRUB2_TEMPLATE_HEADER_BEGIN + r"\n", "", grub2_cfg, flags = re.MULTILINE)
return re.sub(consts.GRUB2_TEMPLATE_HEADER_END + r"\n+", "", cfg, flags = re.MULTILINE)
@@ -480,7 +480,7 @@ def _grub2_cfg_patch(self, d):
grub2_cfg_new = grub2_cfg
patch_initial = False
for opt in d:
- (grub2_cfg_new, nsubs) = re.subn(r"\b(set\s+" + opt + "\s*=).*$", r"\1" + "\"" + self._cmd.escape(d[opt]) + "\"", grub2_cfg_new, flags = re.MULTILINE)
+ (grub2_cfg_new, nsubs) = re.subn(r"\b(set\s+" + opt + r"\s*=).*$", r"\1" + "\"" + self._cmd.escape(d[opt]) + "\"", grub2_cfg_new, flags = re.MULTILINE)
if nsubs < 1 or re.search(r"\$" + opt, grub2_cfg, flags = re.MULTILINE) is None:
patch_initial = True
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_cpu.py b/assets/tuned/daemon/tuned/plugins/plugin_cpu.py
index 79c02ee62..4b90f4081 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_cpu.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_cpu.py
@@ -5,6 +5,7 @@
import tuned.consts as consts
import os
+import errno
import struct
import errno
import platform
@@ -81,7 +82,8 @@ class CPULatencyPlugin(hotplug.Plugin):
`energy_performance_preference`:::
[option]`energy_performance_preference` supports managing energy
- vs. performance hints on some newer Intel processors. Multiple alternative
+ vs. performance hints on newer Intel and AMD processors with active P-State
+ CPU scaling drivers (intel_pstate or amd-pstate). Multiple alternative
Energy Performance Preferences (EPP) values are supported. The alternative
values are separated using the '|' character. Available values can be found
in `energy_performance_available_preferences` file in `CPUFreq` policy
@@ -196,6 +198,7 @@ def __init__(self, *args, **kwargs):
self._is_amd = False
self._has_energy_perf_bias = False
self._has_intel_pstate = False
+ self._has_amd_pstate = False
self._has_pm_qos_resume_latency_us = None
self._min_perf_pct_save = None
@@ -240,15 +243,15 @@ def _check_arch(self):
self._arch = platform.machine()
if self._arch in intel_archs:
- # Possible other x86 vendors (from arch/x86/kernel/cpu/*):
- # "CentaurHauls", "CyrixInstead", "Geode by NSC", "HygonGenuine", "GenuineTMx86",
- # "TransmetaCPU", "UMC UMC UMC"
+ # Possible other x86 vendors (from arch/x86/kernel/cpu/*):
+ # "CentaurHauls", "CyrixInstead", "Geode by NSC", "HygonGenuine", "GenuineTMx86",
+ # "TransmetaCPU", "UMC UMC UMC"
cpu = procfs.cpuinfo()
vendor = cpu.tags.get("vendor_id")
if vendor == "GenuineIntel":
- self._is_intel = True
+ self._is_intel = True
elif vendor == "AuthenticAMD" or vendor == "HygonGenuine":
- self._is_amd = True
+ self._is_amd = True
else:
# We always assign Intel, unless we know better
self._is_intel = True
@@ -256,12 +259,16 @@ def _check_arch(self):
else:
log.info("We are running on %s (non x86)" % self._arch)
- if self._is_intel is True:
+ if self._is_intel:
# Check for x86_energy_perf_policy, ignore if not available / supported
self._check_energy_perf_bias()
# Check for intel_pstate
self._check_intel_pstate()
+ if self._is_amd:
+ # Check for amd-pstate
+ self._check_amd_pstate()
+
def _check_energy_perf_bias(self):
self._has_energy_perf_bias = False
retcode_unsupported = 1
@@ -281,6 +288,11 @@ def _check_intel_pstate(self):
if self._has_intel_pstate:
log.info("intel_pstate detected")
+ def _check_amd_pstate(self):
+ self._has_amd_pstate = os.path.exists("/sys/devices/system/cpu/amd_pstate")
+ if self._has_amd_pstate:
+ log.info("amd-pstate detected")
+
def _get_cpuinfo_flags(self):
if self._flags is None:
self._flags = procfs.cpuinfo().tags.get("flags", [])
@@ -377,8 +389,8 @@ def _instance_apply_static(self, instance):
self._no_turbo_save = self._getset_intel_pstate_attr(
"no_turbo", new_value)
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
- super(CPULatencyPlugin, self)._instance_unapply_static(instance, full_rollback)
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
+ super(CPULatencyPlugin, self)._instance_unapply_static(instance, rollback)
if instance._first_instance and self._has_intel_pstate:
self._set_intel_pstate_attr("min_perf_pct", self._min_perf_pct_save)
@@ -489,7 +501,7 @@ def _get_available_governors(self, device):
return self._cmd.read_file("/sys/devices/system/cpu/%s/cpufreq/scaling_available_governors" % device).strip().split()
@command_set("governor", per_device=True)
- def _set_governor(self, governors, device, sim):
+ def _set_governor(self, governors, device, sim, remove):
if not self._check_cpu_can_change_governor(device):
return None
governors = str(governors)
@@ -506,7 +518,7 @@ def _set_governor(self, governors, device, sim):
log.info("setting governor '%s' on cpu '%s'"
% (governor, device))
self._cmd.write_to_file("/sys/devices/system/cpu/%s/cpufreq/scaling_governor"
- % device, governor)
+ % device, governor, no_error = [errno.ENOENT] if remove else False)
break
elif not sim:
log.debug("Ignoring governor '%s' on cpu '%s', it is not supported"
@@ -535,7 +547,7 @@ def _sampling_down_factor_path(self, governor = "ondemand"):
return "/sys/devices/system/cpu/cpufreq/%s/sampling_down_factor" % governor
@command_set("sampling_down_factor", per_device = True, priority = 10)
- def _set_sampling_down_factor(self, sampling_down_factor, device, sim):
+ def _set_sampling_down_factor(self, sampling_down_factor, device, sim, remove):
val = None
# hack to clear governors map when the profile starts unloading
@@ -558,7 +570,7 @@ def _set_sampling_down_factor(self, sampling_down_factor, device, sim):
val = str(sampling_down_factor)
if not sim:
log.info("setting sampling_down_factor to '%s' for governor '%s'" % (val, governor))
- self._cmd.write_to_file(path, val)
+ self._cmd.write_to_file(path, val, no_error = [errno.ENOENT] if remove else False)
return val
@command_get("sampling_down_factor")
@@ -580,14 +592,14 @@ def _try_set_energy_perf_bias(self, cpu_id, value):
return_err = True)
return (retcode, err_msg)
- def _intel_preference_path(self, cpu_id, available = False):
+ def _pstate_preference_path(self, cpu_id, available = False):
return "/sys/devices/system/cpu/cpufreq/policy%s/energy_performance_%s" % (cpu_id, "available_preferences" if available else "preference")
def _energy_perf_bias_path(self, cpu_id):
return "/sys/devices/system/cpu/cpu%s/power/energy_perf_bias" % cpu_id
@command_set("energy_perf_bias", per_device=True)
- def _set_energy_perf_bias(self, energy_perf_bias, device, sim):
+ def _set_energy_perf_bias(self, energy_perf_bias, device, sim, remove):
if not self._is_cpu_online(device):
log.debug("%s is not online, skipping" % device)
return None
@@ -602,10 +614,11 @@ def _set_energy_perf_bias(self, energy_perf_bias, device, sim):
if not sim:
for val in vals:
val = val.strip()
- if self._cmd.write_to_file(energy_perf_bias_path, val):
- log.info("energy_perf_bias successfully set to '%s' on cpu '%s'"
- % (val, device))
- break
+ if self._cmd.write_to_file(energy_perf_bias_path, val, \
+ no_error = [errno.ENOENT] if remove else False):
+ log.info("energy_perf_bias successfully set to '%s' on cpu '%s'"
+ % (val, device))
+ break
else:
log.error("Failed to set energy_perf_bias on cpu '%s'. Is the value in the profile correct?"
% device)
@@ -700,7 +713,7 @@ def _check_pm_qos_resume_latency_us(self, device):
return self._has_pm_qos_resume_latency_us
@command_set("pm_qos_resume_latency_us", per_device=True)
- def _set_pm_qos_resume_latency_us(self, pm_qos_resume_latency_us, device, sim):
+ def _set_pm_qos_resume_latency_us(self, pm_qos_resume_latency_us, device, sim, remove):
if not self._is_cpu_online(device):
log.debug("%s is not online, skipping" % device)
return None
@@ -718,7 +731,8 @@ def _set_pm_qos_resume_latency_us(self, pm_qos_resume_latency_us, device, sim):
if not self._check_pm_qos_resume_latency_us(device):
return None
if not sim:
- self._cmd.write_to_file(self._pm_qos_resume_latency_us_path(device), latency)
+ self._cmd.write_to_file(self._pm_qos_resume_latency_us_path(device), latency, \
+ no_error = [errno.ENOENT] if remove else False)
return latency
@command_get("pm_qos_resume_latency_us")
@@ -731,18 +745,19 @@ def _get_pm_qos_resume_latency_us(self, device, ignore_missing=False):
return self._cmd.read_file(self._pm_qos_resume_latency_us_path(device), no_error=ignore_missing).strip()
@command_set("energy_performance_preference", per_device=True)
- def _set_energy_performance_preference(self, energy_performance_preference, device, sim):
+ def _set_energy_performance_preference(self, energy_performance_preference, device, sim, remove):
if not self._is_cpu_online(device):
log.debug("%s is not online, skipping" % device)
return None
cpu_id = device.lstrip("cpu")
- if os.path.exists(self._intel_preference_path(cpu_id, True)):
+ if os.path.exists(self._pstate_preference_path(cpu_id, True)):
vals = energy_performance_preference.split('|')
if not sim:
- avail_vals = set(self._cmd.read_file(self._intel_preference_path(cpu_id, True)).split())
+ avail_vals = set(self._cmd.read_file(self._pstate_preference_path(cpu_id, True)).split())
for val in vals:
if val in avail_vals:
- self._cmd.write_to_file(self._intel_preference_path(cpu_id), val)
+ self._cmd.write_to_file(self._pstate_preference_path(cpu_id), val, \
+ no_error = [errno.ENOENT] if remove else False)
log.info("Setting energy_performance_preference value '%s' for cpu '%s'" % (val, device))
break
else:
@@ -752,7 +767,7 @@ def _set_energy_performance_preference(self, energy_performance_preference, devi
% device)
return str(energy_performance_preference)
else:
- log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without the intel_pstate driver.")
+ log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without a P-state driver.")
return None
@command_get("energy_performance_preference")
@@ -761,9 +776,9 @@ def _get_energy_performance_preference(self, device, ignore_missing=False):
log.debug("%s is not online, skipping" % device)
return None
cpu_id = device.lstrip("cpu")
- # intel_pstate CPU scaling driver
- if os.path.exists(self._intel_preference_path(cpu_id, True)):
- return self._cmd.read_file(self._intel_preference_path(cpu_id)).strip()
+ # read the EPP hint used by the intel_pstate and amd-pstate CPU scaling drivers
+ if os.path.exists(self._pstate_preference_path(cpu_id, True)):
+ return self._cmd.read_file(self._pstate_preference_path(cpu_id)).strip()
else:
- log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without the intel_pstate driver.")
+ log.debug("energy_performance_available_preferences file missing, which can happen if the system is booted without a P-state driver.")
return None
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_disk.py b/assets/tuned/daemon/tuned/plugins/plugin_disk.py
index ffeb8ee2d..a5c1c283d 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_disk.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_disk.py
@@ -335,10 +335,11 @@ def _elevator_file(self, device):
return self._sysfs_path(device, "queue/scheduler")
@command_set("elevator", per_device=True)
- def _set_elevator(self, value, device, sim):
+ def _set_elevator(self, value, device, sim, remove):
sys_file = self._elevator_file(device)
if not sim:
- self._cmd.write_to_file(sys_file, value)
+ self._cmd.write_to_file(sys_file, value, \
+ no_error = [errno.ENOENT] if remove else False)
return value
@command_get("elevator")
@@ -349,7 +350,7 @@ def _get_elevator(self, device, ignore_missing=False):
return self._cmd.get_active_option(self._cmd.read_file(sys_file, no_error=ignore_missing))
@command_set("apm", per_device=True)
- def _set_apm(self, value, device, sim):
+ def _set_apm(self, value, device, sim, remove):
if device not in self._hdparm_apm_devices:
if not sim:
log.info("apm option is not supported for device '%s'" % device)
@@ -389,7 +390,7 @@ def _get_apm(self, device, ignore_missing=False):
return value
@command_set("spindown", per_device=True)
- def _set_spindown(self, value, device, sim):
+ def _set_spindown(self, value, device, sim, remove):
if device not in self._hdparm_apm_devices:
if not sim:
log.info("spindown option is not supported for device '%s'" % device)
@@ -428,14 +429,15 @@ def _parse_ra(self, value):
return v
@command_set("readahead", per_device=True)
- def _set_readahead(self, value, device, sim):
+ def _set_readahead(self, value, device, sim, remove):
sys_file = self._readahead_file(device)
val = self._parse_ra(value)
if val is None:
log.error("Invalid readahead value '%s' for device '%s'" % (value, device))
else:
if not sim:
- self._cmd.write_to_file(sys_file, "%d" % val)
+ self._cmd.write_to_file(sys_file, "%d" % val, \
+ no_error = [errno.ENOENT] if remove else False)
return val
@command_get("readahead")
@@ -471,10 +473,11 @@ def _scheduler_quantum_file(self, device):
return self._sysfs_path(device, "queue/iosched/quantum")
@command_set("scheduler_quantum", per_device=True)
- def _set_scheduler_quantum(self, value, device, sim):
+ def _set_scheduler_quantum(self, value, device, sim, remove):
sys_file = self._scheduler_quantum_file(device)
if not sim:
- self._cmd.write_to_file(sys_file, "%d" % int(value))
+ self._cmd.write_to_file(sys_file, "%d" % int(value), \
+ no_error = [errno.ENOENT] if remove else False)
return value
@command_get("scheduler_quantum")
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_modules.py b/assets/tuned/daemon/tuned/plugins/plugin_modules.py
index 04a6fcf12..eb815b2ef 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_modules.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_modules.py
@@ -134,8 +134,8 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
- if full_rollback == consts.ROLLBACK_FULL:
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
+ if rollback == consts.ROLLBACK_FULL:
self._clear_modprobe_file()
def _clear_modprobe_file(self):
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_net.py b/assets/tuned/daemon/tuned/plugins/plugin_net.py
index 1cc7b17bd..508f997e5 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_net.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_net.py
@@ -329,6 +329,8 @@ def _calc_speed(self, speed):
# parse features/coalesce config parameters (those defined in profile configuration)
# context is for error message
def _parse_config_parameters(self, value, context):
+ # expand config variables
+ value = self._variables.expand(value)
# split supporting various dellimeters
v = str(re.sub(r"(:\s*)|(\s+)|(\s*;\s*)|(\s*,\s*)", " ", value)).split()
lv = len(v)
@@ -347,7 +349,7 @@ def _parse_device_parameters(self, value):
# (rhbz#1225375)
value = self._cmd.multiple_re_replace({
"Adaptive RX:": "adaptive-rx:",
- "\s+TX:": "\nadaptive-tx:",
+ "\\s+TX:": "\nadaptive-tx:",
"rx-frame-low:": "rx-frames-low:",
"rx-frame-high:": "rx-frames-high:",
"tx-frame-low:": "tx-frames-low:",
@@ -366,7 +368,7 @@ def _parse_device_parameters(self, value):
"receive-hashing:": "rxhash:",
}, value)
# remove empty lines, remove fixed parameters (those with "[fixed]")
- vl = [v for v in value.split('\n') if len(str(v)) > 0 and not re.search("\[fixed\]$", str(v))]
+ vl = [v for v in value.split('\n') if len(str(v)) > 0 and not re.search(r"\[fixed\]$", str(v))]
if len(vl) < 2:
return None
# skip first line (device name), split to key/value,
@@ -378,7 +380,7 @@ def _nf_conntrack_hashsize_path(self):
return "/sys/module/nf_conntrack/parameters/hashsize"
@command_set("wake_on_lan", per_device=True)
- def _set_wake_on_lan(self, value, device, sim):
+ def _set_wake_on_lan(self, value, device, sim, remove):
if value is None:
return None
@@ -404,14 +406,15 @@ def _get_wake_on_lan(self, device, ignore_missing=False):
return value
@command_set("nf_conntrack_hashsize")
- def _set_nf_conntrack_hashsize(self, value, sim):
+ def _set_nf_conntrack_hashsize(self, value, sim, remove):
if value is None:
return None
hashsize = int(value)
if hashsize >= 0:
if not sim:
- self._cmd.write_to_file(self._nf_conntrack_hashsize_path(), hashsize)
+ self._cmd.write_to_file(self._nf_conntrack_hashsize_path(), hashsize, \
+ no_error = [errno.ENOENT] if remove else False)
return hashsize
else:
return None
@@ -445,7 +448,7 @@ def _ip_link_show(self, device=None):
return self._call_ip_link(args)
@command_set("txqueuelen", per_device=True)
- def _set_txqueuelen(self, value, device, sim):
+ def _set_txqueuelen(self, value, device, sim, remove):
if value is None:
return None
try:
@@ -485,7 +488,7 @@ def _get_txqueuelen(self, device, ignore_missing=False):
return res.group(1)
@command_set("mtu", per_device=True)
- def _set_mtu(self, value, device, sim):
+ def _set_mtu(self, value, device, sim, remove):
if value is None:
return None
try:
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_scheduler.py b/assets/tuned/daemon/tuned/plugins/plugin_scheduler.py
index f365510cc..9b0467b1a 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_scheduler.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_scheduler.py
@@ -135,7 +135,7 @@ def get_priority_max(self, sched):
return schedutils.get_priority_max(sched)
class SchedulerPlugin(base.Plugin):
- """
+ r"""
`scheduler`::
Allows tuning of scheduling priorities, process/thread/IRQ
@@ -1003,8 +1003,8 @@ def _cgroup_cleanup_tasks(self):
for cg in self._cgroups:
self._cgroup_cleanup_tasks_one(cg)
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
- super(SchedulerPlugin, self)._instance_unapply_static(instance, full_rollback)
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
+ super(SchedulerPlugin, self)._instance_unapply_static(instance, rollback)
if self._daemon and instance._runtime_tuning:
instance._terminate.set()
instance._thread.join()
@@ -1414,12 +1414,13 @@ def _get_sched_knob(self, prefix, namespace, knob):
self._secure_boot_hint = False
return data
- def _set_sched_knob(self, prefix, namespace, knob, value, sim):
+ def _set_sched_knob(self, prefix, namespace, knob, value, sim, remove = False):
if value is None:
return None
if not sim:
- if not self._cmd.write_to_file(self._get_sched_knob_path(prefix, namespace, knob), value):
- log.error("Error writing value '%s' to '%s'" % (value, knob))
+ if not self._cmd.write_to_file(self._get_sched_knob_path(prefix, namespace, knob), value, \
+ no_error = [errno.ENOENT] if remove else False):
+ log.error("Error writing value '%s' to '%s'" % (value, knob))
return value
@command_get("sched_min_granularity_ns")
@@ -1427,77 +1428,77 @@ def _get_sched_min_granularity_ns(self):
return self._get_sched_knob("", "sched", "min_granularity_ns")
@command_set("sched_min_granularity_ns")
- def _set_sched_min_granularity_ns(self, value, sim):
- return self._set_sched_knob("", "sched", "min_granularity_ns", value, sim)
+ def _set_sched_min_granularity_ns(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "min_granularity_ns", value, sim, remove)
@command_get("sched_latency_ns")
def _get_sched_latency_ns(self):
return self._get_sched_knob("", "sched", "latency_ns")
@command_set("sched_latency_ns")
- def _set_sched_latency_ns(self, value, sim):
- return self._set_sched_knob("", "sched", "latency_ns", value, sim)
+ def _set_sched_latency_ns(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "latency_ns", value, sim, remove)
@command_get("sched_wakeup_granularity_ns")
def _get_sched_wakeup_granularity_ns(self):
return self._get_sched_knob("", "sched", "wakeup_granularity_ns")
@command_set("sched_wakeup_granularity_ns")
- def _set_sched_wakeup_granularity_ns(self, value, sim):
- return self._set_sched_knob("", "sched", "wakeup_granularity_ns", value, sim)
+ def _set_sched_wakeup_granularity_ns(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "wakeup_granularity_ns", value, sim, remove)
@command_get("sched_tunable_scaling")
def _get_sched_tunable_scaling(self):
return self._get_sched_knob("", "sched", "tunable_scaling")
@command_set("sched_tunable_scaling")
- def _set_sched_tunable_scaling(self, value, sim):
- return self._set_sched_knob("", "sched", "tunable_scaling", value, sim)
+ def _set_sched_tunable_scaling(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "tunable_scaling", value, sim, remove)
@command_get("sched_migration_cost_ns")
def _get_sched_migration_cost_ns(self):
return self._get_sched_knob("", "sched", "migration_cost_ns")
@command_set("sched_migration_cost_ns")
- def _set_sched_migration_cost_ns(self, value, sim):
- return self._set_sched_knob("", "sched", "migration_cost_ns", value, sim)
+ def _set_sched_migration_cost_ns(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "migration_cost_ns", value, sim, remove)
@command_get("sched_nr_migrate")
def _get_sched_nr_migrate(self):
return self._get_sched_knob("", "sched", "nr_migrate")
@command_set("sched_nr_migrate")
- def _set_sched_nr_migrate(self, value, sim):
- return self._set_sched_knob("", "sched", "nr_migrate", value, sim)
+ def _set_sched_nr_migrate(self, value, sim, remove):
+ return self._set_sched_knob("", "sched", "nr_migrate", value, sim, remove)
@command_get("numa_balancing_scan_delay_ms")
def _get_numa_balancing_scan_delay_ms(self):
return self._get_sched_knob("sched", "numa_balancing", "scan_delay_ms")
@command_set("numa_balancing_scan_delay_ms")
- def _set_numa_balancing_scan_delay_ms(self, value, sim):
- return self._set_sched_knob("sched", "numa_balancing", "scan_delay_ms", value, sim)
+ def _set_numa_balancing_scan_delay_ms(self, value, sim, remove):
+ return self._set_sched_knob("sched", "numa_balancing", "scan_delay_ms", value, sim, remove)
@command_get("numa_balancing_scan_period_min_ms")
def _get_numa_balancing_scan_period_min_ms(self):
return self._get_sched_knob("sched", "numa_balancing", "scan_period_min_ms")
@command_set("numa_balancing_scan_period_min_ms")
- def _set_numa_balancing_scan_period_min_ms(self, value, sim):
- return self._set_sched_knob("sched", "numa_balancing", "scan_period_min_ms", value, sim)
+ def _set_numa_balancing_scan_period_min_ms(self, value, sim, remove):
+ return self._set_sched_knob("sched", "numa_balancing", "scan_period_min_ms", value, sim, remove)
@command_get("numa_balancing_scan_period_max_ms")
def _get_numa_balancing_scan_period_max_ms(self):
return self._get_sched_knob("sched", "numa_balancing", "scan_period_max_ms")
@command_set("numa_balancing_scan_period_max_ms")
- def _set_numa_balancing_scan_period_max_ms(self, value, sim):
- return self._set_sched_knob("sched", "numa_balancing", "scan_period_max_ms", value, sim)
+ def _set_numa_balancing_scan_period_max_ms(self, value, sim, remove):
+ return self._set_sched_knob("sched", "numa_balancing", "scan_period_max_ms", value, sim, remove)
@command_get("numa_balancing_scan_size_mb")
def _get_numa_balancing_scan_size_mb(self):
return self._get_sched_knob("sched", "numa_balancing", "scan_size_mb")
@command_set("numa_balancing_scan_size_mb")
- def _set_numa_balancing_scan_size_mb(self, value, sim):
- return self._set_sched_knob("sched", "numa_balancing", "scan_size_mb", value, sim)
+ def _set_numa_balancing_scan_size_mb(self, value, sim, remove):
+ return self._set_sched_knob("sched", "numa_balancing", "scan_size_mb", value, sim, remove)
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_script.py b/assets/tuned/daemon/tuned/plugins/plugin_script.py
index ad7373b4a..ab605e429 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_script.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_script.py
@@ -113,9 +113,9 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
args = ["stop"]
- if full_rollback == consts.ROLLBACK_FULL:
+ if rollback == consts.ROLLBACK_FULL:
args = args + ["full_rollback"]
self._call_scripts(reversed(instance._scripts), args)
- super(ScriptPlugin, self)._instance_unapply_static(instance, full_rollback)
+ super(ScriptPlugin, self)._instance_unapply_static(instance, rollback)
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_scsi_host.py b/assets/tuned/daemon/tuned/plugins/plugin_scsi_host.py
index 2a087de20..a230a1286 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_scsi_host.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_scsi_host.py
@@ -86,13 +86,14 @@ def _get_alpm_policy_file(self, device):
return os.path.join("/sys/class/scsi_host/", str(device), "link_power_management_policy")
@command_set("alpm", per_device = True)
- def _set_alpm(self, policy, device, sim):
+ def _set_alpm(self, policy, device, sim, remove):
if policy is None:
return None
policy_file = self._get_alpm_policy_file(device)
if not sim:
if os.path.exists(policy_file):
- self._cmd.write_to_file(policy_file, policy)
+ self._cmd.write_to_file(policy_file, policy, \
+ no_error = [errno.ENOENT] if remove else False)
else:
log.info("ALPM control file ('%s') not found, skipping ALPM setting for '%s'" % (policy_file, str(device)))
return None
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_selinux.py b/assets/tuned/daemon/tuned/plugins/plugin_selinux.py
index c228f6c8b..313b9c4a9 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_selinux.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_selinux.py
@@ -1,4 +1,5 @@
import os
+import errno
from . import base
from .decorators import *
import tuned.logs
@@ -63,13 +64,14 @@ def _instance_cleanup(self, instance):
pass
@command_set("avc_cache_threshold")
- def _set_avc_cache_threshold(self, value, sim):
+ def _set_avc_cache_threshold(self, value, sim, remove):
if value is None:
return None
threshold = int(value)
if threshold >= 0:
if not sim:
- self._cmd.write_to_file(self._cache_threshold_path, threshold)
+ self._cmd.write_to_file(self._cache_threshold_path, threshold, \
+ no_error = [errno.ENOENT] if remove else False)
return threshold
else:
return None
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_service.py b/assets/tuned/daemon/tuned/plugins/plugin_service.py
index 7f4f68e25..2f2f20eea 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_service.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_service.py
@@ -313,7 +313,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
for name, value in list(instance._services_original.items()):
if value.cfg_file:
self._init_handler.cfg_uninstall(name, value.cfg_file)
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_sysctl.py b/assets/tuned/daemon/tuned/plugins/plugin_sysctl.py
index e8beb08c6..9292df01e 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_sysctl.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_sysctl.py
@@ -66,7 +66,7 @@ def _instance_cleanup(self, instance):
def _instance_apply_static(self, instance):
for option, value in list(instance._sysctl.items()):
- original_value = _read_sysctl(option)
+ original_value = self._read_sysctl(option)
if original_value is None:
log.error("sysctl option %s will not be set, failed to read the original value."
% option)
@@ -77,130 +77,133 @@ def _instance_apply_static(self, instance):
new_value, original_value)
if new_value is not None:
instance._sysctl_original[option] = original_value
- _write_sysctl(option, new_value)
+ self._write_sysctl(option, new_value)
storage_key = self._storage_key(instance.name)
self._storage.set(storage_key, instance._sysctl_original)
if self._global_cfg.get_bool(consts.CFG_REAPPLY_SYSCTL, consts.CFG_DEF_REAPPLY_SYSCTL):
log.info("reapplying system sysctl")
- _apply_system_sysctl(instance._sysctl)
+ self._apply_system_sysctl(instance._sysctl)
def _instance_verify_static(self, instance, ignore_missing, devices):
ret = True
# override, so always skip missing
ignore_missing = True
for option, value in list(instance._sysctl.items()):
- curr_val = _read_sysctl(option)
+ curr_val = self._read_sysctl(option)
value = self._process_assignment_modifiers(self._variables.expand(value), curr_val)
if value is not None:
if self._verify_value(option, self._cmd.remove_ws(value), self._cmd.remove_ws(curr_val), ignore_missing) == False:
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
for option, value in list(instance._sysctl_original.items()):
- _write_sysctl(option, value)
-
-
-def _apply_system_sysctl(instance_sysctl):
- files = {}
- for d in SYSCTL_CONFIG_DIRS:
- try:
- flist = os.listdir(d)
- except OSError:
- continue
- for fname in flist:
- if not fname.endswith(".conf"):
+ self._write_sysctl(option, value)
+
+ def _apply_system_sysctl(self, instance_sysctl):
+ files = {}
+ for d in SYSCTL_CONFIG_DIRS:
+ try:
+ flist = os.listdir(d)
+ except OSError:
continue
- if fname not in files:
- files[fname] = d
-
- for fname in sorted(files.keys()):
- d = files[fname]
- path = "%s/%s" % (d, fname)
- _apply_sysctl_config_file(path, instance_sysctl)
- _apply_sysctl_config_file("/etc/sysctl.conf", instance_sysctl)
-
-def _apply_sysctl_config_file(path, instance_sysctl):
- log.debug("Applying sysctl settings from file %s" % path)
- try:
- with open(path, "r") as f:
- for lineno, line in enumerate(f, 1):
- _apply_sysctl_config_line(path, lineno, line, instance_sysctl)
- log.debug("Finished applying sysctl settings from file %s"
- % path)
- except (OSError, IOError) as e:
- if e.errno != errno.ENOENT:
- log.error("Error reading sysctl settings from file %s: %s"
- % (path, str(e)))
-
-def _apply_sysctl_config_line(path, lineno, line, instance_sysctl):
- line = line.strip()
- if len(line) == 0 or line[0] == "#" or line[0] == ";":
- return
- tmp = line.split("=", 1)
- if len(tmp) != 2:
- log.error("Syntax error in file %s, line %d"
- % (path, lineno))
- return
- option, value = tmp
- option = option.strip()
- if len(option) == 0:
- log.error("Syntax error in file %s, line %d"
- % (path, lineno))
- return
- value = value.strip()
- if option in instance_sysctl and instance_sysctl[option] != value:
- log.info("Overriding sysctl parameter '%s' from '%s' to '%s'"
- % (option, instance_sysctl[option], value))
-
- _write_sysctl(option, value, ignore_missing = True)
-
-def _get_sysctl_path(option):
- return "/proc/sys/%s" % option.replace(".", "/")
-
-def _read_sysctl(option):
- path = _get_sysctl_path(option)
- try:
- with open(path, "r") as f:
- line = ""
- for i, line in enumerate(f):
- if i > 0:
- log.error("Failed to read sysctl parameter '%s', multi-line values are unsupported"
- % option)
- return None
- value = line.strip()
- log.debug("Value of sysctl parameter '%s' is '%s'"
- % (option, value))
- return value
- except (OSError, IOError) as e:
- if e.errno == errno.ENOENT:
- log.error("Failed to read sysctl parameter '%s', the parameter does not exist"
+ for fname in flist:
+ if not fname.endswith(".conf"):
+ continue
+ if fname not in files:
+ files[fname] = d
+
+ for fname in sorted(files.keys()):
+ d = files[fname]
+ path = "%s/%s" % (d, fname)
+ self._apply_sysctl_config_file(path, instance_sysctl)
+ self._apply_sysctl_config_file("/etc/sysctl.conf", instance_sysctl)
+
+ def _apply_sysctl_config_file(self, path, instance_sysctl):
+ log.debug("Applying sysctl settings from file %s" % path)
+ try:
+ with open(path, "r") as f:
+ for lineno, line in enumerate(f, 1):
+ self._apply_sysctl_config_line(path, lineno, line, instance_sysctl)
+ log.debug("Finished applying sysctl settings from file %s"
+ % path)
+ except (OSError, IOError) as e:
+ if e.errno != errno.ENOENT:
+ log.error("Error reading sysctl settings from file %s: %s"
+ % (path, str(e)))
+
+ def _apply_sysctl_config_line(self, path, lineno, line, instance_sysctl):
+ line = line.strip()
+ if len(line) == 0 or line[0] == "#" or line[0] == ";":
+ return
+ tmp = line.split("=", 1)
+ if len(tmp) != 2:
+ log.error("Syntax error in file %s, line %d"
+ % (path, lineno))
+ return
+ option, value = tmp
+ option = option.strip()
+ if len(option) == 0:
+ log.error("Syntax error in file %s, line %d"
+ % (path, lineno))
+ return
+ value = value.strip()
+ if option in instance_sysctl and instance_sysctl[option] != value:
+ log.info("Overriding sysctl parameter '%s' from '%s' to '%s'"
+ % (option, instance_sysctl[option], value))
+
+ self._write_sysctl(option, value, ignore_missing = True)
+
+ def _get_sysctl_path(self, option):
+ # The sysctl name in sysctl tool and in /proc/sys differs.
+ # All dots (.) in sysctl name are represented by /proc/sys
+ # directories and all slashes in the name (/) are converted
+ # to dots (.) in the /proc/sys filenames.
+ return "/proc/sys/%s" % self._cmd.tr(option, "./", "/.")
+
+ def _read_sysctl(self, option):
+ path = self._get_sysctl_path(option)
+ try:
+ with open(path, "r") as f:
+ line = ""
+ for i, line in enumerate(f):
+ if i > 0:
+ log.error("Failed to read sysctl parameter '%s', multi-line values are unsupported"
+ % option)
+ return None
+ value = line.strip()
+ log.debug("Value of sysctl parameter '%s' is '%s'"
+ % (option, value))
+ return value
+ except (OSError, IOError) as e:
+ if e.errno == errno.ENOENT:
+ log.error("Failed to read sysctl parameter '%s', the parameter does not exist"
+ % option)
+ else:
+ log.error("Failed to read sysctl parameter '%s': %s"
+ % (option, str(e)))
+ return None
+
+ def _write_sysctl(self, option, value, ignore_missing = False):
+ path = self._get_sysctl_path(option)
+ if os.path.basename(path) in DEPRECATED_SYSCTL_OPTIONS:
+ log.error("Refusing to set deprecated sysctl option %s"
% option)
- else:
- log.error("Failed to read sysctl parameter '%s': %s"
- % (option, str(e)))
- return None
-
-def _write_sysctl(option, value, ignore_missing = False):
- path = _get_sysctl_path(option)
- if os.path.basename(path) in DEPRECATED_SYSCTL_OPTIONS:
- log.error("Refusing to set deprecated sysctl option %s"
- % option)
- return False
- try:
- log.debug("Setting sysctl parameter '%s' to '%s'"
- % (option, value))
- with open(path, "w") as f:
- f.write(value)
- return True
- except (OSError, IOError) as e:
- if e.errno == errno.ENOENT:
- log_func = log.debug if ignore_missing else log.error
- log_func("Failed to set sysctl parameter '%s' to '%s', the parameter does not exist"
+ return False
+ try:
+ log.debug("Setting sysctl parameter '%s' to '%s'"
% (option, value))
- else:
- log.error("Failed to set sysctl parameter '%s' to '%s': %s"
- % (option, value, str(e)))
- return False
+ with open(path, "w") as f:
+ f.write(value)
+ return True
+ except (OSError, IOError) as e:
+ if e.errno == errno.ENOENT:
+ log_func = log.debug if ignore_missing else log.error
+ log_func("Failed to set sysctl parameter '%s' to '%s', the parameter does not exist"
+ % (option, value))
+ else:
+ log.error("Failed to set sysctl parameter '%s' to '%s': %s"
+ % (option, value, str(e)))
+ return False
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_sysfs.py b/assets/tuned/daemon/tuned/plugins/plugin_sysfs.py
index a638c33c7..4f14e2add 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_sysfs.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_sysfs.py
@@ -72,7 +72,7 @@ def _instance_verify_static(self, instance, ignore_missing, devices):
ret = False
return ret
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
for key, value in list(instance._sysfs_original.items()):
self._write_sysfs(key, value)
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_systemd.py b/assets/tuned/daemon/tuned/plugins/plugin_systemd.py
index 1638c0d50..49304ae48 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_systemd.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_systemd.py
@@ -111,8 +111,8 @@ def _remove_systemd_tuning(self):
conf = self._add_keyval(conf, consts.SYSTEMD_CPUAFFINITY_VAR, cpu_affinity_saved)
self._write_systemd_system_conf(conf)
- def _instance_unapply_static(self, instance, full_rollback = consts.ROLLBACK_SOFT):
- if full_rollback == consts.ROLLBACK_FULL:
+ def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT):
+ if rollback == consts.ROLLBACK_FULL:
log.info("removing '%s' systemd tuning previously added by TuneD" % consts.SYSTEMD_CPUAFFINITY_VAR)
self._remove_systemd_tuning()
log.console("you may need to manualy run 'dracut -f' to update the systemd configuration in initrd image")
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_usb.py b/assets/tuned/daemon/tuned/plugins/plugin_usb.py
index 536a2f221..159d336f1 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_usb.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_usb.py
@@ -3,6 +3,7 @@
import tuned.logs
from tuned.utils.commands import commands
import glob
+import errno
log = tuned.logs.get()
@@ -57,7 +58,7 @@ def _autosuspend_sysfile(self, device):
return "/sys/bus/usb/devices/%s/power/autosuspend" % device
@command_set("autosuspend", per_device=True)
- def _set_autosuspend(self, value, device, sim):
+ def _set_autosuspend(self, value, device, sim, remove):
enable = self._option_bool(value)
if enable is None:
return None
@@ -65,7 +66,8 @@ def _set_autosuspend(self, value, device, sim):
val = "1" if enable else "0"
if not sim:
sys_file = self._autosuspend_sysfile(device)
- self._cmd.write_to_file(sys_file, val)
+ self._cmd.write_to_file(sys_file, val, \
+ no_error = [errno.ENOENT] if remove else False)
return val
@command_get("autosuspend")
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_video.py b/assets/tuned/daemon/tuned/plugins/plugin_video.py
index e955ad934..a93d60991 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_video.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_video.py
@@ -3,6 +3,7 @@
import tuned.logs
from tuned.utils.commands import commands
import os
+import errno
import re
log = tuned.logs.get()
@@ -76,7 +77,7 @@ def _radeon_powersave_files(self, device):
}
@command_set("radeon_powersave", per_device=True)
- def _set_radeon_powersave(self, value, device, sim):
+ def _set_radeon_powersave(self, value, device, sim, remove):
sys_files = self._radeon_powersave_files(device)
va = str(re.sub(r"(\s*:\s*)|(\s+)|(\s*;\s*)|(\s*,\s*)", " ", value)).split()
if not os.path.exists(sys_files["method"]):
@@ -86,20 +87,25 @@ def _set_radeon_powersave(self, value, device, sim):
for v in va:
if v in ["default", "auto", "low", "mid", "high"]:
if not sim:
- if (self._cmd.write_to_file(sys_files["method"], "profile") and
- self._cmd.write_to_file(sys_files["profile"], v)):
- return v
+ if (self._cmd.write_to_file(sys_files["method"], "profile", \
+ no_error = [errno.ENOENT] if remove else False) and
+ self._cmd.write_to_file(sys_files["profile"], v, \
+ no_error = [errno.ENOENT] if remove else False)):
+ return v
elif v == "dynpm":
if not sim:
- if (self._cmd.write_to_file(sys_files["method"], "dynpm")):
- return "dynpm"
+ if (self._cmd.write_to_file(sys_files["method"], "dynpm", \
+ no_error = [errno.ENOENT] if remove else False)):
+ return "dynpm"
# new DPM profiles, recommended to use if supported
elif v in ["dpm-battery", "dpm-balanced", "dpm-performance"]:
if not sim:
state = v[len("dpm-"):]
- if (self._cmd.write_to_file(sys_files["method"], "dpm") and
- self._cmd.write_to_file(sys_files["dpm_state"], state)):
- return v
+ if (self._cmd.write_to_file(sys_files["method"], "dpm", \
+ no_error = [errno.ENOENT] if remove else False) and
+ self._cmd.write_to_file(sys_files["dpm_state"], state, \
+ no_error = [errno.ENOENT] if remove else False)):
+ return v
else:
if not sim:
log.warn("Invalid option for radeon_powersave.")
diff --git a/assets/tuned/daemon/tuned/plugins/plugin_vm.py b/assets/tuned/daemon/tuned/plugins/plugin_vm.py
index 9b5e4f7ff..e86230b63 100644
--- a/assets/tuned/daemon/tuned/plugins/plugin_vm.py
+++ b/assets/tuned/daemon/tuned/plugins/plugin_vm.py
@@ -3,6 +3,7 @@
import tuned.logs
import os
+import errno
import struct
import glob
from tuned.utils.commands import commands
@@ -57,7 +58,7 @@ def _thp_path(self):
return path
@command_set("transparent_hugepages")
- def _set_transparent_hugepages(self, value, sim):
+ def _set_transparent_hugepages(self, value, sim, remove):
if value not in ["always", "never", "madvise"]:
if not sim:
log.warn("Incorrect 'transparent_hugepages' value '%s'." % str(value))
@@ -72,7 +73,8 @@ def _set_transparent_hugepages(self, value, sim):
sys_file = os.path.join(self._thp_path(), "enabled")
if os.path.exists(sys_file):
if not sim:
- cmd.write_to_file(sys_file, value)
+ cmd.write_to_file(sys_file, value, \
+ no_error = [errno.ENOENT] if remove else False)
return value
else:
if not sim:
@@ -81,8 +83,8 @@ def _set_transparent_hugepages(self, value, sim):
# just an alias to transparent_hugepages
@command_set("transparent_hugepage")
- def _set_transparent_hugepage(self, value, sim):
- self._set_transparent_hugepages(value, sim)
+ def _set_transparent_hugepage(self, value, sim, remove):
+ self._set_transparent_hugepages(value, sim, remove)
@command_get("transparent_hugepages")
def _get_transparent_hugepages(self):
@@ -98,11 +100,12 @@ def _get_transparent_hugepage(self):
return self._get_transparent_hugepages()
@command_set("transparent_hugepage.defrag")
- def _set_transparent_hugepage_defrag(self, value, sim):
+ def _set_transparent_hugepage_defrag(self, value, sim, remove):
sys_file = os.path.join(self._thp_path(), "defrag")
if os.path.exists(sys_file):
if not sim:
- cmd.write_to_file(sys_file, value)
+ cmd.write_to_file(sys_file, value, \
+ no_error = [errno.ENOENT] if remove else False)
return value
else:
if not sim:
diff --git a/assets/tuned/daemon/tuned/profiles/functions/function_calc_isolated_cores.py b/assets/tuned/daemon/tuned/profiles/functions/function_calc_isolated_cores.py
index 5c5cad3d3..67b9b950d 100644
--- a/assets/tuned/daemon/tuned/profiles/functions/function_calc_isolated_cores.py
+++ b/assets/tuned/daemon/tuned/profiles/functions/function_calc_isolated_cores.py
@@ -32,7 +32,12 @@ def execute(self, args):
for cpu in glob.iglob(os.path.join(consts.SYSFS_CPUS_PATH, "cpu*")):
cpuid = os.path.basename(cpu)[3:]
if cpuid.isdecimal():
- socket = self._cmd.read_file(os.path.join(cpu, "topology/physical_package_id")).strip()
+ physical_package_id = os.path.join(cpu, "topology/physical_package_id")
+ # Show no errors when the physical_package_id file does not exist -- the CPU may be offline.
+ if not os.path.exists(physical_package_id):
+ log.debug("file '%s' does not exist, cpu%s offline?" % (physical_package_id, cpuid))
+ continue
+ socket = self._cmd.read_file(physical_package_id).strip()
if socket.isdecimal():
topo[socket] = topo.get(socket, []) + [cpuid]
diff --git a/assets/tuned/daemon/tuned/profiles/functions/functions.py b/assets/tuned/daemon/tuned/profiles/functions/functions.py
index a537843b2..6ea2baaf0 100644
--- a/assets/tuned/daemon/tuned/profiles/functions/functions.py
+++ b/assets/tuned/daemon/tuned/profiles/functions/functions.py
@@ -46,7 +46,7 @@ def _process_func(self, _from):
sl = re.split(r'(?[^' + delims + '\s][^' + delims + ']*)'
- r'\s*(?P[' + delims + '])\s*'
+ r'(?P