Nvidia Jetson 安装实时补丁PREEMPT_RT及安装dpdk

243 阅读3分钟

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 引导配置文件
  • 修改后 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
  1. 打开终端。
  2. 输入以下命令:
cat /etc/nv_tegra_release
  1. 查看输出。第一行 就是对应的 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

这里 R355.1 是关键信息,从官网里面去搜索匹配,上面的输出意味着你的设备运行的是 JetPack 5.1

  1. 查看内核版本(Linux 系统版本):
uname -r
# 或者查看更多详细信息
uname -a
方法二:使用 jetson_release 命令

这是一个非常方便的脚本,可以一次性显示大部分关键信息。

  1. 在终端中运行:

    jetson_release
    
  2. 它会输出一个非常清晰的报告,包括:

    • JetPack 版本
    • L4T 版本
    • 内核版本
    • 主板型号 (e.g., Jetson Orin NX, Xavier AGX)
    • CUDA 版本
    • cuDNN 版本

对于大多情况下,直接运行 jetson_release 就行。

2. dpdk 编译使用

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 使用

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网卡的发送函数的实现)

参考