发布日期: 2024/04/23 06:33

【RISC-V技术动态】rv64ilp32之路 - 32位Linux的未来


1月16日,玄铁高级技术专家-郭任受邀参加2024东京RISC-V冬季会议,进行了主题名为《rv64ilp32: The future of 32-bit Linux》的演讲。在计算机科学领域,选择合适的指针位宽和指令架构对系统的性能和资源利用至关重要。本文将探讨:

  • 为何选择 32位指针
  • 为何选择 64位指令架构
  • 介绍玄铁在RISC-V 64ilp32 ABI上的工作

为何选择32位指针?


计算机科学巨擘、图灵奖得主唐纳德在2008年的博客中曾发表过一段著名的言论,他抱怨道:在编译内存需求不足4GB的程序时,使用64位指针是非常不明智的。因为当这些指针值出现在结构体中时,它们不仅浪费了一半的内存,而且还导致一半的缓存被浪费。这表明,在不需64位寻址的情境中,使用64位指针不仅增加了内存消耗,还降低了缓存的使用效率。相比之下,使用32位指针可以更有效地利用内存和缓存资源,提高程序的性能。因此,唐纳德的观点强调了在不需要64位寻址的场景中,应优先选择使用32位指针。

唐纳德指出,不当地使用64位指针会导致内存的浪费。为了验证这一观点,我们进行了一项实验,对比了rv64ilp32和rv64lp64 Linux内核的内存开销。实验环境基于Linux tinyconfig,并且启动日志已进行逐行对齐,以确保两种配置在软件层面完全一致:


实验结果显示,64位指针相比32位指针浪费了高达25%的内存!对于许多嵌入式工程师而言,几百KB的内存都是宝贵的资源,他们无法容忍这种浪费。因此,在不需要64位寻址的场景中,使用32位指针是更为明智的选择,可以有效降低内存开销。

唐纳德还指出,不合理使用64位指针会导致缓存效率降低,进而影响性能。为了验证这一观点,我们对64ilp32和64lp64 SPEC2006的性能进行了对比。实验结果如下:


  • 黄色柱状图表示在对比开发板上的测量结果。柱状体向上表示32位指针相比64位指针的性能提升幅度,柱体向下表示性能下降幅度。

  • 蓝色柱状图表示在Allwinner D1s开发板上的测量结果。

需要注意的是,由于rv64ilp32的编译器仍处于开发阶段,优化尚不完美,因此在456.hmmer测试用例中性能有所下降。经过分析,这是一个编译器性能问题,未来将会得到解决。总体结果显示,在相同的rv64指令架构的硬件上,使用32位指针相比64位指针可以显著提升性能。这一结果进一步支持了唐纳德的观点,即在不需要64位寻址的场景中,使用32位指针是更明智的选择,可以有效提升缓存利用率达到提升性能的目的。


在SPEC 2017测试中,我们进一步验证了32位指针相比64位指针在性能上的优势。实验结果显示,使用32位指针在多个测试用例中都获得了显著的性能提升。

32位指针在嵌入式系统中至关重要,通常人们会选择传统的32位指令架构。然而,近期情况发生了变化,许多嵌入式芯片制造商由 arm32 转向了RISC-V 64位指令架构。

为什么会发生这样的转变?让我们进入下一个主题:

为何选择64位指令架构?


Gary Explains 在 YouTube 上发布了一段热门的视频,标题为“32-bits is DEAD!”。确实,从几个关键现象中我们可以观察到,32位指令架构正在从应用处理器中消失。

  • RISC-V 的应用处理器 profiles 自从 RVA20、RVA22 到 RVA23,包括 RVB23,都未曾采纳过32位指令架构
  • Arm-v9 的应用处理器规范已移除了32位指令架构
  • x86-s 规范同样也剔除了32位指令架构

以上现象揭示了一个趋势,新一代应用处理器正在逐步淘汰32位指令架构。那么,究竟是什么原因导致了这一趋势呢?我尝试着寻找答案:

