FeralInteractive / gamemode

Optimise Linux system performance on demand
BSD 3-Clause "New" or "Revised" License
4.68k stars 184 forks source link

Missing DISPLAY environment variable in systemd user service after first start #45

Open OlliC opened 6 years ago

OlliC commented 6 years ago

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

mdiluz commented 6 years ago

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!

OlliC commented 6 years ago

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.

mdiluz commented 6 years ago

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.

kakra commented 6 years ago

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.

kakra commented 5 years ago

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...

kakra commented 5 years ago

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.

aejsmith commented 5 years ago

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.

kakra commented 5 years ago

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.

aejsmith commented 5 years ago

Yeah, certainly I think DISPLAY should match what the game has.

kakra commented 5 years ago

Could you merge my cleanup PR first? Given it's fine for you...

zany130 commented 3 years ago

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

cheyngoodman commented 1 year ago

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 2560x1440@143.972Hz" ;;
  'end')   swaymsg "output * adaptive_sync off" && swaymsg "output * mode 2560x1440@59.951Hz" ;;
  *) 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.