Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package tuned for openSUSE:Factory checked in at 2025-09-10 20:22:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/tuned (Old) and /work/SRC/openSUSE:Factory/.tuned.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "tuned" Wed Sep 10 20:22:41 2025 rev:48 rq:1303530 version:2.26.0.0+git.181472a Changes: -------- --- /work/SRC/openSUSE:Factory/tuned/tuned.changes 2025-06-02 22:01:20.987185031 +0200 +++ /work/SRC/openSUSE:Factory/.tuned.new.1977/tuned.changes 2025-09-10 20:22:43.666446094 +0200 @@ -1,0 +2,41 @@ +Wed Sep 10 07:01:06 UTC 2025 - Thomas Renninger <[email protected]> + +- Update to version 2.26.0.0+git.181472a: + * new release (2.26.0) + * new release (2.26.0-rc.1) + * fix: add no_turbo option in profiles where boost is used + * If plugin isn't supported, log details why it isn't supported + * Fixed instance priority inheritance + * functions: Make calc_isolated_cores return CPU ranges + * Allow overriding the no_turbo setting + * udev: fix possible traceback in device matcher + * vm: Deprecate dirty_ratio in favour of dirty_bytes with % + * tuned-ppd: Pin virtual files in memory for inotify + * tuned-ppd: Fix indentation + * tuned-ppd: Fix inotify watch for performance degradation + * Dockerfile: New to build on a bootc image + * bootloader: Remove previously appended rpm-ostree kargs + * bootloader: Simplify tuning of rpm-ostree kargs + * udev-settle: obey udev buffer size and handle possible tracebacks + * plugins: Support MMC devices + * CI: build and test for c10s + * tests/beakerlib: remove old API call. + * spec: minor spec cleanup and enabled doc install on RHEL + * tuned-main.conf: added startup_udev_settle_wait option + * consts: fixed whitespaces + * Re-raise daemon init exception in no-daemon mode + * scsi: Do not set ALPM on external SATA ports + * realtime: Disable appropriate P-State drivers + * beakerlib: Use ncat explicitly instead of nc + * hotplug: fixed device remove race condition + * perf: dropped from irqbalance and improved detection in scheduler + * variables: Add an option to prepend child variables before parent ones + * ppd: Enable sysfs_acpi_monitor by default + * GUI: Fix the profile deleter script + * functions: Silence errors if module kvm_intel does not exist + * ppd: Rename thinkpad_function_keys as sysfs_acpi_monitor + * network_latency: Set non-zero rcutree.nohz_full_patience_delay + * profiles: use `med_power_with_dipm` for SATA ALPM Using `min_power` can lead to data loss, and `med_power_with_dipm` delivers similar power savings without the chance of data loss. [1] + * plugins: document `med_power_with_dipm` SATA ALPM option The use of `min_power` can lead to data corruption[1] and has been replaced in the documentation, and an example using `medium_power` was updated to use `med_power_with_dipm` (the kernel default[2] with better better power savings than `medium_power`). + +------------------------------------------------------------------- Old: ---- tuned-2.25.1.0+git.889387b.obscpio New: ---- tuned-2.26.0.0+git.181472a.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ tuned.spec ++++++ --- /var/tmp/diff_new_pack.3m0nyP/_old 2025-09-10 20:22:44.750491856 +0200 +++ /var/tmp/diff_new_pack.3m0nyP/_new 2025-09-10 20:22:44.754492025 +0200 @@ -19,7 +19,7 @@ %define system_dir %{_prefix}/lib/%{name}/ %define profile_dir %{system_dir}profiles/ Name: tuned -Version: 2.25.1.0+git.889387b +Version: 2.26.0.0+git.181472a Release: 0 Summary: A dynamic adaptive system tuning daemon License: GPL-2.0-or-later ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.3m0nyP/_old 2025-09-10 20:22:44.798493882 +0200 +++ /var/tmp/diff_new_pack.3m0nyP/_new 2025-09-10 20:22:44.802494051 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/redhat-performance/tuned</param> - <param name="changesrevision">889387b0001b783514523162de21af406e31a549</param></service></servicedata> + <param name="changesrevision">181472a0be2125c8cd36c7673ec546d75d396a3d</param></service></servicedata> (No newline at EOF) ++++++ tuned-2.25.1.0+git.889387b.obscpio -> tuned-2.26.0.0+git.181472a.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/.dockerignore new/tuned-2.26.0.0+git.181472a/.dockerignore --- old/tuned-2.25.1.0+git.889387b/.dockerignore 1970-01-01 01:00:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/.dockerignore 2025-08-24 23:48:04.000000000 +0200 @@ -0,0 +1,2 @@ +# Avoid rebuilding when this changes +Dockerfile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/.github/workflows/docker-build.yml new/tuned-2.26.0.0+git.181472a/.github/workflows/docker-build.yml --- old/tuned-2.25.1.0+git.889387b/.github/workflows/docker-build.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/.github/workflows/docker-build.yml 2025-08-24 23:48:04.000000000 +0200 @@ -0,0 +1,22 @@ +name: Docker Build + +on: + workflow_dispatch: + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - name: Get a newer podman for heredoc support (from debian testing) + run: | + set -eux + echo 'deb [trusted=yes] https://ftp.debian.org/debian/ testing main' | sudo tee /etc/apt/sources.list.d/testing.list + sudo apt update + sudo apt install -y crun/testing podman/testing skopeo/testing + + - uses: actions/checkout@v4 + + - name: Build container + run: sudo podman build -t localhost/tuned . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/.packit.yaml new/tuned-2.26.0.0+git.181472a/.packit.yaml --- old/tuned-2.25.1.0+git.889387b/.packit.yaml 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/.packit.yaml 2025-08-24 23:48:04.000000000 +0200 @@ -8,6 +8,7 @@ - epel-7-x86_64 - epel-8-x86_64 - centos-stream-9-x86_64 + - centos-stream-10-x86_64 - job: tests trigger: pull_request targets: @@ -15,6 +16,7 @@ - epel-7-x86_64 - epel-8-x86_64 - centos-stream-9-x86_64 + - centos-stream-10-x86_64 files_to_sync: - tuned.spec diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/Dockerfile new/tuned-2.26.0.0+git.181472a/Dockerfile --- old/tuned-2.25.1.0+git.889387b/Dockerfile 1970-01-01 01:00:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/Dockerfile 2025-08-24 23:48:04.000000000 +0200 @@ -0,0 +1,30 @@ +ARG base=quay.io/centos-bootc/centos-bootc:stream10 + +FROM $base as build +COPY tuned.spec /tmp/tuned.spec +# This installs our package dependencies, and we want to cache it independently of the rest. +RUN <<EORUN +set -xeuo pipefail +dnf -y install rpm-build +dnf -y builddep /tmp/tuned.spec +EORUN +# Now copy the rest of the source +COPY . /build +WORKDIR /build +RUN <<EORUN +set -xeuo pipefail +mkdir -p /var/roothome +make rpm +mkdir -p /out +mv ~/rpmbuild/RPMS/noarch/tuned-2*.rpm /out +EORUN + +FROM $base +RUN --mount=from=build,target=/build,type=bind <<EORUN +set -xeuo pipefail +dnf -y install /build/out/*.rpm +dnf clean all +rm -rf /var/{lib,cache,log}/* +bootc container lint --fatal-warnings +EORUN + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc --- old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/con_inheritance-between-tuned-profiles.adoc 2025-08-24 23:48:04.000000000 +0200 @@ -22,14 +22,14 @@ .A power-saving profile based on balanced ==== -The following is an example of a custom profile that extends the `balanced` profile and sets Aggressive Link Power Management (ALPM) for all devices to the maximum powersaving. +The following is an example of a custom profile that extends the `balanced` profile and disables the capability of the CPU to boost above nominal frequencies for brief periods. ---- [main] include=balanced -[scsi_host] -alpm=min_power +[cpu] +boost=0 ---- ==== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc --- old/tuned-2.25.1.0+git.889387b/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/doc/manual/modules/performance/proc_creating-new-tuned-profiles.adoc 2025-08-24 23:48:04.000000000 +0200 @@ -43,7 +43,7 @@ radeon_powersave=dpm-balanced, auto [scsi_host] -alpm=medium_power +alpm=med_power_with_dipm ---- . To activate the profile, use: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/functions new/tuned-2.26.0.0+git.181472a/functions --- old/tuned-2.25.1.0+git.889387b/functions 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/functions 2025-08-24 23:48:04.000000000 +0200 @@ -477,7 +477,7 @@ modinfo -p kvm | grep -q kvmclock_periodic_sync && HAS_KPS=1 modinfo -p kvm | grep -q nx_huge_pages && HAS_NX_HP=1 - modinfo -p kvm_intel | grep -q ple_gap && HAS_PLE_GAP=1 + modinfo -p kvm_intel 2>/dev/null | grep -q ple_gap && HAS_PLE_GAP=1 grep -qs kvmclock_periodic_sync "$kvm_modprobe_file" && WANTS_KPS=1 grep -qs nx_huge_pages "$kvm_modprobe_file" && WANTS_NX_HP=1 grep -qs ple_gap "$kvm_modprobe_file" && WANTS_PLE_GAP=1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/accelerator-performance/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/accelerator-performance/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/accelerator-performance/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/accelerator-performance/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -25,11 +25,11 @@ # # The generator of dirty data starts writeback at this percentage (system default # is 20%) -dirty_ratio = 40 +dirty_bytes = 40% # Start background writeback (via writeback threads) at this percentage (system # default is 10%) -dirty_background_ratio = 10 +dirty_background_bytes = 10% [sysctl] # PID allocation wrap value. When the kernel's next PID value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/balanced/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/balanced/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/balanced/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/balanced/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -30,4 +30,4 @@ # devices=sda [scsi_host] -alpm=medium_power +alpm=med_power_with_dipm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf --- old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/cpu-partitioning-powersave-variables.conf 2025-08-24 23:48:04.000000000 +0200 @@ -12,3 +12,7 @@ # given to force_latency tuned parameter. To have the same behavior # as cpu-partitioning profile, set to "cstate.name:C1|10" max_power_state=cstate.name:C1|10 + +# If set to true, disables turbo mode on all CPUs. +# This is useful for power saving, but may reduce performance. +no_turbo=true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/cpu-partitioning-powersave/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/cpu-partitioning-powersave/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -25,7 +25,7 @@ [cpu] force_latency=${max_power_state} -no_turbo=true +no_turbo=${no_turbo} [bootloader] cmdline_cpu_part=+nohz=on${cmd_isolcpus} nohz_full=${isolated_cores} rcu_nocbs=${isolated_cores} tuned.non_isolcpus=${not_isolated_cpumask} intel_pstate=passive nosoftlockup diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/latency-performance/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/latency-performance/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/latency-performance/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/latency-performance/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -22,11 +22,11 @@ # # The generator of dirty data starts writeback at this percentage (system default # is 20%) -dirty_ratio=10 +dirty_bytes=10% # Start background writeback (via writeback threads) at this percentage (system # default is 10%) -dirty_background_ratio=3 +dirty_background_bytes=3% [sysctl] # The swappiness parameter controls the tendency of the kernel to move diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/mssql/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/mssql/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/mssql/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/mssql/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -12,8 +12,8 @@ [vm] # For multi-instance SQL deployments use 'madvise' instead of 'always' transparent_hugepages=always -dirty_background_ratio=3 -dirty_ratio=80 +dirty_background_bytes=3% +dirty_bytes=80% [sysctl] vm.swappiness=1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/network-latency/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/network-latency/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/network-latency/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/network-latency/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -20,6 +20,6 @@ kernel.timer_migration = 0 [bootloader] -cmdline_network_latency=skew_tick=1 tsc=reliable rcupdate.rcu_normal_after_boot=1 +cmdline_network_latency=skew_tick=1 tsc=reliable rcupdate.rcu_normal_after_boot=1 rcutree.nohz_full_patience_delay=1000 [rtentsk] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/oracle/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/oracle/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/oracle/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/oracle/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -25,6 +25,6 @@ kernel.numa_balancing = 0 [vm] -dirty_background_ratio = 3 -dirty_ratio = 40 +dirty_background_bytes = 3% +dirty_bytes = 40% transparent_hugepages=never diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/powersave/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/powersave/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/powersave/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/powersave/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -34,7 +34,7 @@ # devices=eth0 [scsi_host] -alpm=min_power +alpm=med_power_with_dipm [sysctl] vm.laptop_mode=5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/realtime/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/realtime/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/realtime/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/realtime/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -11,6 +11,9 @@ # User is responsible for updating variables.conf with variable content such as isolated_cores=X-Y include = /etc/tuned/realtime-variables.conf +# Disable appropriate P-State drivers (intel_pstate or amd_pstate) +disable_pstate = ${f:cpuinfo_check:GenuineIntel:intel_pstate=disable:AuthenticAMD:amd_pstate=disable:} + isolated_cores_assert_check = \\${isolated_cores} # Make sure isolated_cores is defined before any of the variables that # use it (such as assert1) are defined, so that child profiles can set @@ -48,7 +51,7 @@ /sys/devices/system/machinecheck/machinecheck*/ignore_ce = 1 [bootloader] -cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} intel_pstate=disable nosoftlockup +cmdline_realtime=+isolcpus=${managed_irq}${isolated_cores} ${disable_pstate} nosoftlockup [irqbalance] banned_cpus=${isolated_cores} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/sap-hana/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/sap-hana/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/sap-hana/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/sap-hana/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -13,8 +13,8 @@ [vm] transparent_hugepages=madvise -dirty_ratio = 40 -dirty_background_ratio = 10 +dirty_bytes = 40% +dirty_background_bytes = 10% [sysctl] kernel.sem = 32000 1024000000 500 32000 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/server-powersave/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/server-powersave/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/server-powersave/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/server-powersave/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -11,4 +11,4 @@ [disk] [scsi_host] -alpm=min_power +alpm=med_power_with_dipm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/spectrumscale-ece/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/spectrumscale-ece/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/spectrumscale-ece/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/spectrumscale-ece/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -12,8 +12,8 @@ min_perf_pct=100 [vm] -dirty_ratio = 40 -dirty_background_ratio = 10 +dirty_bytes = 40% +dirty_background_bytes = 10% [sysctl] kernel.numa_balancing = 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/spindown-disk/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/spindown-disk/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/spindown-disk/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/spindown-disk/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -24,10 +24,10 @@ spindown=6 [scsi_host] -alpm=medium_power +alpm=med_power_with_dipm [vm] -dirty_ratio=60 +dirty_bytes=60% [sysctl] vm.dirty_writeback_centisecs=6000 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/throughput-performance/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/throughput-performance/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/throughput-performance/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/throughput-performance/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -25,11 +25,11 @@ # # The generator of dirty data starts writeback at this percentage (system default # is 20%) -dirty_ratio = 40 +dirty_bytes = 40% # Start background writeback (via writeback threads) at this percentage (system # default is 10%) -dirty_background_ratio = 10 +dirty_background_bytes = 10% # Marvell ThunderX [vm.thunderx] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/virtual-guest/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/virtual-guest/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/virtual-guest/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/virtual-guest/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -14,7 +14,7 @@ # # The generator of dirty data starts writeback at this percentage (system default # is 20%) -dirty_ratio = 30 +dirty_bytes = 30% [sysctl] # Filesystem I/O is usually much more efficient than swapping, so try to keep diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/profiles/virtual-host/tuned.conf new/tuned-2.26.0.0+git.181472a/profiles/virtual-host/tuned.conf --- old/tuned-2.25.1.0+git.889387b/profiles/virtual-host/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/profiles/virtual-host/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -9,7 +9,7 @@ [vm] # Start background writeback (via writeback threads) at this percentage (system # default is 10%) -dirty_background_ratio = 5 +dirty_background_bytes = 5% [cpu] # Setting C3 state sleep mode/power savings diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh new/tuned-2.26.0.0+git.181472a/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh --- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/Expose-TuneD-API-to-the-Unix-Domain-Socket/runtest.sh 2025-08-24 23:48:04.000000000 +0200 @@ -24,7 +24,7 @@ local socket=/run/tuned/tuned.sock # local send_only=--send-only - printf "$data" | nc $send_only -U /run/tuned/tuned.sock + printf "$data" | ncat $send_only -U /run/tuned/tuned.sock } rlJournalStart diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf --- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -2,4 +2,4 @@ summary=Post-loaded profile [vm] -dirty_ratio=8 +dirty_bytes=8% diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf --- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post-vars/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -2,4 +2,4 @@ summary=Post-loaded profile that uses variables from the regular active profile [vm] -dirty_ratio=${foo} +dirty_bytes=${foo}% diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf --- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/bz1798183-RFE-support-post-loaded-profile/post2/tuned.conf 2025-08-24 23:48:04.000000000 +0200 @@ -2,4 +2,4 @@ summary=Second version of the post-loaded profile [vm] -dirty_ratio=7 +dirty_bytes=7% diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tests/beakerlib/error-messages/runtest.sh new/tuned-2.26.0.0+git.181472a/tests/beakerlib/error-messages/runtest.sh --- old/tuned-2.25.1.0+git.889387b/tests/beakerlib/error-messages/runtest.sh 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tests/beakerlib/error-messages/runtest.sh 2025-08-24 23:48:04.000000000 +0200 @@ -24,16 +24,18 @@ rlAssertRpm $PACKAGE rlImport "tuned/basic" - PROFILE_DIR=$(tunedGetSystemProfilesBaseDir) + rlServiceStart "tuned" + tunedProfileBackup rlFileBackup "/var/log/tuned/tuned.log" + tunedDisableSystemdRateLimitingStart - rlServiceStart "tuned" - tunedProfileBackup + + USRPROFILEDIR="$(tunedGetUsrProfilesBaseDir)" rlPhaseEnd rlPhaseStartTest "Test of profile balanced" - rlRun "cat $PROFILE_DIR/balanced/tuned.conf | grep alpm=" + rlRun "cat ${USRPROFILEDIR}/balanced/tuned.conf | grep alpm=" echo > /var/log/tuned/tuned.log rlRun "tuned-adm profile balanced" rlRun "tuned-adm active | grep balanced" @@ -42,7 +44,7 @@ rlPhaseEnd rlPhaseStartTest "Test of profile powersave" - rlRun "cat $PROFILE_DIR/powersave/tuned.conf | grep alpm=" + rlRun "cat ${USRPROFILEDIR}/powersave/tuned.conf | grep alpm=" echo > /var/log/tuned/tuned.log rlRun "tuned-adm profile powersave" rlRun "tuned-adm active | grep powersave" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/admin/admin.py new/tuned-2.26.0.0+git.181472a/tuned/admin/admin.py --- old/tuned-2.25.1.0+git.889387b/tuned/admin/admin.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/admin/admin.py 2025-08-24 23:48:04.000000000 +0200 @@ -303,7 +303,7 @@ print("Trying to (re)start tuned...") (ret, msg) = self._cmd.execute(["service", "tuned", "restart"]) if ret != 0: - raise TunedException("TuneD (re)start failed, you need to (re)start TuneD by hand.") + raise TunedException("TuneD (re)start failed, check TuneD logs for details.") print("TuneD (re)started.") def _set_profile(self, profile_name, manual): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/consts.py new/tuned-2.26.0.0+git.181472a/tuned/consts.py --- old/tuned-2.25.1.0+git.889387b/tuned/consts.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/consts.py 2025-08-24 23:48:04.000000000 +0200 @@ -21,6 +21,7 @@ SYSTEM_PROFILES_DIR = "/usr/lib/tuned/profiles" PERSISTENT_STORAGE_DIR = "/var/lib/tuned" PLUGIN_MAIN_UNIT_NAME = "main" +PLUGIN_VARIABLES_UNIT_NAME = "variables" # Magic section header because ConfigParser does not support "headerless" config MAGIC_HEADER_NAME = "this_is_some_magic_section_header_because_of_compatibility" RECOMMEND_DIRECTORIES = ["/usr/lib/tuned/recommend.d", "/etc/tuned/recommend.d"] @@ -43,7 +44,6 @@ INITRD_IMAGE_DIR = "/boot" BOOT_CMDLINE_TUNED_VAR = "TUNED_BOOT_CMDLINE" BOOT_CMDLINE_INITRD_ADD_VAR = "TUNED_BOOT_INITRD_ADD" -BOOT_CMDLINE_KARGS_DELETED_VAR = "TUNED_BOOT_KARGS_DELETED" BOOT_CMDLINE_FILE = "/etc/tuned/bootcmdline" PETITBOOT_DETECT_DIR = "/sys/firmware/opal" MACHINE_ID_FILE = "/etc/machine-id" @@ -106,17 +106,17 @@ PPD_DBUS_BUS = "org.freedesktop.UPower.PowerProfiles" PPD_DBUS_BUS_LEGACY = "net.hadess.PowerProfiles" PPD_DBUS_NAMES = [ - { - "bus": PPD_DBUS_BUS, - "namespace": PPD_DBUS_BUS, - "interface": PPD_DBUS_BUS, - "object": "/org/freedesktop/UPower/PowerProfiles" + { + "bus": PPD_DBUS_BUS, + "namespace": PPD_DBUS_BUS, + "interface": PPD_DBUS_BUS, + "object": "/org/freedesktop/UPower/PowerProfiles" }, - { - "bus": PPD_DBUS_BUS_LEGACY, - "namespace": PPD_DBUS_BUS_LEGACY, - "interface": PPD_DBUS_BUS_LEGACY, - "object": "/net/hadess/PowerProfiles" + { + "bus": PPD_DBUS_BUS_LEGACY, + "namespace": PPD_DBUS_BUS_LEGACY, + "interface": PPD_DBUS_BUS_LEGACY, + "object": "/net/hadess/PowerProfiles" } ] @@ -146,6 +146,7 @@ CFG_CPU_EPP_FLAG = "hwp_epp" CFG_ROLLBACK = "rollback" CFG_PROFILE_DIRS = "profile_dirs" +CFG_STARTUP_UDEV_SETTLE_WAIT = "startup_udev_settle_wait" # no_daemon mode CFG_DEF_DAEMON = True @@ -197,6 +198,8 @@ CFG_DEF_ROLLBACK = "auto" # default profile directories CFG_DEF_PROFILE_DIRS = [SYSTEM_PROFILES_DIR, USER_PROFILES_DIR] +# default startup udev settle wait +CFG_DEF_STARTUP_UDEV_SETTLE_WAIT = 0 PATH_CPU_DMA_LATENCY = "/dev/cpu_dma_latency" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/daemon/controller.py new/tuned-2.26.0.0+git.181472a/tuned/daemon/controller.py --- old/tuned-2.25.1.0+git.889387b/tuned/daemon/controller.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/daemon/controller.py 2025-08-24 23:48:04.000000000 +0200 @@ -6,6 +6,8 @@ import tuned.consts as consts from tuned.utils.commands import commands from tuned.plugins import hotplug +import pyudev +import time __all__ = ["Controller"] @@ -54,13 +56,39 @@ Controller main loop. The call is blocking. """ log.info("starting controller") + self._terminate.clear() + wait_settle = self._global_config.get_int(consts.CFG_STARTUP_UDEV_SETTLE_WAIT, \ + consts.CFG_DEF_STARTUP_UDEV_SETTLE_WAIT) + if wait_settle > 0: + log.info("waiting for udev to settle") + monitor = pyudev.Monitor.from_netlink(pyudev.Context()) + udev_buffer_size = self._global_config.get_size("udev_buffer_size", consts.CFG_DEF_UDEV_BUFFER_SIZE) + try: + monitor.set_receive_buffer_size(udev_buffer_size) + except EnvironmentError: + log.warning("cannot set udev monitor receive buffer size, we are probably running inside " + + "container or with limited capabilites, TuneD functionality may be limited") + p = True + t = time.time() + try: + while time.time() < (t + wait_settle) and not self._terminate.is_set() and p: + p = monitor.poll(timeout = 1) + if not self._terminate.is_set(): + if p: + log.info("udev settle timed out") + else: + log.info("udev settled") + # https://github.com/pyudev/pyudev/issues/194 + except (OSError, IOError) as e: + log.warning("udev settle failed, '%s'" % e) + del monitor + res = self.start() daemon = self._global_config.get_bool(consts.CFG_DAEMON, consts.CFG_DEF_DAEMON) if not res and daemon: exports.start() if daemon: - self._terminate.clear() # we have to pass some timeout, otherwise signals will not work while not self._cmd.wait(self._terminate, 1): exports.period_check() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/daemon/daemon.py new/tuned-2.26.0.0+git.181472a/tuned/daemon/daemon.py --- old/tuned-2.25.1.0+git.889387b/tuned/daemon/daemon.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/daemon/daemon.py 2025-08-24 23:48:04.000000000 +0200 @@ -51,6 +51,8 @@ self._init_profile(profile_names) except TunedException as e: log.error("Cannot set initial profile. No tunings will be enabled: %s" % e) + if not self._daemon: + raise TunedException("Applying TuneD profile failed, check TuneD logs for details.") def _init_threads(self): self._thread = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/gtk/gui_profile_deleter.py new/tuned-2.26.0.0+git.181472a/tuned/gtk/gui_profile_deleter.py --- old/tuned-2.25.1.0+git.889387b/tuned/gtk/gui_profile_deleter.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/gtk/gui_profile_deleter.py 2025-08-24 23:48:04.000000000 +0200 @@ -2,6 +2,12 @@ import sys import shutil +import tuned.consts + if __name__ == '__main__': - shutil.rmtree('/etc/tuned/%s' % (os.path.basename(os.path.abspath(sys.argv[1])))) + shutil.rmtree( + os.path.join( + tuned.consts.USER_PROFILES_DIR, + os.path.basename(os.path.abspath(sys.argv[1])) + )) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/hardware/device_matcher_udev.py new/tuned-2.26.0.0+git.181472a/tuned/hardware/device_matcher_udev.py --- old/tuned-2.25.1.0+git.889387b/tuned/hardware/device_matcher_udev.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/hardware/device_matcher_udev.py 2025-08-24 23:48:04.000000000 +0200 @@ -16,7 +16,10 @@ try: items = device.properties.items() except AttributeError: - items = device.items() + try: + items = device.items() + except AttributeError: + return False for key, val in sorted(list(items)): properties += key + '=' + val + '\n' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/hotplug.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/hotplug.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/hotplug.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/hotplug.py 2025-08-24 23:48:04.000000000 +0200 @@ -13,8 +13,8 @@ super(Plugin, self).__init__(*args, **kwargs) def cleanup(self): - super(Plugin, self).cleanup() self._hardware_events_cleanup() + super(Plugin, self).cleanup() def _hardware_events_init(self): pass @@ -46,6 +46,7 @@ def _add_device(self, device_name): if device_name in (self._assigned_devices | self._free_devices): + log.debug("device: '%s' already exists, ignoring" % device_name) return for instance_name, instance in list(self._instances.items()): @@ -102,13 +103,17 @@ """ if device_name not in (self._assigned_devices | self._free_devices): + log.debug("device: '%s' doesn't exist, ignoring" % device_name) return for instance in list(self._instances.values()): if self._remove_device_process(instance, device_name): break else: - self._free_devices.remove(device_name) + try: + self._free_devices.remove(device_name) + except KeyError: + log.debug("device: '%s' isn't initialized, not removing it" % device_name) def _remove_devices_nocheck(self, instance, device_names): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_bootloader.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_bootloader.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_bootloader.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_bootloader.py 2025-08-24 23:48:04.000000000 +0200 @@ -105,7 +105,7 @@ ---- [main] include=profile_1 - + [bootloader] cmdline_profile_2=-quiet ---- @@ -114,7 +114,7 @@ ---- [main] include=profile_1 - + [bootloader] cmdline_profile_1=-quiet ---- @@ -209,24 +209,6 @@ "skip_grub_config": None, } - @staticmethod - def _options_to_dict(options, omit=""): - """ - Returns dict created from options - e.g.: _options_to_dict("A=A A=B A B=A C=A", "A=B B=A B=B") returns {'A': ['A', None], 'C': ['A']} - """ - d = {} - omit = omit.split() - for o in options.split(): - if o not in omit: - arr = o.split('=', 1) - d.setdefault(arr[0], []).append(arr[1] if len(arr) > 1 else None) - return d - - @staticmethod - def _dict_to_options(d): - return " ".join([k + "=" + v1 if v1 is not None else k for k, v in d.items() for v1 in v]) - def _rpm_ostree_status(self): """ Returns status of rpm-ostree transactions or None if not run on rpm-ostree system @@ -241,68 +223,45 @@ return None return splited[1] - def _wait_till_idle(self): + def _wait_till_rpm_ostree_idle(self): + """Check that rpm-ostree is idle, allowing some waiting time.""" sleep_cycles = 10 sleep_secs = 1.0 - for i in range(sleep_cycles): + for _ in range(sleep_cycles): if self._rpm_ostree_status() == "idle": return True sleep(sleep_secs) - if self._rpm_ostree_status() == "idle": - return True - return False + return self._rpm_ostree_status() == "idle" - def _rpm_ostree_kargs(self, append={}, delete={}): - """ - Method for appending or deleting rpm-ostree karg - returns None if rpm-ostree not present or is run on not ostree system - or tuple with new kargs, appended kargs and deleted kargs - """ - (rc, out, err) = self._cmd.execute(['rpm-ostree', 'kargs'], return_err=True) - log.debug("rpm-ostree output stdout:\n%s\nstderr:\n%s" % (out, err)) + def _get_rpm_ostree_kargs(self): + """Retrieve the output of rpm-ostree kargs, i.e., current default kernel arguments.""" + if not self._wait_till_rpm_ostree_idle(): + log.error("Error getting rpm-ostree kargs: rpm-ostree is busy") + return None + (rc, out, err) = self._cmd.execute(["rpm-ostree", "kargs"], return_err=True) + if out: + log.debug("rpm-ostree kargs: %s" % out) if rc != 0: - return None, None, None - kargs = self._options_to_dict(out) + log.error("Error getting rpm-ostree kargs: %s" % err) + return None + return out - if not self._wait_till_idle(): - log.error("Cannot wait for transaction end") - return None, None, None - - deleted = {} - delete_params = self._dict_to_options(delete).split() - # Deleting kargs, e.g. deleting added kargs by profile - for k, val in delete.items(): - for v in val: - kargs[k].remove(v) - deleted[k] = val - - appended = {} - append_params = self._dict_to_options(append).split() - # Appending kargs, e.g. new kargs by profile or restoring kargs replaced by profile - for k, val in append.items(): - if kargs.get(k): - # If there is karg that we add with new value we want to delete it - # and store old value for restoring after profile unload - log.debug("adding rpm-ostree kargs %s: %s for delete" % (k, kargs[k])) - deleted.setdefault(k, []).extend(kargs[k]) - delete_params.extend([k + "=" + v if v is not None else k for v in kargs[k]]) - kargs[k] = [] - kargs.setdefault(k, []).extend(val) - appended[k] = val - - if append_params == delete_params: - log.info("skipping rpm-ostree kargs - append == deleting (%s)" % append_params) - return kargs, appended, deleted - - log.info("rpm-ostree kargs - appending: '%s'; deleting: '%s'" % (append_params, delete_params)) - (rc, _, err) = self._cmd.execute(['rpm-ostree', 'kargs'] + - ['--append=%s' % v for v in append_params] + - ['--delete=%s' % v for v in delete_params], return_err=True) + def _modify_rpm_ostree_kargs(self, delete_kargs=[], append_kargs=[]): + """ + Modify (delete and append) kernel arguments in a rpm-ostree system. + Return a boolean indicating whether the operation was successful. + """ + if not self._wait_till_rpm_ostree_idle(): + log.error("Error modifying rpm-ostree kargs: rpm-ostree is busy") + return False + (rc, _, err) = self._cmd.execute( + ["rpm-ostree", "kargs"] + + ["--delete=%s" % karg for karg in delete_kargs] + + ["--append=%s" % karg for karg in append_kargs], return_err=True) if rc != 0: - log.error("Something went wrong with rpm-ostree kargs\n%s" % (err)) - return self._options_to_dict(out), None, None - else: - return kargs, appended, deleted + log.error("Error modifying rpm-ostree kargs: %s" % err) + return False + return True def _get_effective_options(self, options): """Merge provided options with plugin default options and merge all cmdline.* options.""" @@ -368,18 +327,16 @@ log.info("removing initrd image '%s'" % self._initrd_dst_img_val) self._cmd.unlink(self._initrd_dst_img_val) - def _get_rpm_ostree_changes(self): + def _get_appended_rpm_ostree_kargs(self): + """Return the list of kernel arguments that were appended by this profile (in a rpm-ostree system).""" f = self._cmd.read_file(consts.BOOT_CMDLINE_FILE) appended = re.search(consts.BOOT_CMDLINE_TUNED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE) - appended = appended[1] if appended else "" - deleted = re.search(consts.BOOT_CMDLINE_KARGS_DELETED_VAR + r"=\"(.*)\"", f, flags=re.MULTILINE) - deleted = deleted[1] if deleted else "" - return appended, deleted + return appended[1].split() if appended else [] def _remove_rpm_ostree_tuning(self): - appended, deleted = self._get_rpm_ostree_changes() - self._rpm_ostree_kargs(append=self._options_to_dict(deleted), delete=self._options_to_dict(appended)) - self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: "", consts.BOOT_CMDLINE_KARGS_DELETED_VAR: ""}) + """Remove kernel parameter tuning in a rpm-ostree system.""" + self._modify_rpm_ostree_kargs(delete_kargs=self._get_appended_rpm_ostree_kargs()) + self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR: ""}) def _instance_unapply_static(self, instance, rollback = consts.ROLLBACK_SOFT): if rollback == consts.ROLLBACK_FULL and not self._skip_grub_config_val: @@ -489,14 +446,30 @@ return True def _rpm_ostree_update(self): - appended, _ = self._get_rpm_ostree_changes() - _cmdline_dict = self._options_to_dict(self._cmdline_val, appended) - if not _cmdline_dict: - return None - (_, _, d) = self._rpm_ostree_kargs(append=_cmdline_dict) - if d is None: + """Apply kernel parameter tuning in a rpm-ostree system.""" + appended_kargs = self._get_appended_rpm_ostree_kargs() + profile_kargs = self._cmdline_val.split() + active_kargs = self._get_rpm_ostree_kargs() + if active_kargs is None: + log.error("Not updating kernel arguments, could not read the current ones.") + return + # Ignore kargs previously appended by TuneD, these will be removed later. + non_tuned_kargs = active_kargs.split() + for karg in appended_kargs: + non_tuned_kargs.remove(karg) + # Only append key=value pairs that do not yet appear in kernel parameters, + # otherwise we would not be able to restore the cmdline to the previous state + # via rpm-ostree kargs --delete. + kargs_to_append = [karg for karg in profile_kargs if karg not in non_tuned_kargs] + if appended_kargs == kargs_to_append: + # The correct kargs are already set in /etc/tuned/bootcmldine, + # we are likely post-reboot and done. + log.info("Kernel arguments already set, not updating.") return - self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : self._cmdline_val, consts.BOOT_CMDLINE_KARGS_DELETED_VAR : self._dict_to_options(d)}) + # If there are kargs in /etc/bootcmdline and they do not match + # the requested ones, there was no rollback, so remove them now. + if self._modify_rpm_ostree_kargs(delete_kargs=appended_kargs, append_kargs=kargs_to_append): + self._patch_bootcmdline({consts.BOOT_CMDLINE_TUNED_VAR : " ".join(kargs_to_append)}) def _grub2_update(self): self._grub2_cfg_patch({consts.GRUB2_TUNED_VAR : self._cmdline_val, consts.GRUB2_TUNED_INITRD_VAR : self._initrd_val}) @@ -646,11 +619,10 @@ v = self._variables.expand(self._cmd.unquote(value)) if verify: if self._rpm_ostree: - rpm_ostree_kargs = self._rpm_ostree_kargs()[0] - cmdline = self._dict_to_options(rpm_ostree_kargs) + cmdline = self._get_rpm_ostree_kargs() else: cmdline = self._cmd.read_file("/proc/cmdline") - if len(cmdline) == 0: + if cmdline is None or len(cmdline) == 0: return None cmdline_set = set(cmdline.split()) value_set = set(v.split()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_cpu.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_cpu.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_cpu.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_cpu.py 2025-08-24 23:48:04.000000000 +0200 @@ -190,7 +190,9 @@ `boost`::: The [option]`boost` option allows the CPU to boost above nominal - frequencies for shorts periods of time. + frequencies for shorts periods of time. On Intel systems with the + intel_pstate driver, setting boost=0 will automatically set no_turbo=1 + to ensure boost is properly disabled. + .Allowing CPU boost ==== @@ -771,17 +773,38 @@ log.debug("%s is not online, skipping" % device) return None cpu_id = device.lstrip("cpu") + boost_set = False + if os.path.exists(self._pstate_boost_path(cpu_id)): if not sim: if boost == "0" or boost == "1": self._cmd.write_to_file(self._pstate_boost_path(cpu_id), boost, \ no_error = [errno.ENOENT] if remove else False, ignore_same=True) log.info("Setting boost value '%s' for cpu '%s'" % (boost, device)) + boost_set = True else: log.error("Failed to set boost on cpu '%s'. Is the value in the profile correct?" % device) - return str(boost) else: log.debug("boost file missing, which can happen on pre 6.11 kernels.") + + # For Intel systems with intel_pstate driver, handle no_turbo + # This ensures boost=0 works properly on Intel CPUs + if self._has_intel_pstate and boost in ["0", "1"]: + no_turbo_val = "1" if boost == "0" else "0" + + if not sim: + try: + self._set_intel_pstate_attr("no_turbo", no_turbo_val) + log.info("Setting no_turbo to '%s' for intel_pstate driver (boost=%s)" % (no_turbo_val, boost)) + boost_set = True + except Exception as e: + log.warning("Failed to set no_turbo for intel_pstate: %s" % str(e)) + + if boost_set or sim: + return str(boost) + elif boost in ["0", "1"]: + log.warning("Unable to set boost on cpu '%s'. Neither per-policy boost nor intel_pstate no_turbo is available." % device) + return None @command_get("boost") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_disk.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_disk.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_disk.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_disk.py 2025-08-24 23:48:04.000000000 +0200 @@ -134,7 +134,8 @@ return device.device_type == "disk" and \ device.attributes.get("removable", None) == b"0" and \ (device.parent is None or \ - device.parent.subsystem in ["scsi", "virtio", "xen", "nvme"]) + device.parent.subsystem in ["scsi", "virtio", "xen", "nvme", + "mmc"]) def _hardware_events_init(self): self._hardware_inventory.subscribe(self, "block", self._hardware_events_callback) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_irqbalance.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_irqbalance.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_irqbalance.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_irqbalance.py 2025-08-24 23:48:04.000000000 +0200 @@ -3,7 +3,6 @@ from tuned import consts import tuned.logs import errno -import perf import re log = tuned.logs.get() @@ -29,7 +28,7 @@ def __init__(self, *args, **kwargs): super(IrqbalancePlugin, self).__init__(*args, **kwargs) - self._cpus = perf.cpu_map() + self._cpus = self._cmd.get_cpus() def _instance_init(self, instance): instance._has_dynamic_tuning = False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scheduler.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scheduler.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scheduler.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scheduler.py 2025-08-24 23:48:04.000000000 +0200 @@ -447,6 +447,11 @@ "latency_ns": "", } + def _disable_perf(self): + log.warning("python-perf unavailable, disabling perf support and " \ + "runtime tuning, you can try to (re)install python(3)-perf package") + self._perf_available = False + def __init__(self, monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg, variables): super(SchedulerPlugin, self).__init__(monitor_repository, storage_factory, hardware_inventory, device_matcher, device_matcher_udev, plugin_instance_factory, global_cfg, variables) self._has_dynamic_options = True @@ -465,14 +470,15 @@ self._ps_blacklist = "" self._kthread_process = True self._cgroup_ps_blacklist_re = "" - # perf is optional, if unavailable, it will be disabled later + self._perf_available = True + try: self._cpus = perf.cpu_map() except (NameError, AttributeError): - cpus = self._cmd.read_file(consts.SYSFS_CPUS_PRESENT_PATH) + self._disable_perf() # it's different type than perf.cpu_map(), but without perf we use it as iterable - # which should be compatible, fallback to single core CPU if sysfs is unavailable - self._cpus = self._cmd.cpulist_unpack(cpus) if cpus else [ 0 ] + # which should be compatible + self._cpus = self._cmd.get_cpus() self._scheduler_storage_key = self._storage_key( command_name = "scheduler") @@ -541,7 +547,7 @@ if self._cmd.get_bool(instance._scheduler.get("runtime", 1)) == "0": instance._runtime_tuning = False instance._terminate = threading.Event() - if self._daemon and instance._runtime_tuning: + if self._daemon and instance._runtime_tuning and self._perf_available: try: instance._threads = perf.thread_map() evsel = perf.evsel(type = perf.TYPE_SOFTWARE, @@ -558,9 +564,9 @@ instance._evlist.mmap(pages = perf_mmap_pages) # no perf except: - log.warning("python-perf unavailable, disabling perf support and " \ - "runtime tuning, you can try to (re)install python(3)-perf package") - instance._runtime_tuning = False + self._disable_perf() + if not self._perf_available: + instance._runtime_tuning = False def _instance_cleanup(self, instance): if instance._evlist: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scsi_host.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scsi_host.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_scsi_host.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_scsi_host.py 2025-08-24 23:48:04.000000000 +0200 @@ -14,8 +14,8 @@ Tunes options for SCSI hosts. The plug-in sets Aggressive Link Power Management (ALPM) to the value specified - by the [option]`alpm` option. The option takes one of three values: - `min_power`, `medium_power` and `max_performance`. + by the [option]`alpm` option. The option takes one of four values: + `min_power`, `med_power_with_dipm`, `medium_power` and `max_performance`. NOTE: ALPM is only available on SATA controllers that use the Advanced Host Controller Interface (AHCI). @@ -24,7 +24,7 @@ ==== ---- [scsi_host] - alpm=min_power + alpm=med_power_with_dipm ---- ==== """ @@ -83,10 +83,27 @@ def _get_alpm_policy_file(self, device): return os.path.join("/sys/class/scsi_host/", str(device), "link_power_management_policy") + def _get_ahci_port_cmd_file(self, device): + return os.path.join("/sys/class/scsi_host/", str(device), "ahci_port_cmd") + + def _is_external_sata_port(self, device): + port_cmd_file = self._get_ahci_port_cmd_file(device) + if not os.path.isfile(port_cmd_file): + return False + port_cmd = int(self._cmd.read_file(port_cmd_file), 16) + # Bit 18 is HPCP (Hot Plug Capable Port) + # Bit 21 is ESP (External SATA Port) + return port_cmd & (1 << 18 | 1 << 21) != 0 + @command_set("alpm", per_device = True) def _set_alpm(self, policy, device, instance, sim, remove): if policy is None: return None + if self._is_external_sata_port(device): + # According to the SATA AHCI specification, external (or hot-plug capable) + # SATA ports must have power management disabled to reliably detect hot plug removal. + log.info("Device '%s' is an external SATA controller, skipping ALPM setting to support hot plug" % str(device)) + return None policy_file = self._get_alpm_policy_file(device) if not sim: if os.path.exists(policy_file): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_vm.py new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_vm.py --- old/tuned-2.25.1.0+git.889387b/tuned/plugins/plugin_vm.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/plugins/plugin_vm.py 2025-08-24 23:48:04.000000000 +0200 @@ -53,7 +53,7 @@ @staticmethod def _check_conflicting_dirty_options(instance, first, second): if instance.options[first] is not None and instance.options[second] is not None: - log.error("Conflicting options '%s' and '%s', this may cause undefined behavior." % (first, second)) + log.warning("Conflicting options '%s' and '%s', this may cause undefined behavior." % (first, second)) @staticmethod def _proc_sys_vm_option_path(option): @@ -160,18 +160,24 @@ @command_custom("dirty_bytes") def _dirty_bytes(self, enabling, value, verify, ignore_missing, instance): + if value is not None and value.strip().endswith("%"): + return self._dirty_option("dirty_ratio", "dirty_bytes", self._check_ratio, enabling, value.strip().rstrip("%"), verify) return self._dirty_option("dirty_bytes", "dirty_ratio", self._check_twice_pagesize, enabling, value, verify) @command_custom("dirty_ratio") def _dirty_ratio(self, enabling, value, verify, ignore_missing, instance): + log.warning("The 'dirty_ratio' option is deprecated and does not support inheritance, use 'dirty_bytes' with '%' instead.") return self._dirty_option("dirty_ratio", "dirty_bytes", self._check_ratio, enabling, value, verify) @command_custom("dirty_background_bytes") def _dirty_background_bytes(self, enabling, value, verify, ignore_missing, instance): + if value is not None and value.strip().endswith("%"): + return self._dirty_option("dirty_background_ratio", "dirty_background_bytes", self._check_ratio, enabling, value.strip().rstrip("%"), verify) return self._dirty_option("dirty_background_bytes", "dirty_background_ratio", self._check_positive, enabling, value, verify) @command_custom("dirty_background_ratio") def _dirty_background_ratio(self, enabling, value, verify, ignore_missing, instance): + log.warning("The 'dirty_background_ratio' option is deprecated and does not support inheritance, use 'dirty_background_bytes' with '%' instead.") return self._dirty_option("dirty_background_ratio", "dirty_background_bytes", self._check_ratio, enabling, value, verify) def _dirty_option(self, option, counterpart, check_fun, enabling, value, verify): @@ -189,6 +195,7 @@ int_value = int(value) except ValueError: log.error("The value of '%s' must be an integer." % option) + return None if not check_fun(option, int_value): return None if current_value == value: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/config.py new/tuned-2.26.0.0+git.181472a/tuned/ppd/config.py --- old/tuned-2.25.1.0+git.889387b/tuned/ppd/config.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/config.py 2025-08-24 23:48:04.000000000 +0200 @@ -11,7 +11,7 @@ BATTERY_SECTION = "battery" DEFAULT_PROFILE_OPTION = "default" BATTERY_DETECTION_OPTION = "battery_detection" -THINKPAD_FUNCTION_KEYS_OPTION = "thinkpad_function_keys" +SYSFS_ACPI_MONITOR_OPTION = "sysfs_acpi_monitor" class ProfileMap: @@ -75,13 +75,13 @@ return self._tuned_to_ppd @property - def thinkpad_function_keys(self): + def sysfs_acpi_monitor(self): """ Whether to react to changes of ACPI platform profile done via function keys (e.g., Fn-L) on newer Thinkpad machines. Experimental feature. """ - return self._thinkpad_function_keys + return self._sysfs_acpi_monitor def load_from_file(self, config_file): """ @@ -141,4 +141,4 @@ self._ppd_to_tuned = ProfileMap(profile_dict_ac, profile_dict_dc) self._tuned_to_ppd = ProfileMap({v: k for k, v in profile_dict_ac.items()}, {v: k for k, v in profile_dict_dc.items()}) - self._thinkpad_function_keys = cfg.getboolean(MAIN_SECTION, THINKPAD_FUNCTION_KEYS_OPTION, fallback=False) + self._sysfs_acpi_monitor = cfg.getboolean(MAIN_SECTION, SYSFS_ACPI_MONITOR_OPTION, fallback=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/controller.py new/tuned-2.26.0.0+git.181472a/tuned/ppd/controller.py --- old/tuned-2.25.1.0+git.889387b/tuned/ppd/controller.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/controller.py 2025-08-24 23:48:04.000000000 +0200 @@ -229,6 +229,7 @@ self._watch_manager = pyinotify.WatchManager() self._notifier = pyinotify.ThreadedNotifier(self._watch_manager) self._inotify_watches = {} + self._pinned_virtual_files = [] self._platform_profile_supported = os.path.isfile(PLATFORM_PROFILE_PATH) self._no_turbo_supported = os.path.isfile(NO_TURBO_PATH) self._lap_mode_supported = os.path.isfile(LAP_MODE_PATH) @@ -289,19 +290,25 @@ """ Sets up inotify file watches. """ + for f in self._pinned_virtual_files: + f.close() + self._pinned_virtual_files.clear() self._watch_manager.rm_watch(list(self._inotify_watches.values())) if self._no_turbo_supported: + self._pinned_virtual_files.append(open(NO_TURBO_PATH, "r")) self._inotify_watches |= self._watch_manager.add_watch(path=os.path.dirname(NO_TURBO_PATH), mask=pyinotify.IN_MODIFY, - proc_fun=PerformanceDegradedEventHandler(NO_TURBO_PATH, self)) + proc_fun=PerformanceDegradedEventHandler(self, NO_TURBO_PATH)) if self._lap_mode_supported: + self._pinned_virtual_files.append(open(LAP_MODE_PATH, "r")) self._inotify_watches |= self._watch_manager.add_watch(path=os.path.dirname(LAP_MODE_PATH), mask=pyinotify.IN_MODIFY, - proc_fun=PerformanceDegradedEventHandler(LAP_MODE_PATH, self)) - if self._platform_profile_supported and self._config.thinkpad_function_keys: - self._inotify_watches |= self._watch_manager.add_watch(path=os.path.dirname(PLATFORM_PROFILE_PATH), - mask=pyinotify.IN_OPEN | pyinotify.IN_MODIFY | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CLOSE_NOWRITE, - proc_fun=PlatformProfileEventHandler(self)) + proc_fun=PerformanceDegradedEventHandler(self, LAP_MODE_PATH)) + if self._platform_profile_supported and self._config.sysfs_acpi_monitor: + self._pinned_virtual_files.append(open(PLATFORM_PROFILE_PATH, "r")) + self._inotify_watches |= self._watch_manager.add_watch(path=os.path.dirname(PLATFORM_PROFILE_PATH), + mask=pyinotify.IN_OPEN | pyinotify.IN_MODIFY | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CLOSE_NOWRITE, + proc_fun=PlatformProfileEventHandler(self)) def check_performance_degraded(self): """ @@ -379,6 +386,9 @@ self._notifier.start() while not self._cmd.wait(self._terminate, 1): pass + for f in self._pinned_virtual_files: + f.close() + self._pinned_virtual_files.clear() self._watch_manager.rm_watch(list(self._inotify_watches.values())) self._notifier.stop() exports.stop() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/ppd/ppd.conf new/tuned-2.26.0.0+git.181472a/tuned/ppd/ppd.conf --- old/tuned-2.25.1.0+git.889387b/tuned/ppd/ppd.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/ppd/ppd.conf 2025-08-24 23:48:04.000000000 +0200 @@ -2,6 +2,7 @@ # The default PPD profile default=balanced battery_detection=true +sysfs_acpi_monitor=true [profiles] # PPD = TuneD diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/functions/function_calc_isolated_cores.py new/tuned-2.26.0.0+git.181472a/tuned/profiles/functions/function_calc_isolated_cores.py --- old/tuned-2.25.1.0+git.889387b/tuned/profiles/functions/function_calc_isolated_cores.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/functions/function_calc_isolated_cores.py 2025-08-24 23:48:04.000000000 +0200 @@ -3,8 +3,10 @@ import tuned.logs from . import base import tuned.consts as consts +from tuned.utils.commands import commands log = tuned.logs.get() +cmd = commands() class calc_isolated_cores(base.Function): """ @@ -46,4 +48,4 @@ cpus.sort(key = int) isol_cpus = isol_cpus + cpus[cpus_reserve:] isol_cpus.sort(key = int) - return ",".join(isol_cpus) + return ",".join(cmd.cpulist_pack(isol_cpus)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/loader.py new/tuned-2.26.0.0+git.181472a/tuned/profiles/loader.py --- old/tuned-2.25.1.0+git.889387b/tuned/profiles/loader.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/loader.py 2025-08-24 23:48:04.000000000 +0200 @@ -51,15 +51,9 @@ processed_files = [] self._load_profile(profile_names, profiles, processed_files) - if len(profiles) > 1: - final_profile = self._profile_merger.merge(profiles) - else: - final_profile = profiles[0] - + final_profile = self._profile_merger.merge(profiles) final_profile.name = " ".join(profile_names) - if "variables" in final_profile.units: - self._variables.add_from_cfg(final_profile.units["variables"].options) - del(final_profile.units["variables"]) + self._variables.add_from_cfg(final_profile.variables) # FIXME hack, do all variable expansions in one place self._expand_vars_in_devices(final_profile) self._expand_vars_in_regexes(final_profile) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/merger.py new/tuned-2.26.0.0+git.181472a/tuned/profiles/merger.py --- old/tuned-2.25.1.0+git.889387b/tuned/profiles/merger.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/merger.py 2025-08-24 23:48:04.000000000 +0200 @@ -1,5 +1,6 @@ -import collections +import tuned.consts as consts from functools import reduce +from tuned.profiles.profile import Profile class Merger(object): """ @@ -14,7 +15,7 @@ Merge multiple configurations into one. If there are multiple units of the same type, option 'devices' is set for each unit with respect to eliminating any duplicate devices. """ - merged_config = reduce(self._merge_two, configs) + merged_config = reduce(self._merge_two, configs, Profile()) return merged_config def _merge_two(self, profile_a, profile_b): @@ -23,16 +24,29 @@ from the newer profile. If the 'replace' options of the newer unit is 'True', all options from the older unit are dropped. """ + if profile_a.name is None: + profile_a.name = profile_b.name profile_a.options.update(profile_b.options) for unit_name, unit in list(profile_b.units.items()): - if unit.replace or unit_name not in profile_a.units: + if unit.type == consts.PLUGIN_VARIABLES_UNIT_NAME: + if unit.replace: + profile_a.variables.clear() + overwritten_variables = set(profile_a.variables.keys()) & set(unit.options.keys()) + profile_a.variables.update(unit.options) + if unit.prepend: + for variable in reversed(unit.options): + if variable not in overwritten_variables: + profile_a.variables.move_to_end(variable, last=False) + elif unit.replace or unit_name not in profile_a.units: profile_a.units[unit_name] = unit else: profile_a.units[unit_name].type = unit.type profile_a.units[unit_name].enabled = unit.enabled profile_a.units[unit_name].devices = unit.devices + if unit.priority is not None: + profile_a.units[unit_name].priority = unit.priority if unit.devices_udev_regex is not None: profile_a.units[unit_name].devices_udev_regex = unit.devices_udev_regex if unit.cpuinfo_regex is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/profile.py new/tuned-2.26.0.0+git.181472a/tuned/profiles/profile.py --- old/tuned-2.25.1.0+git.889387b/tuned/profiles/profile.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/profile.py 2025-08-24 23:48:04.000000000 +0200 @@ -7,10 +7,11 @@ Representation of a tuning profile. """ - __slots__ = ["_name", "_options", "_units"] + __slots__ = ["_name", "_options", "_variables", "_units"] - def __init__(self, name, config): + def __init__(self, name=None, config={}): self._name = name + self._variables = collections.OrderedDict() self._init_options(config) self._init_units(config) @@ -41,6 +42,10 @@ self._name = value @property + def variables(self): + return self._variables + + @property def units(self): """ Units included in the profile. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/profiles/unit.py new/tuned-2.26.0.0+git.181472a/tuned/profiles/unit.py --- old/tuned-2.25.1.0+git.889387b/tuned/profiles/unit.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/profiles/unit.py 2025-08-24 23:48:04.000000000 +0200 @@ -6,7 +6,7 @@ Unit description. """ - __slots__ = [ "_name", "_priority", "_type", "_enabled", "_replace", "_drop", "_devices", "_devices_udev_regex", \ + __slots__ = [ "_name", "_priority", "_type", "_enabled", "_replace", "_prepend", "_drop", "_devices", "_devices_udev_regex", \ "_cpuinfo_regex", "_uname_regex", "_script_pre", "_script_post", "_options" ] def __init__(self, name, config): @@ -15,6 +15,7 @@ self._type = config.pop("type", self._name) self._enabled = config.pop("enabled", True) in [True, "True", "true", 1, "1"] self._replace = config.pop("replace", False) in [True, "True", "true", 1, "1"] + self._prepend = config.pop("prepend", False) in [True, "True", "true", 1, "1"] self._drop = config.pop("drop", None) if self._drop is not None: self._drop = re.split(r"\b\s*[,;]\s*", str(self._drop)) @@ -59,6 +60,10 @@ return self._replace @property + def prepend(self): + return self._prepend + + @property def drop(self): return self._drop diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/units/manager.py new/tuned-2.26.0.0+git.181472a/tuned/units/manager.py --- old/tuned-2.25.1.0+git.889387b/tuned/units/manager.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/units/manager.py 2025-08-24 23:48:04.000000000 +0200 @@ -89,8 +89,8 @@ plugin = self._plugins_repository.create(plugin_name) plugins_by_name[plugin_name] = plugin self._plugins.append(plugin) - except tuned.plugins.exceptions.NotSupportedPluginException: - log.info("skipping plugin '%s', not supported on your system" % plugin_name) + except tuned.plugins.exceptions.NotSupportedPluginException as e: + log.info("skipping plugin '%s', not supported on your system: %s" % (plugin_name, e)) continue except Exception as e: log.error("failed to initialize plugin %s" % plugin_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/utils/commands.py new/tuned-2.26.0.0+git.181472a/tuned/utils/commands.py --- old/tuned-2.25.1.0+git.889387b/tuned/utils/commands.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/utils/commands.py 2025-08-24 23:48:04.000000000 +0200 @@ -555,3 +555,9 @@ def getconf(self, variable): return check_output(["getconf", variable]).decode().strip() + + # Gets list of available CPUs + def get_cpus(self): + cpus = self.read_file(consts.SYSFS_CPUS_PRESENT_PATH) + # fallback to single core CPU if sysfs is unavailable + return self.cpulist_unpack(cpus) if cpus else [ 0 ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/utils/global_config.py new/tuned-2.26.0.0+git.181472a/tuned/utils/global_config.py --- old/tuned-2.25.1.0+git.889387b/tuned/utils/global_config.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/utils/global_config.py 2025-08-24 23:48:04.000000000 +0200 @@ -75,7 +75,10 @@ if isinstance(i, int): return i else: - return int(i, 0) + try: + return int(i, 0) + except ValueError: + log.error("Error parsing integer '%s', using '%d'." %(str(i), default)) return default def get_list(self, key, default = []): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned/version.py new/tuned-2.26.0.0+git.181472a/tuned/version.py --- old/tuned-2.25.1.0+git.889387b/tuned/version.py 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned/version.py 2025-08-24 23:48:04.000000000 +0200 @@ -1,5 +1,5 @@ TUNED_VERSION_MAJOR = 2 -TUNED_VERSION_MINOR = 25 -TUNED_VERSION_PATCH = 1 +TUNED_VERSION_MINOR = 26 +TUNED_VERSION_PATCH = 0 TUNED_VERSION_STR = "%d.%d.%d" % (TUNED_VERSION_MAJOR, TUNED_VERSION_MINOR, TUNED_VERSION_PATCH) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned-main.conf new/tuned-2.26.0.0+git.181472a/tuned-main.conf --- old/tuned-2.25.1.0+git.889387b/tuned-main.conf 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned-main.conf 2025-08-24 23:48:04.000000000 +0200 @@ -77,7 +77,7 @@ # connections_backlog = 1024 # TuneD daemon rollback strategy. Supported values: auto|not_on_exit -# - auto: rollbacks are always performed on a profile switch or +# - auto: rollbacks are always performed on a profile switch or # graceful TuneD process exit # - not_on_exit: rollbacks are always performed on a profile # switch, but not on any kind of TuneD process exit @@ -87,3 +87,13 @@ # In case of conflicts in profile names, the later directory # takes precedence # profile_dirs = /usr/lib/tuned/profiles,/etc/tuned/profiles + +# Timeout in seconds to wait until udev settles. Value 0 disables the wait. +# With non-zero wait TuneD startup is delayed until there are no pending +# udev events or the specified timeout occurs. +# The delay can help in situations where there are a lot of udev events +# during TuneD startup and TuneD is too slow to handle them. +# In environments where systemd is utilised for starting TuneD +# it is better to keep this feature disabled and rely on systemd +# functionality (systemd-udev-settle). +startup_udev_settle_wait = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/tuned-2.25.1.0+git.889387b/tuned.spec new/tuned-2.26.0.0+git.181472a/tuned.spec --- old/tuned-2.25.1.0+git.889387b/tuned.spec 2025-02-03 20:17:00.000000000 +0100 +++ new/tuned-2.26.0.0+git.181472a/tuned.spec 2025-08-24 23:48:04.000000000 +0200 @@ -59,13 +59,14 @@ Summary: A dynamic adaptive system tuning daemon Name: tuned -Version: 2.25.1 +Version: 2.26.0 Release: 1%{?prerel1}%{?with_snapshot:.%{git_suffix}}%{?dist} 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 -BuildRequires: systemd, desktop-file-utils +BuildRequires: systemd +BuildRequires: desktop-file-utils %if 0%{?rhel} BuildRequires: asciidoc %else @@ -75,7 +76,8 @@ Requires(preun): systemd Requires(postun): systemd BuildRequires: make -BuildRequires: %{_py}, %{_py}-devel +BuildRequires: %{_py} +BuildRequires: %{_py}-devel # BuildRequires for 'make test' # python-mock is needed for python-2.7, but it's not available on RHEL-7, only in the EPEL %if %{without python3} && ( ! 0%{?rhel} || 0%{?rhel} >= 8 || 0%{?epel}) @@ -91,15 +93,23 @@ # requires for packages with inconsistent python2/3 names %if %{with python3} # BuildRequires for 'make test' -BuildRequires: python3-dbus, python3-gobject-base -Requires: python3-dbus, python3-gobject-base +BuildRequires: python3-dbus +BuildRequires: python3-gobject-base +Requires: python3-dbus +Requires: python3-gobject-base %else # BuildRequires for 'make test' -BuildRequires: dbus-python, pygobject3-base -Requires: dbus-python, pygobject3-base +BuildRequires: dbus-python +BuildRequires: pygobject3-base +Requires: dbus-python +Requires: pygobject3-base %endif -Requires: virt-what, ethtool, gawk -Requires: util-linux, dbus, polkit +Requires: virt-what +Requires: ethtool +Requires: gawk +Requires: util-linux +Requires: dbus +Requires: polkit %if 0%{?fedora} > 22 || 0%{?rhel} > 7 Recommends: dmidecode # https://src.fedoraproject.org/rpms/tuned/pull-request/8 @@ -306,10 +316,8 @@ make install-ppd DESTDIR="%{buildroot}" BINDIR="%{_bindir}" \ SBINDIR="%{_sbindir}" DOCDIR="%{docdir}" %{make_python_arg} -%if ! 0%{?rhel} # manual make install-html DESTDIR=%{buildroot} DOCDIR=%{docdir} -%endif # conditional support for grub2, grub2 is not available on all architectures # and tuned is noarch package, thus the following hack is needed @@ -638,6 +646,42 @@ %config(noreplace) %{_sysconfdir}/tuned/ppd.conf %changelog +* Sun Aug 24 2025 Jaroslav Škarvada <[email protected]> - 2.26.0-1 +- new release + +* Sun Aug 17 2025 Jaroslav Škarvada <[email protected]> - 2.26.0-0.1.rc1 +- new release + - tuned-ppd: renamed thinkpad_function_keys as sysfs_acpi_monitor + - tuned-ppd: enabled sysfs_acpi_monitor by default + - tuned-ppd: fixed inotify watch for performance degradation + - tuned-ppd: pinned virtual files in memory for inotify + - fixed instance priority inheritance + resolves: RHEL-94842 + - hotplug: added fixes for device remove race condition + - tuned-main.conf: added startup_udev_settle_wait option + resolves: RHEL-88238 + - functions: silenced errors if module kvm_intel does not exist + resolves: RHEL-79943 + - functions: make calc_isolated_cores return CPU ranges + resolves: RHEL-75751 + - scsi: used 'med_power_with_dipm' for SATA ALPM + - scsi: do not set ALPM on external SATA ports + resolves: RHEL-79913 + - network_latency: Set non-zero rcutree.nohz_full_patience_delay + resolves: RHEL-61801 + - realtime: Disable appropriate P-State drivers + resolves: RHEL-85637 + - plugin_disk: added support for MMC (MultiMediaCard) devices + - udev: fix possible traceback in device matcher + resolves: RHEL-97087 + - udev-settle: obey udev buffer size and handle possible tracebacks + resolves: RHEL-92637 + - daemon: re-raise daemon init exception in no-daemon mode + resolves: RHEL-71304 + - vm: deprecate dirty_ratio in favour of dirty_bytes with percents + resolves: RHEL-101578 + - gui: fix the profile deleter script + * Mon Feb 3 2025 Jaroslav Škarvada <[email protected]> - 2.25.1-1 - new release - plugins: added missing instance parameters ++++++ tuned.obsinfo ++++++ --- /var/tmp/diff_new_pack.3m0nyP/_old 2025-09-10 20:22:45.054504689 +0200 +++ /var/tmp/diff_new_pack.3m0nyP/_new 2025-09-10 20:22:45.058504858 +0200 @@ -1,5 +1,5 @@ name: tuned -version: 2.25.1.0+git.889387b -mtime: 1738610220 -commit: 889387b0001b783514523162de21af406e31a549 +version: 2.26.0.0+git.181472a +mtime: 1756072084 +commit: 181472a0be2125c8cd36c7673ec546d75d396a3d
