perf: the session's background watchers share two loops and one D-Bus service process (#575)

This commit is contained in:
Kurt Himebauch authored and GitHub committed 2026-10-14 01:02:24 -04:00
1 parent a0d3e03ca0
commit 7ea4efef98
4 files changed
+172 -137

No files matched your search

@@ -5,6 +5,8 @@ Android owns device power. Suspend here pauses the guest through SessionService;
the app's Resume action thaws it and completes PrepareForSleep(false). Steam
must see this service before startup or it can stay black after its idle timer.
"""
import importlib.machinery
import importlib.util
import os
from pathlib import Path
import re
@@ -193,6 +195,15 @@ class LoginManager:
self.notify(False)
def load_netmanager():
path = Path(__file__).resolve().with_name("droiddeck-netmanager")
loader = importlib.machinery.SourceFileLoader("droiddeck_netmanager", str(path))
spec = importlib.util.spec_from_loader(loader.name, loader)
module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
return module
def main():
directory = os.environ.get("BL_LAUNCH_DIR")
if not directory or not Path(directory).is_dir():
@@ -218,6 +229,8 @@ def main():
owners = [Gio.bus_own_name(Gio.BusType.SYSTEM, name, Gio.BusNameOwnerFlags.NONE, connected, acquired, lost)
for name in (NAME, UPOWER)]
if "--with-netmanager" in sys.argv[1:]:
owners.append(load_netmanager().own(loop))
try:
loop.run()
finally:
@@ -408,8 +408,7 @@ class NetworkManager:
self.bus.emit_signal(None, path, OBJECT_MANAGER, signal, body)
def main():
loop = GLib.MainLoop()
def own(loop):
state = {}
def acquired(bus, name):
@@ -419,7 +418,12 @@ def main():
print("== netmanager: the system bus is gone", file=sys.stderr)
loop.quit()
Gio.bus_own_name(Gio.BusType.SYSTEM, NAME, Gio.BusNameOwnerFlags.NONE, acquired, None, lost)
return Gio.bus_own_name(Gio.BusType.SYSTEM, NAME, Gio.BusNameOwnerFlags.NONE, acquired, None, lost)
def main():
loop = GLib.MainLoop()
own(loop)
loop.run()
@@ -328,23 +328,6 @@ case $mode in
fi
if [ -n "${BL_CLIENT_CPUS:-}" ]; then
step "client cores: $BL_CLIENT_CPUS"
(
declare -A _bl_pinned=()
for ((_i = 0; _i < 720; _i++)); do
for _d in /proc/[0-9]*; do
IFS= read -r -d '' _c < "$_d/cmdline" 2>/dev/null || continue
case $_c in *steamwebhelper*|*steamrtarm64/steam|*gamescope*) ;; *) continue ;; esac
_t=("$_d"/task/*)
_p=${_d#/proc/}
if [ "${_bl_pinned[$_p]:-}" = "${#_t[@]}" ] && client_single_core_matches "$BL_CLIENT_CPUS" "${_t[@]}"; then
continue
fi
taskset -a -cp "$BL_CLIENT_CPUS" "$_p" >/dev/null 2>&1 || true
_bl_pinned[$_p]=${#_t[@]}
done
nap 5
done
) &
fi
if [ "${BL_ZRAM:-0}" = 1 ]; then
printf 0 > /tmp/.bl-zram
@@ -459,105 +442,50 @@ case $mode in
) &
fi
fi
[ -z "${BL_DESKTOP:-}" ] && [ "${BL_STRETCHED:-0}" = 1 ] && (
while :; do
nap 1
cur=$(xprop -root GAMESCOPE_NEW_SCALING_SCALER 2>/dev/null) || continue
case $cur in *" = "*) cur=${cur##* = } ;; *) cur=0 ;; esac
[ "$cur" = 0 ] || continue
xprop -root -f GAMESCOPE_NEW_SCALING_SCALER 32c -set GAMESCOPE_NEW_SCALING_SCALER 4 2>/dev/null \
&& echo "== stretch 16:9 to panel: the client's scaler was Auto, set to Stretch"
done
) &
[ -z "${BL_DESKTOP:-}" ] && [ "${BL_RESTORE_ON_RESUME:-1}" = 1 ] && (
prev=
xprop -spy -root GAMESCOPE_FOCUSED_APP 2>/dev/null | while read -r line; do
app=${line##*= }
case $app in ''|*[!0-9]*) prev=; continue ;; esac
if [ "$prev" = 769 ] && [ "$app" != 769 ]; then
nap 1
bl_xprop_set_all GAMESCOPE_RESTORE_FOCUS_WINDOW 1 \
&& echo "== resume: asked gamescope to restore the game window (app $app)"
fi
prev=$app
done
) &
[ -z "${BL_DESKTOP:-}" ] && (
xprop_value() {
case $1 in *'not found'*|*=) echo "$2"; return ;; esac
local v=${1#*=}
v=${v# }
echo "${v:-$2}"
stretch=0 restore=0
[ "${BL_STRETCHED:-0}" = 1 ] && stretch=1
[ "${BL_RESTORE_ON_RESUME:-1}" = 1 ] && restore=1
atoms=(STEAM_TOUCH_CLICK_MODE GAMESCOPE_FOCUSED_APP)
[ "$stretch" = 1 ] && atoms+=(GAMESCOPE_NEW_SCALING_SCALER)
prop_value() {
case $1 in *'not found'*|*=) pv=$2; return ;; esac
pv=${1#*=}
pv=${pv# }
pv=${pv:-$2}
}
tmode= app=
xprop -spy -root STEAM_TOUCH_CLICK_MODE GAMESCOPE_FOCUSED_APP 2>/dev/null | while read -r line; do
tmode= app= prev=
while read -r line; do
case $line in
STEAM_TOUCH_CLICK_MODE*)
v=$(xprop_value "$line" unset)
[ "$v" = "$tmode" ] && continue
tmode=$v
prop_value "$line" unset
[ "$pv" = "$tmode" ] && continue
tmode=$pv
echo "== touch mode: $tmode (focused app ${app:-?}) at $(date +%T)"
;;
GAMESCOPE_FOCUSED_APP*)
v=$(xprop_value "$line" none)
[ "$v" = "$app" ] && continue
app=$v
echo "== focused app: $app (touch mode ${tmode:-unset}) at $(date +%T)"
prop_value "$line" none
if [ "$pv" != "$app" ]; then
app=$pv
echo "== focused app: $app (touch mode ${tmode:-unset}) at $(date +%T)"
fi
[ "$restore" = 1 ] || continue
case $pv in ''|*[!0-9]*) prev=; continue ;; esac
if [ "$prev" = 769 ] && [ "$pv" != 769 ]; then
nap 1
bl_xprop_set_all GAMESCOPE_RESTORE_FOCUS_WINDOW 1 \
&& echo "== resume: asked gamescope to restore the game window (app $pv)"
fi
prev=$pv
;;
GAMESCOPE_NEW_SCALING_SCALER*)
prop_value "$line" 0
[ "$pv" = 0 ] || continue
xprop -root -f GAMESCOPE_NEW_SCALING_SCALER 32c -set GAMESCOPE_NEW_SCALING_SCALER 4 2>/dev/null \
&& echo "== stretch 16:9 to panel: the client's scaler was Auto, set to Stretch"
;;
esac
done
) &
(
beat=0
compat_stamp=$HOME/.bl-compat-beat
seed_stamp=$HOME/.bl-seed-beat
rm -f "$compat_stamp" "$seed_stamp"
changed_since() {
local d
for d in "${@:2}"; do
[ "$d" -nt "$1" ] && return 0
done
return 1
}
compat_due() {
[ -e "$compat_stamp" ] && [ "$((beat % 60))" -ne 0 ] || return 0
changed_since "$compat_stamp" "${libraries[@]}" "$steam_root/steamapps/common" "$steam_root/config" \
"$steam_root/compatibilitytools.d"
}
seed_due() {
local reg
[ -e "$seed_stamp" ] && [ "$((beat % 60))" -ne 0 ] || return 0
changed_since "$seed_stamp" "${libraries[@]}" && return 0
for reg in "$steam_root"/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
/mnt/droiddeck-sd/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
/root/Games/*/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
"$steam_root"/compatibilitytools.d/*/files/share/default_pfx*/system.reg \
"$steam_root"/steamapps/compatdata/*/pfx/system.reg \
/mnt/droiddeck-sd/steamapps/compatdata/*/pfx/system.reg \
/root/Games/*/steamapps/compatdata/*/pfx/system.reg; do
[ -f "$reg" ] && [ ! -f "${reg%/*}/.droiddeck-redists" ] && return 0
done
return 1
}
for ((_i = 0; _i < 720; _i++)); do
nap 5
beat=$((beat + 1))
[ "$((beat % 3))" -eq 0 ] || continue
libraries=("$steam_root/steamapps" /mnt/droiddeck/steamapps /mnt/droiddeck-sd/steamapps /root/Games/*/steamapps)
seed=; compat=
seed_due && seed=1
compat_due && compat=1
[ -n "$seed$compat" ] || continue
pgrep -x wineserver >/dev/null 2>&1 && continue
if [ -n "$seed" ]; then
: > "$seed_stamp"
droiddeck-seed-redists "$steam_root" >/dev/null 2>&1 || true
fi
if [ -n "$compat" ]; then
: > "$compat_stamp"
steam-compatibility "$steam_root" >/dev/null 2>&1 || true
fi
done
done < <(xprop -spy -root "${atoms[@]}" 2>/dev/null)
) &
if [ -n "${BL_LAUNCH_DIR:-}" ] && [ -z "${BL_DESKTOP:-}" ]; then
_bl_held=
@@ -630,11 +558,9 @@ BUSCONF
sleep 0.1
done
if [ -S /run/dbus/system_bus_socket ]; then
droiddeck-netmanager &
netmanager=$!
echo "== network: system bus up, NetworkManager stand-in running"
rm -f "$BL_LAUNCH_DIR/steam-sleep-ready"
droiddeck-login1 &
droiddeck-login1 --with-netmanager &
login_manager=$!
for ((_i = 0; _i < 50; _i++)); do
[ -f "$BL_LAUNCH_DIR/steam-sleep-ready" ] && break
@@ -739,22 +665,6 @@ BUSCONF
droiddeck-steam-games watch "$steam_root" "$BL_ADDED_GAMES" &
games_watcher=$!
fi
if [ "${BL_LOSSLESS_OWNED:-0}" != 1 ]; then
(
owned=$HOME/.config/droiddeck/lossless-owned
for ((_i = 0; _i < 60; _i++)); do
nap 30
[ -e "$owned" ] && exit 0
pgrep -x wineserver >/dev/null 2>&1 && continue
answer=$(droiddeck-steam-games probe "$steam_root" 993090 2>/dev/null) || continue
case $answer in
*'"993090": true'*) mkdir -p "${owned%/*}" && : > "$owned" && echo "== Lossless Scaling: owned" ;;
*) echo "== Lossless Scaling: not owned by this account" ;;
esac
exit 0
done
) &
fi
echo "== steam args: ${_bl_ui[*]} ${_bl_cdp[*]} ${_bl_lang[*]} -clientbeta $steam_channel -no-cef-sandbox -cef-ozone-platform=x11 ${_bl_cef[*]} $*"
steam_updates=0
rm -f "$HOME/.bl-stop-requested" "$STEAMOS_STEAM_SHUTDOWN_SENTINEL" "$STEAMOS_STEAM_REBOOT_SENTINEL"
@@ -781,10 +691,54 @@ BUSCONF
return 0
done
}
requests=
if [ -n "${BL_LAUNCH_DIR:-}" ] && [ -d "$BL_LAUNCH_DIR" ]; then
rm -f "$BL_LAUNCH_DIR/steam-stop" "$BL_LAUNCH_DIR/steam-game" "$BL_LAUNCH_DIR/steam-game.tmp"
(
while :; do
requests=1
fi
(
tick=0
beat=0
library_job=
lossless_job=
lossless_left=0
lossless_owned=$HOME/.config/droiddeck/lossless-owned
lossless_asked=$HOME/.bl-lossless-asked
rm -f "$lossless_asked"
[ "${BL_LOSSLESS_OWNED:-0}" != 1 ] && lossless_left=60
declare -A _bl_pinned=()
compat_stamp=$HOME/.bl-compat-beat
seed_stamp=$HOME/.bl-seed-beat
rm -f "$compat_stamp" "$seed_stamp"
changed_since() {
local d
for d in "${@:2}"; do
[ "$d" -nt "$1" ] && return 0
done
return 1
}
compat_due() {
[ -e "$compat_stamp" ] && [ "$((beat % 60))" -ne 0 ] || return 0
changed_since "$compat_stamp" "${libraries[@]}" "$steam_root/steamapps/common" "$steam_root/config" \
"$steam_root/compatibilitytools.d"
}
seed_due() {
local reg
[ -e "$seed_stamp" ] && [ "$((beat % 60))" -ne 0 ] || return 0
changed_since "$seed_stamp" "${libraries[@]}" && return 0
for reg in "$steam_root"/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
/mnt/droiddeck-sd/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
/root/Games/*/steamapps/common/Proton*/files/share/default_pfx*/system.reg \
"$steam_root"/compatibilitytools.d/*/files/share/default_pfx*/system.reg \
"$steam_root"/steamapps/compatdata/*/pfx/system.reg \
/mnt/droiddeck-sd/steamapps/compatdata/*/pfx/system.reg \
/root/Games/*/steamapps/compatdata/*/pfx/system.reg; do
[ -f "$reg" ] && [ ! -f "${reg%/*}/.droiddeck-redists" ] && return 0
done
return 1
}
while :; do
if [ -n "$requests" ]; then
if [ -e "$BL_LAUNCH_DIR/steam-stop" ]; then
rm -f "$BL_LAUNCH_DIR/steam-stop"
: > "$HOME/.bl-stop-requested"
@@ -813,11 +767,56 @@ BUSCONF
;;
esac
fi
nap 0.5
done
) &
stop_watcher=$!
fi
fi
nap 0.5
tick=$((tick + 1))
[ "$((tick % 10))" -eq 0 ] || continue
beat=$((beat + 1))
if [ "$beat" -le 720 ] && [ -n "${BL_CLIENT_CPUS:-}" ]; then
for _d in /proc/[0-9]*; do
IFS= read -r -d '' _c < "$_d/cmdline" 2>/dev/null || continue
case $_c in *steamwebhelper*|*steamrtarm64/steam|*gamescope*) ;; *) continue ;; esac
_t=("$_d"/task/*)
_p=${_d#/proc/}
[ "${_bl_pinned[$_p]:-}" = "${#_t[@]}" ] && client_single_core_matches "$BL_CLIENT_CPUS" "${_t[@]}" && continue
taskset -a -cp "$BL_CLIENT_CPUS" "$_p" >/dev/null 2>&1 || true
_bl_pinned[$_p]=${#_t[@]}
done
fi
if [ "$beat" -le 720 ] && [ "$((beat % 3))" -eq 0 ] && { [ -z "$library_job" ] || ! kill -0 "$library_job" 2>/dev/null; }; then
libraries=("$steam_root/steamapps" /mnt/droiddeck/steamapps /mnt/droiddeck-sd/steamapps /root/Games/*/steamapps)
seed=; compat=
seed_due && seed=1
compat_due && compat=1
if [ -n "$seed$compat" ] && ! pgrep -x wineserver >/dev/null 2>&1; then
[ -n "$seed" ] && : > "$seed_stamp"
[ -n "$compat" ] && : > "$compat_stamp"
(
[ -z "$seed" ] || droiddeck-seed-redists "$steam_root" >/dev/null 2>&1 || true
[ -z "$compat" ] || steam-compatibility "$steam_root" >/dev/null 2>&1 || true
) &
library_job=$!
fi
fi
if [ "$lossless_left" -gt 0 ] && [ "$((beat % 6))" -eq 0 ] && { [ -z "$lossless_job" ] || ! kill -0 "$lossless_job" 2>/dev/null; }; then
lossless_left=$((lossless_left - 1))
if [ -e "$lossless_owned" ] || [ -e "$lossless_asked" ]; then
lossless_left=0
elif ! pgrep -x wineserver >/dev/null 2>&1; then
(
answer=$(droiddeck-steam-games probe "$steam_root" 993090 2>/dev/null) || exit 0
case $answer in
*'"993090": true'*) mkdir -p "${lossless_owned%/*}" && : > "$lossless_owned" && echo "== Lossless Scaling: owned" ;;
*) echo "== Lossless Scaling: not owned by this account" ;;
esac
: > "$lossless_asked"
) &
lossless_job=$!
fi
fi
done
) &
stop_watcher=$!
while :; do
rm -f "$HOME/.bl-restart-once"
if [ -f "$steam_beta" ] && [ "$(cat "$steam_beta" 2>/dev/null)" != "$steam_channel" ]; then
+20 -1
View File
@@ -22,6 +22,8 @@ IFACE = NAME + ".Manager"
@unittest.skipUnless(Gio and os.environ.get("DBUS_SESSION_BUS_ADDRESS"), "requires dbus-run-session and PyGObject")
class SleepHandshakeTest(unittest.TestCase):
ARGS = []
def setUp(self):
self.directory = tempfile.TemporaryDirectory()
self.dir = Path(self.directory.name)
@@ -35,7 +37,7 @@ class SleepHandshakeTest(unittest.TestCase):
lambda bus, sender, path, interface, name, body: self.signals.append(body.unpack()[0]))
env = dict(os.environ, BL_LAUNCH_DIR=str(self.dir),
DBUS_SYSTEM_BUS_ADDRESS=os.environ["DBUS_SESSION_BUS_ADDRESS"])
self.process = subprocess.Popen(["/usr/bin/python3", str(SCRIPT)], env=env,
self.process = subprocess.Popen(["/usr/bin/python3", str(SCRIPT), *self.ARGS], env=env,
stdout=subprocess.DEVNULL)
self.wait_for(lambda: (self.dir / "steam-sleep-ready").exists())
@@ -218,5 +220,22 @@ class SleepHandshakeTest(unittest.TestCase):
self.call(IFACE, "PowerOff", GLib.Variant("(b)", (True,)))
class WithNetworkManagerTest(SleepHandshakeTest):
ARGS = ["--with-netmanager"]
def owner(self, name):
return self.bus.call_sync("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus",
"GetConnectionUnixProcessID", GLib.Variant("(s)", (name,)), None,
Gio.DBusCallFlags.NONE, 2000, None).unpack()[0]
def test_one_process_owns_login1_and_networkmanager(self):
self.wait_for(lambda: self.bus.call_sync(
"org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameHasOwner",
GLib.Variant("(s)", ("org.freedesktop.NetworkManager",)), None,
Gio.DBusCallFlags.NONE, 2000, None).unpack()[0])
self.assertEqual(self.owner("org.freedesktop.NetworkManager"), self.process.pid)
self.assertEqual(self.owner(NAME), self.process.pid)
if __name__ == "__main__":
unittest.main()