Skip to content

[6.18] Track gaming patches - #44

Draft
kakra wants to merge 24 commits into
base-6.18from
rebase-6.18/gaming-patches
Draft

[6.18] Track gaming patches#44
kakra wants to merge 24 commits into
base-6.18from
rebase-6.18/gaming-patches

Conversation

@kakra

@kakra kakra commented Dec 15, 2025

Copy link
Copy Markdown
Owner

Export patch series: https://github.com/kakra/linux/pull/44.patch

Gaming und Desktop Interactivity Patches

This is a combined patchset from various sources, including some ports of old legacy Proton features (deprecated). The patchset mostly focuses around memory management and interactivity, optimizing the system for responsiveness rather than maximum throughput, to reduce stutters, memory thrashing and frame drops. Most unrelated ZEN patches have been dropped.

Changes since 6.12 LTS

  • ntsync: dropped because it's upstream now (you may need to add a udev rule ACTION=="add|change", KERNEL=="ntsync", SUBSYSTEM=="misc", MODE="0666" to set proper permissions)

Included Patches

  • Selected ZEN interactive patches: memory management, interactivity, gaming defaults, disk scheduler defaults
  • Threaded IRQs by default: cherry-picked from CK for better responsiveness
  • Prefer full idle SMT cores: prefers idle CPU cores for better throughput and better response times
  • BORE scheduler from CachyOS: ignores ZEN interactive if enabled (https://github.com/firelzrd/bore-scheduler)
  • ADIOS IO scheduler from CachyOS: The "Adaptive Deadline I/O Scheduler", optimized for latency instead of throughput should reduce load stutters in games, this overrides the ZEN default for BFQ if enabled

Recommendation

Kernel 6.18 LTS seems to have worse performance characteristics for games compared to kernel 6.12, especially frame pacing can jitter a lot more, resulting in reduced perceived smoothness despite average FPS being identical or better. I found that I can fix it by building the kernel with support for sched_ext, and then running with the LAVD scheduler which also yields lower power consumption when idle (sys-app/kernel in Gentoo):

CONFIG_BPF=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_BPF_SYSCALL=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_FUNCTION_TRACER=y
CONFIG_KPROBE_EVENTS=y
CONFIG_SCHED_CLASS_EXT=y

Here's a talk on the technical details of the LAVD scheduler which initially has been made for the Steam Deck: https://www.youtube.com/watch?v=5F-vQgv4sI0


Deprecated

  • FUTEX wait multiple opcode 31: most likely only used by old Proton versions, will be dropped with the next LTS

Dropped

  • Soft dirty flag with reset: dropped during the rebase because it no longer applied cleanly. Modern Wine/Proton uses the newer writewatch/userfaultfd path instead, so this old soft-dirty implementation is no longer needed.

@kakra kakra mentioned this pull request Dec 15, 2025
@kakra

kakra commented Dec 25, 2025

Copy link
Copy Markdown
Owner Author

Added note about performance characteristics to the top post:

Kernel 6.18 LTS seems to have worse performance characteristics for games compared to kernel 6.12, especially frame pacing can jitter a lot more, resulting in reduced perceived smoothness despite average FPS being identical or better. I found that I can fix it by building the kernel with support for sched_ext, and then running with the LAVD scheduler which also yields lower power consumption when idle (sys-app/kernel in Gentoo)

@kakra

kakra commented Dec 28, 2025

Copy link
Copy Markdown
Owner Author

Added Adaptive Deadline I/O Scheduler (ADIOS) from CachyOS. It is optimized for latency instead of throughput and should reduce load stutters in games but also improve general desktop responsiveness. This overrides the ZEN default for BFQ if enabled.

@kakra
kakra force-pushed the rebase-6.18/gaming-patches branch from a6e3ab8 to 93dfd44 Compare January 3, 2026 18:05
@kakra

kakra commented Jan 3, 2026

Copy link
Copy Markdown
Owner Author

Rebased to v6.18.3 to resolve conflicts.

@kakra
kakra force-pushed the rebase-6.18/gaming-patches branch from 93dfd44 to c4cbc0c Compare March 17, 2026 14:27
@kakra

kakra commented Mar 17, 2026

Copy link
Copy Markdown
Owner Author

Rebased to v6.18.18 to resolve conflicts.

@kakra
kakra force-pushed the rebase-6.18/gaming-patches branch from c4cbc0c to 7ba5879 Compare May 31, 2026 23:39
@kakra

kakra commented May 31, 2026

Copy link
Copy Markdown
Owner Author

Rebased to 6.18.33 to resolve conflicts.

kakra pushed a commit that referenced this pull request Aug 28, 2026
…aths

[ Upstream commit f958c78 ]

Several iso_pi(sk) fields (qos, qos_user_set, bc_sid, base, base_len,
sync_handle, bc_num_bis) are written under lock_sock in
iso_sock_setsockopt() and iso_sock_bind(), but read and written under
hci_dev_lock only in two other paths:

  - iso_connect_bis() / iso_connect_cis(), invoked from connect(2),
    read qos/base/bc_sid and reset qos to default_qos on the
    qos_user_set validation failure -- all without lock_sock.

  - iso_connect_ind(), invoked from hci_rx_work, writes sync_handle,
    bc_sid, qos.bcast.encryption, bc_num_bis, base and base_len on
    PA_SYNC_ESTABLISHED / PAST_RECEIVED / BIG_INFO_ADV_REPORT /
    PER_ADV_REPORT events. The BIG_INFO handler additionally passes
    &iso_pi(sk)->qos together with sync_handle / bc_num_bis / bc_bis
    to hci_conn_big_create_sync() while setsockopt may be mutating
    them.

Acquire lock_sock around the affected accesses in both paths.

The locking order hci_dev_lock -> lock_sock matches the existing
iso_conn_big_sync() precedent, whose comment documents the same
requirement for hci_conn_big_create_sync(). The HCI connect/bind
helpers do not wait for command completion -- they enqueue work via
hci_cmd_sync_queue{,_once}() / hci_le_create_cis_pending() and
return -- so the added hold time is comparable to iso_conn_big_sync().

KCSAN report:

BUG: KCSAN: data-race in iso_connect_cis / iso_sock_setsockopt

read to 0xffffa3ae8ce3cdc8 of 1 bytes by task 335 on cpu 0:
 iso_connect_cis+0x49f/0xa20
 iso_sock_connect+0x60e/0xb40
 __sys_connect_file+0xbd/0xe0
 __sys_connect+0xe0/0x110
 __x64_sys_connect+0x40/0x50
 x64_sys_call+0xcad/0x1c60
 do_syscall_64+0x133/0x590
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

write to 0xffffa3ae8ce3cdc8 of 60 bytes by task 334 on cpu 1:
 iso_sock_setsockopt+0x69a/0x930
 do_sock_setsockopt+0xc3/0x170
 __sys_setsockopt+0xd1/0x130
 __x64_sys_setsockopt+0x64/0x80
 x64_sys_call+0x1547/0x1c60
 do_syscall_64+0x133/0x590
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Reported by Kernel Concurrency Sanitizer on:
CPU: 1 UID: 0 PID: 334 Comm: iso_setup_race Not tainted 7.0.0-10949-g8541d8f725c6 #44 PREEMPT(lazy)

The iso_connect_ind() races were found by inspection.

Fixes: ccf74f2 ("Bluetooth: Add BTPROTO_ISO socket type")
Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Stable-dep-of: 4311fd6 ("Bluetooth: ISO: lock sk in iso_connect_ind")
Signed-off-by: Sasha Levin <sashal@kernel.org>
dsd and others added 20 commits August 28, 2026 19:54
Contains:
  - PCI: Add Intel remapped NVMe device support

    Consumer products that are configured by default to run the Intel SATA AHCI
    controller in "RAID" or "Intel RST Premium With Intel Optane System
    Acceleration" mode are becoming increasingly prevalent.

    Unde this mode, NVMe devices are remapped into the SATA device and become
    hidden from the PCI bus, which means that Linux users cannot access their
    storage devices unless they go into the firmware setup menu to revert back
    to AHCI mode - assuming such option is available. Lack of support for this
    mode is also causing complications for vendors who distribute Linux.

    Add support for the remapped NVMe mode by creating a virtual PCI bus,
    where the AHCI and NVMe devices are presented separately, allowing the
    ahci and nvme drivers to bind in the normal way.

    Unfortunately the NVMe device configuration space is inaccesible under
    this scheme, so we provide a fake one, and hope that no DeviceID-based
    quirks are needed. The interrupt is shared between the AHCI and NVMe
    devices.

    Allow pci_real_dma_dev() to traverse back to the real DMA device from
    the PCI devices created on our virtual bus, in case the iommu driver
    will be involved with data transfers here.

    The existing ahci driver is modified to not claim devices where remapped
    NVMe devices are present, allowing this new driver to step in.

    The details of the remapping scheme came from patches previously
    posted by Dan Williams and the resulting discussion.

    https://phabricator.endlessm.com/T24358
    https://phabricator.endlessm.com/T29119

    Signed-off-by: Daniel Drake <drake@endlessm.com>

  - PCI: Fix order of remapped NVMe devices

Signed-off-by: Kai Krakow <kai@kaishome.de>
There's plenty of room on the stack for a few more inlined bytes here
and there. The measured stack usage at runtime is still safe without
this, and performance is surely improved at a microscopic level, so
remove it.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
From ClearLinux's own patches, disable both AVX2 and tree vectorization
when using O3 and higher than generic amd64 architectures.

Source: https://github.com/clearlinux-pkgs/linux/blob/main/0133-novector.patch
Signed-off-by: Kai Krakow <kai@kaishome.de>
ATA init is the long pole in the boot process, and its asynchronous.
move the graphics init after it so that ata and graphics initialize
in parallel

Signed-off-by: Kai Krakow <kai@kaishome.de>
Significant time was spent on synchronize_rcu in evdev_detach_client
when applications closed evdev devices. Switching VT away from a
graphical environment commonly leads to mass input device closures,
which could lead to noticable delays on systems with many input devices.

Replace synchronize_rcu with call_rcu, deferring reclaim of the evdev
client struct till after the RCU grace period instead of blocking the
calling application.

While this does not solve all slow evdev fd closures, it takes care of a
good portion of them, including this simple test:

	#include <fcntl.h>
	#include <unistd.h>

	int main(int argc, char *argv[])
	{
		int idx, fd;
		const char *path = "/dev/input/event0";
		for (idx = 0; idx < 1000; idx++) {
			if ((fd = open(path, O_RDWR)) == -1) {
				return -1;
			}
			close(fd);
		}
		return 0;
	}

Time to completion of above test when run locally:

	Before: 0m27.111s
	After:  0m0.018s

Signed-off-by: Kenny Levinsen <kl@kl.wtf>
Per [Fedora][1], they intend to change the default max map count for
their distribution to improve OOTB compatibility with games played
through Steam/Proton.  The value they picked comes from the Steam Deck,
which defaults to INT_MAX - MAPCOUNT_ELF_CORE_MARGIN.

Since most ZEN and Liquorix users probably play games, follow Valve's
lead and raise this value to their default.

[1]: https://fedoraproject.org/wiki/Changes/IncreaseVmMaxMapCount

Signed-off-by: Kai Krakow <kai@kaishome.de>
Contains:
  - mm: Stop kswapd early when nothing's waiting for it to free pages

    Keeping kswapd running when all the failed allocations that invoked it
    are satisfied incurs a high overhead due to unnecessary page eviction
    and writeback, as well as spurious VM pressure events to various
    registered shrinkers. When kswapd doesn't need to work to make an
    allocation succeed anymore, stop it prematurely to save resources.

    Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>

  - mm: Don't stop kswapd on a per-node basis when there are no waiters

    The page allocator wakes all kswapds in an allocation context's allowed
    nodemask in the slow path, so it doesn't make sense to have the kswapd-
    waiter count per each NUMA node. Instead, it should be a global counter
    to stop all kswapds when there are no failed allocation requests.

    Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>

  - mm: Increment kswapd_waiters for throttled direct reclaimers

    Throttled direct reclaimers will wake up kswapd and wait for kswapd to
    satisfy their page allocation request, even when the failed allocation
    lacks the __GFP_KSWAPD_RECLAIM flag in its gfp mask. As a result, kswapd
    may think that there are no waiters and thus exit prematurely, causing
    throttled direct reclaimers lacking __GFP_KSWAPD_RECLAIM to stall on
    waiting for kswapd to wake them up. Incrementing the kswapd_waiters
    counter when such direct reclaimers become throttled fixes the problem.

    Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>

Signed-off-by: Kai Krakow <kai@kaishome.de>
This patch disabled the staggered spinup used for HDDs.

The goal is to make boot times faster on systems
with the small downside of a small spike in power consumption.

Systems with a bunch of HDDs would see considerable faster boots

This does make sense in the zen kernel as its supposed to be a kernel
specialized for desktop performance, and faster boot times does fit
into that description

Signed-off-by: Pedro Montes Alcalde <pedro.montes.alcalde@gmail.com>
Signed-off-by: Kai Krakow <kai@kaishome.de>
Signed-off-by: Kai Krakow <kai@kaishome.de>
In case of a multi-queue device, the code pointlessly loaded the
default elevator just to drop it again.

Signed-off-by: Kai Krakow <kai@kaishome.de>
Fall back straight to none instead of mq-deadline. Some benchmarks in a
[recent paper][1] suggest that mq-deadline has too much lock contention,
hurting throughput and eating CPU waiting for spinlocks.

[1]: https://research.spec.org/icpe_proceedings/2024/proceedings/p154.pdf

Signed-off-by: Kai Krakow <kai@kaishome.de>
Use [defer+madvise] as default khugepaged defrag strategy:

For some reason, the default strategy to respond to THP fault fallbacks
is still just madvise, meaning stall if the program wants transparent
hugepages, but don't trigger a background reclaim / compaction if THP
begins to fail allocations.  This creates a snowball affect where we
still use the THP code paths, but we almost always fail once a system
has been active and busy for a while.

The option "defer" was created for interactive systems where THP can
still improve performance.  If we have to fallback to a regular page due
to an allocation failure or anything else, we will trigger a background
reclaim and compaction so future THP attempts succeed and previous
attempts eventually have their smaller pages combined without stalling
running applications.

We still want madvise to stall applications that explicitely want THP,
so defer+madvise _does_ make a ton of sense.  Make it the default for
interactive systems, especially if the kernel maintainer left
transparent hugepages on "always".

Reasoning and details in the original patch: https://lwn.net/Articles/711248/

Signed-off-by: Kai Krakow <kai@kaishome.de>
5.7:
Take "sysctl_sched_nr_migrate" tune from early XanMod builds of 128. As
of 5.7, XanMod uses 256 but that may affect applications that require
timely response to IRQs.

5.15:
Per [a comment][1] on our ZEN INTERACTIVE commit, reducing the cost of
migration causes the system less responsive under high load.  Most
likely the combination of reduced migration cost + the higher number of
tasks that can be migrated at once contributes to this.

To better handle this situation, restore the mainline migration cost
value and also reduce the max number of tasks that can be migrated in
batch from 128 to 64.

If this doesn't help, we'll restore the reduced migration cost and keep
total number of tasks that can be migrated at once to 32.

[1]: zen-kernel@be5ba23#commitcomment-63159674

6.6:
Port the tuning to EEVDF, which removed a couple of settings.

6.7:
Instead of increasing the number of tasks that migrate at once, migrate
the amount acceptable for PREEMPT_RT, but reduce the cost so migrations
occur more often.

This should make CFS/EEVDF behave more like out-of-tree schedulers that
aggressively use idle cores to reduce latency, but without the jank
caused by rebalancing too many tasks at once.

Signed-off-by: Kai Krakow <kai@kaishome.de>
4.10:
During some personal testing with the Dolphin emulator, MuQSS has
serious problems scaling its frequencies causing poor performance where
boosting the CPU frequencies would have fixed them.  Reducing the
up_threshold to 45 with MuQSS appears to fix the issue, letting the
introduction to "Star Wars: Rogue Leader" run at 100% speed versus about
80% on my test system.

Also, lets refactor the definitions and include some indentation to help
the reader discern what the scope of all the macros are.

5.4:
On the last custom kernel benchmark from Phoronix with Xanmod, Michael
configured all the kernels to run using ondemand instead of the kernel's
[default selection][1].  This reminded me that another option outside of
the kernels control is the user's choice to change the cpufreq governor,
for better or for worse.

In Liquorix, performance is the default governor whether you're running
acpi-cpufreq or intel-pstate.  I expect laptop users to install TLP or
LMT to control the power balance on their system, especially when
they're plugged in or on battery.  However, it's pretty clear to me a
lot of people would choose ondemand over performance since it's not
obvious it has huge performance ramifications with MuQSS, and ondemand
otherwise is "good enough" for most people.

Lets codify lower up thresholds for MuQSS to more closely synergize with
its aggressive thread migration behavior.  This way when ondemand is
configured, you get sort of a "performance-lite" type of result but with
the power savings you expect when leaving the running system idle.

[1]: https://www.phoronix.com/scan.php?page=article&item=xanmod-2020-kernel

5.14:
Although CFS and similar schedulers (BMQ, PDS, and CacULE), reuse a lot
more of mainline scheduling and do a good job of pinning single threaded
tasks to their respective core, there's still applications that
confusingly run steady near 50% and benefit from going full speed or
turbo when they need to run (emulators for more recent consoles come to
mind).

Drop the up threshold for all non-MuQSS schedulers from 80/95 to 55/60.

5.15:
Remove MuQSS cpufreq configuration.

Signed-off-by: Kai Krakow <kai@kaishome.de>
This option is already disabled when CONFIG_PREEMPT_RT is enabled, lets
turn it off when CONFIG_ZEN_INTERACTIVE is set as well.

Signed-off-by: Kai Krakow <kai@kaishome.de>
What watermark boosting does is preemptively fire up kswapd to free
memory when there hasn't been an allocation failure. It does this by
increasing kswapd's high watermark goal and then firing up kswapd. The
reason why this causes freezes is because, with the increased high
watermark goal, kswapd will steal memory from processes that need it in
order to make forward progress. These processes will, in turn, try to
allocate memory again, which will cause kswapd to steal necessary pages
from those processes again, in a positive feedback loop known as page
thrashing. When page thrashing occurs, your system is essentially
livelocked until the necessary forward progress can be made to stop
processes from trying to continuously allocate memory and trigger
kswapd to steal it back.

This problem already occurs with kswapd *without* watermark boosting,
but it's usually only encountered on machines with a small amount of
memory and/or a slow CPU. Watermark boosting just makes the existing
problem worse enough to notice on higher spec'd machines.

Disable watermark boosting by default since it's a total dumpster fire.
I can't imagine why anyone would want to explicitly enable it, but the
option is there in case someone does.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Per an [issue][1] on the chromium project, swap-in readahead causes more
jank than not.  This might be caused by poor optimization on the
swapping code, or the fact under memory pressure, we're pulling in pages
we don't need, causing more swapping.

Either way, this is mainline/upstream to Chromium, and ChromeOS
developers care a lot about system responsiveness. Lets implement the
same change so Zen Kernel users benefit.

[1]: https://bugs.chromium.org/p/chromium/issues/detail?id=263561

Signed-off-by: Kai Krakow <kai@kaishome.de>
Partially overrides ZEN interactive adjustments if enabled.

Signed-off-by: Piotr Gorski <lucjan.lucjanov@gmail.com>
Link: https://aur.archlinux.org/packages/linux-cachyos-bore
When selecting an idle CPU for a task, always try to prioritize
full-idle SMT cores (CPUs belonging to an SMT core where all its sibling
are idle) over partially-idle cores.

Signed-off-by: Andrea Righi <arighi@nvidia.com>
ckolivas and others added 4 commits August 28, 2026 19:54
Signed-off-by: Kai Krakow <kai@kaishome.de>
Add an option to wait on multiple futexes using the old interface, that
uses opcode 31 through futex() syscall. Do that by just translation the
old interface to use the new code. This allows old and stable versions
of Proton to still use fsync in new kernel releases.

Signed-off-by: André Almeida <andrealmeid@collabora.com>
ADIOS (Adaptive Deadline I/O Scheduler) is a block layer I/O scheduler
for the Linux kernel, designed for modern multi-queue block devices
(blk-mq). It aims to provide low latency for I/O operations by
combining deadline scheduling principles with a learning-based adaptive
latency control mechanism.

Link: https://github.com/firelzrd/adios
Signed-off-by: Kai Krakow <kai@kaishome.de>
Signed-off-by: Kai Krakow <kai@kaishome.de>
@kakra
kakra force-pushed the rebase-6.18/gaming-patches branch from 7ba5879 to c1759f9 Compare August 28, 2026 18:25
@kakra

kakra commented Aug 28, 2026

Copy link
Copy Markdown
Owner Author

Rebased to 6.18.46: Two older soft-dirty patches were dropped during the rebase because they conflicted. Modern Proton/Wine no longer relies on that soft-dirty path, so this should not affect current users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.