使用實時補丁內核的ubuntu中安裝nvidia顯卡驅動

根據上上篇的博客,安裝了打了PREEMPT_RT實時補丁的內核。在我的應用場景中,是想在一臺機器上同時能夠使用兩種內核,並且在nvidia-docker中,跑一個需要用到顯卡的程序。

結果發現在實時內核中,非實時內核中裝好的顯卡驅動不能用,直接使用apt install nvidia-410又說已經update了。如果系統是剛裝的,非實時內核中還沒有裝過顯卡驅動,直接在實時內核中apt install nvidia-410會看到報錯說,不支持rt內核。

經過一番折騰,終於摸索到了在兩個內核中都用上顯卡驅動的方法。如果你只需要在實時內核上安裝顯卡驅動,或許也可以使用類似的思路,但我沒有驗證過。

 

我的環境:

Ubuntu16.04

自帶內核4.15.0-45-generic

實時內核4.16.18-rt12

顯卡:NVIDIA GEFORCE GTX 1080Ti

 

1、在非實時內核中安裝顯卡驅動

sudo執行以下命令:

rm -f /etc/apt/sources.list.d/graphics-drivers-ubuntu-ppa-*
add-apt-repository -y ppa:graphics-drivers
sed -i 's/http:\/\/ppa.launchpad.net/https:\/\/launchpad.proxy.ustclug.org/g' /etc/apt/sources.list.d/graphics-drivers-ubuntu-ppa-*.list
apt update
apt install -y nvidia-410;     

在高於Ubuntu16.04的環境下,可能還要裝些別的東西,我沒有試過,如果這樣裝完有問題可以再查查高版本ubuntu中的安裝指導。上面裝完後,重啓,nvidia-smi應該可以正確顯示顯卡的信息。

此時,我也可以成功啓動nvidia-docker,並在其中正確運行nvidia-smi和使用顯卡的程序。

 

2、在實時內核中安裝顯卡驅動

這一步是在第1步完成的前提下進行的。如果沒有apt install nvidia-410,僅僅執行下面的腳本,是無法安裝成功的。

這個腳本來自於apollo的開源,我是在https://github.com/ApolloAuto/apollo/issues/1872#issuecomment-352624933這個回答裏看到這個腳本的。一開始,我直接註釋掉了啓動對於uname -r的檢查,因爲我知道我的確是在一個實時內核上安裝,裝完之後確實能用nvidia-smi了,但是切換回普通內核,顯卡驅動卻不能使用了。

我們先來看下這個腳本,我把每個函數的函數體在這裏先省略掉,可以直接去上述鏈接中下載到完整的腳本文件。

#!/bin/bash

# ....

# check environment
check_env

# prepare for nvidia
prepare_nv

# build nvidia.ko
build_nv

# install user lib
install_lib

# clean environment
clean_env

echo "Done to install nvidia kernel driver and user libraries."

從這個文件最後幾行,可以看出它大概幹了些什麼。首先是檢查環境,然後是準備工作,然後編譯、安裝,最後清理環境。

(1)check_env

如果你用的不是apollo提供的實時內核,在check_env的時候,腳本就會報錯退出,所以我們可以根據自己的情況註釋掉這個檢查,或者把目標內核版本改成我們自己的實時內核版本,用#####標出的是修改過的行:

function check_env() {
    # check if in rt kernel     #####
    uname -r | grep rt 1>/dev/null 2>&1   #####
    if [ $? -ne 0 ]
    then
        echo "Not in rt kernel, Please install rt kernel and reboot machine first."  #####
        exit 2
    fi

    # check if nv ko already in kernel
    if [ ! -f /lib/modules/`uname -r`/kernel/drivers/video/nvidia.ko ]
    then
        export NEED_TO_COMPILE_NV_KO=1
    fi
}

(2)prepare_nv

在prepare_nv這步中,其實就是下載了nvidia驅動的.run文件。可能在我們的網絡環境下,直接從這個url下載會很慢,也可以在網絡環境好的地方先下載好,然後註釋掉下載的命令。然後有一點非常重要:這裏一定要用和非實時內核中相同版本的驅動,否則會出現各種問題,我之前應該就是因爲在不同內核中裝了不同版本的驅動,導致後來驅動不可用,無奈之下只能重裝系統。

NV_FILE="NVIDIA-Linux-x86_64-410.78.run"
NV_URL="https://us.download.nvidia.cn/XFree86/Linux-x86_64/410.78/${NV_FILE}"

在非實時內核中,nvidia-smi顯示驅動版本爲410.78,所以這裏也改成410.78,這兩行在腳本的開頭處。

(3)build_nv

function build_nv() {

    if [ ${NEED_TO_COMPILE_NV_KO} == 0 ]
    then
        return
    fi

    NVIDIA_MOD_REL_PATH='kernel/drivers/video'
    NVIDIA_OUTPUT_PATH="/lib/modules/`uname -r`/${NVIDIA_MOD_REL_PATH}"
    CPUNUM=`cat /proc/cpuinfo | grep processor | wc | awk -F " " '{print $1}'`

    export IGNORE_PREEMPT_RT_PRESENCE=true    #####
    cd ${NVIDIA_SOURCE} && make -j ${CPUNUM} module
    cd ${BUILD_BASE}

    unset IGNORE_PREEMPT_RT_PRESENCE  #####

    mkdir -p ${NVIDIA_OUTPUT_PATH}

    [ -f ${NVIDIA_SOURCE}/nvidia.ko ] && cp ${NVIDIA_SOURCE}/nvidia.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-modeset.ko ] && cp ${NVIDIA_SOURCE}/nvidia-modeset.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-drm.ko ] && cp ${NVIDIA_SOURCE}/nvidia-drm.ko ${NVIDIA_OUTPUT_PATH}
    [ -f ${NVIDIA_SOURCE}/nvidia-uvm.ko ] && cp ${NVIDIA_SOURCE}/nvidia-uvm.ko ${NVIDIA_OUTPUT_PATH}

    depmod -a
}

