system: [SYSTEM]

user: 3. 实时性改进 3.1. 工业互联网操作系统的实时性保证 虽然现有的工业操作系统功能完善且资源利用率高，但是这类系统一开始就被设计成通用操作系统，其目的是尽量缩短系统的平均响应时间，提高吞吐量，注重操作系统的整体功能需求，达到更好的平均意义上的性能。然而工业互联网应用强调工业控制过程的实时性，通用系统其在这方面的就用中存在一定的局限性。本文研究工业互联网云操作系统的实时性保证，通过改造现有的通用操作系统的内核可抢占性、进程调度方式、中断处理机制、时钟粒度等多个方面以支持实时性保证 [ 9 ] - [ 14 ] 。 1) 进程调度 实时调度理论是分析任务的可调度性和进行调度的基本理论 [ 15 ] [ 16 ] 。任务调度技术主要包括两个方面一是调度策略，二是可调度性分析方法，这两个方面缺一不可，两者结合才能对任务调度做出更好的解决方案。任务调度针对的研究对象涉及任务进行时的系统资源(主要有处理机、内存、I/O、网络等资源)的策略和机制，并且提供了能否事先预测系统性能的方法。例如，任务调度运行的耗时、什么时候开始运行、当系统为多处理机系统或分布式系统时在哪运行的问题等等；以及判断一个添加参数约束的实时任务能不能正确运行和调度。然而一个系统的大部分任务一般都处于阻塞或待命状态，这是因为一个时刻只有一个任务可以得到的CPU的执行权。因此，在系统的任务数和调度器类型不同的时候，一般都会有大量项目在待命队列里等待被执行。一般而言，对于简单的时间触发的调度程序，等待任务列表的数据结构应设计为在最坏的情况下最大程度地减少调度程序关键部分的执行时间，以防止其他任务无法及时得到执行机会。因此，抢占式任务要避免在这种类型调度器中应用，有为了保证所有任务及时得到执行甚至将除调度器之外的所有中断都关闭。另一方面，还应根据系统所需的最大任务数，进一步优化等待任务列表的数据结构。如果平时有大量的任务在等待列表里，这样会导致性能下降，这时最好使用双向链表作为任务列表的数据结构。如果等待任务列表通常包含少量任务，只是偶尔会出现较大量任务等待的情况，那么任务应该根据优先级排序，使系统性能更好发挥。这样，要找到优先级最高的任务，就不必在整个列表中逐个寻找，减少搜索时间。而插入任务需要在列表中逐个寻找，插入到比将要插入的任务的优先级低的任务之前；如果将要插入的任务的优先级是最低的，就插入到任务列表末尾。其中要注意的是在插入任务列表的过程中，要尽量避免抢占的发生。对于运行时间较长的关键部分要拆分成多个小的部分分别执行。若在寻找任务列表以插入低优先级任务时发生了中断，使高优先级任务进入待命状态，那么高优先级任务应该在低优先级任务被插入之前立即执行。Linux系统提供符合POSIX标准的调度策略，包括FIFO调度策略(SCHED_FIFO)、带时间片轮转的实时调度策略(SCHED_RR)和静态优先级抢占式调度策略(SCHED_OTHER)。Linux进程默认采用的调度策略为SCHED_OTHER，但缺点是，这种调度方式不能保证实时性要求高的任务或者优先级高的任务严格先于其他要求低的任务执行，因为这种调度策略是所有任务公平使用系统资源。显然这不适合有实时性要求的任务来使用。Linux系统在用户态支持可抢占调度策略，而在内核态却不完全支持抢占式调度策略。因此，将实时进程的调度策略设置为SCHED_FIFO或SCHED_RR，也不能很好地支持实时调度。所以在Linux内核态运行的任务(包括系统调用和中断处理)是不能被抢占的，并且会导致优先级逆转问题。为解决这个问题需要内核支持抢占机制，以满足实时性要求。 2) 内核抢占机制 Linux的系统进程运行分为用户态和内核态两种模式如图1所示。这两种模式最大的不同是进程是否可被抢占。运行在用户态的进程，低优先级的进程可能会被较高优先级的进程所抢占。但不同的是当进程运行在内核态时，进程是不能被抢占的，即使优先级高的进程也不能抢占优先级低的进程 [ 17 ] [ 18 ] 。这就和实时性的要求产生了矛盾，当进程进入内核态运行时，只有在系统完成前面的任务调用后才有可能让实时性任务得到执行机会。在较新的Linux版本中内核是抢占式的。主要有内3种抢占模式：PREEMPT_NONE，没有强制性的抢占，整体的平均延时较低，但偶尔也会出现一些较长的延时。它最适合整体吞吐率要求高的应用；PREEMPT_VOLUNTARY，降低延时的第一阶段，它会在内核代码的一些关键位置上放置额外的显示抢占点，以降低延时。但这是以牺牲整体吞吐率为代价的；PREEMPT_DESKTOP，这种模式使内核在除临界区外的任何地方都是可抢占的，对于没有硬实时性要求的任务比较合适。 图1. 实时Linux中断机制 3) 中断屏蔽 默认情况下，Linux操作系统会在发生中断处理时关闭中断，这是为了在完成任务前不被打断，能更迅速、更安全地完成自己的任务，但是这时更高优先级的任务中断也无法得到响应，直至当前中断任务处理完毕，才能得系统资源 [ 19 ] 。这对实时性要求高的任务是不可接受的，因为，这种状况下会导致中断延时和调度延时不可确定。通过利用内核线程处理中断就可以解决这种问题，能让优先级高的中断及时上报及时处理。 4) 时钟粒度 时钟粒度是指操作系统能达到的最小时间间隔。在Linux中时钟粒度是指两次时钟中断的时间间隔。时间间隔越小，系统开销就越大。时间间隔越大，虽然开销可以减小，但带来的问题就是进程的响应延迟变大 [ 20 ] 。所以时钟粒度要根据不同的应用场景调整。在Linux内核中，时钟中断发生频率范围是50~1200 Hz，周期不小于0.8 ms，遗憾的是这无法达到工业应用中微秒级的实时性要求。但是处理器可以提供更高精度的定时，能够达到纳秒级。因此想要满足对时间精度的较高需求可以利用处理器的时钟。 5) 虚拟内存管理 虚拟内存管理是操作系统的核心之一。操作系统中诸如进程间隔离，文件缓存，存储交换等高级的功能都是依赖于虚拟内存得以实现。这需要频繁的页面换进换出，过程要消耗大量时间。因此应用在实时系统上是不可接受的。一般可以通过内存锁定功能对实时应用的内存空间进行锁定，避免在实时处理中存储页被换出，提高实时性。 6) 共享资源的互斥访问差异 信号量或自旋锁等机制是用来解决同步时数据可能被破坏的问题。然而却带来了另一个弊端，在基于优先级调度的实时系统中，自旋锁可能会造成优先级倒置问题，致使高优先级任务无法保证及时处理。为了使系统更好地应用于工业实时环境，可以将自旋锁改造为支持优先级继承的互斥量以支持不同优先级任务间的抢占。 3.2. 工业互联网虚拟化环境中的任务实时性保证 由于传统的虚拟化环境是一个独立于宿主机的封闭环境，宿主机无法得知它内部进程的优先级，因此无法保证将虚拟化环境中具有高优先级的实时进程先于宿主机进程或其它虚拟化环境中的进程运行。内核提供的锁机制也存在相同的问题，它们对于宿主机也不可见，导致跨虚拟机的优先级调度无法得到保证。 1) 提高虚拟CPU的优先级 解决虚拟化环境中优先级保证的一种方法是提高虚拟CPU的优先级，使虚拟环境中的进程能够先于宿主机进程运行。此时，为了保证外部中断能够传递到虚拟化环境中，宿主机的软中断处理进程的优先级应当高于虚拟CPU的优先级。 2) isolcpus技术 通过isolcpus技术也可以提高任务执行实时性。isolcpus功能用于在SMP均衡调度算法中将一个或多个CPU孤立出来，同时通过亲和性设置将进程置于“孤立CPU”运行，isolcpus后面所跟的CPU参数，可设置孤立的多个CPU。isolcpus带来的好处是有效地提高了孤立CPU上任务运行的实时性。该功能在保证孤立CPU上任务的运行，同时减少了其他任务可以运行的CPU资源，所以需要使用前对CPU资源进行合理的规划。 3) 新的处理器特性 此外，通过利用一些新的处理器特性也有助于实时性的改进。例如，Intel较新的采用了Haswell架构的CPU包含了一项缓存分配(Cache Allocation Technology， CAT)技术，启用该技术后，在任务切换时即使内存和TLB同时都没有未命中，仍然可以保证切换延迟小于50微秒。CAT允许对指定的应用保留部分缓存，以防止一个工作负载将另一个工作负载驱逐出缓存，这可以使用一个基于控制组的接口进行控制。