用于探索高级内存系统概念的树莓派操作系统
帕斯卡·弗朗西斯‐梅泽格 缅因大学 pascal.francismezger@maine.edu
文森特·M·韦弗 缅因大学 vincent.weaver@maine.edu
1 引言
现代计算机存储器层次结构十分复杂,通过结合各种相互关联的缓存、内存控制器和内存技术,试图掩盖内存与处理器访问延迟之间的巨大差距。这一长期存在的延迟差异问题通常被称为内存墙 [43]。除了涉及的缓存之外,大多数现代系统还具备某种虚拟内存基础设施,这增加了自身的复杂性和延迟。新型内存技术(包括非易失性存储器)的引入只会使情况更加恶化。
面对如此复杂的底层架构,编写能够获得高性能的代码十分困难。用户代码通常依赖于操作系统来处理内存层次结构的设置、配置和管理。操作系统中与内存相关的代码变得与底层硬件一样复杂且难以理解。当前的操作系统最终都针对现有的内存系统进行了高度优化;要修改它们以利用内存系统设计中的最新进展可能是一个困难的过程。
这种复杂性使得教授现代内存系统及其与系统软件的交互变得困难。在Linux这样的功能完整的操作系统中梳理相关代码可能是一项令人沮丧的任务。
为了方便学生,我们提出了vmwOS,这是一个为低成本树莓派开发板设计的简单操作系统。尽管这些广泛使用的开发板价格低廉,但它们支持现代内存系统的大多数功能,包括64位地址、多级缓存、多核以及完整的ARMv8处理器和MMU支持。该操作系统足够简单,使学生能够理解、修改,并探索现代内存环境。
我们介绍了树莓派开发板上的硬件、vmwOS的功能,并提出了可进行的各种内存系统探索。这包括研究各级缓存的优势与权衡、对虚拟内存基础设施的动手操作,以及对非易失性RAM概念的实验。
2 内存教育中的复杂性
内存系统对现代处理器性能至关重要,但这一主题非常复杂,难以在典型的计算机体系结构课程中深入涵盖。相关主题足以填满一本长达1000页的教科书 [19]。
以下是讲解存储器层次结构的一些常见方法,我们将在下文详细阐述。
2.1 简单缓存示例
在为期一个学期的本科计算机组成或计算机架构课程中,通常会花几周时间讲解缓存和虚拟内存。一种常见的教学方式是先讲解概念,然后进行一些人为设计的缓存示例。这些示例可能只涉及几十条指令,且所涉及的缓存层次结构是20世纪90年代台式机中曾使用的简化类型。
尽管学生通常可以在纸上计算出这些简单缓存的缓存未命中行为,但这往往无法转化为对现代内存系统所面临问题的深刻直观理解。
2.2 硬件测量
另一种研究内存系统的方法是在实际硬件上进行测量。大多数现代系统都支持硬件性能计数器,可以用于测量程序执行期间发生的体系结构事件。这包括诸如周期、分支预测未命中和退休指令等事件,也包括内存系统事件,如缓存命中与未命中以及TLB未命中。更高级的处理器能够报告更详细的信息,例如DRAM统计、缓存一致性事件、处理器间和核外内存传输,以及采样缓存延迟值。在Linux系统上,可以使用诸如perf [14]之类的工具来收集这些结果。
虽然收集这些缓存和内存统计数据是直接且简单的,但解释这些数据可能会很困难。即使是退休指令这类确定性事件,也可能出现计数过多和非确定性的情况[42]。像缓存未命中这样的非确定性事件可能产生令人惊讶的结果,尤其是在运行有其他程序的系统上执行时。诸如硬件预取等高级硬件特性可能导致缓存未命中率出人意料地低,与课程中通常讲授的简单模型不符。许多现代芯片在与内存相关的性能计数器方面存在相当全面的勘误表,这再次导致当采集结果不符合预期时产生困惑。即使是确定预期的正确结果也可能很困难,因为缓存层次结构的完整参数属于专有信息,通常无法获得大多数处理器的这些参数,特别是高端台式机和服务器。
由于这些问题,硬件性能计数器可能成为探索存储器层次结构的宝贵工具,但结果往往引发更多问题,而非答案。
2.3 现场可编程门阵列实现
解决无法了解商用内存层次结构细节问题的一种方法是从头开始构建自己的内存层次结构。如今,使用真正的硅材料来制造自己的芯片已不切实际,但可以使用现场可编程门阵列(FPGA)[34]来进行设计。FPGA本质上是可重编程硬件,可用于设计完整的内存层次结构。
在课程中使用现场可编程门阵列的一个缺点是,除非学生事先具备现场可编程门阵列相关知识,否则可能需要花费大量时间让他们掌握所需的各种工具和技术。完整的内存层次结构设计起来可能非常复杂,尤其是涉及多核时。此外,实现具有数兆字节静态随机存取存储器存储的现代规模的缓存将需要相当大且昂贵的现场可编程门阵列。为现代DDR4 DRAM设计内存控制器是一项复杂的挑战;通常现场可编程门阵列开发板会带有内置的DRAM接口,但学生从零开始设计一个这样的接口可能是不现实的。
2.4 缓存模拟器
软件缓存模拟器通常比基于FPGA的模拟器更容易设计。复杂的硬件结构通常只需几行代码即可实现。软件缓存模拟器的主要缺点是其运行速度远慢于真实硬件。一个典型的“周期精确”中央处理器和内存系统模拟器(如Gem5[7])相较于原生执行可能会有1000倍的性能下降。Gem5包含一个简单的DRAM模拟器,但接入更精确的DRAM模拟器(如MemSys)会使它的运行速度几乎再降低2倍[24]。另一个DRAM模拟器DRAMSim2[33]会使本已较慢的模拟器MARSSx86的运行时间增加30%。
除了速度之外,软件模拟还可能存在其他问题。软件缓存模拟器并不总是经过验证[41],,即使经过验证,其准确性也可能存在巨大差异[15]。使用软件模拟时会带来显著的性能下降,这意味着通常只能运行一些简单的示例,否则即使是小型基准测试也可能需要数天到数周的时间才能完成。此外,模拟器代码库往往较为复杂,因此尽管为实验而更改缓存参数通常较为直接,但若要对整个内存层次结构进行更复杂的实验,则很快会超出课程项目所能涵盖的复杂度,而变成硕士甚至博士论文级别的工作量。
2.5 操作系统探索
最后一种研究内存的方法,也是本文所提出的方法:在操作系统层面进行研究。操作系统负责配置内存系统,并可以深度参与其运行过程,尤其是在涉及虚拟内存时。
截至版本4.17,Linux mm内存管理目录包含近13万行C语言代码,这还不包括每个平均包含数千行代码的特定架构目录。即使是负责维护该代码的专家也难以理解这段复杂的代码。
理解代码的主要问题在于,它为了实现高性能而牺牲了可读性。ARM和x86等现代高端架构可能具有复杂的虚拟内存设置。跨平台代码的需求可能导致多层抽象,从而难以理解。
为了提供一个教学环境,让学生能够学习内存系统与操作系统之间的交互,我们建议使用简单的vmwOS操作系统,针对低成本的树莓派开发板。这使得学生可以在相对简单的系统上进行实验,使用一种极简且易于理解的操作系统。采用低成本开发板具有优势:如果出现问题,重新开始的成本较低且操作简单,无需担心损坏或破坏更重要的桌面计算机或工作站。此外,当学生进入高级内存课程时,他们通常已经具备树莓派类开发板的使用经验,因此至少已有一定的基础知识。
3 相关工作
现有的教学用操作系统有很多。我们的系统不同寻常之处在于,我们希望使其易于探索内存层次结构中的现代发展。
3.1 教学用操作系统
安德鲁·S. Tanenbaum 的 Minix [35, 36] 是一种类 UNIX 操作系统,用于教授操作系统设计。他还编写了 Amoeba,旨在用于探索分布式系统 [37]。另一个流行的教学用操作系统是麻省理工学院开发的基于 UNIX第六版的xv6[26]。虽然存在一个树莓派版本的xv6[18],但它目前尚不支持多核。麻省理工学院开发的另一个教学用操作系统是JOS,主要运行在x86系统上[25]。
Xinu [12]是一个教育用操作系统,最近已被移植到Beaglebone Black嵌入式开发板上。
NACHOS(Not Another Completely Heuristic Operating System)[10]是一个教学用操作系统,但它仅在MIPS处理器上运行。
Pintos [28]被设计为运行在x86硬件上的NACHOS替代品。目前有一个Re-Pintos[21]项目,计划将其移植到树莓派上。
3.2 裸机树莓派
有许多为树莓派编写的简单裸机操作系统。其中很多只是人们在该平台上进行实验,很少能达到具备多任务、文件系统和设备驱动程序的完整传统操作系统阶段。大多数系统是出于测试或好奇而编写,并未专门针对教育环境进行设计。
一个相当完整的嵌入式类型操作系统是用Free Pascal编写的 Ultibo [2],。虽然它具有相当全面的设备驱动程序支持,但其内存支持主要是设置缓存和虚拟内存,以便简单程序能够运行。
BakingPi [1] 是一个用于课堂教学的裸机操作系统开发套件。它通过一系列课程指导如何设置裸机树莓派操作系统,但在达到程序加载和多任务阶段之前停止。
对于大多数这些项目来说,虚拟内存只需设置到足以使缓存正常工作即可,然后便不再理会。它不像我们在 vmwOS 中尝试的那样,成为操作系统体验的一个核心部分。
4 树莓派架构
树莓派是由树莓派基金会开发的一系列低成本ARM开发板[30]。这些开发板最初设计用于教育市场,但也在其他领域取得了巨大成功。它们被电子爱好者广泛使用,并作为通用低成本计算的基础。尽管以当今的标准来看性能较低,但这些开发板完全能够用作桌面电脑,一种常见用途是构建小规模的低成本计算集群[11]。
自2012年首款树莓派发布以来,已经推出了大量树莓派型号,如表1所示。我们将重点
介绍树莓派3中的硬件,因为它已发布足够长时间,学生普遍在使用,而且它是一个64位系统,因此对我们希望进行的探索类型更具吸引力。部分型号的一些选定细节见表2。
4.1 树莓派 3
树莓派3B是树莓派系列中首款64位产品。最近发布的Pi 3B+ 主要改进在于散热性能,将ACT(活动)LED重新移回正常的 GPIO引脚,并升级至千兆以太网(仍受限于由USB2连接驱动)。在大多数讨论中,我们将主要描述Pi 3B(而非3B+)。
图1展示了树莓派3B的外观。
4.1.1 中央处理器。 Pi 3B中的中央处理器是博通BCM2837(也称为 BCM2710)。它是一款四核64位Cortex-A53 ARMv8处理器。其运行频率可达1.2吉赫兹,但在负载情况下常因散热原因自动降至600兆赫兹。
4.1.2 图形处理器。树莓派上的图形处理器是博通 VideoCore IV。BCM2835 系列最初设计为一个大型图形处理器,并在其旁边附加了一个 ARM CPU。因此,与大多数 ARM 架构不同,系统启动由图形处理器负责。图形处理器甚至运行自己的操作系统(ThreadX)。在 Pi 3B 上,图形处理器的性能可达 28.8 千兆浮点运算每秒,并具备内置的视频解码硬件。系统内存由图形处理器和中央处理器共享,内存分配比例在启动时设定。
GPU的架构并不广为人知。一些人已经开展了对GPU汇编语言的逆向工程工作[9, 16]。在博通聘请Linux开发者埃里克·安霍尔特开发一个功能完整的Linux驱动程序后,更多相关信息被披露给社区[22]。Linux支持四核处理器单元(QPU)接口,该接口可为计算提供一种简单的通用图形处理器计算(GPGPU)式 GPU访问方式[17, 27]。
4.1.3 内存层次结构。 该开发板包含1GB的LPDDR2 RAM。
关于树莓派平台的一个抱怨是内存相对较少。
| 模型 | ARMv6 5 | 12MB | Idle | 电源 Linpack |
|---|---|---|---|---|
| Zero型号 Zero-W型号 | BCM2835 BCM2835 | ARMv6 512MB ARMv6 5 | 12MB | 0.8W 0.6W |
| 计算节点 计算节点3 | BCM2835 BCM2837 | ARMv8 ARMv6 25 | 1GB 6兆字节 | 1.9W ? |
| 型号1A 型号1A+ | BCM2835 BCM2835 | ARMv6 512MB ARMv6 5 | 12MB | ? 0.8W |
| 1B型号 1B型号+ | BCM2835 BCM2835 | ARMv6 512MB | 2.7W 1.6W | |
| 型号2B (v1) 型号2B(v1.2) | BCM2836 BCM2837 | ARMv7 ARMv8 | 1GB 1GB | 1.8W 1.7W |
| 型号3B 型号3B+ | BCM2837 BMC2837 | ARMv8 ARMv8 | 1GB 1GB | 1.8W 2.6W |
CPU Arch RAM电源 Cost
表1:树莓派型号:CPU类型、成本以及空闲和Linpack负载下的功耗。标为未知的功耗是因为我们没有该类型的开发板进行测试。
| Pi Zero | Pi 1B+ | Pi 3B | |
|---|---|---|---|
| CPU Arch 速度 核心 Bits | BCM2835 ARM1176 1GHz 1 32 | BCM2835 ARM1176 700MHz 1 32 | BCM2837 ARMv8 1GHz 4 64 |
| GPU | VideoCore IV 250兆赫兹 | VideoCore IV 250兆赫兹 | VideoCore IV 300兆赫兹 |
| 内存 内存类型 一级指令缓存 一级数据缓存 L2缓存 | 512MB LPDDR2 16k 16k 128k(GPU) | 512MB LPDDR2 16k 16k 128k(GPU) 100MB(USB) | 1GB LPDDR2 32k 32k 512k 100MB(USB) |
| 网络 | none | ||
| Cost | $5 | $25 | $35 |
表2:部分树莓派型号的更详细规格
根据树莓派基金会创始人埃本·厄普顿的说法,这并不是因为芯片的架构(尽管SoC寻址块的设计使得以向后兼容的方式增加更多内存变得困难)。真正的原因在于当前RAM成本相对较高[31]。
一级指令缓存为32k、2路组相联、64字节宽,采用VIPT结构,伪随机替换策略,关键字优先。一级数据缓存为32k、4路组相联、64字节宽,采用PIPT结构,具有伪随机替换机制。两个缓存均受到错误检测与纠正保护。L2缓存为512k、16路组相联,主要作为牺牲缓存。具备硬件预取器以及软件预取指令。内存一致性采用MOESI协议。
内存管理单元支持多种页面大小。采用两级TLB:包含10个条目的微TLB和512个条目4路组相联的主TLB。此外还设有页表遍历缓存和IPA缓存(后者用于翻译虚拟机页面)。微TLB可配置为轮询或随机替换方式。
4.1.4 功耗。 树莓派最初是一款设计为通过USB-micro接口供电的开发板。因此,早期型号的功耗并未超过USB2.0连接所能提供的电量(500mA * 5V = 2.5W)。对于3B型号,建议使用2.4安电源,其功耗可能超过5瓦。表1列出了部分型号在空闲状态以及运行高性能Linpack(HPL)基准测试时的功耗测量数据。
4.1.5 散热问题。如前所述,该芯片封装最初设计为一块 GPU板,旁边附加了一个小型CPU作为辅助处理器。因此,用于降频的温度传感器位于GPU上方。随着多年来CPU性能的提升,这导致了问题:在高负载下,CPU可能在热量扩散到温度传感器之前就已过热。这引发了诸如型号3B在高负载下运行时崩溃的问题,例如运行高性能Linpack [32]。过热问题已在新的3B+型号中得到解决。
4.1.6 硬件性能计数器。 树莓派具有多种可用于架构探索的硬件性能计数器。与大多数现代CPU一样,所涉及的计数器因硬件代次而异。Pi3B 支持超过三十种不同事件,包括 TLB、一级指令、一级数据和二级综合指标。
4.1.7 硬件接口。 尽管这些接口不一定适用于内存实验,但SoC支持大量其他硬件接口。这包括I2C、串行外设接口、摄像头、GPIO、脉宽调制、高清多媒体接口、复合视频、USB、以太网、无线网络、蓝牙、串行端口和SD卡接口。更多信息请参见博通2835外设文档 [8]。
5 VMWOS 背景
vmwOS是我们机构为高级操作系统课程编写的一个操作系统。其最初的设计目标是允许在通用的高年级或研究生级别操作系统课程中进行动手编程。
在本课程中,学生将逐步实现各种功能。他们从第一周的闪烁LED开始,在后续的作业中逐步添加功能,最终完成一个有限的多任务操作系统。课程还包括一个开放式期末项目,学生可以探索之前作业中未涵盖的更高级的主题。
vmwOS 是一个完整的、可运行的操作系统,课程作业均基于此系统。虽然直接将 ARM 架构参考手册 和 博通外设文档 交给 学生 并让他们自行摸索可能听起来不错,但对于本课程的范围而言并不现实。因此,我们基于 vmwOS 代码提供了解决方案,以确保在某次作业中遇到困难的学生不会随着课程推进而彻底落后。
多年来,随着课程的讲授,vmwOS 已经积累了足够的功能,成为一个相当可用的独立操作系统。我们已经开始探索将其用于其他用途,包括本文的主题,即将其改编用于研究生级别的高级内存系统主题课程教学。
有人可能会猜测该操作系统的名称与虚拟内存或虚拟机有关,但实际上它是以主要作者姓名的首字母命名的,这一命名方式并不算谦虚。在启动后不久运行多任务演示时的系统截图如图2所示。
vmwOS的当前目标是提供一个完全可用的、多核、64位操作系统,能够提供对内存层次结构的高度可配置访问。作为一个额外的挑战,代码应保持足够简洁,以便可用于教授高年级操作系统课程。
5.1 vmwOS:当前状态
VMWOS 正在持续开发中,以下是该操作系统的当前状态。
64位支持
vmwOS最初是在最初的32位树莓派系统上开发的。目前它可以在所有型号的Pi上运行,但以32位模式运行。尽管Pi 3B配备了ARMv8 64位处理器,vmwOS目前仍在ARMv7 32位兼容模式下运行。升级到原生64位应该相对简单。所有的驱动程序工作已经完成,但仍有一些困难部分需要解决(包括将所有汇编语言代码转换为ARM64,而ARM64与ARM32汇编可能有很大不同)。
多核支持
多核支持已部分实现,有望在不久的将来完成。启动时,四个核心均已配置,并且通过进程间中断(IPI)实现的核心间通信已正常工作。剩余的任务包括确保所有地方的锁机制正确无误,以及使调度器具备多核感知能力。
虚拟内存支持
目前,VMWOS 激活了 MMU(内存管理单元)并设置了基本的内核/用户内存保护。然而,尚未启用页级别的完整虚拟内存功能。相反,页表使用粗粒度的 1兆字节“段”页面,并采用物理地址到内核地址的 1:1映射。在位于底部 16MB 的内核与其余用户空间之间存在内存保护,但没有进程间保护。这意味着内核目前的行为类似于无内存管理单元的Linux( ucLinux)[39]。二进制文件是位置无关的,进程之间的内存保护依赖于诚信机制。
调度器/多任务
该操作系统支持多任务,包括在后台运行作业( waitpid())。调度器采用简单的循环调度算法。如果没有就绪的作业,则运行空闲任务,通过wfi指令进入低功耗模式。系统定时器被设置为以64赫兹触发调度器。
等待队列
当进程在输入/输出上阻塞时,它会被放入等待队列中并进入睡眠状态。当输入/输出完成时,所有等待线程都会被唤醒。
内存分配
内核内存分配非常简单。有两个区域:用户和内核。内存以4千字节块的形式分配,采用首次适配法。空闲列表位图用于跟踪内存。
可执行文件
可执行文件使用二进制扁平(BFLT)文件格式[38]。代码首先被编译为标准的ARM Linux ELF可执行文件,然后使用一个内置的自定义工具将其转换为更简单的BFLT格式。尽管BFLT比 ELF更简单且更容易实现,但它支持一些更高级的功能,例如对运行时链接和共享库的有限支持。目前我们的操作系统尚不支持这些更高级的功能。
用户空间
操作系统的用户空间可执行文件使用C语言编写,并提供了一个非常简单的C库(vlibc)。该库为包含的程序提供了最基本的支持,这些程序包括一个简单shell以及各种系统工具和游戏。
虽然通用的类Linux C程序可以相对容易地移植,但存在一些限制可能导致移植困难(C库有限,变量/函数应声明为静态以避免使用GOT等)。
驱动程序
树莓派在SoC上支持大量设备,但目前我们的操作系统中仅有少数设备具有驱动程序。我们实现了控制台输出驱动程序,支持串行端口和帧缓冲。控制台输入通过串行端口支持,并可通过GPIO连接外部PS/2键盘适配器(目前不支持USB)。系统包含随机数生成器和温度传感器的驱动程序。通过GPIO的脉宽调制(PWM)功能实现了一个简单的蜂鸣声效果。目前唯一的支持的块设备是内存盘,但通过SPI驱动支持SD卡的工作正在进行中。
文件系统
目前唯一支持的文件系统是 romfs。该操作系统当前使用只读的 romfs 内存盘镜像启动。我们计划在不久的将来实现对 FAT 和 ext2 的支持。
5.2 vmwOS 挑战
编写vmwOS一直颇具挑战性,主要是由于缺乏文档。Pi硬件的说明见于BCM外设文档[8],而较新的Pi 3特性可以在 Quad-A7文档[40]中找到。ARMv7处理器的相关描述见于架构参考手册[3, 4],以及更具体的文档可以在Cortex-A53 相关文档[5, 6]中找到。尽管这些文档内容繁多,但往往最好的资源还是在官方树莓派基金会论坛[29]的“裸机”版块中提问。
挑战:启动
启动是第一个挑战。我们之前为较早的 Pi 型号编写了可用的引导代码,但最近的固件版本更改导致多核以虚拟机监控模式启动。这要求修改引导代码,使其首先切换回普通模式。
以前,系统信息通过旧的 Linux ATAGS 接口在启动时提供。最近,树莓派已过渡到使用设备树文件,这需要在启动过程早期运行完整的设备树解析器。
挑战:内存管理单元
在最佳情况下,设置MMU和页表也是复杂的。在树莓派上,必须在启用缓存之前启动MMU(以便将内存映射I/O区域标记为不可缓存)。在多核设置中,虚拟内存正常工作前需要正确设置大约20个不同的位。更大的挑战是正确设置这些位以实现核心之间的缓存一致性。其他问题也可能造成干扰,例如当某些核心意外地停留在虚拟机监控模式下而主核心却没有时会发生什么情况。这个问题在多核支持的启动过程中导致了大量的挫败感。
挑战:锁机制
在Pi3上,您需要使用加载链接/存储条件的ldrex/strex指令来实现锁机制。这些指令只有在缓存运行时才能工作,而缓存需要先启动内存管理单元(MMU)。这使得系统启动变得困难,因为在能够使用锁机制之前,上述所有组件都必须正常工作。在串行I/O控制台中实现正确的锁机制可能会很困难,特别是当您使用相同的例程来打印早期(缓存设置前)的启动消息时。
挑战:缓存刷新
ARM处理器提供了多种缓存刷新方式,一旦启用了多核支持,这些方式就变得至关重要。文档中记录的缓存刷新方法似乎并不总是有效。查找可用的缓存刷新代码的最佳来源是 Linux内核,因为这些代码已被证实有效,并且通常由ARM工程师编写。此外,树莓派与图形处理器之间存在复杂的关系,并通过邮箱接口与图形处理器通信时使用了各种不可缓存的内存地址范围。有时在这些交互之后也需要刷新缓存,而这一点又缺乏充分的文档说明。
6 建议的内存探索
我们的vmwOS工作的目标是为操作系统和内存层次结构的探索提供一个便捷的平台。以下是我们设置中可以研究的一些感兴趣的研究领域。
6.1 缓存实验
一个相对简单的探索主题是,当操作各种参数时,现代缓存层次结构的行为表现。
一个值得探索的简单问题是现代系统在缓存子系统不同参数下的行为表现。并非所有硬件都支持低级缓存操作,而在大多数其他操作系统中,一旦系统启动并运行,更改这些参数可能非常困难甚至不可能。
6.1.1 禁用缓存。 各种树莓派型号均支持禁用缓存。事实上,在某些型号上,固件在启动时不会启用缓存,因此由操作系统负责启用它们。在较早的型号上,一级数据缓存和指令缓存(以及相关的分支预测器)可以分别启用。
启用缓存可能会带来巨大的性能差异。在较早的型号1A+ 系统上,通过memset()基准测试得到的差异示例如表3所示。
这些结果来自布置给学生的作业,他们需要在启用和禁用缓存的情况下对各种memset()实现进行计时。学生通常会对性能的大幅提升感到惊讶。他们还需要自己实现一个memset(),以尝试是否能超过所提供的版本。
在多核模式下运行时,此类实验更加困难,因为互斥锁使用的ldrex / strex锁机制依赖于缓存处于启用状态。尽管仍有可能进行实验,但前提是必须禁用多核模式。
6.1.2 禁用预取器。 各种 Pi 型号均支持禁用/启用硬件内存预取器。此外,某些预取参数可以进行调优。
我们之前曾尝试在其他ARM开发板(如Cortex-A9熊猫板)的Linux系统下禁用预取器,并遇到了许多困难。有一次,预取器被禁用后,当我们询问情况时,被告知该特定设备上的预取器硬件存在故障。在其他情况下,尝试通过Linux设置底层 CPU寄存器来禁用或启用预取器时,由于固件通过TrustZone 安全设置在启动后禁止更改该设置,导致操作被阻止。
我们希望在树莓派上测试预取器的设置,期望其比我们尝试过的其他开发板更具可配置性。这些实验还可以涉及树莓派上可用的ARM软件预取指令。
6.2 虚拟内存实验
虚拟内存是一个复杂的话题,即使是计算机架构师也往往理解得不够透彻。我们发现,与其依赖现有的操作系统来完成所有工作,不如尝试从零开始搭建虚拟内存,这样可以学到更多知识。
6.2.1 更改页面大小。 vmwOS目前仅支持1MB段式分页,但一旦我们增加对更细粒度分页的支持,就应能够对多种页面大小的权衡进行有趣的探索,甚至实现透明大页(THP)。
Cortex A53 支持 4KB、64KB、1MB、2MB、16MB、512MB 和 1GB 页面大小。
此外,一旦完成64位支持,就可以探索并以非传统方式利用较大的虚拟地址空间(目前为48位)。一个示例是研究用于安全性的地址空间布局随机化的开销。
6.2.2 页面保护。ARM页表支持常规的保护集,包括不可执行页面。Cortex-A53支持内核非执行支持,因此无法将内核执行重定向到用户空间代码。测试启用此安全特性的可行性将十分有意义。
6.2.3 独立一致性区域。 在 Cortex-A53 上,你可以独立配置核心,使其不参与缓存一致性。理论上,这可以允许不同区域拥有主内存的独立视图。研究如何有效利用此功能将非常有趣。此外,可以通过页表项中的一个位在每页级别上指定缓存一致性。
6.2.4 TLB 性能。 TLB 是多级的,并支持使用地址空间标识符(ASID)来避免上下文切换时刷新TLB 的成本。可以在此处进行实验,以了解使用此功能时的权衡。
此外,某些 Pi 型号上的 TLB 是可配置的,并且页面替换算法可以动态更改。
6.3 DRAM
Pi3B 配备了 1GB 的 LPDDR2 内存。由于内置的内存控制器和焊接式DRAM芯片(在某些情况下它直接与处理器绑定!),我们在可做的事情上受到一定限制。
6.3.1 DRAM 配置。固件在启动时配置DRAM参数。该固件只是启动SD卡上的一个文件,由图形处理器在启动时运行,已有研究人员逆向工程了其部分工作原理。理论上,有可能重写固件以任意设置DRAM的配置,从而对时序进行实验。
6.3.2 Rowhammer。 通过底层操作系统访问内存,研究触发Rowhammer [20] style内存损坏的难度将十分有趣。由于我们的内存采用1:1虚拟/物理映射,并且能够禁用缓存,这应该会使实验更容易实现。
6.4 非易失性随机存取存储器
使用易失性RAM的操作系统通常处于潜在故障的持续状态中。任何微小的电源波动都可能擦除内存,导致数据永久丢失。这会增加希望安全写入内存的任何例程的开销,因为即使脏数据仍驻留在内存中,也必须将其写回磁盘才能保存。最近人们越来越关注通过在系统中使用非易失性RAM(NVRAM)来避免此问题。尽管这不一定是一种新发展(使用磁芯存储器的老式系统就表现得如此),但现代系统通常假设系统内存是易失性的,并且在断电时会丢失其内容。
现代操作系统在设计时并未考虑非易失性随机存取存储器,因此可能无法最优地处理系统中添加的非易失性随机存取存储器。例如,Linux开发者们已就如何支持非易失性随机存取存储器进行了多次讨论,旨在避免内存的冗余复制,或无需修改或创建新的文件系统 [13]。
关于如何通过操作系统呈现非易失性随机存取存储器存在各种担忧。一种方法是直接在其之上实现一个文件系统,但目前文件系统假设通过各种总线对磁盘的访问具有高延迟(而非直接内存连接)。操作系统文件系统层未针对高速访问进行优化,可能会浪费非易失性随机存取存储器的低延迟优势。另一个问题是,通常在访问来自磁盘的数据时,会将数据复制到内存中(例如磁盘缓存中,或仅为了加载程序以执行)。这些额外的复制在非易失性随机存取存储器系统上没有任何好处,因此应修改操作系统,通过关闭磁盘缓存以及允许二进制文件就地执行来避免这些复制。
非易失性随机存取存储器的最后一个问题是一致性,即确保处理器写入非易失性随机存取存储器的值能够在崩溃情况下正确存储。处理器缓存会缓存内存访问,因此需要显式的缓存刷新指令,以确保数值被写入非易失性随机存取存储器。
所有这些非易失性随机存取存储器与操作系统之间的交互都可以通过 vmwOS进行研究,但受限于树莓派系统本身无法直接支持非易失性随机存取存储器。我们建议通过软件模拟非易失性随机存取存储器以实现此类实验。
6.4.1 更多关于非易失性随机存取存储器的背景。非易失性随机存取存储器(NVRAM)是一种即使断电也能保留存储数据的存储介质,与传统的静态随机存取存储器(SRAM)和动态随机存取存储器(DRAM)不同。直到最近,尚无任何非易失性随机存取存储器选项能够在较大容量方面与SDRAM竞争,但现在已有几种技术即将进入消费市场展开竞争。这些类型的非易失性随机存取存储器包括相变存储器(PRAM)、铁电随机存取存储器(F-RAM)和磁阻随机存取存储器(MRAM)。这些技术各自存在一定的缺点,但其价格有望与传统SDRAM相竞争。同时,它们在容量、写-擦周期和速度方面也将具备竞争力。非易失性随机存取存储器在消费领域的普及将为计算技术带来有趣的优势,并将引发软件和操作系统在内存管理方式上的重大重新设计。
6.4.2 使用SPI闪存模拟非易失性随机存取存储器的缺点。当前使用的硬件是树莓派3 Model B+;被选中仅仅因为它是最新的树莓派型号。VMWOS在所有研究所需方面都支持Pi 3B+。
非易失性随机存取存储器目前难以获得,尤其是容量超过几兆字节的型号,且通常使用专用总线,而树莓派等设备无法提供外部连接支持。为了模拟非易失性随机存取存储器,采用通过串行外设接口(SPI)连接的微型SD卡作为后端存储,以提供永久性的非易失性存储。这种方法作为仿真工具非常实用,因为其成本低、易于连接且容易获取。
我们使用Adafruit SPI microSD转接板将SD卡连接到系统,如图3所示。SD卡有一个启动命令序列,可用于将卡设置为SPI模式,且必须在100-400kHz的时钟频率下完成。随后可以发送命令以检查SD卡的类型和版本,从而验证卡所支持的功能和命令。
使用SD卡模拟非易失性随机存取存储器存在各种缺点。
挑战:缺乏字节寻址能力
新型非易失性随机存取存储器技术的一个共同特点是具有字节可寻址能力。这使得在操作当前不必要的数据时开销非常小。然而,通常情况下SD卡只能以块为单位进行读写,常见的块大小为512或1024字节。这意味着如果需要更新单个字节,则必须先读出整个512字节的块,修改后再写回。如果将这些频繁写入RAM中小的局部变量的行为直接映射到SD闪存上,则可能导致巨大的开销和浪费。
挑战:速度
微SD存储的一个缺点是其速度明显慢于SDRAM,也慢于正在模拟的NVRAM。例如,DDR4 PC4-25600 SDRAM是消费级计算机中常用的一种内存,其理论最大带宽为25.6GB/s。当前测试中,微SD通过SPI以117.37千赫兹的时钟速率进行通信。忽略发送命令的开销,这提供了理论上的最大带宽为14.671KB/s,意味着SDRAM理论上快1.75×10⁶ 倍。将SPI时钟速度提高到25MHz(这通常是与SD卡进行高性能SPI通信的上限),SDRAM仍然快8192倍。
访问延迟也是如此。大多数SD卡必须以512字节块进行读写。读/写一个字节的延迟最小为命令大小加上读取一个字节的时间,最大为命令大小加上读取512字节的时间。在117.37千赫兹下,这相当于477微秒-35.3毫秒。相比之下,SDRAM的平均延迟通常仅为几纳秒。
挑战:直接内存映射
在通用计算中,中央处理器可以直接读写内存中的数据。这种方式开销低且速度极快。当使用微型SD卡作为非易失性随机存取存储器时,数据无法由中央处理器直接访问,而必须先读入 SDRAM。这会增加使用非易失性随机存取存储器的进程的开销,并提高代码复杂性。
另一个问题是关于写操作的处理。一种方法是将所有RAM标记为只读,并利用虚拟内存子系统捕获写操作,然后在此时将内存数据同时写入SD卡和内存(或者 alternatively,缓存写操作,在方便时或积累足够多的脏内存后再写入)。
挑战:有限的读写次数
计算系统或多或少会持续访问内存,无论是为了获取指令还是加载和存储数据。存储数据令人困扰,因为基于闪存的存储普遍存在写入周期限制。某个扇区的写入周期越多,其发生故障的可能性就越高。对于金士顿MLC闪存,额定写入周期为3000次。在SPI以117.37千赫兹时钟频率达到最大带宽的情况下,完成一个512字节区域的写入仅需105.9秒。一张2GB SD卡大约包含3906个可用的512字节区域,因此即使采用磨损均衡技术将写操作均匀分布到所有可用空间,连续写入也会在114.9小时内使其完全耗尽。
最大的问题不一定在于完全失效,而在于随着扇区故障的增加,发生不可恢复的数据丢失的可能性会大大增加。这可能导致系统不稳定以及重要数据的丢失。基于SD卡容量和写入速度的随时间推移的扇区故障率如图4所示。
6.4.3 提出的SD/NVRAM内存仿真。在操作系统中,NVRAM有多种实现方式。我们考虑采用混合NVRAM/DRAM接口,其中系统同时具有DRAM和NVRAM。用户进程可以请求将NVRAM的某些区域映射到其地址空间中,之后这些区域即可像普通RAM一样被访问。我们通过虚拟内存系统来模拟这一机制,并确保所有写访问都被备份到SD卡中。重启后,操作系统会恢复这些内存区域,进程便能再次找到它们。
内存分配表的损坏可能导致所有存储的非易失性内存损坏。因此,实现了一种安全保护机制,向内存分配表添加了一个额外的512字节缓冲区和一个512字节信息块。每次向内存分配表写入数据时,首先将数据写入缓冲区,然后在信息块中设置一个位,表示内存分配表即将被写入,并将要写入的地址添加到信息块中。只有当内存分配表的写入操作成功完成后,信息块中的该位才会被清除。如果写入操作在部分字节已写入但未全部完成时失败,或者内核启动并读取信息块时发现该位仍被设置,则表明先前的写入操作可能未完成。
如果设置了信息块和写入位,则内核可以在不损坏数据的情况下恢复。
虽然这不是唯一的故障途径,但确实是一个被排除的重要风险。进一步的保护措施包括备份内存分配表,但根据已分配数据的进程数量,该表可能会变得非常大。这些问题在文件系统的开发中已经得到了广泛研究,因此实现一个真正的文件系统将提供更高的可靠性。作为折衷方案,已经开发出针对 NVRAM的特定文件系统,例如NOVA [44],,旨在 NVRAM系统中实现最佳性能。
6.4.4 用户空间程序的实现。非易失性随机存取存储器的SD卡模型依赖于SPI通信,而SPI在vmwOS操作系统中是作为驱动程序实现的。这导致在启动期间将NVRAM用于内核内存时会遇到困难,但可以轻松地将其用于用户空间程序。每当用户空间程序需要从NVRAM读取信息时,都会将512字节读入SDRAM中的本地缓冲区。这相较于SDRAM会产生开销,但如果忽略本地缓冲区的使用,则很容易看出其与未来如何利用NVRAM的方式相似。
6.5 其他潜在研究领域
6.5.1 功耗与能耗。功耗与能耗在现代CPU和内存设计中变得越来越重要。遗憾的是,树莓派并未提供一种简便的方式来监控能耗,而这对本文提出的任何研究来说都将是一个极大的补充。我们已对树莓派进行了多次功耗/能耗研究,但这些研究需要通过检测电阻手动对输入电源连接进行监测,并借助外部设备记录功耗。
树莓派支持动态电压频率调节。使用该功能并观察其对内存层次结构性能的影响可能会很有趣。但遗憾的是,Pi硬件上的DVFS接口缺乏完善的文档说明。
6.5.2 硬件性能计数器。 各种 Pi 型号均支持硬件性能计数器,包括多种与缓存和 TLB 相关的事件。在系统运行期间可以读取这些计数器,并可根据内存系统行为的实时反馈动态优化系统运行。
6.5.3 GPU.树莓派拥有一个强大的图形处理器。它与中央处理器共享主内存,两者之间的通信通过邮箱接口进行。尽管 Linux通过“QPU”接口支持GPGPU风格编程以及完整的硬件加速3D图形支持,但该图形处理器的文档资料并不完善。
如果能够将GPU/CPU组合更像一个异构系统来对待,并围绕这一概念设计操作系统,那将非常有趣。其中一个难点在于,与一些较新的高端GPU设计不同,该GPU无法参与缓存一致性。另一个主要障碍是缺乏底层GPU文档,因为目前大部分文档都是通过逆向工程获得的。
6.5.4 虚拟化/管理程序。Cortex-A53 具备完整的虚拟化支持,这可能会以复杂的方式与内存层次结构。该系统为虚拟机的实验提供了低成本的基础。
6.5.5 系统调用开销。目前所有 Pi 型号中使用的中央处理器(ARM1176、Cortex-A7、Cortex-A53)均为顺序执行架构,因此不会受到近期熔断和幽灵漏洞 [23] 的影响。我们仍然可以研究各种缓解方法的开销,特别是那些涉及改变缓存行为或将内核移至独立地址空间的方法。
此外,对于熔断类修复,大部分开销出现在系统调用时。尝试使用其他用户/内核通信方法会很有趣,这些方法可能比传统系统调用接口的开销更小。
6.5.6 旧版Pi功能。 各种较早的树莓派型号及其ARM1176 CPU具有一些在较新系统上找不到的有趣功能。这可以提供极具吸引力的研究领域,尤其是如果我们像你们一样,手头堆积着大量闲置的旧型号设备。
一个有趣的功能是提供了16kB的紧耦合内存(TCM),可作为快速暂存存储器使用。树莓派上现有的其他操作系统似乎并未支持此功能。在旧版CPU上发现的另一项功能是能够禁用分支预测器、配置硬件预取器行为以及更改TLB替换策略。
6.6 错失的机会
现代高端CPU,特别是x86架构的CPU,具备一些很有趣可供实验的功能,但树莓派上的ARM核心并不支持这些功能。
这包括加密内存和硬件边界检查等功能。通过仿真层模拟支持(例如我们对NVRAM支持所做的那样),仍有可能在这些领域进行实验。
另一个领域是添加其他内存类型。我们受限于开发板提供的DRAM。如果能够通过某种方式提供自定义内存控制器 (可能通过现场可编程门阵列实现),并尝试新颖的DRAM配置,将会很有帮助。但目前在不进行大规模侵入式重新设计的情况下,该开发板尚不具备此能力。
7 结论与未来工作
我们介绍了vmwOS,这是一个在低成本树莓派系列嵌入式板卡上运行的简单教学用操作系统。我们计划在高级操作系统课程中使用该操作系统,以介绍现代计算硬件中内存层次结构的各个方面。大多数操作系统与现代CPU中的内存管理系统存在极为复杂的交互,而我们希望保持操作系统的简洁性,以便更易于探索其底层接口。
我们计划继续扩展vmwOS,使其在尽可能保持简洁的同时,成为一个更完整的操作系统。目前最紧迫的需求包括:完整的多核支持、64位支持、完整的读写文件系统支持以及块设备支持。一旦这些功能全部实现,vmwOS将成为教授学生现代存储器层次结构的理想平台。
vmwOS 的所有代码都可以在我们的 git 仓库中找到: https://github.com/deater/vmwos.git
52

被折叠的 条评论
为什么被折叠?



