Nvidia Jetson 安装实时补丁PREEMPT_RT及安装dpdk
PREEMPT_RT 是 Linux 内核的一个实时补丁,旨在将 Linux 转变为一个实时操作系统。它通过引入可抢占性和实时调度策略来提供更好的实时性能,使 Linux 能够满足一些对实时性要求较高的应用场景。PREEMPT_RT 的主要目标是减少 Linux 内核的抢占延迟(Preemption Latency)和中断延迟(Interrupt Latency)。
DPDK 是Linux基金会旗下的开源项目,它提供一系列库文件来加速运行于多种CPU架构(如x86、ARM...)的网络数据包处理工作负载。主要用来提高网络性能、吞吐量,降低延迟和抖动。
1. Nvidia Jetson 安装实时补丁
souce源码获取一般需要从工控机厂家获取,或直接使用nvidia公版的源码(不建议,设备树可能不匹配,存在一些问题)。
1.1 交叉编译工具获取
gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
解压即可使用:
tar -xJvf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
1.2 安装所需库和工具
env_install.sh- 实际使用,最好结合docker创建一个纯净的容器去运行,我用的是
ubuntu:18.04的镜像。
#install kernel build tools
apt install bc cmake libncurses5-dev libncursesw5-dev kmod wget xxd dpkg-dev ninja-build pkg-config
apt install vim
# install python 3.12
mkdir -p ~/miniconda3
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm ~/miniconda3/miniconda.sh
# install menson ninja
source ~/miniconda3/bin/activate
conda init --all
python -m pip install meson
python -m pip install pyelftools
1.3 添加环境变量
env.bash- 添加一些环境变量,方便后续脚本使用
- 添加到
~/.bashrc,echo "source ~/env.bash" >> ~/.bashrc
#!/bin/bash
clear
# 设置工作空间
export WORK_DIR=/root/ws/ethercat
echo $WORK_DIR
# 设置 交叉编译工具路径
export CROSS_COMPILE=$WORK_DIR/tool/cross_chain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
# 输出路径 rt
export outrt=$WORK_DIR/out/outrt
# 输出路径 rootfs
export rootfs=$WORK_DIR/out/rootfs
# 输出路径 dpdk
export outdpdk=$WORK_DIR/out/outdpdk
source ~/miniconda3/bin/activate
conda init --all
1.4 打实时补丁rt-patch
cd $WORK_DIR/kernel/Linux_for_Tegra/source/public/kernel/kernel-4.9
./scripts/rt-patch.sh apply-patches
1.5 linux 源码编译
export LOCALVERSION=-tegra && export ARCH=arm64
mkdir -p $outrt && cd $WORK_DIR/kernel/Linux_for_Tegra/source/public/kernel/kernel-4.9
make O=$outrt tegra_defconfig
# 添加编译选项
make menuconfig
# General setup -> Timers subsystem -> Timer tick handling -> Full dynticks system (tickless)
# 作用是 提高系统响应性和降低功耗的高级功能,尽可能彻底地消除 CPU 的周期性时钟中断(tick)
# 编译
make O=$outrt -j16 && make mrproper && cd $outrt && make scripts && make modules_install INSTALL_MOD_PATH=$rootfs
# 打成 deb包 ,方便后面安装
make bindeb-pkg O=$outrt -j16
编译完成后会在 $outrt 生成如下deb包:
linux-4.9.253-rt168+_4.9.253-rt168+-3_arm64.changes
linux-headers-4.9.253-rt168+_4.9.253-rt168+-3_arm64.deb
linux-image-4.9.253-rt168+_4.9.253-rt168+-3_arm64.deb
linux-firmware-image-4.9.253-rt168+_4.9.253-rt168+-3_arm64.deb
linux-image-4.9.253-rt168+-dbg_4.9.253-rt168+-3_arm64.deb
linux-libc-dev_4.9.253-rt168+-3_arm64.deb
并且把 $outrt/arch/arm64/boot/Image cp 出来 Image-rt,后面会用到。
1.6 安装及启动配置
- 官方提供的文档都是烧写镜像,耗时太长不方便,所以我目前都是通过切换内核实现。
- 把上述编译的包使用dpkg安装到系统,
sudo dpkg -i linux*.deb - 由于Nvidia Jetson 使用的是
exlinux引导,而不是grub,无法通过grub切换内核,需要手动修改/boot/extlinux.conf。- 备份源内核、替换rt内核
sudo cp /boot/Image /boot/Image.bak && sudo cp ./Image-rt /boot/Image - 修改 extlinux 引导配置文件
- 备份源内核、替换rt内核
- 修改后 exlinux.conf 文件示例:
TIMEOUT 30
DEFAULT primary
MENU TITLE L4T boot options
LABEL primary
MENU LABEL primary kernel
LINUX /boot/Image
INITRD /boot/initrd
APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyTCU0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 default_hugepagesz=1G hugepagesz=1G hugepages=4 isolcpus=1,3 nohz_full=1
# 原内核设置成 backup,以防意外无法启动
LABEL backup
MENU LABEL backup kernel
LINUX /boot/Image.bak
INITRD /boot/initrd
APPEND ${cbootargs}
添加项作用注释,跟dpkg有关:
default_hugepagesz=1G # 默认大内存页大小为1GB
hugepagesz=1G # 支持1GB的大页内存
hugepages=4 # 预分配4个1GB大页(总计4GB)
isolcpus=1,3 # 隔离CPU核心1,3(不参与进程调度)
nohz_full=1 # 在CPU1上禁用时钟中断(用于低延迟场景)
1.7 重启检查
工控机重启后,通过bash指令 uname -a 检查内核信息,如带有linux-rt168-tegra字样,说明内核已更新为实时内核。
1.8 查看Jetson版本
方法一:查看文件 /etc/nv_tegra_release
- 打开终端。
- 输入以下命令:
cat /etc/nv_tegra_release
- 查看输出。第一行 就是对应的 JetPack 版本。
示例输出 (例如在 JetPack 5.1.2 上):
# R35 (release), REVISION: 5.1, GCID: 33463798, BOARD: t186ref, EABI: aarch64, DATE: Thu Mar 30 07:07:28 UTC 2023
这里 R35 和 5.1 是关键信息,从官网里面去搜索匹配,上面的输出意味着你的设备运行的是 JetPack 5.1。
- 查看内核版本(Linux 系统版本):
uname -r
# 或者查看更多详细信息
uname -a
方法二:使用 jetson_release 命令
这是一个非常方便的脚本,可以一次性显示大部分关键信息。
-
在终端中运行:
jetson_release -
它会输出一个非常清晰的报告,包括:
- JetPack 版本
- L4T 版本
- 内核版本
- 主板型号 (e.g., Jetson Orin NX, Xavier AGX)
- CUDA 版本
- cuDNN 版本
对于大多情况下,直接运行 jetson_release 就行。
2. dpdk 编译使用
- dpdk 下载:core.dpdk.org/download/
2.1 numactl库交叉编译 (dpdk 编译依赖)
git clone https://github.com/numactl/numactl.git -b v2.0.13
cd numactl
# 交叉编译
./autogen.sh
autoconf -i
./configure --host=aarch64-linux-gnu CC=$CROSS_COMPILE"gcc" --prefix=$outnuma
make install
2.2 dpdk 编译
cd $WORK_DIR/dpdk-stable-21.11.9
mkdir -p $outdpdk && rm $outdpdk -r
mkdir -p nvidia_build && rm nvidia_build -r
meson setup nvidia_build --cross-file $WORK_DIR/config/dpdk/arm64_armv8_linux_gcc_nvidia --prefix $outdpdk -Ddisable_drivers=common/cnxk,net/cnxk,crypto/cnxk,event/cnxk,mempool/cnxk
ninja -C nvidia_build install
2.3 dpdk 使用
- 参考官方手册:core.dpdk.org/doc/quick-s…
- 网卡直接使用Intel I211,I210 等支持的网卡就可以
2.4 一些问题
- 之前在 rk3588 上使用遇到了些问题,dpdk不能正常工作,在此记录一下;
- 问题说明:
# RK平台特殊说明
RK主控硬件层不支持DMA访问外部内存一致性,而开源DPDK代码网卡驱动使用的API:rte_eth_dma_zone_reserve 和 rte_mbuf_raw_alloc,默认要求硬件保证访问内存一致性,比如:
发送数据的场景:CPU把数据写到内存(带cache),然后通知网卡DMA来搬运这块内存的数据,DPDK默认支持的硬件平台会自动刷新cache,使的网卡DMA能直接拿到最新数据,而RK平台需要手动取刷新;
# DPDK内存主要有两种:
一个是给网卡BD描述符使用的内存,使用rte_eth_dma_zone_reserve来分配,由于它会被频繁使用,所以解决策略是在内核使用dma_alloc_coherent分配非cache的内存,然后映射给dpdk的网卡驱动使用(查看igb_uio驱动的修改);
二是网卡存放数据的内存,比如用rte_mbuf_raw_alloc分配,由于内存分配量比较大,所以直接使用arm标准的指令刷cache的命令来实现,比如写发送数据时,写完数据后主动刷新这块内存,让实际的内存写到DDR里面取,此时DMA就能拿到实际写入的数据;(参考e1000网卡的发送函数的实现)
- rockchip 官方文档 :gitlab.com/rockchip_li…