当DuckDB遇上RISC-V
关于DuckDB的RISC-V CI的工作已于2025.3.14合并入DuckDB主线,在此回顾下这次贡献的来龙去脉
契机
最早接触RISC-V架构,是在B站看了吴伟老师(lazyparser)的视频
而接触到DuckDB,则是在CMU的课上(不记得是15799还是15445,反正是Andy上的其中一门)
今年年初的时候搞了一台MilkV Jupiter玩,顺带瞟了一眼DuckDB在RISC-V的支持情况——当时官方文档并没有相关说明,反倒是Youtube上有人去踩了RISC-V编译DuckDB的坑:Building DuckDB on RISC-V
视频本身并没有多少评论,但介绍区指向了一个Bsky Blog,Blog里面有DuckDB的成员对这个想法产生了兴趣,并邀请视频作者(ID:LivingLinux)添加RISC-V架构的CI Pull Request。
、
但这位仁兄(@LivingLinux)不太熟悉Docker😂于是跑到Reddit去求助:Who is willing to help with RISC-V support for DuckDB? (Docker),讨论一番后——并没人准备付出行动😅
那,我就只能帮忙代劳了😂
开工
首先是在自己的MilkV Jupiter上试试,这点很顺利,那个视频也是在和MilkV Jupiter同款的CPU上实现的,其工作可以完美复现
那么接下来就是上Github Action了——目前Github Action只提供X86-64和ARM架构的Github Action,想要尝试RISC-V就只能上QEMU
由于有在学校服务器上用QEMU模拟RISC-V,环境就直接沿用了Debian(DQIB)
方案一:全部在QEMU系统中运行
这个方案的好处显而易见:所有在MilkV Jupiter的操作原样照抄即可,源码也直接Git Clone到QEMU系统里面
在我机器上这个方案也很顺利,但搬运到Github Action上就会有各种各样的问题🤣
踩到的第一个坑,是Github Action的权限问题:放在Github仓库内QEMU镜像是只读权限,一旦QEMU加载内存进内存就报错
解决方案:QDIB的镜像等到运行CI的时候,再进行下载
接下来踩第二个坑:QEMU镜像一旦加载,整个界面就停止交互
解决方案:nohup或screen挂后台启动。Github Action不能终端交互,QEMU回显是个问题。能想到的解决方案是通过SSH实现交互
第三个坑:如何添加这个QEMU镜像的SSH免登录?
Github Action对于权限管理很严,我采用了个土办法:直接sshpass
命令输入密码直通。这不是个好看的方法,但它一定能Work
sshpass -p 'root'
第四个坑:既然前面都配置好了,为什么SSH登录不上去?
QEMU启动要时间,所以需要等待一个QEMU一定能启动的时间再去SSH连接
走完上述工作,应该没问题了吧,😍
事实上,我的电脑确实也顺利跑起来了,我也没想太多,Github Action跑起来就去睡觉了
第二天起床,返现Github Action——它居然超时了!!
正常的编译工作直接被掐断,如果时间充足,机器够强,这流程一定能跑通
Anyway,这条路是行不通了😥QEMU损失大量性能的事情,也不是第一天才发生,只能说在这个问题上太大意了
方案二:交叉编译+Docker中QEMU运行验证
一开始并不想尝试这种方案——交叉编译的坑不会少,而且并不清楚DuckDB的依赖在交叉编译中是否会报错,riscv-gnu-toolchain本身的编译也需要很长时间,同时占用大量硬盘空间
但Github Action是支持Docker镜像构建和运行的,这意味着我可以使用debian:sid
镜像,里面可以直接安装riscv-gnu-toolchain
,那事情也会相对好办许多
Docker镜像里面只需要准备好QEMU的环境即可
FROM debian:sid
# Install dependenciesRUN apt-get update && apt-get install -y \ qemu-system-riscv \ u-boot-qemu \ openssh-server \ screen \ sshpass \ wget \ unzip
# Download and extract Debian imageRUN wget -O debian.zip https://gitlab.com/api/v4/projects/giomasce%2Fdqib/jobs/artifacts/master/download?job=convert_riscv64-virt && \ unzip debian.zip
# Copy startup scriptCOPY --chmod=755 start_qemu.sh start_qemu.sh
# Set the entrypoint to the startup scriptENTRYPOINT ["/bin/bash"]
# Expose SSH portEXPOSE 2222
添加上DuckDB对应的测试脚本
docker run -i --rm -v $(pwd):/duckdb --workdir /duckdb ghcr.io/mocusez/duckdb-riscv-ci/duckdb-riscv-ci <<< "apt-get update && export DEBIAN_FRONTEND=noninteractive && apt-get install cmake ninja-build libssl-dev g++-riscv64-linux-gnu -y && GEN=ninja CC='riscv64-linux-gnu-gcc -march=rv64gcv_zicsr_zifencei_zihintpause_zvl256b' CXX='riscv64-linux-gnu-g++ -march=rv64gcv_zicsr_zifencei_zihintpause_zvl256b' DUCKDB_PLATFORM=linux_riscv make && cd / && ./start_qemu.sh && cd /duckdb && make clean && echo 'DOCKER TEST RESULT: SUCCESS' || (echo 'DOCKER TEST RESULT: FAILURE' && make clean)" 2>&1
运行QEMU
screen -dmS qemu qemu-system-riscv64 \ -machine virt \ -cpu rv64,zba=true,zbb=true,v=true,vlen=256,vext_spec=v1.0,rvv_ta_all_1s=true,rvv_ma_all_1s=true \ -smp 4 \ -m 4G \ -device virtio-blk-device,drive=hd \ -drive file=dqib_riscv64-virt/image.qcow2,if=none,id=hd \ -device virtio-net-device,netdev=net \ -netdev user,id=net,hostfwd=tcp::2222-:22 \ -kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf \ -append "root=LABEL=rootfs console=ttyS0" \ -nographicsleep 120 # wait for qemu to bootsshpass -p 'root' scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -r -P 2222 /duckdb/build/release/duckdb root@localhost:/rootsshpass -p 'root' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "chmod +x duckdb && ./duckdb -c 'PRAGMA platform;'"
Well Done !😁 GitHub Action顺利通过了,让我最为担心的DuckDB依赖问题并没有发生
把代码托管到Github仓库(mocusez/duckdb-riscv-ci),就跑去DuckDB那里开了个Discussion,
我觉得代码应该还需要再规范些,希望DuckDB的人员能给些建议,但等了一周后见没什么动静,就直接提Pull Request(DuckDB PR#16549)——于是3月13日晚上通过Review,3月14日就Merge了
3月15日下午补齐相关文档,3月16日晚些时间关于文档的Pull Request被合并
结语
感谢Reddit用户@LivingLinux,@Self在RISC-V编译DuckDB的前期工作中探索付出的努力,以及DuckDB热心的审核人员,快速完成了Pull Request的合并😍
期待未来有机会能继续完善DuckDB在RISC-V的生态😁