Help creating systemd unit for running optimus-manager command at startup

Hello,

I am relatively new to Linux and am requesting a little hand-holding here.
I have a laptop with an iGPU as well as a discrete Nvidia GPU. As a result, fox external displays to function, I must run the following command:

optimus-manager --switch nvidia --no-confirm

I would like for this command to run when the machine starts. My understanding is I should do this with a systemd unit so I have attempted to create one.

I have created a script file setnvidia.sh containing the following:

#!/bin/zsh
optimus-manager --switch nvidia --no-confirm

I also created the systemd unit file setnvidia.service which contains the following:

[Unit]
Description=SetNVGPU
After=optimus-manager.service
After=sddm.service
After=display-manager.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setnvidia.sh

[Install]
WantedBy=multi-user.target

The service appears to enable and start properly, but upon rebooting the desired effect is not achieved.
systemctl status setnvidia.service yields:

setnvidia.service - SetNVGPU
     Loaded: loaded (/etc/systemd/system/setnvidia.service; enabled; preset: disabled)
     Active: failed (Result: exit-code) since Thu 2024-04-18 00:44:25 PDT; 2min 5s ago
    Process: 690 ExecStart=/usr/local/bin/setnvidia.sh (code=exited, status=1/FAILURE)
   Main PID: 690 (code=exited, status=1/FAILURE)
        CPU: 36ms

Apr 18 00:44:25 zirconium setnvidia.sh[691]: ERROR: a GPU setup was initiated but Xorg post-start hook did not run.
Apr 18 00:44:25 zirconium setnvidia.sh[691]: Log at /var/log/optimus-manager/switch/switch-20240418T004425.log
Apr 18 00:44:25 zirconium setnvidia.sh[691]: If your login manager is GDM, make sure to follow those instructions:
Apr 18 00:44:25 zirconium setnvidia.sh[691]: https://github.com/Askannz/optimus-manager#important--gnome-and-gdm-users
Apr 18 00:44:25 zirconium setnvidia.sh[691]: If your display manager is neither GDM, SDDM nor LightDM, or if you don't use one, read the wiki:
Apr 18 00:44:25 zirconium setnvidia.sh[691]: https://github.com/Askannz/optimus-manager/wiki/FAQ,-common-issues,-troubleshooting
Apr 18 00:44:25 zirconium setnvidia.sh[691]: Cannot execute command because of previous errors.
Apr 18 00:44:25 zirconium systemd[1]: setnvidia.service: Main process exited, code=exited, status=1/FAILURE
Apr 18 00:44:25 zirconium systemd[1]: setnvidia.service: Failed with result 'exit-code'.
Apr 18 00:44:25 zirconium systemd[1]: Failed to start SetNVGPU.

var/log/optimus-manager/switch/switch-20240418T004425.log contains:

[6] INFO: # Xorg pre-start hook
[6] INFO: Previous state was: {'type': 'pending_pre_xorg_start', 'requested_mode': 'integrated', 'current_mode': None}
[6] INFO: Requested mode is: integrated
[28] INFO: Available modules: ['nouveau', 'nvidia', 'nvidia_drm', 'nvidia_modeset', 'nvidia_uvm']
[28] INFO: Unloading modules ['nvidia_drm', 'nvidia_modeset', 'nvidia_uvm', 'nvidia'] (if loaded)
[31] INFO: switching=none, nothing to do
[81] INFO: Writing to /etc/X11/xorg.conf.d/10-optimus-manager.conf
[81] INFO: Writing state {'type': 'pending_post_xorg_start', 'switch_id': '20240418T004425', 'requested_mode': 'integrated'}
[81] INFO: Xorg pre-start hook completed successfully.
[5] INFO: # Xorg post-start hook
[106] INFO: Running /etc/optimus-manager/xsetup-integrated.sh
[116] INFO: Writing state {'type': 'done', 'switch_id': '20240418T004425', 'current_mode': 'integrated'}
[117] INFO: Xorg post-start hook completed successfully.

Hi @entropywins,

@cscs has a better answer, but I'll leave this one here, anyway.

I think you’d rather want a systemd user unit, which is for your user only, not system-wide. I have a couple of those myself. Creating them is easy:

  1. Create a file, the new unit, in ~/.config/systemd/user:

    touch ~/.config/systemd/user/start-external-graphics.service
    
  2. Edit the file with the unit contents:

    [Unit]
    Description=SetNVGPU
    After=optimus-manager.service
    After=sddm.service
    After=display-manager.service
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/sh -c "optimus-manager --switch nvidia --no-confirm"
    
    [Install]
    WantedBy=multi-user.target
    

    Save the file and exit the editor.

  3. Reload the systemd daemon:

    sudo systemctl daemon-reload
    
  4. Start and enable the newly created unit ass a user, not as root:

    systemctl --user enable --now start-external-graphics.service
    

Theoretically that should be it.

Hope this helps!

1 Like

If this is the route you would like to go I might suggest using envycontrol for a plethora of reasons including it does not require you to hack up your display manager and also that this service would not be required.

For other approaches you might see examples like here:

2 Likes

Thank you so much for the immediate assistance.
Envycontrol worked beautifully right away, and now I’m a little embarrassed to admit how much time I spent on the systemd unit file.
Thanks again to both of you for your help.

1 Like

This topic was automatically closed 36 hours after the last reply. New replies are no longer allowed.