在 Ubuntu 下使用 SCons 进行交叉编译嘉楠堪智 CanMV K230 大小核(不同的玄铁 C908 核心)的 C 程序,以 Coremark 程序为例,顺便测试一下大小核和编译器的性能。
2024年3月14日,嘉楠科技宣布推出了全球首款支持 RISC-V Vector 1.0 标准的商用量产端侧 AIoT 芯片 K230,我们顺便了解一下其采用的玄铁 C908 核心,并测试一下实际的表现。
玄铁 C908 采用 9 级双发按序流水线,典型工作频率>2GHz,通过指令融合技术进一步提升流水线效率,实现了卓越的能效比。兼容 RVA22 标准,同时兼容 RISC-V 最新 Vector1.0 标准以进一步提升 AI 算力。可以应用在行业 IPC、智能交互、AR/VR、无线通讯等场景。
阿里 T-Head 提供了与 C906 单发按序处理器的性能对比:
玄铁 C908 的运行频率最高可达 2GHz,采用的是台积电 12 纳米工艺,单核动态功耗低至 52.8mW/GHz。在相同频率和工艺限制的典型场景下,玄铁 C908 的能效比玄铁 C906 提升了 20% 以上。
RISC-V Vector Extension 1.0 确实有助于 AI 工作负载,在相同条件下,对使用 INT4 数据类型的唤醒词检测、图像分类、关键字定位和 MLPerf 微型 V0.7 推理性能测试的异常检测中,C908 比 C906 快了大约 2 到 3.5 倍。
一、安装 SCons:
可以使用 apt
包管理器安装 SCons:
sudo apt update
sudo apt install scons
二、准备交叉编译工具链:
k230_sdk 中提供了工具链,buildroot package 和 AI package,可用如下命令下载:
cd k230_sdk
source tools/get_download_url.sh && make prepare_sourcecode
嘉楠堪智 CanMV K230 大小核是不同的玄铁 C908 核心,嘉楠给出了不同的工具链:
- 大核 rt-samrt 工具链:
k230_sdk/toolchain/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu
这个工具链使用 Musl libc 作为 C 标准库,而不是更常见的 glibc。Musl libc 是一种轻量级的 C 库,旨在提供与 glibc 类似的 API,但更小、更快、更简单,非常适合嵌入式系统或需要减少程序大小的环境。
- 小核 linux 工具链:
k230_sdk/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0
这个工具链使用 glibc 作为 C 标准库。glibc 是 Linux 系统上最常用的 C 标准库,提供了丰富的功能和良好的兼容性。
也可通过以下链接下载工具链:
wget https://download.rt-thread.org/rt-smart/riscv64/riscv64-unknown-linux-musl-rv64imafdcv-lp64d-20230222.tar.bz2
wget https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1659325511536/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0-20220715.tar.gz
三、准备 Coremark 程序
1. 下载代码
git clone https://github.com/eembc/coremark.git
cd coremark/
2. 移植代码
将 simple 目录下的 core_portme.c 和 core_portme.h 拷贝到当前 coremark 目录下,按照下面做修改:
四、编写 SConstruct 文件:
SConstruct 文件是 SCons 的构建脚本。编写一个 SConstruct 文件,指定源文件、构建目标、编译器和其他构建选项。
1. 小核 Linux 的 SConstruct 文件
如下所示:
# 引入SCons的环境
import os # 交叉编译工具链的路径
toolchain_path = '/home/xu/k230_sdk/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin' # 设置环境变量
env = Environment(ENV={'PATH' : os.environ['PATH'] + ':' + toolchain_path}) # 设置交叉编译器
env['CC'] = 'riscv64-unknown-linux-gnu-gcc'
env['LINK'] = '$CC' # 添加编译和链接选项(根据你的需要调整)
#env['CFLAGS'] = ['-mcmodel=medany', '-march=rv64imafdcv', '-mabi=lp64d']
#env['LINKFLAGS'] = env['CFLAGS'] env.Append(CCFLAGS=['-O2'])
#env.Append(DEFS=['PERFORMANCE_RUN=1', 'ITERATIONS=100000'])# 假设你的CoreMark源文件在'src'目录下 src_files = Glob('*.c') # 构建程序(假设你的目标文件名为'coremark')
env.Program(target='coremark_linux.elf', source=src_files)
2. 大核 RT- smart 的 SConstruct 文件:
如下所示:
# 引入SCons的环境
import os # 交叉编译工具链的路径
toolchain_path = '/home/xu/k230_sdk/toolchain/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin' # 初始化环境变量
env = Environment(tools=['default', 'gcc'], ENV={'PATH' : os.environ['PATH'] + ':' + toolchain_path}) # 设置交叉编译器
env['CC'] = 'riscv64-unknown-linux-musl-gcc'
env['LINK'] = '$CC'
#设置编译器标志
env.Append(CCFLAGS=['-O2','-mcmodel=medany', '-march=rv64imafdcv', '-mabi=lp64d'])
#设置链接器标志
env.Append(LINKFLAGS=['-mcmodel=medany', '-march=rv64imafdcv', '-mabi=lp64d','-T', '/home/xu/k230_sdk/src/big/mpp/userapps/sample/linker_scripts/riscv64/link.lds','-L/home/xu/k230_sdk/src/big/rt-smart/userapps/sdk/rt-thread/lib','-Wl,--whole-archive', '-lrtthread', '-Wl,--no-whole-archive','-n', '--static'])env['CPPPATH'] = ['#'] # 如果有头文件路径需要添加
env['LIBPATH'] = [
# '/home/xu/k230_sdk/src/big/rt-smart/userapps/sdk/rt-thread/lib', '/home/xu/k230_sdk/src/big/rt-smart/userapps/sdk/lib/risc-v/rv64', '/home/xu/k230_sdk/src/big/rt-smart/userapps/sdk/rt-thread/lib/risc-v/rv64'
]
env['LIBS'] = ['rtthread']
env['RPATH'] = [] # 如果有需要添加的运行时搜索路径 # 添加源文件
src_files = Glob('*.c') # 假设CoreMark源文件在目录下 # 设置链接选项(针对-Wl, --whole-archive 和 -Wl, --no-whole-archive)
#env.Append(LINKFLAGS=['-Wl,--whole-archive', '-lrtthread', '-Wl,--no-whole-archive'])
#env.Append(LINKFLAGS=['-Wl,--start-group', '-lrtthread', '-Wl,--end-group']) #编译源文件
#objects = [env.Object(file) for file in src_files]# 构建程序
env.Program(target='coremark_rt.elf', source=src_files) # 如果需要额外的构建步骤或目标,可以在这里添加
编译参数:
-
-mcmodel=medany:
mcmodel
代表“代码模型”(code model)。在 RISC-V 架构中,代码模型决定了代码和数据的布局方式,以及编译器如何生成对它们的引用。medany
程序及其静态定义的符号必须位于单个4 GiB地址范围内。使用 auipc 和 addi 指令对来生成地址。使用 auipc 指令取符号地址的高 20 位。auipc 配合其它包含低 12 位立即数的指令后,可以访问当前 PC 的前后 2GiB
(PC - 2GiB ~ PC + 2GiB) 的地址空间。程序可以是静态链接或动态链接。-
medlow 程序及其静态定义的符号必须位于单个2 GiB地址范围内,并且必须位于 -2 GiB 到 +2 GiB 的绝对地址之间。使用 lui 和 addi 指令对来生成地址。使用 lui 指令取符号地址的高 20 位。 lui 配合其它包含低 12 位立即数的指令后,可以访问的地址空间是 -2GiB ~ 2GiB。程序可以是静态链接或动态链接。
-
-march=rv64imafdcv:
march
标志用于指定RISC-V架构的版本或变种。rv64imafdcv
指示编译器生成针对64位RISC-V(RV64)的代码,并且包含I
(基本整数指令集)、M
(乘法/除法指令)、A
(原子指令)、F
(单精度浮点指令)、D
(双精度浮点指令)、C
(压缩指令集)和V
(向量指令集)等指令集的代码。- 这个选项确保你的代码可以利用 RISC-V 的这些特定功能,从而可能提供更好的性能或功能。
-
-mabi=lp64d:
mabi
标志用于指定应用程序二进制接口(ABI)。ABI 定义了如何在机器代码级别上调用函数、传递参数、返回结果以及数据的内存布局。lp64d
是一种ABI,其中 “lp64” 表示 longs 和指针都是 64 位,而 “d” 表示双精度浮点数是 64 位。这是 RISC-V 架构中常用的 ABI 之一,它提供了与许多其他 64 位架构(如x86_64)相似的数据模型。
五、运行 Scons 编译:
进入 k230_sdk/src/big/rt-smart/userapps 目录,编译程序:
xu@HP:~/k230_sdk/src/big/rt-smart/userapps$scons --directory=coremark
小核 Linux 编译:
大核 RT- smart 编译:
六、运行 coremark:
标号为 USB 的端口连接到电脑后,会识别为 U 盘 CanMV ,把产生的文件拷贝到 U 盘上:
在串口终端里,ttyACM1 对应 Linux 小核,ttyACM2 对应 rt-smart 大核,可以通过 sharefs 目录交换文件:
小核 Linux 执行程序:
./coremark_linux.elf
大核 RT- smart 执行程序:
msh /sdcard/app>./coremark_rtO3.elf
七、小结:
阿里 T-Head 表示,玄铁 C908 的性能介于 2020 年和 2019 年分别推出的 C906 和 C910 内核之间。玄铁 C906 的 coremark 分数是:3.40 CoreMark/MHz,玄铁 C910 的 coremark 分数是:7.10 CoreMark/MHz,StarFive U74 的 coremark 分数是:5.09 CoreMark/MHz,玄铁 C908 小核的 coremark 分数是:4.29 CoreMark/MHz?
嘉楠堪智 CanMV K230 800MHz 小核的 coremark 分数是:3433(4.29 CoreMark/MHz),1.6GHz 大核的 coremark 分数是:4522(2.83 CoreMark/MHz)?(不知道哪个设置有问题,应该是:8368(5.23 CoreMark/MHz))
老徐,2024/5/8