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 + + True + False + + + True + False + Add Value + True + + + + + + True + False + Add Custom Value + True + + + + + + True + False + + + + + True + False + Delete Value + True + + + + + + 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 + True + Value ... + + + False + True + 1 + + + + + False + True + 1 + + + + + + button3 + button4 + + 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