A Linux Environment Zero Overhead
本文翻译自Tilera公司关于ZOL机制的白皮书报告,原文为《Tilera_ZOL_White_Paper_0》,原文可以到这里下载http://download.csdn.net/detail/linux_embedded/7120265。如果翻译不当之处请多多指正。
转载请注明出处!
A Linux Environment ZeroOverhead
软件开发人员期望在他们的项目里能够做到低延时I/O处理和比较短的上市时间。软件开发过程中,较短的上市时间与低延时的I/O操作往往为相互矛盾。可是,如果利用Zero Overhead Linux? (ZOL)开发软件,就有可能同时满足上述两个需求。
ZOL提供了这样一种方案达到上述两个目标:能够以较低的延时处理实时I/O,同时仍允许访问整个linux开发工具集和模块。应用程序代码就像传统方式那样访问linux内核,但是如果不需要内核的支持,ZOL允许将100%的时钟周期分配给运行着具体应用的众核处理器,使其能够专心的执行应用程序代码。
Tilera on-chip硬件支持用户空间的直接控制,通过结合该项机制,利用ZOL提供的开发工具完全可以驱动100Gb/s的数据通道而不会丢失任何数据包,同时所有的快速开发、测试、软件质量提升都是在标准的linux环境下,所以你可以完全使用linux下的调试、跟踪、错误处理机制。
1. 编写用户层的驱动程序
一般意义上,系统驱动应用都是在内核实现,通过中断系统检测硬件的行为。CPU核心资源是稀有的,所以在整个系统不能对系统任务及时响应之前,CPU只能执行及其有限的轮询工作。如果实现对于中断请求做出低延时的响应,需要内核在驱动的中断系统中实现抢占的功能。更重要的是,在内核中编写驱动程序需要开发者按照内核环境开发、调试、优化驱动代码,而不像标准的用空间的应用代码。
Tilera硬件被设计成中允许开发者直接编写用户空间的驱动应用。所有属于每个CPU核的不同类型的硬件资源被特权等级检查器保护,并且该机制可以被动态的配置。每个芯片的资源例如I/O资源都是通过内存映射机制(memory-mapped I/O MMIO)加载和存储,同时芯片被设计成不同类型的硬件资源被不同的MMIO地址访问。因此,内核能够提供对于基于某些特殊实现的I/O硬件资源的访问权限,已达到在用户空间直接实现驱动级别的应用。
开发者可以自行设计、实现、调试、架构具有错误管理功能的用户空间的代码,它可以利用用户空间的所有的工具包括复杂的调试工具,IDE、性能测试工具、文件系统、网络数据等。这种开发模式可以缩减产品上市的时间,可以更简单的额更快速地编写、优化、改善代码。
2.“裸机”不是问题的答案
其他的架构解决方案经常关注裸机开发环境,并linux系统移除作为去除产品性能负载的方式,然而这将导致该环境很难进行编码。相比之下,基于linux系统开发应用程序可以在运行性能敏感的代码之间初始化好所有的linux支撑的环境。Linux同时能够依靠后台的“管家”任务简化进程终止和资源清除的工作。
不幸的是,用户空间实现的驱动程序往往会因为内核的限制而不能很好地工作。一个用户空间的任务可能因为上下文切换到另外一个任务,或则可能被内核周期性的管理操作而中断。同样内核驱动程序也会处理递送给CPU的中断请求。ZOL的创新之处在于它会避免所有的内核负载,所以可以保证用户空间的应用程序独占CPU而不会被切换或抢占,同时不会丢弃linux环境所提供的任何优势。
3. 禁用linux调度器
如果程序对于延时、实时性的要求十分的严格的话,linux理论上不会胜任这项要求。数据包管理要求数据包必须几百个时钟周期内处理完毕,否则将会导致下一个数据包的丢失。
内核定时器中断是用户空间代码运行时较为常见的负载类型。内核定时器允许内核优先上下文切换多个进程,同时会改变一些内部管理状态,例如为了负载均衡会在CPU之间迁移一些任务,更新统计信息(例如,相对于内核时间的用户时间),支持用户空间关于服务的请求例如间隔定时器信号等。当用户空的代码运行时,该定时器会按照配置100~1000Hhz频率产生中断信号。
在Tilera实现的ZOL内部,当CPU上只运行一个进程时,其被配置为禁止运行内核计时器模式。在至少有一个CPU运行在控制面(non-ZOL)的模式下,标准的linux内核事务会被这些模式下CPU计时器处理。ZOL模式下的CPU会被配置成不支持为了负载均衡而迁移任务的功能。只要唯一一个单独的任务运行在ZOL cpu上,内核就会在任务运行的过程中禁止定时器中断。但是,不管什么原因,因为在ZOLCPU上应用程序需要调度多个任务(多线程、多进程),系统就会透明的转换到正常的具有优先级调度的模式下以支持正确的行为(进程调度)。
4. 禁用其他内核负载内容
内核时钟计时器无疑是中断用户空间代码的各种中断的原因,同时内核中还存在很多其他的导致内核开销的原因。ZOL保证不可能存在增加绑定了ZOL内核的CPU任何上述原因导致的开销。
典型的多核系统为设备中断会运行某种中断分发器,该分配器会将设备产生的中断分发到不同的CPU。在ZOL下,内核驱动被设计成对ZOL CPU敏感的模式,并且保证设备产生的中断不会被递送给任何ZOL CPU。对于像PCIe和网络驱动这样特殊的事务,内核会保证它们不会向ZOL CPU发送任何的中断信号。
Translation Lookaside Buffer(TLB)管理模块同样为引起内核开销的事务。TLB能够快速的完成虚拟地址到物理地址的转换。一旦这些映射信息改变,受影响的CPU就会被中断触发,调用刷新代码执行TLB刷新动作。通常这只发生在 多线程进程的用户空间内存中,但有时处理内核内存映射时系统上的所有CPU都会发生TLB刷新动作。内核中ZOL相关的代码会收集关于TLB刷新的请求,然后ZOL会不定期的推迟内核TLB刷新动作。因为ZOL CPU运行于用户空间,所有它们会与内核老化的TLB信息保持隔离。然而,当它们再次进入内核空间,此刻它们执行内核TLB刷新动作,以清除任何老化的TLB表项。该机制被设计成race-free的,即使当ZOL CPU进入或离开内核就立即刷新TLB表项。
各种不同的其他运行在CPU上的linux内核代码,在ZOL上也被禁止运行。例如,soft lockup testing is typically done with kernel tasks that run onall cores; ZOL cores suppress the soft lockup task, losing that functionalitybut removing the requirement that preemptive context-switching be enabled tosupport it(此处待翻译)。其他的被ZOL禁用的功能包括:vmst刷新、每个CPU会执行的内存分配(slab)任务。另外,ZOL不允许那些能够运行于多个CPU上的内核线程运行于绑定了ZOL CPU之上。
5. 开启ZOL
为一个应用程序添加ZOL支持是非常简单的。通过,应用会有控制面部分和数据面部分。而数据面部分经常被配置成ZOL模式。被定制了linux内核启动选项的CPU组成了数据面。例如,TILE-GX 36的控制面可能包括编号的为 0的CPU,其他的CPU被分配给数据面,对应的配置选项为“dataplane=1-35”。用户通过查看位于“/sys/devices/system/cpu/dataplane”下的配置文件查看当前的配置情况。
由于ZOL不会执行调度器负载均衡机制,所以用户必须明确的将进程或者线程绑定到每一个数据面的CPU上。使用通用的sched_setaffinity()系统调用或者其在MDE开发库中实现的简单的封装实现达到调度器的负载均衡。一旦一个单独的任务被绑定到某个CPU之上,该CPU就会立即执行ZOL模式而不再需要其他额外的配置。然后,该task可以执行任何的系统调用完成进一步的配置、初始化,之后该任务就在纯粹的用户空间开始处理事务了。内核不会再次中断该CPU。ZOL允许一个数据面CPU绑定多个任务处理单元。
另外,为了避免在task处理过程中产生其他的系统调用,该任务应该避免产生任何页错误。当某一个任务欲读写一块已经申请配置了但是已经不能被该任务访问的时候页错误便产生了。页错误产生后,页错误中断会使linux内核接管系统,计算出出现页错误的地址对应的内存,如果有必要会分配内存,最终将控制权返还给用户空间的应用。另外,如果内存交换功能启用的话,内核会将已经被进程访问的内存交换出去,一般到为硬盘。为了保证所有的这些处理负载在用户空间的应用开始执行之前被处理完成,同时进一步避免将来的类似的负载的产生,应用程序需要调用mlockall(MCL_FUTURE)系统调用完成分配、初始化所有属于该应用的地址空间的内存。
6. ZOL配置、调试
Set_dataplane系统调用可以有效地追踪在复杂的应用中导致内核负载的来源。例如,某一个第三方库可以不可预料的执行系统调用,或者运行于控制面的进程可能在不恰当的时机向数据面发送中断信号。
设置DP_STRICT模式阻止用户空间的应用不再因为任何原因进入内核空间,包括系统调用、页错误。如果用户空间应用程序陷入内核空间,一个跟踪信息马上呈现在终端以表示发生的了什么,同时进程会发送SIGKILL信息终止自己。这对于调试非常的有益。DP_DEBUG相似的模式,能够保证将任何应用的其他部分或则内核产生的中断当前ZOL CPU信息通过一条跟踪信息显示下终端上。
另外一种模式,DP_QUIESCE,能够保证当用户空间的应用程序确实执行了一个系统调用之时,内核会在返回空间之前保持静默状态。通常,内核在系统调用完成之后直接返回用户空间,但是系统调用之后会激发一些内核处理行为,内核会等待这些内核行为执行完成之后才能返回用空间。例如,Read-Copy-Update写实复制锁机制就利用了内核空间的计数器作为其实现的一部分,所以CPU需要完成一个RCU锁的时钟计数器操作之后才能返回用户空间。DP_QUIESCE模式意味着CPU一直自旋直到所有的时钟计数器完成计数,这样可能致使系统调用执行变慢,但是可以保证不会存在内核空间的计数操作被递送给用户空间。
7. 基于ZOL编程
当应用程序启动并且执行初始化流程或者其完成并完全退出或者其由于异常导致处于异常错误的状态时,其都可以利用内核所有的工具。在数据面模式,应用程序并需清除那些库可以安全使用而不会意外陷入内核。
对于锁机制,Tilera Multicore Components(TMC)库提供了一系列的纯用户空间的锁实现,例如tmc_spin_*函数族。应用程序可以使用系统任务调度相关的锁机制实现数据面和控制面之间的锁的共享,例如基于内核的futex(fast userspace mutex)技术,但是在数据面只能使用上述所列出的tcm_spin_*函数族。
应用程序可以利用共享内存和tmc_queue_*实现数据面和控制面之间的通信; 可以定义多个发送者或者接收者,如果需要可以在基于某类型的锁机制实现两边的同步。
应用程序可以在数据面的CPU上预先分配固定大小的内存空间,然后使用tmc_mspace_*函数族实现封装了malloc/free调用的函数在该块内存区域上分配内存,同时使用TMC锁机制实现对于共享数据内存的同步管理。
I/O处理基于Tile-GxI/O(gxio)库实现,其在用户空间完成所有操作,处理初始化和I/O资源分配操作。一旦I/O建立完成,实际的读写操作都是在纯用户空间完成的。Gxio和tmc库提供了完全一整套内核无关I/O和同步机制基础件。可是使用tilera用户空间的TCP/IP协议栈实现承载与以太网之上的高级协议。可以使用Tile-Gx crypto(gxcr)库完成加解密相关的操作。所有的这些库函数都是内核无关和ZOL友好的。
Tilera提供例程完成用户空间的时间管理功能。gettimeofday()为C库函数在用户空间的实现的函数,其通过检测内核管理的映射到每一个进程空间的内存页来计算如何将每一个CPU的循环计数器转换为正确的当前时间。
软件设计者可以使用标准的posix多线程或者协同进程模型构建应用程序的部分数据面应用。
ZOL模式下,调试和性能工具工作方式就像在其下运行应用程序一样。这些工具在其运行过程中可能会禁用ZOL模式,但是这些操作对于内核是透明的,并且其不能影响这些工具所带来的效益。例如,性能测试工具需要用户空间组件完成内核性能数据的收集,所以当用户空间的应用过程中,进程切换需要被允许已达到上述数据的收集。
8. 总结
Tilera的ZeroOverhead Linux模式允许软件开发者能够在较短的时间内开发高性能和特性丰富的代码。性能和软件正确性事务可以被很容易的调试和优化。ZOL模式可以管理高带宽的I/O处理而产生内核处理开销带来的抖动,同时其还可以随时使用linux内核提供的完全的功能,所以ZOL模式对于编写用户空间的驱动应用来说是最为理想的软件环境。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。