第二章:开发环境搭建——交叉编译工具链安装、OpenCV for ARM编译、CUDA/OpenCL环境配置、性能分析工具安装
好,咱们直接进入正题。嵌入式GPU开发,第一步不是写代码,而是搭环境。这事儿听起来枯燥,但说实话,环境没搭好,后面全是坑。我见过太多新手卡在编译环节,一卡就是一整天。所以这一章,咱们把交叉编译工具链、OpenCV for ARM、CUDA/OpenCL,还有性能分析工具,一个一个捋清楚。
2.1 交叉编译工具链安装
先说说交叉编译。你想想看,你的开发机是x86架构,但目标板是ARM架构。代码在x86上写,编译出来的二进制却要在ARM上跑。这就叫交叉编译。说白了,就是让一台电脑替另一台电脑干活。
我个人习惯用Linaro提供的工具链。为什么?因为它更新快,支持全,而且社区活跃。遇到问题,搜一下基本都有答案。
安装步骤(以aarch64为例):
# 下载Linaro GCC工具链
wget https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz
# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu.tar.xz -C /opt/
# 配置环境变量
export PATH=/opt/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
小提示: 我建议把环境变量写到 ~/.bashrc 里,这样每次打开终端就不用重新设了。我曾经因为忘记 export,折腾了半小时才发现问题。
验证是否安装成功,跑一下这个命令:
aarch64-linux-gnu-gcc --version
如果能正常显示版本号,恭喜你,第一步搞定了。
2.2 OpenCV for ARM编译
OpenCV在嵌入式平台上编译,嗯,这里要注意。你不能直接用apt-get install,因为那样装的是x86版本。你得自己从源码编译,指定ARM架构。
为什么会这样?因为OpenCV底层调了很多硬件加速指令,比如NEON、VFPv3。这些指令集在不同架构上不一样。所以必须针对你的目标平台重新编译。
警告: 编译OpenCV时,内存要留够。我建议至少4GB的swap空间。否则编译到一半直接OOM,那感觉...你懂的。
具体步骤:
# 安装依赖
sudo apt-get install build-essential cmake git pkg-config
# 下载OpenCV源码
git clone https://github.com/opencv/opencv.git
cd opencv
mkdir build && cd build
# 配置交叉编译
cmake -DCMAKE_TOOLCHAIN_FILE=../platforms/linux/aarch64-gnu.toolchain.cmake \
-DCMAKE_INSTALL_PREFIX=/opt/opencv-arm \
-DWITH_NEON=ON \
-DWITH_VFPV3=ON \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF ..
# 编译(使用多核加速)
make -j$(nproc)
# 安装
sudo make install
我在项目中遇到过一个问题:编译出来的OpenCV在板子上跑,图像处理速度比预期慢很多。后来发现是忘了开NEON优化。你想想看,ARM平台最值钱的就是NEON指令集,不开等于白干。
关键配置项说明:
| 配置项 | 作用 | 建议值 |
|---|---|---|
| WITH_NEON | 启用ARM NEON SIMD加速 | ON |
| WITH_VFPV3 | 启用浮点运算加速 | ON |
| BUILD_TESTS | 是否编译测试用例 | OFF(节省时间) |
| CMAKE_INSTALL_PREFIX | 安装路径 | 自定义路径 |
2.3 CUDA/OpenCL环境配置
嵌入式GPU,说白了就是要在小芯片上跑并行计算。CUDA和OpenCL是两条主流路线。NVIDIA的Jetson系列用CUDA,其他平台比如RK3588、树莓派,用OpenCL更多。
我个人习惯是:如果目标板是NVIDIA的,无脑选CUDA。生态好,工具链成熟,文档也全。如果是其他平台,那就得看OpenCL了。
2.3.1 CUDA环境配置(以Jetson Nano为例)
# Jetson Nano默认自带CUDA,但需要配置环境变量
export PATH=/usr/local/cuda-10.2/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda-10.2/lib64:$LD_LIBRARY_PATH
# 验证CUDA是否可用
nvcc --version
nvidia-smi
这里有个坑:Jetson系列的CUDA版本和桌面版不一样。桌面版是x86,Jetson是ARM。所以你不能把桌面版的CUDA Toolkit直接拷过来用。我曾经犯过这个错,编译了一整天,最后发现架构不对。
2.3.2 OpenCL环境配置
OpenCL的配置相对复杂一些。因为不同厂商的OpenCL实现不一样。ARM平台一般用Mali GPU,需要安装ARM的OpenCL SDK。
# 下载ARM OpenCL SDK
wget https://developer.arm.com/-/media/Files/downloads/OpenCL/ARM-OpenCL-SDK.zip
# 解压并安装
unzip ARM-OpenCL-SDK.zip
cd ARM-OpenCL-SDK
sudo ./install.sh
# 验证OpenCL是否可用
clinfo
小提示: 如果clinfo报错,别慌。先检查一下GPU驱动是否加载。用lsmod | grep mali看看。驱动没加载,OpenCL肯定跑不起来。
2.4 性能分析工具安装
环境搭好了,代码写完了,怎么知道跑得快不快?这就需要性能分析工具了。嵌入式平台上,我常用的工具就三个:perf、gprof、以及NVIDIA自带的Nsight。
2.4.1 perf安装
# 安装perf
sudo apt-get install linux-tools-common linux-tools-$(uname -r)
# 基本用法
perf stat ./your_program
perf record ./your_program
perf report
perf的好处是轻量,几乎不引入额外开销。我在项目中用它定位过一个CPU占用率异常的问题,发现是某个函数里有个死循环。perf record + perf report,一目了然。
2.4.2 gprof安装
# 编译时加上-pg选项
gcc -pg -o program program.c
# 运行程序
./program
# 生成分析报告
gprof program gmon.out > analysis.txt
注意: gprof会引入额外的性能开销,所以它更适合做函数级别的热点分析,不适合做精确的时间测量。说白了,用它看趋势,别用它看绝对值。
2.4.3 Nsight Systems(Jetson平台)
# 安装Nsight Systems
sudo apt-get install nsight-systems
# 使用命令行分析
nsys profile -o output_file ./your_program
Nsight的界面比perf友好得多。它能直观地显示CPU和GPU的时间线,哪个kernel跑得慢,哪个数据传输是瓶颈,一眼就能看出来。我个人觉得,如果你用Jetson平台,Nsight是必装的。
2.5 环境验证与常见问题
环境搭完了,怎么确认一切正常?我一般会写一个简单的测试程序,跑一下看看。
// test_opencv.cpp
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
cv::Mat img = cv::Mat::zeros(480, 640, CV_8UC3);
std::cout << "OpenCV version: " << CV_VERSION << std::endl;
std::cout << "Image size: " << img.size() << std::endl;
return 0;
}
交叉编译这个程序,拷到板子上跑。如果能正常输出版本号和图像尺寸,说明OpenCV环境没问题。
常见问题汇总:
- 编译时报错找不到头文件:检查CMAKE_INSTALL_PREFIX路径是否正确,或者是不是忘了设置PKG_CONFIG_PATH。
- 运行时提示找不到动态库:用export LD_LIBRARY_PATH把库路径加进去,或者用ldconfig更新缓存。
- CUDA程序编译通过但运行报错:检查CUDA版本是否匹配,以及GPU计算能力是否支持你用的特性。
- OpenCL平台数为0:大概率是驱动没装好,或者设备节点权限不对。试试用sudo运行clinfo。
好了,环境搭建这部分就到这里。说实话,搭环境是最磨人的一步,但也是最能积累经验的一步。你把这些坑都踩一遍,后面写代码的时候就会顺手很多。下一章,咱们开始真正接触图像处理流水线,到时候这些工具就全派上用场了。