无论是基于Arm-v8还是x86架构的64位处理器,都保留了32位指令架构模式。这种模式将64位寄存器压缩至32位使用,导致丢弃了寄存器的高32位。唐纳德认为,浪费一半缓存和内存的行为是“absolutely idiotic”。那么,浪费一半的寄存器的行为又该如何评价呢?


寄存器作为计算机系统中宝贵的存储部件,直接参与处理器流水线的执行单元运作,对性能起到关键作用。然而,为了兼容性,过去十几年间,我们浪费了一半的寄存器资源。这一现象的根本原因是,无论是Arm还是x86都已建立了根深蒂固的传统32位软件生态,导致他们继续沿用传统32位。与这些传统架构不同,RISC-V没有32位历史包袱,它的32位软件生态还处于萌芽期,这恰好为矫正和优化提供了绝佳时机。rv64ilp32 ABI 正是瞄准这一机遇,旨在规避过去架构中出现的谬误,为嵌入式RISC-V应用处理器提供更卓越的新32位解决方案,以替代已显老旧的传统32位架构,实现性能与成本的双赢。

那么,扔掉一半寄存器究竟会有什么样的后果?


我们在相同 RISC-V 64位架构的硬件上,对比 rv64ilp32 和 rv32ilp32 的 Linux 内核 memcpy/memload/memset 函数的性能。蓝色柱状图代表 Allwinner D1s硬件平台,而橘色柱状图代表对比硬件平台。rv64ilp32 相比 rv32ilp32 在所有测试用例上,都获得了性能提升,尤其是在对比硬件平台上,平均获得了接近翻倍的性能提升,这得益于其内存控制器提供了充足的带宽, D1s硬件平台受限于内存带宽,性能提升幅度虽不如对比组,但也非常显著。测试结果告诉我们,64位指令架构相比32位在性能上有巨大优势,因为它有效提升流水线的吞吐带宽,就如同大炮的口径,口径越大威力越大。那么,用纯32位指令架构设计芯片,能否降低芯片面积?


我们的同行 ARM 已经做过尝试,Cortex-A32 就是从 Cortex-A35 裁剪64位模式仅保留32位模式而来,单核面积下降了 13%,乍听起来不错,但这 13% 并不简单,它还包含了调整位宽之外的其他变更:

  • AArch64 有 31 个寄存器,但 AArch32 只有 15 个,剔除了16个通用寄存器,这项修改所涉及的 bit 总数和改变通用寄存器位宽(从64位到32位)是一样多的。
  • AArch64 有 32 个128位 SIMD 寄存器,但 AArch32 只有 16 个,又剔除16个SIMD寄存器,这项修改所涉及的 bit 总数是改变通用寄存器位宽的 4 倍。
  • Cortex-A35 是 AArch32 + AArch64 的结合体,并不是纯 64位指令架构的处理器,但 Cortex-A32 只支持 AArch32,是纯32位指令架构的处理器,所以这不是 AArch64 v.s. AArch32。

所以当我们将 13% 换算到 RISC-V 上时,结合以上3个因素打一个折扣,13%/4=3.25%,而这仅仅是从单核的视角去思考。如果再从整个应用处理器 SoC 的维度看,当加上 L2 缓存、系统总线和各种 IP后,CPU核面积在整个应用处理器芯片的占比,不会超过 10%(一般小于5%)。综上所述,使用 32 位指令架构能为整个 SoC 芯片面积带来的收益,实在太小了!让我们再回顾下这些小内存应用处理器芯片:

这些厂商选择 RISC-V 64位指令架构替换 arm32 是有远见且明智的,他们在用真金白银的行动告诉我们,RISC-V 64位指令架构才是 32位Linux 的未来!而我们的工作就是实现 rv64ilp32 ABI,在 RISC-V 64位指令架构上完美运行 32位 Linux:

玄铁在RISC-V 64ilp32 ABI上的工作

