Page 510 - 《软件学报》2024年第4期
P. 510
2088 软件学报 2024 年第 35 卷第 4 期
配器运行的系统环境考虑在内. 本文通过系统设计实现了一种低延迟的无锁/无等待内存分配器 wfslab. 该分配器
使用两种方式减少内存请求延迟.
wfslab 基础层使用无锁/无等待数据结构和算法, 在处理小内存分配时使用无等待分配算法, 而在处理大于
64 KB 的大内存时使用分离适配的无锁分配算法. 在高并发系统中, 核间同步方式往往会成为系统瓶颈. 为了降低
同步开销, 开发者通常在竞争激烈的数据结构中使用无锁技术. 针对高并发系统的内存分配器的设计同样可以使
用无锁数据结构优化并发性能, 降低内存请求延迟. 无锁技术能够保证所有竞争线程中, 至少有一个线程能够取得
进展. 然而, 使用无锁数据结构有可能会导致线程饥饿, 因此在时间敏感的应用场合通常要求能够保证无饥饿的无
锁, 即无等待 [39,40] . 使用无等待数据结构好处是并发执行过程中所有线程的执行时间是有上界的, 这有助于减少内
存请求的延迟.
wfslab 系统接口层使用线程私有堆和透明巨页机制. 向操作系统申请内存页必须通过系统调用. 一方面, 系统
调用可能会触发操作系统内核的调度行为; 另一方面, 现代操作系统分配给用户的内存页通常是虚拟的, 当进程读
写该内存页时, 操作系统产生缺页中断, 在缺页中断的处理过程中操作系统才会为用户真正分配物理页. 这些操作
系统的行为可能会造成内存请求延迟的增加. 为此, wfslab 使用线程本地的堆, 尽可能减少向系统请求内存页的次
数, 同时使用透明巨页机制降低 minor 缺页中断发生次数. 此外, 使用透明巨页也有助于减少硬件 TLB 未命中的
概率, 降低访存延迟.
wfslab 分配器结构的抽象模型可表示为:
mmap_heap(faa_heap_growth=1, threadlocal_heap_size=256MB, huge_page=1)::segfit_lf(sizeclass=log2b,
size_handle=[65536, SIZE_MAX))::slab_wf(sizeclass=prime, slab_size=64KB, tlslabs=40, size_handle=[0,
65536))::malloc_socket.
4 实验分析
与 HeapLayer 相比, 榫卯内存分配框架一大改进是提供额外的策略组合与定制. 这为构造内存分配器提供了
更多的自由度. 本节的实验将使用 tlsfcc, hslab 与 wfslab 运行内存分配器基准测试, 通过与多个通用和专用内存分
配器对比来说明榫卯框架有效性.
4.1 实验环境与设置
实验使用的硬件平台包括一台 8 核 x86/64 设备和一台异构 8 核 aarch64 嵌入式设备, 其硬件规格与软件环境
的具体说明如表 3 所示. 在两个不同体系结构的平台进行实验是为了说明榫卯框架的可移植性和兼容性. 在实验
平台的系统参数设置上, aarch64 平台的 Linux 内核启用了 EAS (energy-aware scheduling, 能量感知的调度) 和
DVFS (dynamic voltage and frequency scaling, 动态电压与频率调整), 其中 DVFS 功能会根据工作负载动态调整核
心频率, EAS 会根据当前负载将任务动态迁移到不同的异构核心. 为了减少动态频率调整对实验结果稳定性的影
响, 本文在两个实验平台均开启了 performance 频率策略, 强制操作系统内核使用最大核心频率运行负载. 此外, 由
于 aarch64 平台的 Linux 内核没有启用透明巨页支持, wfslab 使用透明巨页请求实际上获得到只是 4 KB 的内存页.
表 3 实验平台说明
配置 x86/64实验平台 aarch64实验平台
CPU型号 AMD Ryzen 3700x Qualcomm Snapdragon 888+
CPU核心数 8核16线程 (SMT开启) 异构8核8线程
CPU组成 分为两个CCX簇, 每簇4核4.2 GHz 1x Cortex-X1 3.0 GHz, 3x Cortex-A78 2.4 GHz, 4x Cortex-A55 1.8 GHz
Cache 每簇共享16 MB L3 cache 共享4 MB L3 cache
内存 16 GB DDR4-3800 MHz 12 GB LPDDR5-3200 MHz
操作系统 Linux 5.15.12 / Fedora 35 Linux 5.4.86 / Android 12 / Ubuntu 21.10运行在container中
编译器 GCC 11.2.1 / Clang 13.0.0 GCC 11.2.0 / Clang 13.0.0