上面用#####標出的兩行需要特別注意,這是編譯驅動源碼時涉及的一個環境變量,默認如果沒有設置過的話,是會檢查當前是否是實時內核,如果是的話,會報錯說不支持。這樣設置一下,就可以編譯了。這也是整個腳本的靈魂所在。

build_env中生成的.ko文件,其實是整個安裝過程中,對於實時和非實時內核來說,生成的唯一不同的東西。.ko文件是內核的模塊文件,depmod -a是在生成.ko文件後,重新生成內核模塊的依賴關係的一個命令,加載內核時應該會用到這個文件來查看模塊文件的位置和依賴關係。

(4)install_lib

function install_lib() {

    NV_LIB_OUTPUT_PATH="/usr/lib/x86_64-linux-gnu/"
    NV_BIN_OUTPUT_PATH="/usr/bin/"

    [ -f ./${NV_DIR}/libnvidia-ml.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-ml.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libnvidia-fatbinaryloader.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-fatbinaryloader.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libnvidia-ptxjitcompiler.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libnvidia-ptxjitcompiler.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/libcuda.so.${NV_VERSION} ] && /bin/cp -f ./${NV_DIR}/libcuda.so.${NV_VERSION} ${NV_LIB_OUTPUT_PATH}
    [ -f ./${NV_DIR}/nvidia-modprobe ] && /bin/cp -f ./${NV_DIR}/nvidia-modprobe ${NV_BIN_OUTPUT_PATH}
    [ -f ./${NV_DIR}/nvidia-smi ] && /bin/cp -f ./${NV_DIR}/nvidia-smi ${NV_BIN_OUTPUT_PATH}

    chmod +x /usr/bin/nvidia*
    chmod +s /usr/bin/nvidia-modprobe

    # link for nvidia
    /bin/rm -rf /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1  /usr/lib/x86_64-linux-gnu/libnvidia-ml.so
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.${NV_VERSION} /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1 /usr/lib/x86_64-linux-gnu/libnvidia-ml.so

    /bin/rm -rf /usr/lib/x86_64-linux-gnu/libcuda.so  /usr/lib/x86_64-linux-gnu/libcuda.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libcuda.so.${NV_VERSION} /usr/lib/x86_64-linux-gnu/libcuda.so.1
    /bin/ln -s /usr/lib/x86_64-linux-gnu/libcuda.so.1 /usr/lib/x86_64-linux-gnu/libcuda.so

    # take effect
    /sbin/ldconfig 1>/dev/null 2>&1
}

這一步是將.run文件解壓後,目錄中的一些.so、可執行文件拷貝到一些系統路徑下。在執行腳本後,可以看到這些文件的時間戳並未改變,所以不管內核有沒有實時補丁,這些東西是不受影響的。

 

 

根據上述,對這個腳本需要做兩處改動,一是check_env中的內核版本檢查,而是顯卡驅動的版本。sudo執行該腳本後,在實時內核中nvidia-smi就可以使用了。如果非實時內核中沒有安裝過apt install nvidia-410,只跑了這個腳本,nvidia-smi還是不能用的。

 

3、實時內核的nvidia-docker中使用顯卡驅動

啓動nvidia-docker的時候報錯:

nvidia-container-cli: initialization error: cuda error: unknown error

直接執行nvidia-container-cli -k -d /dev/tty info也可以看到這個報錯。

 

查了一圈,看到有人提到說是因爲nvidia-uvm這個內核模塊沒有被加載成功。用 lsmod | grep -i nvidia查看了一下,果然沒有這個模塊。nvidia-uvm.ko正是上面這個腳本build_nv中生成的一個文件。在腳本里可以看到這個文件最終被拷貝到了/lib/modules/4.16.18-rt12/kernel/drivers/video/下

嘗試加載這個模塊:sudo modprobe nvidia-uvm,報錯說找不到nvidia_410_uvm這個模塊。

之前在折騰的時候,偶爾發現過,在非實時內核中,/lib/modules/4.15.0-45-generic/updates/這個路徑下,有四個.ko文件,和上面生成的四個.ko文件名字上一一對應,但是是類似nvidia_410_uvm這樣包含了版本號的名字。就試着把nvidia_uvm.ko拷貝過去:

sudo cp /lib/modules/4.16.18-rt12/kernel/drivers/video/nvidia-uvm.ko /lib/modules/4.16.18-rt12/updates/nvidia_410_uvm.ko
sudo depmod -a
sudo modprobe nvidia-uvm   #不再報錯,沒有輸出
nvidia-container-cli -k -d /dev/tty info  #不再報錯,輸出一堆東西

然後再打開nvidia-docker,就不再報錯了,可以運行nvidia-smi以及使用顯卡的程序。

不過最後一步感覺路子有點野,雖然暫時看起來可以用了,不知道會不會有什麼坑,或許把4個.ko都拷過去會更好一些。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章