实现 rv64ilp32 意味着引入了一个全新的ABI,这是一个庞大的工程,需要大量的投入来推动整个软件生态的发展。尽管有人因为畏惧挑战而犹豫不前,甚至将这种情绪蔓延到整个Linux世界,认为x86-x32、mips-n32和arm64-ilp32都失败了,凭什么RISC-V会成功。但我对此不以为然。这些架构之所以失败,是因为它们的32位ABI根深蒂固,难以改变。如果人们想要使用32位指针,只需让硬件在32位模式下运行现有的软件即可。然而,RISC-V的32位软件生态尚处于萌芽阶段,没有历史包袱。

我们汲取了前人的经验,并在此基础上进行了创新。在实现了用户态u64ilp32 ABI的基础上,我们首次实现了s64ilp32 Linux内核,并以嵌入式小内存场景为切入点,使其更贴近实际应用场景(而非x86-x32的科学计算和基准测试场景)。


我们为Linux内核实现了36个补丁:

  • 前11个补丁是 u64ilp32 用户态支持,而X86、MIPS和ARM也仅实现了这一步。
  • 后25个补丁是 s64ilp32 Linux内核,即让32位Linux完美运行在64位指令架构的硬件上,是世界上第一个 64ilp32 ABI 的 Linux 内核。

上图中展示:该补丁集为Linux引入了新的内核模式s64ilp32,该模式同时支持u64ilp32和u32ilp32两种用户态ABI。

此外,该补丁集还为s64lp64内核模式增加了对u64ilp32用户态ABI的支持。

相较于传统的s32ilp32内核,新的s64ilp32内核具有以下优势:

  • 内核的内存拷贝函数性能大幅提升。
  • ebpf JIT性能大幅领先。
  • 支持原生64位原子指令。
  • 支持原生64位算术指令。

目前,我们已初步完成Fedora 38的移植工作:


由于构建u64ilp32用户态的道路漫长,我们决定先采用s64ilp32+u32ilp32的混合模式,以快速交付完整的32位Linux解决方案。该方案可在配备玄铁c908和c907的芯片上运行,这些处理器都支持sxl=64 uxl=32的混合模式。此项工作由三个团队共同完成:

PLCT团队负责编译器和工具链的开发。

玄铁处理器团队负责Linux内核和CPU的适配工作。

Fedora团队则负责Linux发行版的构建与维护。

由于RISC-V的32位软件生态相对薄弱,我们开创性地引入了兼容u64lp64的模式:


使64位应用程序得以在32位Linux内核上运行。我们已经完成了原型验证,成功将64位地址空间压缩至2GB,并顺利启动了整个64位根文件系统。这一创新特性将作为下一版本[RFC PATCH V3]的重要组成部分,旨在弥补RISC-V在32位软件生态方面的不足。在完成 “s64ilp32 + u64lp64” 特性后,我们进一步统一了s64ilp32和s64lp64支持的用户态模式,实现了根文件系统的二进制兼容性:


这意味着在这两种模式下,应用程序和操作系统可以无缝地运行,无需进行额外的修改或适配。这一改进不仅简化了软件开发和部署过程,还增强了RISC-V架构的灵活性和可扩展性。我们的最终目标是,通过实现 “s64ilp32 + u64ilp32” 的组合取代传统32位,并复用64位的系统调用接口,删除老32位,实现Linux用户ABI的统一:


这将有助于简化软件的开发、部署和维护过程,提高系统的稳定性和兼容性。RISC-V 64ilp32 ABI 也将进一步推动RISC-V架构的发展和普及,使其成为更多应用领域的理想选择。

Linux CPU子系统的维护者 Arnd Bergmann 曾写过一篇同名文章 "The future of 32-bit Linux",文中他详细分析了当前32位Linux的历史和现状,给出了一个不幸的结论:等 arm32 退出历史舞台,32位Linux就会消亡。然而,我们认为rv64ilp32 ABI 将进一步推动玄铁 RISC-V 在嵌入式 Linux 领域的商业化进程,并有望取代 Arm32 架构,为32位 Linux 开创一个光明的未来。