gamemode
gamemode copied to clipboard
Missing DISPLAY environment variable in systemd user service after first start
Hi,
i have started using the new custom user script functionality to put my Nvidia GPU into performance mode. I am using this config for that:
[custom]
; Custom scripts (executed using the shell) when gamemode starts and ends
start=notify-send "GameMode started"
nvidia-settings -a '[gpu:0]/GPUPowerMizerMode=1'
end=notify-send "GameMode ended"
nvidia-settings -a '[gpu:0]/GPUPowerMizerMode=0'
The problem with this is sometimes nvidia-settings fails to run because it needs the DISPLAY enviroment variable (+ XAUTHORITY probably), which is missing when the service first gets started.
I can see with systemctl --user show-environment
that the variables are there. But when i look at the actual environment from the gamemoded process with tr '\0' '\n' < /proc/<pid>/environ
they are missing. But after a service restart the variables are there. I suspect the problem is that the service is run too early before the X server had time to execute /etc/X11/xinit/xinitrc.d/50-systemd-user.sh
(See [1]) which source these variables into systemds user daemon.
By using a small delay with ExecStartPre=/usr/bin/sleep 5
the problem is gone, but there must be a better solution to this. I have this problem on Fedora and Arch Linux so it probably affects all distros.
[1] https://wiki.archlinux.org/index.php/Systemd/User#DISPLAY_and_XAUTHORITY
Cheers @OlliC this is a good report.
So from what I'm aware it's complicated to get this right, see: this superuser post for discussions. Would be open to suggestions about clean ways, as it's unfortunate you can't just specify Wants=xorg.service
!
My current workaround is to restart the service with Gnomes autostart feature with this desktop file:
$ cat .local/share/applications/gamemoded-restart.desktop
[Desktop Entry]
Name=Restart gamemoded user service
Exec=systemctl --user try-restart gamemoded.service
Type=Application
Terminal=false
This works quite well and is probably better than sleep for 5 seconds, because the time to startup the desktop environment could vary. The real solution is probably to use graphical-session.target
, but that only works when the desktop environments start using systemd to bring it up, which is a work in progress as it seems.
To be honest, you could just disable the service with systemctl entirely and only initialize it with gnome like that. A Meson option could probably be constructed to do that automatically.
The problem is how some distributions start the systemd bus... It should not be started by the Xorg script. I think it should be included in PAM. In Gentoo there's -session optional pam_systemd.so
in /etc/pam.d/system-auth
. According to man pam_systemd
this would start the user session bus. User services will then see all variables the user login sees.
The Xorg script is only there to import environment:
#!/bin/sh
systemctl --user import-environment DISPLAY XAUTHORITY
if command -v dbus-update-activation-environment >/dev/null 2>&1; then
dbus-update-activation-environment DISPLAY XAUTHORITY
fi
So it may be sufficient to start a process in Gnome to import the environment.
One other note: Can't we just make the service dbus activatable instead of autostarting with the session? Systemd has support for this. I could come up with a PR for this...
I think the underlying problem is completely different and should not be solved by injecting the DISPLAY variable into the gamemoded process. The DISPLAY variable is coupled to the game executed, not the session gamemoded is started in.
To properly solve this, we need to extract the environment of the game and inject it into the scripts started by gamemoded.
I've queued patches in my PRs which would make this easy. If they are merged, I'd work on a PR to solve this. Injecting the proper environment into the scripts would probably also solve some other problems which may arise.
One other note: Can't we just make the service dbus activatable instead of autostarting with the session? Systemd has support for this. I could come up with a PR for this...
This has already been done by commit 432a21f5. I think existing installs will need to do systemctl --user disable gamemoded
to disable the autostart, and then it'll be activated as needed.
We should still present the environment that the game is seeing to scripts, and not what the daemon is seeing, right? Since you merged the wine PR which contains a function to access the environment, I could start working on such a solution and close some open issues here while on the way. It's not really complicated to do now, actually it's really easy now.
Yeah, certainly I think DISPLAY
should match what the game has.
Could you merge my cleanup PR first? Given it's fine for you...
I think I'm getting this issue on garuda Linux. I made a form post here https://forum.garudalinux.org/t/gamemode-not-working-with-steam the strange thing is i don't get this issue in vanilla arch. Should mention restating the service does not help in my case
I'm experiencing this issue on Wayland using SwayWM. The start / end scripts are helpful to work around SwayWM issues High refresh rate flickering #7087 and Variable refresh rate flickering #5076.
# ~/.config/gamemode.ini
[custom]
start=gamemode-script start
end=gamemode-script end
#!/bin/bash
# gamemode-script
case "$1" in
'start') swaymsg "output * adaptive_sync on" && swaymsg "output * mode [email protected]" ;;
'end') swaymsg "output * adaptive_sync off" && swaymsg "output * mode [email protected]" ;;
*) echo 'Requires start or end as a parameter'
esac
Adding this line to my sway config resolved the issue: exec --no-startup-id systemctl try-restart gamemoded.service --user
Thank you for that workaround.