通过轻型线程提高多核设备中的Linux实时性能
简介
本文引用地址://m.amcfsurvey.com/article/134608.htm上个世纪,研发人员投入了大量精力提高Linux实时性能和行为,最著名的是 PREEMPT_RTLinux实时扩展。最近,研发人员致力于研究适用于多核设备的Linux用户空间解决方案,该解决方案允许从用户空间中直接访问基础硬件,从而可避免因将 Linux 内核引入用户空间应用而带来的额外系统开销。这些用户空间扩展(有多个)已首先由电信/网络高性能 IP 数据包处理系统进行驱动,以实现所谓的“裸金属”实施,其中,多核设备中的 Linux 用户空间应用可以模拟“无操作系统”解决方案的执行过程,即在每个内核上进行简单“运行到完成”、轮询循环,以便进行数据包处理。在从根本上实现该目标的同时,该解决方案仍可用于非常特殊的用例。还有其他需要提高性能的用例无法通过以上解决方案完全解决吗?如果有的话,请列举出来,是否可应用更完善的 Linux 实时改进?答案是肯定的,采用 Linux 用户空间轻型线程 (light-weight threading, LWT) 即可。我们来研究一下实时 Linux,以及轻型线程如何能成为适用于某些应用的解决方案。研究的重点受电信、网络或常用通信应用的影响,Enea 侧重于这些应用中采用的技术。但总体上来说,对轻型线程的重点应用会使多方受益。
实时 Linux 及其解决的问题
在过去的 10 年中,Linux 已在实时性能和行为方面取得了显著的进步,满足了大量应用的需求。具体归纳如下:
PREEMPT_RT
PREEMPT_RT 也许是 Linux 实时扩展取得的最显著的成就,PREEMPT_RT 数据包解决了多核设备 Linux 中存在的特别棘手的问题,即“中断延迟”问题。将事件/数据传送到真实用户空间应用之前,处理Linux内核中的中断占用的系统开销非常高 - 该系统开销往往会延迟其他中断,从而增大发生中断时测得的中断信息接收方进行处理的总体延迟。同样,Linux 内核中还有许多所谓的“重要部分”,可在其中通过自旋锁禁用中断。标准Linux 内核的总体中断延迟与许多实时应用的最重要的中断延迟要求不符,特别是无线接入网(移动)和移动核心基础设施,这两者要求最差情况下的中断延迟应在 20-30 微秒范围内。这一点也适用于许多其他市场应用。在快速“nutshell”PREEMPT_RT 中,这一问题是通过以下方式解决的:
- 将全部设备驱动器中断句柄传递到可调度线程中,这样可最大程度地减少 Linux 内核对中断的处理工作,因此,无需等待前一中断处理完成便可处理新中断。之后,中断处理会变为受优先级驱动,根据用户需求,会先完成优先级最高的中断处理。
- 将 Linux 内核中的所有死空间自旋锁传递到互斥量中,从而允许其他内核线程代替内核空间自旋锁运行。
基本上,PREEMPT_RT 已根据非常高性能的实时标准将总体中断延迟成功缩短,这样对大量 Linux 应用都非常有帮助。要了解具体应用?请继续往下读。
用户空间 Linux 调整
如上文所述,近年来,研发人员对 Linux 用户空间应用投入了大量精力。目的是避免用户空间应用(Linux 用户对其附加价值投入了大量精力)占用 Linux 内核本身的系统开销来处理某些特定的设备/中断交互。Linux 采用的模型可极大程度地防止用户空间应用受到内核的影响,在该模型中,所有用户空间操作(包括线程)始终会映射到 Linux 内核,以便处理其 I/O 请求。这样便使 Linux 具有强大的行为和特性。但是,对于数据处理性能非常高的应用来说,即使采用 PREEMPT_RT,Linux 也会有短时故障,这是因为,总是需要进行 Linux 内核上下文切换才能直接访问硬件。用户空间 Linux 实施允许应用在不涉及 Linux 内核的情况下直接访问硬件和中断,并可极大程度地提高性能。但这种性能提升只能在 I/O 密度极高的环境中实现。大部分 Linux 用户空间调整都侧重于单线程应用(如高性能数据包处理),其中,Linux 下只有一个线程用于模拟多核设备中的“无操作系统”性能。
多线程问题
实时 Linux 解决方案调查中缺少的是认真检查多线程在实时嵌入式应用中的有效性。实际上,早在 20 世纪 80 年代 Linux 出现之前,人们就提出了需要采用嵌入式实时操作系统 (RTOS) 来实现低延迟、高吞吐量、极具实时特点的应用。操作系统的结构发生了变化,但对这方面的需求却没有改变。此类 RTOS 解决方案所具有的各种性能、行为和特性是过去十多年中 Linux 一直尝试达到的。这并不意味着倾向于恢复使用 RTOS,而是要达到 RTOS 所具有的功能。就便携性、应用的广阔生态系统以及设备支持和常规支持来讲,Linux 在实时嵌入式解决方案中的总体价值是任何 RTOS 都无法比拟的。存在两个实际问题:
- 多线程为何重要?
- 如果多线程很重要,那么我们应如何将 RTOS 多线程性能、行为和特性添加到 Linux 中,以便取得更大的成功?关键问题是了解 Linux 多线程实施与 RTOS,然后考虑可以进行哪些改进。
多线程为何重要?
30 多年前,当计算机解决方案软件设计人员碰到单线程解决方案无法解决的复杂问题时,便已提出了对多线程实时性方面的需求。所需解决方案要求单个应用具有多个任务,也许一些是计算任务,一些是受 I/O 驱动的任务,但是,就任务的总体执行而言,所有任务均密切相关。但多个任务密切相关意味着这些任务应共享一部分 CPU 时间才能达到 CPU 的有效总体利用率。在很多此类应用中,必须禁止执行某些操作、等待某些 I/O 事件或另一应用发出的其他通信。因此出现了简单的可执行程序,这些可执行程序可以处理多个线程,同时可禁用线程,并可在各线程之间进行低延迟通信。
并非所有实时应用都需要支持重要的多线程处理功能。本文并未对相关应用进行分类。但很显然,需要使用多线程处理功能的应用是那些需要在协议中设定“等待状态”的任何类型的复杂协议,即等待允许应用继续进行的响应或事件。之后,应用应放弃对 CPU 的控制权,允许运行其他类似的线程,来代替该响应或事件。
也许上述教程对于许多人来说很简单。请注意,很多移动基础设施和核心网络设备供应商得出的结论是,虽然 Linux 是当前或未来系统的首选,但目前构建的 Linux 还不足以满足业界的全部要求。原因是什么?
采用 PTHREADS 的 Linux 多线程
Pthreads 是由 IEEE 规划的可移植操作系统接口 (POSIX) 创建的,目的是为了解决 Unix 中存在的高性能、多线程问题,之后被 Linux 用在最早的版本中,用于为企业实施可移植 Unix,目前用于嵌入式应用中。
创建pthreads模型是为了解决原始 Unix Fork/Join 模型创建 Unix“子”进程时出现的问题。由于该模型涉及到创建(还可能涉及删除)整个受内存保护的环境及执行模式,因此Unix 进程模型非常庞大。需要在 Unix 下采用适用于多线程的较轻型模型,因此pthreads应运而生。
但 Unix(也包括 Linux)模型是专为将内核与用户空间应用完全分离而设计的,其优势之一在于提供的保护、安全性和可靠性远胜于其他实施方案(包括过去 10 几年间使用的 RTOS)。实质上,这意味着 Linux 用户空间中的每个 pthread 都会由 Linux 内核线程表示,因此,全部或大部分 Linux 系统调用(特别是设备驱动器)均可通过用户空间进行访问。但是,由于 OEM 制造的产品并不具备 GPL,因此用户空间中实际存储了所有嵌入式 Linux 实时应用。因此,在每种情况下,使用pthreads都涉及到调用 Linux 内核,从而为本可以在本地实施的应用带来了额外的系统开销。
linux操作系统文章专题:linux操作系统详解(linux不再难懂)
评论