标题中文释义:利用 LAKE 实现机器学习辅助内核
作者:Henrique Fingler et al.
会议:ASPLOS '23
GitHub库:https://github.com/utcs-scea/LAKE
作者改过的内核代码:https://github.com/utcs-scea/LAKE-linux-6.0
Archived?:https://zenodo.org/records/7277139和https://zenodo.org/records/7277147
分享用PPT:【免费】TowardsaMachineLearning-AssistedKernelwithLAKE内容介绍资源-CSDN文库
实验环境
所有评估都是在一台服务器上完成的
环境 | 版本 |
Ubuntu | 22.04 |
Linux内核 | 6.0,默认不支持浮点运算,作者修改过的 |
CUDA driver API | 11.0 |
TensorFlow | 2.4.0 |
Keras | 2.2.5 |
设备 | 配置 |
CPU | 16 核 Intel Xeon Gold 6226R |
内存 | 376GB DDR4 |
GPU | NVIDIA A100 |
NVMes | Samsung 980 Pro 1TB (PCIe 4.0) |
ABSTRACT
我们猜想,ML 可以更好地管理内存管理、进程和 I/O 调度等子系统的权衡空间,而这些子系统目前依赖手工调整的启发式方法来提供合理的平均性能。
我们探讨了在五个内核子系统中用 ML 驱动的决策取代启发式方法的问题,并考虑了对内核设计、共享操作系统级组件和访问硬件加速的影响。我们找出了障碍,解决了挑战,并描述了 ML 在内核空间所能提供的优势的权衡。
我们发现,使用 GPU 等专用硬件对于吸收ML 决策所需的额外计算负荷至关重要,但内核空间中加速器的可及性较差(poor accessibility of accelerators in kernel space,加速器在内核空间的可访问性差),这是一个障碍。
我们还发现,ML 和加速对操作系统的好处取决于子系统、工作负载和硬件,这表明在内核中使用 ML 将需要框架来帮助内核开发人员在新的权衡空间中进行导航。
为了应对这些挑战,我们建立了一个名为 LAKE 的系统,用于支持 ML 并在内核空间公开加速器。
LAKE的功能:
-
LAKE includes APIs for feature collection and management across abstraction layers and module boundaries. (跨抽象层和模块边界的特征收集和管理的应用程序接口)
-
LAKE provides mechanisms for managing the variable profitability of acceleration, and interfaces for mitigating contention for resources between user and kernel space. (管理加速可变收益的机制、缓解用户空间和内核空间之间资源争用的接口)
1.INTRODUCTION
硬件设备爆炸给OS带来了压力
操作系统内核包含管理这些资源的子系统,如内存管理、I/O 、进程调度、文件系统
目前依靠启发式方法来处理对性能至关重要的复杂权衡空间,这些启发式方法是通过观察系统行为并结合内核开发人员的经验开发出来的,旨在提供合理的平均性能。
本文希望可以用ML的方式替代这些启发式方法
虽然有人提出了操作系统子系统中的 ML 支持策略,如 CPU 负载均衡 [16]、文件系统预取 [11、26、49]、I/O 延迟预测 [32]、CPU 时钟和功耗控制 [60、82] 等 [32、46、71、82、87],但以前的工作仅侧重于展示 ML 对单个子系统的潜在益处。我们将重点放在将ML 决策集成到操作系统内核所带来的系统挑战上。
1.五个子系统
本文研究了五个子系统:process scheduling, memory management, and others.
-
进程调度(Process Scheduling):负责管理 CPU 核心上进程的执行顺序,确保合理分配 CPU 时间,以优化系统性能。
-
内存管理(Memory Management):涉及内存分配、回收和优化,以确保系统高效地使用内存资源。
-
I/O 调度(I/O Scheduling):管理数据的输入输出操作,优化存储设备的访问,以减少延迟并提高吞吐量。
-
文件系统预取(Filesystem Prefetching):预测用户空间应用程序的未来 I/O 访问模式,提前加载数据到内存中,以减少访问延迟。
-
CPU 时钟和电源控制(CPU Clock and Power Control):管理 CPU 的时钟频率和电源状态,以平衡性能和能耗。
2.三个面临的挑战
-
C1:使用专用硬件(如GPU/TPU)对于减少ML算法对性能的影响至关重要,但内核空间中加速器的可访问性差是一个采用障碍。当加速器是I/O附加的时,加速卸载会引入额外的开销,并可能产生用户空间和内核空间使用加速器的新形式的争用。
-
C2:由于硬件加速必须摊销数据传输成本,所以ML的加速好处是子系统、工作负载和硬件依赖的。(加速效果依赖于子系统、工作负载和硬件)
-
C3:存在抽象层边界和跨层数据共享需求之间的基本紧张关系,以暴露用于训练和推理的特征。
然后就是简短的说怎么解决的
3.LAKE的效果
LAKE为内核空间中的ML支持的子系统提供了高效的硬件加速,可以通过争用管理减少内核的CPU利用率,并避免对用户空间应用程序的性能降级。
例如,LAKE为ML辅助的I/O延迟预测提供了性能优势,将推理时间减少了高达95%,并且ML驱动的负载平衡推理速度提高了高达3.1倍。
我们评估了GPU加速的文件系统加密,发现相对于AES-NI,潜在的读取吞吐量增加了高达62%,并且CPU利用率降低了高达64%。
2.BACKGROUND
讲了OS Kernels and ML、Accelerators,不重要
3.MOTIVATION
这部分内容是论文的“动机”部分,它主要讨论了为什么作者们要开发一个名为 LAKE 的系统,以及他们在将机器学习(ML)集成到操作系统内核中时遇到的挑战和考虑。主要说了两个部分:
1.争用和性能变化
图1:图 1 展示了当 ML 辅助内核和计算绑定用户进程共享 GPU 时(争用GPU),争用引起的性能下降
不争用和争用的分别情况:用户空间的性能下降高达 68%。
图中的曲线展示了用户空间进程在不同时间点的性能(以每秒处理的页面数表示)。在T0时刻,用户空间进程开始使用GPU。在T1时刻,内核空间的ML组件开始与用户空间进程争用GPU资源。在T2时刻,又有一个ML组件加入争用。随着争用的增加,用户空间进程的性能显著下降,这表明了内核和用户空间之间的资源争用可能导致性能下降,甚至可能影响服务质量。
2.Data movement数据移动
从内核空间调用用户空间应用程序接口(通常通过向上调用完成)需要将数据从源上下文转储和复制到用户空间进程,并在完成后将结果和修改后的缓冲区复制回来。
这可能导致用户-内核边界上的冗余数据传输和不必要的同步,并带来严重的性能损失(第 6 节)
由于没有向加速器传输数据的内核级接口,内核级数据缓冲区必须先复制到用户空间,然后再使用 cudaMemcpy 等应用程序接口从加速器复制到用户空间。
·巧妙地结合内核机制,可实现自动数据调用,并消除用户-内核边界数据传输的双重缓冲。
4.KERNEL ACCELERATION WITH LAKE(LAKE的核心内容)
要在内核中使用复杂的、依赖加速器的机器学习算法,LAKE 必须提供基础设施,使未来和当前的内核空间应用程序能够使用加速器。这在目前是不可能的,因为加速器供应商提供的库是为用户空间设计的(由于目前的ML库一般都是为用户空间设计的,在内核中用ML算法很难)
在 LAKE 中,让加速器访问内核空间的核心是一个 API 远程系统,它将任意 API 暴露给内核子系统。LAKE 公开的 API 由用户空间的进程通过向上调用来执行。(LAKE给内核空间API)
技术设备:NVIDIA GPUs and CUDA
1.LAKE设计思路,结构体系
LAKE 有三个主要组件:内核侧 API 提供者(lakeLib)、批量数据内核-用户通信链路(lakeShm)和实现 API 的用户侧守护进程(lakeD)。
-
lakeLib 是一个内核模块,它将诸如供应商的加速器用户空间库之类的 API 作为符号公开到内核空间。该模块有一个与内核空间要支持的 API 同名的函数。(内核空间的模块)
-
lakeD 是一个用户空间守护进程,负责监听来自 lakeLib 的命令,对其进行反序列化,并执行所请求的 API。该守护进程必须能访问供应商的库(如 cudart.so(NVIDIA CUDA 运行时库的一部分,它是 CUDA Toolkit 中提供的一个共享对象库(在 Linux 系统中以
.so
为文件扩展名)。CUDA 运行时库提供了一组 API,允许开发者编写能够在 NVIDIA GPU 上执行的程序。)),以实现 lakeLib 请求的 API。继续以 cuMemAlloc API 为例,此类 API 的命令包括一个字段,用于标识要执行的 API 及其参数:分配多少字节和用于存储新分配起始地址的指针。 lakeD 反序列化命令以获取这些字段,使用供应商的原始库执行 API,并通过与初始命令相同的通道发回结果:返回代码和 API 调用返回的指针。 -
lakeShm 是一个内核模块,为 lakeLib 和 LAKE 驱动的应用程序提供内存分配。通过 lakeShm 的 API 分配的内存经过优化,可用于内核空间应用程序和用户空间 lakeD 之间的数据传输。当 lakeD 启动时,同样的区域会映射到其进程中。虽然仍需要进行主机到设备的传输,但这使得内核模块和 lakeD 之间的内存移动实现了零拷贝。(LakeShm 可以消除传输数据的开销,原文见第六节,以及图6)
2.系统工作流程
LAKE API 远程系统的实现类似于 RPC 系统:lakeLib 向内核输出符号(存根),而 lakeD 则是处理传入请求的用户空间进程。由于延迟较低,两者之间的命令通过 Netlink 套接字传输。较大的内存传输则通过零拷贝共享内存机制完成。(原文内容在第六节,并且对于为什么使用Netlink ,作者比较了linux的几种方式的平均延迟,见Table 2)
step1.从内核到用户(Figure 2中的lakelib到lakeD)
step2.从用户到内核空间(Figure 2中的lakeD到lakeShm)
具体来说:
从内核空间到用户空间的穿越:
内核空间中的组件(例如,通过内核模块)需要执行依赖于硬件加速器的操作。
内核空间的代码(例如,
lakeLib
模块)通过上调用(upcall)向用户空间发送请求,这个请求包含了要执行的操作和必要的参数。用户空间的守护进程(
lakeD
)监听来自内核的请求,然后执行相应的操作,这些操作可能涉及到调用硬件加速器的 API(例如 CUDA API)。从用户空间回到内核空间的穿越:
用户空间的守护进程(
lakeD
)完成操作后,将结果发送回内核空间。结果可能需要通过共享内存(例如,通过
lakeShm
模块)传递回内核空间,以便内核空间的组件可以访问这些结果。
举例:考虑一个简单的应用程序,它在本地和 GPU 上分配内存,将本地数据复制到 GPU,并调用内核在 GPU 上进行一些计算。
将LAKE的应用程序可进行的操作分为三类:local operations(本地操作), API-remoted operations(API 远程操作) and copiable memory allocations(可复制内存分配)
-
本地操作:这些操作包括现有的内核功能和内核空间的内存分配。这类操作不需要远程控制,也不会被 LAKE 修改。例如,常规内存分配可通过调用内核内存分配器(如 vmalloc)来完成。
-
API 远程操作: LAKE 通过 lakeLib 向内核空间提供加速器 API。当应用程序调用加速器 API 时,执行流程会切换到 lakeLib 模块。一个足够大的命令缓冲区将被创建,以容纳 API 函数标识符(如数字)和所有函数参数。然后,该命令将通过类似套接字的通道发送到 lakeD。进入用户空间后,命令将被反序列化,并在加速器上执行所请求的 API。执行完成后,会创建一个带有返回值的返回命令并发送回去。执行 API 时产生的错误会转发给应用程序,应用程序必须自行进行错误检查。+
-
可复制的内存分配:应用程序使用的内存区域将被复制到加速器或从加速器复制到内存区域,应使用 lakeShm 进行分配,它提供了一个类似于 malloc 的函数。lakeShm 分配的内存区域是共享的,避免了内核空间和用户空间之间的内存拷贝。使用 lakeShm 本身并不能实现内核空间应用程序与加速器之间的零拷贝数据传输。
3.引入硬件加速器确保性能提升
在大量数据处理时使用GPU,数据量少时用CPU比较快,LAKE 允许在 CPU 和加速器之间进行即时切换
-
这种切换是通过自定义执行策略实现的,开发者可以使用 eBPF(扩展的 Berkeley Packet Filter)编写和安装这些策略。这些策略通过Towards a Machine Learning-Assisted Kernel with LAKE回调函数来指定何时使用加速器是有利的。
图3:一个ebpf程序举例,设置阈值选用CPU和GPU
4.高层次API
lakelib和lakeD之间
现有的机器学习库(如 Tensorflow [10])将复杂的机器学习功能抽象为高级应用程序接口(API),其简洁性使应用程序不愿直接使用 CUDA 运行时应用程序接口。尽管有可能,但我们不能强迫开发人员在 CUDA 中实现复杂且难以优化的算法。同时,将 Tensorflow 等庞大的库移植到内核也是不切实际的;这些库依赖于用户空间独占库,而且体积庞大。因此,我们必须为应用程序提供使用高级库的机制。
作者做了一些API,见Table 1,我们也可以自己加API:
上述API设计的原则:
1)尽量减少 ML 相关功能对性能的影响;2)在存在抽象和模块边界的情况下,实现简单、可能异步的特征向量捕获,并预测多线程代码的需求(例如,是否需要在锁定的情况下或在中断上下文中查询相关数据结构);3)简化在成批特征向量上调用推理的任务。
涉及的方面:
用于管理注册表(模型的命名组合,以及与内核子系统相关的特征向量模式)、管理 ML 模型、捕获特征以及调用分类器/推理。
添加API的两个步骤:向内核空间提供高级应用程序接口需要做两件事:在 lakeLib 中添加函数原型和在 lakeD 中实现其功能。
5.IN-KERNEL FEATURE REGISTRY
作者详细介绍了 LAKE 系统中的内核内特征注册表(in-kernel feature registry)的设计和实现
1.考虑表现
API通过内核操作以及精心的数据结构和应用程序接口设计,实现了第一个目标(最小开销,上面说的原则里面的第一个)。
ML 模型保存在文件系统中,并在启动时加载到内存中。加载和更新并不频繁,因此文件系统开销是可以接受的,但在推理时,内存中的模型对性能至关重要。特征向量存储在内存中的循环缓冲区中,大小根据指定的窗口参数而定,一般格式为 <numfeatures, kvpair*, ts_begin, ts_end>。kvpair* 是由无锁哈希表支持的从特征键到值的键值映射。我们考虑过在用户空间支持特征注册表,以避免在内核中引入敏感代码,但最终决定,用于特征捕获和访问模型进行推理的内核交叉会给关键路径带来过多开销。
2.registry of Schema
每个注册表都有一个模式registry,描述了特征向量的格式:具体来说,模式是从特征键(名称)到 <size, entries> 元组的映射,其中 size 是特征类型所需的字节数(例如 int 为 4 字节),而 entries 则为包含历史值的特征向量提供数组支持。LAKE 避免跟踪特征向量项的实际值类型,而是提供必要的容量,并将值视为未键入的字节。对于大多数特征类型,例如整数值,entries 为 1,这意味着向量包含一个标量值。当条目大于 1 时,特征是一个长度为条目数组,其中位于索引 0 的条目是最近的样本,而位于索引 1...(N-1)的条目是来自最近 N - 1 个特征向量的历史样本。我们发现,由特定值的最近 N 次测量组成的特征非常常见,因此为该习语提供 API 级支持是一种值得简化的做法。下面的案例研究(第 5.5 节)将举例说明该习语。
3.使用异步方式捕获特征
同步特征捕获(在调用推理之前询问相关数据结构):模块边界和锁定规则会使访问广泛分散的数据,不切实际
LAKE 利用异步 API 解决了这一问题:特点如下:
-
程序员可以在已维护仪器数据的代码站点进行简单调用,从而逐步建立特征向量。
-
寄存器依赖于无锁数据结构,可在任意内核线程上进行仪器调用,而无需额外的锁定规范。
具体捕获方式:该API支持特征捕获打开(调用 begin_fv_capture())的习例:当特征捕获打开时,可在任何线程上使用 capture_feature()捕获单个特征向量值,该功能会更新特征映射中给定键(kvpair)上的值。我们发现,通过 capture_feature_incr()支持特征值的增量更新,内核开发人员可以大大简化一些情况(见下文示例:第 5.5 节)。创建一个新的特征向量会设置一个开始时间戳(ts_begin),而提交则会设置一个结束时间戳(ts_end),从而最终完成捕获。
4.简化批量管理
性能(推理速度)和准确性的权衡,不同的应用场景可能对这两者有不同的需求
LAKE 的 API 允许开发者显式控制批处理大小,这对于优化机器学习模型的性能和准确性至关重要。通过调整批处理大小,可以在 CPU 和加速器(如 GPU)之间动态分配工作负载。
总的来说,这段内容强调了在 LAKE 系统中,内核开发人员如何通过 API 控制批处理大小和特征向量的管理,以及如何通过策略函数来优化硬件加速器的使用。
下面是具体的实现方法:
-
批量查询:
-
LAKE 的 API 允许通过时间戳
ts
查询特征注册表中的特定特征向量。使用get_features()
函数,可以获取时间戳在ts_begin
和ts_end
之间的第一个特征向量。如果查询时使用空时间戳,将返回循环缓冲区中的所有特征,形成一个批量。
-
-
批量确认和截断:
-
一旦特征向量被处理,可以通过调用
truncate_features()
函数来确认这些特征的消耗,并从注册表中移除它们。这对于管理循环缓冲区中的特征向量和维护其最新状态至关重要。
-
-
历史样本和特征值:
-
当注册表中的特征依赖于历史样本时(即
entries > 1
),LAKE 会在截断操作中保留最新的特征向量。这样做是为了确保系统能够正确地填充依赖于历史数据的特征值。
-
-
推理和分类器回调:
-
score_features()
API 调用一个由程序员定义的回调函数(使用register_classifier()
指定),以运行模型的推理。这个回调函数负责执行实际的机器学习模型推理过程。
-
-
策略函数和加速器管理:
-
register_policy()
函数用于指定一个策略函数,该函数由框架在需要管理硬件加速器使用时调用。这个策略函数可以根据当前的系统状态和性能指标来决定是否使用硬件加速器,以及如何优化资源使用。
-
5.一个举例
用于说明如何在实际的内核空间应用程序中集成和利用机器学习模型,以及如何通过特征注册表来管理和优化特征数据的收集和使用
案例:在使用并行和冗余存储系统(例如 RAID)的情况下,如何预测 I/O 延迟,进而提高吞吐量
方法:拒绝高延迟的 I/O 请求(使用上面提到的特征捕获,捕获延迟相关的特征),并将相同的 I/O 请求重新发送到不同的设备上。
并且提供了一些伪代码:两张图分别为在 I/O 请求发出和完成时捕获的代码
图 4:发出
图 5:完成
6.IMPLEMENTATION
1.讨论安全问题
意思就是是安全的,有一系列的安全措施
以下是这段的译文:
LAKE 引入了一个用户空间组件,将加速器暴露在用户空间,通过用户空间移动内核私有的数据。在 LAKE 中,用户空间守护进程是一个受信任的进程,它以根进程的身份运行,类似于任何其他与内核紧密集成的用户空间守护进程(如微内核中典型的用户空间内存管理器、调度器和文件系统,以及 Windows 等现代操作系统中普遍存在的用户模式设备驱动程序)。尽管守护进程不在内核模式下执行,但地址空间分离提供了防止泄漏的强大安全保证。不过,为了提供更多保证,用户空间守护进程(lakeD)可以被沙盒化,并使用 seccomp。LakeD 守护进程与操作系统的接口非常有限(它需要为 lakeShm 使用 ioctl 和 mmap,为 lakeLib 使用 netlink sockets,以及由 CUDA 运行时完成的系统调用)。虽然我们在这项工作中没有考虑侧信道,但 lakeD 可以扩展到使用安全的 GPU TEE,如 Graviton[79] 或 Telekine[35]。
2.源代码
git仓库见头上
7.EVALUATION
评估了 LAKE 系统的性能和实用性
用来评估的场景:
现有文献已经证明,在所有工作负载中,ML 都能提高决策质量。为了验证这些优势在 LAKE 引入硬件加速和组件的情况下是否依然存在,我们对 I/O 延迟预测进行了端到端案例研究,在最新硬件上重温了之前的工作 [32],展示了加速带来的额外优势,并描述了硬件演进对 ML 盈利能力的影响(第 7.1 节)。本节的其余部分将评估我们的基础架构在提供加速访问、提高 ML 决策性能、帮助管理竞争以及简化管理加速的可变盈利能力方面的能力(§7.2-§7.5)。
1.IO 延迟预测/IO 调度
与LinnOS
在另一篇论文中,有提高:
如果系统预测 I/O 速度较慢,则可通过向另一个存储节点发出重复 I/O 请求来减轻延迟惩罚 [32]。LinnOS [32] 展示了操作系统如何利用神经网络学习和推断每次 I/O 延迟。在原始论文中,LinnOS 将平均 I/O 延迟提高了 79.6%,其模型的准确率高达 97%。LinnOS 根据系统状态(如待处理的 I/O 数量和最近提供的 I/O 的延迟)使用阈值将 I/O 分为慢速和快速。
作者将 LinnOS 的纯 CPU 神经网络移植到了使用 CUDA 的 LAKE 内核模块中,并且在系统上进行了评估,分析了原始模型以及更复杂模型的优势。
图7:不进行 I/O 重路由(基线)、通过使用 CPU 的神经网络进行重路由以及通过 LAKE 使用 GPU 的神经网络的工作负载平均延迟。后缀 +1 和 +2 表示在原始两层神经网络的基础上增加了多少层。*迹线的生成反映了 [32] 中报告的特征。
图8:通过 LAKE 对使用 cpu 和 GPU 的不同批量大小的 I/O 延迟预测时间,包括数据复制延迟。后缀 +1 和 +2 表示在原始两层神经网络的基础上增加了多少层。显示了使用 LAKE 的原始 NN 和两个增强 NN 在不同批次大小的 CPU 和 GPU 上的推理时间。对于原始 NN 而言,当批量大于 8 时,使用 GPU 是有利可图的,这在具有高 IOPS 速率的系统中是可行的。例如,亚马逊 EBS[1] 中的配置固态硬盘支持 256k IOPS,这意味着 I/O 请求的平均到达时间为 4µs。在这种情况下,如果批量大小为 8,使用 CPU 在请求到达时进行推理将耗时约 120µs(CPU 上每次推理耗时约 15µs)。相反,我们可以等待 8 个请求到达(28µs),然后在 GPU 上以 58µs 的时间进行推理,总计 86µs,缩短了 28%。对于增加了一层和两层的增强型 NN,当批次规模分别大于 3 和 2 时,使用 GPU 是有利可图的。随着批量大小的增加,盈利能力也在增加。
2.页面热度分类/内存管理
使用机器学习(ML)优化多级存储系统中的数据放置问题,与Kleio
也是另一篇论文:
Kleio [19] 模拟了不同的页面调度器,并实现了基于 LSTM 的分类器,它比基于历史记录的解决方案做出了更好的决策 [58]。Kleio 是使用 TensorFlow 实现的,因此我们使用 LAKE 将其移植到内核模块中。
图 9: 显示了不同规模输入的推理时间。我们发现,通过 LAKE 使用 GPU 而不是 CPU 时,推理速度明显加快。在用户空间或内核空间运行 Kleio 时没有明显差异,因为 LAKE 的 API 远程系统的成本相对于执行时间来说可以忽略不计。有同步数据移动(在图中显示为 “LAKE (sync.)”)和无同步数据移动(显示为 “LAKE”)时
3.ML做负载均衡:MLLB/进程调度
原来的问题:CPU 内核之间的负载不均衡会导致一些 CPU 负载过重,而另一些则利用不足,从而损害系统的总体性能。 Linux 内核使用一种基于拉动的工作偷取机制来实现负载平衡,这种机制会在 CPU 之间移动进程的执行。先前的研究 [55] 发现,负载平衡启发式存在性能关键性缺陷,导致非最佳选择。
ML很有前途:ML 是一个很有前途的选择。由于存在大量可能的系统配置:调度组的组织、应用程序的执行模式(如许多短期应用程序或少数长期运行的应用程序)、NUMA 节点的数量及其内存距离,编写良好的负载平衡启发式算法变得更加困难。
面临困难:开发用于负载平衡的 ML 算法的主要困难在于收集数据,以便比较不同的算法结果,并估算加强 ML 模型的奖励。
使用多层感知器进行负载平衡,将 MLLB 的模型移植到 CUDA,并使用 LAKE将其置于内核模块中
图10:在批量大小可变的情况下,使用 MLLB 预测负载平衡决策所需的时间;只有当批次输入大于 128 个时,使用 GPU 才有利可图。目前拥有数十个 CPU 和每个内核多个进程的服务器可以轻松超过这一阈值:例如,2013 年之前的研究表明,90% 的谷歌服务器会同时加载多达 4500 个线程 [86]。
4.文件系统预取
按需从外存读取数据的速度可能比从内存读取数据慢几个数量级。预取块可减少等待设备存储所浪费的时间,并可将应用程序吞吐量提高 50%[70]。Linux 的固定超前预取策略(启发式的)会按顺序预取可配置的数据量。
知道自己的 I/O 不是顺序 I/O 的应用程序可以建议内核不要预取。(尽量选用顺序IO)
使用启发式方法高效预测应用程序的非顺序读取具有挑战性。通过收集应用程序 I/O 操作的统计数据,ML 算法可以学习应用程序的模式并执行定制的预取。KML [11] 使用预先训练好的神经网络,根据 I/O 模式对应用程序进行分类,其中每种模式都有一个最佳的预取读配置。在使用固态硬盘时,KML 可将 RocksDB 的吞吐量提高 2.3 倍。
通过 LAKE 将最初为 CPU 实现的 KML NN 移植到使用 CUDA 的内核空间模块。
图 11: 显示了对不同数量的进程输入进行分类所需的时间。在超过 64 个输入的批处理中,GPU 是有效的。我们相信,这一模型和文件系统可以扩展到行为分类和按文件配置(be expanded to classify behavior and configure readahead per-file)超前读取。
5.恶意软件检测
先前的工作 [18, 22, 42, 54] 可以通过使用 ML 分类器分析性能计数器和系统调用跟踪来检测恶意软件。J. Demme 等人[18]使用 K-Nearest Neighbors (KNN) 分类器准确检测了主机入侵,准确率超过 90%,误报率小于 10%。G. Kim 等人[42] 使用 LSTM 分析系统调用跟踪,进行基于异常的入侵检测,准确率大于 95%,误报率小于 5.5%。我们开发了一个内核驱动程序,它使用 KNN 分类器将用户程序分类为恶意或良性。
KNN 分类器使用的特征向量可以跟踪与目标恶意软件相关的系统调用频率和 PMU(性能监控单元)计数器。
例如,希望在野外暴露 Spectre 攻击[45]的内核开发人员可以使用 PMU 计数器,通过缓存未命中、页面故障和分支错误预测来跟踪微架构状态扰动。另外,希望检测系统调用 API 滥用情况的开发人员可以根据进程使用异常或可疑系统调用序列的频率对进程进行分类。
图 12 :使用 4096 次 K-Nearest Neighbors (KNN)查询,在包含 16,384 个参考点的数据库中,针对不同的输入大小(特征向量中的系统调用次数),预测一连串系统调用是否来自恶意软件所需的平均运行时间。
将每个样本中的特征数量从 1 个变为 1024 个,并根据其 16 个近邻对查询进行分类。与 CPU 的顺序执行相比,KNN 的 GPU 执行速度提高了约 1.5k× speedup,而通过 LAKE 从用户空间和内核空间使用 CUDA 的开销可以忽略不计:平均为 4.2%,最多为 5.6%。(使用LAKE后执行效率提高很多,并且引入的额外开销可以忽略)
6.用户内核争用
图1已经展示了性能下降的问题,LAKE 允许内核空间访问加速器,而不会降低同时使用加速器的用户空间进程的性能。
图 13: 展示了图3 所示的自适应竞争调解策略的影响。使用 I/O 延迟分类器(第 7.1 节)可避免与用户空间进程竞争 GPU。该策略使用加速器 API 被动监控加速器的利用率。一旦用户工作负载(GPU 加速的并行散列算法)开始执行,LAKE 就会检测到 GPU 资源的压力,并切换执行 CPU。 当用户进程终止时,LAKE 会收回 GPU。(T0 时,GPU 加速的 I/O 延迟分类器正在运行。T1 时,启动计算哈希值的用户空间进程。T2 时,用户空间进程开始在 GPU 上进行哈希计算。LAKE 会检测到 GPU 计算资源的竞争,并退回到 CPU。T3 时,用户空间进程终止。LAKE 检测到 GPU 未被争用,并将执行切换回 GPU。)
7.非机器学习领域潜力
就讲了文件系统加密解密方面,非常有潜力
强调了 LAKE 系统在非机器学习领域的应用潜力,特别是在文件系统加密方面的性能提升
这里是加密
论文中提到了使用 LAKE 系统对文件系统加密进行加速。具体来说,作者们修改了 eCryptfs 文件系统,使用 AES-GCM 替代了 CBC 模式,因为 AES-GCM 可以并行处理,更适合 GPU 加速。
-
图 14 :展示了使用 CPU、AES-NI 和 LAKE 实现的 eCryptfs 在不同块大小下的 I/O 吞吐量。
这里是解密
图 15 :显示了在 CPU 或 GPU 上解密一个 2 GB 文件的 CPU 和 GPU 利用率,文件块大小为 2 MB,解密过程中使用了原始的 eCryptfs 实现和由 LAKE 驱动的 eCryptfs 实现(第 7.7 节)。CPU 和 AES-NI 使用内核 CPU 利用率进行测量。LAKE 可分为内核 CPU 利用率(LAKE CPU)、用户空间 API 处理器 CPU 利用率(LAKE API)和 GPU 利用率。启用 AES-NI 后,所有数据的解密利用率会出现一个短暂的峰值。LAKE 平均消耗 20% 的 CPU 资源,而原始 CPU 和 AES-NI 版本分别消耗 56% 和 24% 的 CPU 资源。
8.RELATEDWORK
Accelerator virtualization、Hardware acceleration in kernel、Machine learning in kernel
9.CONCLUSION
我们介绍了 LAKE,它能让内核空间应用访问用于 ML 辅助决策的加速器。我们确定并评估了可以从加速器中获益的五个基于 ML 的内核空间应用,证明了 LAKE 能够提供高性能加速,并简化在存在抽象边界、异步和多线程的情况下收集 ML 特征的挑战。