diff --git a/README.md b/README.md index 6c43a41..135adbf 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,16 @@ It started with a revelation that bumblebee in current state offers very poor pe 1. run `nvidia-xrun [app]` 1. enjoy -Currently sudo is required as the script needs to wake up GPU, modprobe the nvidia driver and perform cleanup afterwards. +### Passwordless `sudo` +Whitelisting `nvidia-toggle` in your sudoer's file allows you to use `nvidia-xrun` without entering your password: + +``` +%users ALL=(root) NOPASSWD:/usr/bin/nvidia-toggle +``` + +...where `/usr/bin/nvidia-toggle` is the full path to the `nvidia-toggle` script. + +Note: it is a good practice to ensure binaries/scripts/etc. that are whitelisted for passwordless `sudo` are owned by root. The systemd service can be used to completely remove the card from the kernel device tree (so that it won't even show in `lspci` output), and this will diff --git a/config/nvidia-xrun b/config/nvidia-xrun index c13363e..1beb8ac 100644 --- a/config/nvidia-xrun +++ b/config/nvidia-xrun @@ -11,8 +11,16 @@ ENABLE_PM=1 # and some other programs tend to load the nvidia module if they detect a # nvidia card in the system, and when the module is loaded the card can't save # power. +# +# USE_BBSWITCH option below can override the behavior of this option. REMOVE_DEVICE=1 +# When enabled, nvidia-xrun will toggle power for the card using bbswitch. +# This *requires* bbswitch to be installed. +# +# Note that this option overrides REMOVE_DEVICE paramter above when enabled. +USE_BBSWITCH=0 + # Bus ID of the PCI express controller CONTROLLER_BUS_ID=0000:00:01.0 diff --git a/nvidia-toggle b/nvidia-toggle new file mode 100755 index 0000000..5b76770 --- /dev/null +++ b/nvidia-toggle @@ -0,0 +1,147 @@ +#!/usr/bin/env bash + +# avoid tee to print in the stdout +TEE='tee > /dev/null' +VERBOSE=0 +DRY_RUN=0 + +function printHelp { + echo "Utility to toggle discrete Nvidia graphic card" + echo "Usage: " + echo "nvidia-toggle [] []" + echo "Options: " + echo " -d Dry run - prints the final command but does not execute it" + echo " -v Verbose - verbose output" +} + +function execute { + if [[ ${DRY_RUN} -ne 0 ]]; then + echo ">>Dry run. Command: $@" + else + eval "$@" + fi +} + +function say { + if [[ "$VERBOSE" == '1' ]]; then + echo "$@" + fi +} + +function turn_off_gpu { + if [[ "$USE_BBSWITCH" == '1' ]]; then + echo 'Turning off GPU using bbswitch ' + execute "sudo tee /proc/acpi/bbswitch <<<'OFF'" + else + if [[ "$REMOVE_DEVICE" == '1' ]]; then + say 'Removing Nvidia bus from the kernel' + execute "$TEE /sys/bus/pci/devices/${DEVICE_BUS_ID}/remove <<<1" + else + say 'Enabling powersave for the graphic card' + execute "$TEE /sys/bus/pci/devices/${DEVICE_BUS_ID}/power/control <<&2 + exit 1 +fi + +# load config file +. /etc/default/nvidia-xrun + +# this is used by the systemd service to turn off the gpu at boot +if [[ "$TURN_OFF_GPU_ONLY" == '1' ]]; then + turn_off_gpu + exit 0 +fi + +case $1 in +on) + # --------- TURNING ON GPU ----------- + if [[ "$ENABLE_PM" == '1' ]]; then + turn_on_gpu + fi + + # ---------- LOADING MODULES ---------- + load_modules + ;; +off) + # ---------- UNLOADING MODULES -------- + unload_modules + + # --------- TURNING OFF GPU ---------- + if [[ "$ENABLE_PM" == '1' ]]; then + turn_off_gpu + fi + ;; +*) + printHelp + exit 1 + ;; +esac diff --git a/nvidia-xinitrc b/nvidia-xinitrc index d7f38ce..04249cf 100644 --- a/nvidia-xinitrc +++ b/nvidia-xinitrc @@ -1,4 +1,7 @@ -#!/usr/bin/env bash +#!/bin/sh +# NOTICE: Do not use bash syntaxes here. +# At least in my machine (Ubuntu 18.04), +# this script seem to always be executed with sh. CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/X11 userresources=$CONFIG_DIR/xresources @@ -8,39 +11,39 @@ sysmodmap=/etc/X11/xinit/.Xmodmap userxinitrc=$CONFIG_DIR/nvidia-xinitrc # merge in defaults and keymaps -if [[ -f ${sysresources} ]]; then +if [ -f ${sysresources} ]; then xrdb -merge ${sysresources} fi -if [[ -f ${sysmodmap} ]]; then +if [ -f ${sysmodmap} ]; then xmodmap ${sysmodmap} fi -if [[ -f "$userresources" ]]; then +if [ -f "$userresources" ]; then xrdb -merge "$userresources" fi -if [[ -f "$usermodmap" ]]; then +if [ -f "$usermodmap" ]; then xmodmap "$usermodmap" fi -export LD_LIBRARY_PATH=/usr/lib64/nvidia/:/usr/lib32/nvidia:/usr/lib:${LD_LIBRARY_PATH} +export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/nvidia:/usr/lib:${LD_LIBRARY_PATH} # load additional configs -if [[ -d /etc/X11/xinit/nvidia-xinitrc.d ]] ; then - for f in /etc/X11/xinit/nvidia-xinitrc.d/?*.sh ; do - [[ -x "$f" ]] && . "$f" - done - unset f +if [ -d /etc/X11/xinit/nvidia-xinitrc.d ]; then + for f in /etc/X11/xinit/nvidia-xinitrc.d/?*.sh; do + [ -x "$f" ] && . "$f" + done + unset f fi xrandr --setprovideroutputsource modesetting NVIDIA-0 xrandr --auto -if [[ -f "$userxinitrc" ]]; then +if [ -f "$userxinitrc" ]; then sh ${userxinitrc} $* else - if [[ $# -gt 0 ]]; then + if [ $# -gt 0 ]; then sh -c "exec $*" fi fi diff --git a/nvidia-xorg.conf b/nvidia-xorg.conf index 46b345b..d5eba5b 100644 --- a/nvidia-xorg.conf +++ b/nvidia-xorg.conf @@ -1,13 +1,3 @@ -Section "Files" - ModulePath "/usr/lib/nvidia" - ModulePath "/usr/lib32/nvidia" - ModulePath "/usr/lib32/nvidia/xorg/modules" - ModulePath "/usr/lib32/xorg/modules" - ModulePath "/usr/lib64/nvidia/xorg/modules" - ModulePath "/usr/lib64/nvidia/xorg" - ModulePath "/usr/lib64/xorg/modules" -EndSection - Section "ServerLayout" Identifier "layout" Screen 1 "nvidia" @@ -23,7 +13,7 @@ EndSection Section "Screen" Identifier "nvidia" Device "nvidia" -# Option "AllowEmptyInitialConfiguration" "Yes" +# Option "AllowEmptyInitialConfiguration" "yes" # Option "UseDisplayDevice" "none" EndSection diff --git a/nvidia-xrun b/nvidia-xrun index c7c217d..bd12558 100755 --- a/nvidia-xrun +++ b/nvidia-xrun @@ -1,8 +1,5 @@ #!/usr/bin/env bash -# avoid tee to print in the stdout -TEE='tee > /dev/null' -VERBOSE=0 DRY_RUN=0 function printHelp { @@ -11,7 +8,6 @@ function printHelp { echo "nvidia-xrun [] []" echo "Options: " echo " -d Dry run - prints the final command but does not execute it" - echo " -v Verbose - verbose output" } function execute { @@ -22,83 +18,22 @@ function execute { fi } -function say { - if [[ "$VERBOSE" == '1' ]]; then - echo $* - fi -} - -function turn_off_gpu { - if [[ "$REMOVE_DEVICE" == '1' ]]; then - say 'Removing Nvidia bus from the kernel' - execute "sudo $TEE /sys/bus/pci/devices/${DEVICE_BUS_ID}/remove <<<1" - else - say 'Enabling powersave for the graphic card' - execute "sudo $TEE /sys/bus/pci/devices/${DEVICE_BUS_ID}/power/control <<&2 + echo "This script must not be run as root" >&2 exit 1 fi @@ -140,21 +75,11 @@ EXECL="/etc/X11/xinit/nvidia-xinitrc \"$EXECL\"" COMMAND="xinit $EXECL -- $NEWDISP vt$LVT -nolisten tcp -br -config nvidia-xorg.conf -configdir nvidia-xorg.conf.d" -# --------- TURNING ON GPU ----------- -if [[ "$ENABLE_PM" == '1' ]]; then - turn_on_gpu -fi - -# ---------- LOADING MODULES ---------- -load_modules +# ---------- TURNING ON GPU ------------ +execute "sudo nvidia-toggle -v on" # ---------- EXECUTING COMMAND -------- execute "${COMMAND}" -# ---------- UNLOADING MODULES -------- -unload_modules - # --------- TURNING OFF GPU ---------- -if [[ "$ENABLE_PM" == '1' ]]; then - turn_off_gpu -fi +execute "sudo nvidia-toggle -v off" diff --git a/nvidia-xrun-pm.service b/nvidia-xrun-pm.service index 038bba7..991ecfb 100644 --- a/nvidia-xrun-pm.service +++ b/nvidia-xrun-pm.service @@ -4,7 +4,7 @@ Description="Remove Nvidia GPU from kernel devices list and enable PM" [Service] Type=oneshot Environment="TURN_OFF_GPU_ONLY=1" -ExecStart=/usr/bin/nvidia-xrun +ExecStart=/usr/bin/nvidia-toggle [Install] WantedBy=multi-user.target