From d62525f5af76985be5d6ed15f6dca81ce4b1172a Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 29 Sep 2026 14:39:53 -0400 Subject: [PATCH 1/2] perf: stop proot's kompat from trapping futex/epoll/fcntl and stripping the vDSO when only the hostname changes --- tools/proot/PATCHES.md | 11 ++++ .../patches/0011-kompat-utsname-only.patch | 64 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tools/proot/patches/0011-kompat-utsname-only.patch diff --git a/tools/proot/PATCHES.md b/tools/proot/PATCHES.md index aa528b746..503e4fbed 100644 --- a/tools/proot/PATCHES.md +++ b/tools/proot/PATCHES.md @@ -44,3 +44,14 @@ Ported from WinNative (`main`, 53836ca9, "Fix/performance and vac"): - `0009-tracee-relatives-sweep.patch` - tracees count their children, so a terminating thread with no children or ptracees no longer walks every tracee; the per-stop memory collector is emptied instead of freed and reallocated. + +Added by DroidDeck: + +- `0011-kompat-utsname-only.patch` - `--kernel-release` (the guest's `DroidDeck` hostname) loads + kompat, whose filter traps `futex`, `fcntl`, `epoll_pwait`, `pselect6`, `pipe2`, `eventfd2`, + `socket` and more, and which strips `AT_SYSINFO_EHDR` on every `execve`, so glibc runs without + the vDSO. When the virtual release is not older than the real kernel and the hwcap is left + alone, every one of those handlers is a no-op: kompat now traces only `uname`, `sethostname` + and `setdomainname` and leaves the auxv as the kernel wrote it. On an SD 8 Gen 2 guest this + took a futex ping-pong from 467 to 97 us, `epoll_pwait` from 60 to 0.8 us and `fcntl` from + 40-107 to 0.4 us, and `clock_gettime` back to the vDSO. diff --git a/tools/proot/patches/0011-kompat-utsname-only.patch b/tools/proot/patches/0011-kompat-utsname-only.patch new file mode 100644 index 000000000..9c1949cce --- /dev/null +++ b/tools/proot/patches/0011-kompat-utsname-only.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: DroidDeck +Date: Tue, 29 Sep 2026 00:00:00 +0000 +Subject: [PATCH] kompat: only trace the utsname calls when no older kernel is + emulated + +--- + src/extension/kompat/kompat.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/src/extension/kompat/kompat.c b/src/extension/kompat/kompat.c +index 5c39942..4cb7dec 100644 +--- a/src/extension/kompat/kompat.c ++++ b/src/extension/kompat/kompat.c +@@ -985,6 +985,29 @@ static FilteredSysnum filtered_sysnums[] = { + FILTERED_SYSNUM_END, + }; + ++/* When the virtual kernel is not older than the actual one and the ++ * hwcap is left alone, the only thing left to emulate is the utsname ++ * itself: every other handler above returns without a change. */ ++static FilteredSysnum utsname_only_sysnums[] = { ++ { PR_setdomainname, FILTER_SYSEXIT }, ++ { PR_sethostname, FILTER_SYSEXIT }, ++ { PR_uname, FILTER_SYSEXIT }, ++ FILTERED_SYSNUM_END, ++}; ++ ++/** ++ * Return whether @config only renames the kernel identity (nodename, ++ * domainname, version string) without emulating an older kernel or ++ * another hwcap, in which case futex, fcntl, epoll_pwait, ... don't ++ * have to stop in the tracer and the vDSO can be left in place. ++ */ ++static bool utsname_only(const Config *config) ++{ ++ return config->actual_release != 0 ++ && config->virtual_release >= config->actual_release ++ && config->hwcap == (word_t) -1; ++} ++ + /** + * Handler for this @extension. It is triggered each time an @event + * occured. See ExtensionEvent for the meaning of @data1 and @data2. +@@ -1007,7 +1030,9 @@ int kompat_callback(Extension *extension, ExtensionEvent event, + if (status < 0) + return -1; + +- extension->filtered_sysnums = filtered_sysnums; ++ extension->filtered_sysnums = utsname_only(config) ++ ? utsname_only_sysnums ++ : filtered_sysnums; + return 0; + } + +@@ -1038,7 +1063,7 @@ int kompat_callback(Extension *extension, ExtensionEvent event, + + /* Note: this can be done only before PRoot pushes the + * load script into tracee's stack. */ +- if ((int) result >= 0 && sysnum == PR_execve) ++ if ((int) result >= 0 && sysnum == PR_execve && !utsname_only(config)) + adjust_elf_auxv(tracee, config); + return 0; + } From 0f4e83eefdc604dc4dbf4a2ba9919565df003e1a Mon Sep 17 00:00:00 2001 From: xXJsonDeruloXx Date: Tue, 29 Sep 2026 15:08:28 -0400 Subject: [PATCH 2/2] fix: stop gamescope respawning a mangoapp that keeps dying at start --- tools/mangoapp/mangoapp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/mangoapp/mangoapp b/tools/mangoapp/mangoapp index 4d541f73e..e912be1a8 100644 --- a/tools/mangoapp/mangoapp +++ b/tools/mangoapp/mangoapp @@ -5,4 +5,17 @@ # WAYLAND_DISPLAY as Wayland-only, and unset, libwayland falls back to wayland-0 - DroidDeck's own # compositor, which shares XDG_RUNTIME_DIR - so both fail; x11 makes GLFW use gamescope's X server. export XDG_SESSION_TYPE=x11 +# gamescope's reaper restarts mangoapp the moment it exits, with no backoff. One that dies at start +# (a stale session preload without the System V queue, a driver it crashes on) was started about +# once a second for the whole session, each start a full exec under proot - the Steam menu itself +# lagged. More than 5 starts in 60 s leaves the overlay off: this waits instead of exiting, so the +# reaper has nothing to restart until the session ends. +starts=/tmp/droiddeck-mangoapp-starts +now=$(date +%s) +recent=$(awk -v now="$now" '$1 > now - 60' "$starts" 2>/dev/null) +printf '%s\n%s\n' "$recent" "$now" | sed '/^$/d' > "$starts" +if [ "$(wc -l < "$starts")" -gt 5 ]; then + echo "mangoapp: started $(wc -l < "$starts") times in 60 s; the performance overlay stays off for this session" >&2 + exec sleep infinity +fi LD_LIBRARY_PATH=/usr/local/lib/mangoapp${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} exec /usr/local/lib/mangoapp/mangoapp "$@"