Ubuntu 20.04打RT实时内核补丁
编译实时内核并安装
查看当前内核版本
uname -r
笔者当前版本为 5.15.0-46-generic
,去下面网址中下载版本相近的内核文件和补丁文件,笔者选择的是 linux-5.15.113.tar.gz
和 patch-5.15.113-rt64.patch.gz
,可以先下 patch 包,然后根据对应的版本找内核包,不过不一定需要版本完全一致,相近的版本大概率也是可行的,如果需要某些工具如 linux-tools-5.15.0-113-generic
,建议先用 apt 搜一搜是否支持对应版本
https://www.kernel.org/pub/linux/kernel/
https://www.kernel.org/pub/linux/kernel/projects/rt/
解压内核然后解压补丁,版本不同的话可以使用 TAB 键来补全
tar -xzvf linux-5.15.113.tar.gz
cd linux-5.15.113
gzip -cd ../patch-5.15.113-rt64.patch.gz | patch -p1 --verbose
安装依赖
sudo apt-get install autoconf bison build-essential dkms dwarves fakeroot flex libelf-dev libiberty-dev libidn11 libidn11-dev libncurses-dev libpci-dev libssl-dev libudev-dev minizip openssl zlibc zstd
复制当前内核的配置文件(用 TAB 补全),进入 config 交互界面调整下面设置,SAVE 后 EXIT
# 想重新生成 .config 可以使用 make defconfig
cp /boot/config-$(uname -r) .config
make menuconfig
General Setup -> Timers subsystem -> Timer tick handling 设置为 Full dynticks system
General Setup -> Timers subsystem 开启 High Resolution Timer Support
General Setup -> Preemption Model 设置为 Fully Preemptible Kernel(RT)
Processor type and features -> Timer frequency 设置为 1000 HZ
然后编辑 .config
并修改以下内容
sudo vim .config
CONFIG_SYSTEM_TRUSTED_KEY=""
CONFIG_SYSTEM_REVOCATION_KEYS=""
apt 安装某些工具依赖内核版本号,因此可以修改一下 Makefile
,改成 5.15.0-113-generic
的形式,如果打了实时内核补丁,后面会自动加上-rt
后缀(目前还没找到解决方法)
VERSION = 5
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION = -113-generic
编译内核,线程数设为和 CPU 线程数相同
make -j`nproc` deb-pkg
安装内核,* 不要替换,所有编译后的文件都需要安装
sudo dpkg -i ../*.deb
图形化界面更换内核
如果没有成功设置为新内核,可以尝试用图形界面设置一下
sudo add-apt-repository ppa:danielrichter2007/grub-customizer
sudo apt-get update
sudo apt-get install grub-customizer
grub-customizer
保存后重启系统
sudo reboot -f
命令行更换内核
当然也可以用命令行更换内核,查看当前所有已安装内核
grep "menuentry '" /boot/grub/grub.cfg
(如果是用 dpkg 方式安装的一般不需要这一步)找到新安装的内核并设置为默认启动项
sudo grub-set-default 'Ubuntu, Linux 5.15.0-113-generic'
可以设置开机等待时间手动选择内核,默认以新内核启动,高级选项里面可以看到旧内核
sudo vim /etc/default/grub
# 修改下面键值
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5
更新grub后重启
sudo update-grub
sudo reboot -f
重启后查看内核是否更新
uname -r
可以自动删除多余的内核
sudo apt autoremove --purge
也可以手动卸载不需要的内核
dpkg --list | grep linux-image
sudo apt-get purge linux-image-xxx
安装 Nvidia 显卡驱动
首先重启切回非实时内核,然后禁用nouveau,在文件末尾插入以下内容
sudo gedit /etc/modprobe.d/blacklist.conf
blacklist nouveau
options nouveau modeset=0
保存后重启生效
sudo update-initramfs -u
reboot
重启后验证,如无任何输出则生效
lsmod | grep nouveau
卸载显卡驱动
sudo apt purge nvidia*
去 Nvidia 官网下载安装文件后安装(即不能直接安装二进制版本),在有 DKMS 字样的页面选择 YES ,其他都选择 NO ,否则可能无法开机,因此先设定好 root 密码再重启
chmod +x xxx.run
sudo bash ./xxx.run
如果不慎选错无法开机,则重启进 Recovery Mode 后卸载驱动,重启后若提示 nvidia-drm 相关错误无法安装则输入第二段内容
mount -n -o remount,rw /
apt purge nvidia*
rm /etc/X11/xorg.conf
reboot
systemctl isolate multi-user.target
# 进root账户
modprobe -r nvidia-drm
systemctl start graphical.target
查看是否安装成功
nvidia-smi
重启切回实时内核,然后保存下面内容为 install-nvidia.sh
,记得修改第四行的文件名
原始版本(运行时下载)
https://github.com/ApolloAuto/apollo-kernel/blob/master/linux/install-nvidia.sh
查看代码
#!/bin/bash
BUILD_BASE=`pwd`
NV_FILE="NVIDIA-Linux-x86_64-xxx.run" # 这里改成自己下载的.run文件名(之前安装过的)
#NV_URL="https://us.download.nvidia.cn/XFree86/Linux-x86_64/430.50/${NV_FILE}" # 之前已经下好了显卡驱动.run文件,就不用从网上下载了,直接注释掉,而且如果要下载的话,则慢
NEED_TO_COMPILE_NV_KO=1
function clean_env() {
[ -d ./${NV_DIR} ] && rm -rf ./${NV_DIR}
}
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 apollo 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
}
function prepare_nv() {
## download nv install file from nvidia home page
#if [ ! -f ./${NV_FILE} ]
#then
# echo "Downloading ${NV_FILE} from nvidia website..."
# wget ${NV_URL} -O ${NV_FILE}
# if [ $? -ne 0 ]
# then
# echo "Downloading ${NV_FILE} failed, please check your network connection!"
# rm -rf ./${NV_FILE}
# exit 1
# fi
#fi
###########上面是下载驱动的代码,我们已经提前下载好了,就不需要这段代码了,直接注释掉############
# +x
chmod +x ./${NV_FILE}
echo "Extracting nvidia install run file..."
./${NV_FILE} -x 1>/dev/null 2>&1
NV_DIR="`echo ${NV_FILE} | awk -F '.run' '{print $1}'`"
NV_VERSION="`echo ${NV_FILE} | awk -F '-' '{print $4}' | awk -F '.run' '{print $1}'`"
export NV_DIR
export NV_VERSION
export NVIDIA_SOURCE="${NV_DIR}/kernel"
}
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
}
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
}
# 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."
执行脚本
chmod +x ./install-nvidia.sh
sudo bash ./install-nvidia.sh
查看驱动信息
nvidia-smi
设置首选独显
sudo apt install nvidia-prime
sudo prime-select nvidia
测试实时性,观察最右侧的 MAX ,如果一直只有几十,说明是实时系统了,如果是非实时系统,运行一段时间会增加到几千甚至上万
sudo apt-get install rt-tests
sudo cyclictest -a -t -p 99
感谢
ubuntu打实时内核补丁教程以及安装后显卡驱动问题解决方法
https://blog.csdn.net/weixin_39275295/article/details/119173247
Ubuntu 20.04安装RT-PREEMPT实时内核补丁
https://blog.csdn.net/qq_28882933/article/details/118293544?spm=1001.2014.3001.5506
为ROS 2构建实时Linux
http://dev.ros2.fishros.com/doc/Tutorials/Building-Realtime-rt_preempt-kernel-for-ROS-2.html
使用实时补丁内核的ubuntu中安装nvidia显卡驱动
https://blog.csdn.net/tang05505622334/article/details/103477086
如何为 Apollo 安装低时延/实时内核
https://daobook.github.io/apollo/docs/howto/how_to_install_apollo_kernel_cn.html?highlight=realtime
How to unload kernel module 'nvidia-drm'?
https://unix.stackexchange.com/questions/440840/how-to-unload-kernel-module-nvidia-drm
How can I remove nvidia drivers?
https://askubuntu.com/questions/50617/how-can-i-remove-nvidia-drivers
jlelli/rt-tests
https://github.com/jlelli/rt-tests