基于RISC-V平台openEuler系统的COMO构件技术移植与应用①
2022-09-20黄玉坤裴喜龙徐志宇王建民
黄玉坤, 裴喜龙, 徐志宇, 王建民
1(江西财经大学 信息管理学院, 南昌 330032)
2(同济大学 电子与信息工程学院, 上海 200092)
3(中国科学院 软件研究所, 北京100190)
近年来, 伴随着云计算、物联网、人工智能技术不断进步, 智能设备迅速发展, 数据无处不在, 最终实现万物互联. 移动终端和智能设备广泛普及, 异构计算开始兴起, 边缘计算应用爆发式增长[1,2]. 边缘计算是物联网中重要的一环, 它将算力下沉到边缘侧, 大大减少云端算力压力, 节约带宽, 且能快速响应端设备请求.面向万物互联的边缘计算具有丰富的场景和应用[3,4],如何应对不同场景下对算力的差异化需求, 对边缘计算平台软硬件体系的开放性、灵活性、可定制、可扩展性等方面提出了挑战.
在物联网碎片化环境中, RISC-V架构具有广泛的发展前景. RISC-V是一种开源的指令集架构(instruction set architecture, ISA), RISC-V指令集架构的开放性、模块化、高度可定制性的特点使得其成为体系结构和软件系统创新的理想实验平台[5,6]. RISC-V的发展十分迅速, 涌现了大量采用RISC-V指令集架构的开源或商用处理器和SoC, 如鲲鹏、PulSAR等[7]; 除了硬件的微架构设计、逻辑设计外, 在软件生态方面也日渐成熟,如UCB提供了RISC-V的开源编译器GCC、LLVM[8],开源仿真器Spike、QEMU, 社区也实现了支持RISC-V架构的openEuler[9]开源操作系统和 FreeBSD、Debian等操作系统的移植. 在一个系统级的方案中, 芯片是核心和基础, 但构筑在芯片之上的整个系统软硬件方案,才是最终与应用直接接口的关键.
在边缘计算领域中, 采用RISC-V架构的操作系统无论是内核的架构还是应用组织的方式, 都在不断的发生着创新和变化. openEuler是一个基于RISC-V指令集架构的开源Linux发行版本, 具有开放、灵活、不断演进和架构包容的软件生态体系. openEuler的目标是从系统软件的角度, 打通不同算力, 让开发者可以在其之上进行技术创新, 使其适应多样性的计算场景,支撑边缘侧应用的运行需求. 因此, 基于RISC-V指令集架构的openEuler操作系统是一个很好的构建边缘计算应用的创新平台.
然而, 边缘计算应用对底层软件工具链的要求也非常高, 包括对一些主流的算法库和程序开发框架的支持, 这对上层开发者的使用体验以及市场的接受度和认可度有直接的影响. 理想状态下, 应用开发者应该可以在无需了解芯片底层硬件的细节和指令集架构的情况下进行应用程序的开发, 这需要扩展操作系统功能、增强底层软件开发环境和工具链. 另外, 不同的应用场景和应用模式, 对面向边缘计算的软件开发框架等基础设施也提出了需求.
1 基于RISC-V指令集架构的边缘计算软硬件基础服务架构
在云计算和边缘计算的软件架构中, 广泛采用了XaaS模式, 即Paas平台即服务、IaaS基础设施即服务、SaaS软件即服务等模式. 在边缘计算中实现面向XaaS的软件架构能够将边缘端与云端进行融合. COMO(C++ component model)技术[10,11]是一个改进C++构件技术的开源项目, 它可以将细粒度的计算(机器指令或软件程序)抽象成构件服务, 并提供XaaS服务架构, 有利于对软件系统在编译阶段和运行时的动态演进.
RISC-V架构相比其他成熟的商业架构的最大的不同在于它是一个模块化的架构. ISA在CPU软件和CPU硬件设计者之间, 提供了一个抽象层(接口).RISC-V架构不仅短小精悍, 而且其不同的部分还能以模块化的方式组织在一起, 从而试图通过一套统一的架构满足各种不同的应用. 基于虚拟原型(virtual prototype)扩展和配置RISC-V是基于RISC-V的计算机系统开发的重要手段[12,13].
COMO技术可以在系统服务和软件服务抽象的接口层面保持构件的一致性. COMO同样采用虚拟原型的设计方法, 把程序分为元数据和逻辑两层, 元数据则是程序的原型抽象, 这一特性使得COMO构件可以在支持RISC-V架构的系统中与底层硬件的接口层保持统一的模块化结构. 结合RISC-V架构及openEuler的模块化设计的技术特点, COMO提供了一个面向XaaS模式的ServiceManager软件开发框架, 使得COMO可以在云计算、边缘计算及其结合的应用场景提供一个统一的构件化程序运行环境和开发模型. COMO在ISC-V指令集和openEuler操作系统上的系统架构如图1所示.
图1 COMO在RISC-V指令集和openEuler操作系统上的系统架构
本文的主要工作是在基于RISC-V架构和openEuler操作系统的软硬件平台上移植COMO构件程序运行与开发环境, 为面向云计算与物联网的边缘计算应用提供面向XaaS服务的构件化程序开发模式; 并通过一个简单的实例介绍COMO的ServiceManager框架在边缘计算中的应用. 基于RISC-V和openEuler系统之上的QEMU模拟器进行了COMO运行与开发环境移植的实验, 证明了COMO构件技术与RISC-V指令集架构和openEuler操作系统的兼容性和可行性. COMO构件技术与RISC-V指令集系统和openEuler操作系统的结合, 为openEuler生态圈注入了新的特性和活力,同时, 借助RISC-V硬件技术和openEuler生态圈的发展, COMO构件技术能够获得更多机会得到推广和使用.
2 COMO在RISC-V指令集架构和openEuler系统上的移植
2.1 基于QEMU搭建RISC-V上的openEuler系统环境
由于COMO、openEuler、RISC-V都处于研发的起步和发展阶段, 从无到有地研发一个计算环境比开发一个应用要难得多. 在一个新的体系架构的计算机上开发软件系统, 首先要在上面运行起较完整的开发环境, 本文采用openEuler的RISC-V镜像作为实验环境[14]. 目前支持“openEuler on RISC-V”的硬件平台有:(1) NutShell (果壳, UCAS) COOSCA 1.0; (2) SiFive HiFive Unleashed. 然而现在RISC-V还不普及, 在实际的硬件平台上进行移植工作之前, 利用RISC-V的QEMU进行COMO移植的仿真, 可以以较低的硬件成本和时间成本验证COMO移植的可行性和COMO构件在openEuler on RISC-V上运行的兼容性.
工作的第一步需要通过QEMU仿真出RISC-V硬件. 本文的实验环境是X86的Ubuntu 18.04, 以及自己编译RISC-V版的QEMU[15-17].
从官方资源库下载openEuler RISC-V 移植版, 并通过wget下载互联网资源.
通过下列命令启动虚拟机.
$qemu-system-riscv64-nographic -machine virt-smp 8 -m 2G-kernel fw_payload_oe.elf-drive file=oe-rv-rv64g-30G.qcow2, format=qcow2, id=hd0-object rng-random, filename=/dev/urandom, id=rng0-device virtio-rng-device, rng=rng0-device virtio-blk-device, drive=hd0-device virtio-net-device, netdev=usernet-netdev user, id=usernet, hostfwd=tcp::12055-:22-append 'root=/dev/vda1 rw console=ttyS0 systemd.default_timeout_start_sec=600 selinux=0 highres=off mem=4096M earlycon'
RISC-V没有X86平台上的基本输入输出系统BIOS, 所以openEuler操作系统的引导加载程序是基于OpenSBI项目的OpenSBI RISC-V, 后者实现了Supervisor二进制接口[18]. 如果虚拟机正常工作, 则显示结果如图2所示. RISC-V上openEuler成功启动后的界面如图3所示.
图2 qemu-system-riscv64起动界面
图3 RISC-V上openEuler启动成功
2.2 搭建COMO的build环境
COMO的组成部分包括: (1)工具部分, C++构件化需要的构件定义语言(componentdefinition language,CDL)编译器cdlc、构件编译环境; (2)与Java基础类库对应的Libcore核心库. openEuler在RISC-V上的基础类库支持不够完整, 所以这里把第2部分做了部分裁剪. 这样做的好处是能得到一个精简的COMO, 使得精简COMO可以在计算能力更弱的环境中运行. 下面以RISC-V为开发机, 进行本地编译.
一个软件, 如果能在与目标机体系结构及操作系统等硬件、软件一致的环境中编译自己, 那比较容易实现开发、调试、测试的集成化. 可是openEuler在RISC-V上还很弱小, 这个环境的可安装包也不完整,于是只能从编译COMO所需要的环境开始构建, 即以RISC-V为开发机, 进行本地编译, 除了cmake, 其它COMO所依赖工具都是从源码开始构建的.
从源码开始安装cmake, 遇到了C/C++编译器版本上的问题. 通过验证, 这个问题可以在openEuler发行版上解决, 从源头治理一个生态往往成本是最小的,解决软件包(库)的版本依赖是所有操作系统开发商都要面对的困难. 最后决定从openEuler的发行软件包中安装cmake.
通过yum安装cmake等软件时, 遇到了“Cannot download repomd.xml”错误, 这是软件的安装源有问题引起的, 可以用非正式(preview)的源, 并在.repo文件中加sslverify=0解决.
/etc/yum.repos.d/oe-rv.repo[base]name=base baseurl=https://isrc.iscas.ac.cn/mirror/openeuler-sig-riscv/oe-RISCV-repo/enabled=1 gpgcheck=0 sslverify=0
在git clone COMO源码仓库时, 遇到“SSL certificate problem”问题, 可通过下列命令解决.
git config --global http.sslVerify false
在“openEuler on RISC-V”环境中编译COMO, 选COMO本地Linux编译环境: como_linux_riscv64.
由于COMO仓库中缺省的构件描述语言编译工具cdlc是面向openEuler X86平台的, 所以在编译COMO前, 首先要编译出COMO工具链, 所用的COMO环境是: Comotools.
在Comotools环境中编译完成cdlc后, 发布cdlc工具链:
cp ./out/host/como/tools/cdlc/cdlc ./tools/cdlc
编译COMO前, 需要安装并配置dbus开发包.
$yum install dbus-devel
$ cp ./lib64/dbus-1.0/include/dbus/dbus-arch-deps.h/usr/include/dbus-1.0/dbus
在搭建完成openEuler on RISC-V和COMO的build环境之后, 下一步的工作是COMO的代码移植.
2.3 COMO代码移植
将COMO代码移植到openEuler平台上需要关注以下问题.
(1) ELF格式的约定
openEuler是一种Linux操作系统, 它的可执行文件及动态链接库等二进制文件是ELF格式的, COMO的元数据存放在ELF格式文件的“.metadata”段中, 所以COMO在openEuler上没有发行文件格式上的问题.
COMO采用与Java类似的元数据与代码编译结果放在一起的发行方式, 构件存储为ELF格式文件. 传统的基于PE/ELF可执行文件格式的线性符号表导出为标志的软件运行时资源共享机制, 在计算能力已经大大发展的时代, 显得臃肿. COMO的类、接口、方法等定义信息是通过元数据表达的, 不产生导出符号, 所以其发行文件的导出符号表很简洁.
(2) RISC-V EABI参数对齐
各种约定的一致性是评价一个操作系统成熟度的重要指标. COMO代码中, 反射机制构造调用栈的一段汇编代码是与平台相关的, 它要求把从RPC等渠道得到的COMO方法调用参数, 遵守RISC-V ABI规范形成调用栈. ABI定义了调用C/C++程序传参数方法.
嵌入式系统上的RISC-V的ABI标准是EABI,Linux上的RISC-V的ABI标准是UABI[19,20]. COMO采用了RISC-V EABI参数对齐规则: 如果参数可以完全放在寄存器内, 则放在寄存器内, 否则把寄存器内摆放不下的参数放在栈里. 无论参数是在寄存器里, 还是在栈上, 所有参数传递时要数据对齐. XLEN这个参数是指数据总线宽度, 可能的值是32或64.
1)对于XLEN=32的系统, 数据总线宽度8 B.
2)对于XLEN=64的系统, 数据总线宽度16 B.
EABI函数调用参数所用寄存器, 如表1所示. 浮点数参数也通过整数寄存器(x10-x11、x12-x17)或者栈传递.
表1 EABI函数调用参数所用寄存器
(3) COMO在RISC-V上的移植
COMO是采用C++ 11 (-std=gnu++11)标准实现的, 但有少部分用汇编写的程序是与计算机体系结构相关的, 以下代码需要用RISC-V汇编重写:
?
另外还需要创建一个RISC-V的CMake编译脚本文件:
build/como_linux_riscv64.cmake
3 COMO技术的ServiceManager框架在边缘计算中的应用实验
为了验证COMO构件技术在RISC-V指令集架构和openEuler操作系统上的兼容性、可行性和实用性,搭建基于RISC-V和openEuler上的QEMU模拟器的实验环境并实现COMO技术的移植, 利用COMO的协同计算能力, 组成一个边缘计算集群, 实现多台RISC-V节点协同计算, 实验软硬件架构如图4所示.
图4 COMO技术的ServiceManager框架实现集群式RISC-V协同计算
COMO构件技术能够方便实现程序框架模型, 但它本身不强调对某一框架的支持. ServiceManager是COMO面向服务的开发框架之一. ServiceManager提供了Server的Name和Handle之间对应关系的查询能力, 它主要包含的功能: (1) 注册, 当一个 Server 创建后, 应该将这个 Server 的 Name 和 Handle 对应关系记录到 ServiceManager 中. (2) 查询, 其他应用可以根据Server 的 Name 查询到对应的 Service Handle.
为了验证“openEuler on RISC-V”的网络通信能力,基于IP通信, 实现了一个COMO ServiceManager版本的应用程序, 该程序位于COMO源码中的samples/democomponent目录, 由Client和Component两部分组成. Component实现了一个COMO构件, Client实现了如何对这个构件进行调用. 类似于OSGi, Service-Manager框架实现了一个优雅、完整和动态的组件模型, 构件无需重新引导就可以被远程安装、启动、升级和卸载. 本实验中, 客户端和服务管理程序都运行在Master结点, 服务提供者运行在Workers结点, 通过FindService找到COMO构件的服务, 不需要知道它的提供者在哪个结点运行, 就可以调用它的服务.
运行起来的COMO示例程序效果如图5所示, 这个示例演示了一个宿主程序通过反射机制调用COMO构件编写的服务组件的过程.
图5 COMO示例的运行结果
4 结论与展望
随着云计算、物联网等技术的兴起和广泛应用,边缘计算作为云计算的补充和延伸, 可充分利用边缘算力. 但是, 边缘计算因为其条件受限的软硬件部署限制, 对服务器在环境适配性、程序运行环境的部署和程序运行的效率上有更严苛要求. 面对海量边缘应用场景, 硬件指令集架构ISA、软件基础平台的操作系统和其上的软件开发框架、程序编译、运行的工具链等基础设施尤为重要.
本文完成了基于RISC-V和openEuler上的QEMU模拟器的实验环境搭建和COMO运行与开发环境的移植, 证明了COMO构件技术与RISC-V指令集架构和openEuler操作系统的兼容性和可行性. 实验应用实例表明, 在一个以RISC-V指令集架构和openEuler操作系统为软硬件平台的集群上可以成功运行COMO构件技术和其所支持的ServiceManager框架编写的面向服务的应用程序, 为云计算和物联网为主要应用场景的边缘计算提供了一个简单、有效和可行的面向XaaS计算模式, 以及一个与C++语言无缝衔接的构件化程序设计开发模式.
由于现在RISC-V的发展还不够成熟, 不能完全靠RISC-V环境把COMO完整编译出来, 因此提供交叉编译支持就很必要. 本文下一步的工作方向是, 尝试使用Clang/LLVM编译器, 把COMO裁成多个比较小的模块集合. 但这个尝试目前还处于交叉编译环境定义阶段. 随着交叉编译环境的完善, 逐步发现openEuler上Clang/LLVM应该做的工作. Clang/LLVM是现在使用较多的编译器[21], 所以这个尝试是很有意义的.
希望COMO能在这个新的工具链建设中发挥一定作用, 并在与openEuler与RISC-V社区共同发展的过程中壮大自己.