狮子的雄心,骆驼的耐力,孩子的执著!
分类: 嵌入式
2010-01-13 10:21:40
过去的30年,计算性能不断提高,主要是由于时钟频率、流水线效率和缓存大小的提升。但最近,传统的微处理器优化遇到了瓶颈。尽管像进一步增加缓存这样的小动作能够继续提升性能,但很明显,摩尔定律已经被甩在我们后面。同时,嵌入式系统在软件方面继续增加复杂度,而消费者希望价格、体积、重量和功耗持续降低。
微处理器设计者们总结出,要在取得高性能的同时控制器件封装,最好的方式是采用多核架构;这里,大前提是分割软件,多个处理单元间并行化或减少执行操作。对称多处理(symmetric multiprocessing,SMP)就是这样的架构,包含了紧密耦合的、拥有共同子存储系统的多个同质核。SMP实际上已是台式计算机的标准做法,但其在嵌入式应用中的采用却很缓慢。最近的调查显示,只有小部分设计者在使用单芯片SMP器件。
如果你的设计需要额外的马力,如何确定SMP就是合理的选择呢?下面几点关键要求可以使你认识到SMP的潜力。首先,软件要被分割和并行化,以利用硬件的并行性。其次,操作系统必须提供负载均衡服务,这样才能将软件分配到多个处理单元上。最后,你需要学习和使用专门针对多核系统的调试开发工具,从而快速找到并行方面的问题,避免面市时间延误。
并行编程
如果你的软件没有应用层并行化的能力(如一个简单的控制系统),那么SMP并不适合你。如果软件有并行化能力,但目前不是多线程的,那么采用SMP则是很合适的。
为了利用多核并行性,有两种分割、并行化软件的方式:手动和自动并行化。手动并行化要求程序员推断出应用程序的哪些部分可被并行化,并用明晰的代码显示并行性。例如,开发人员可将代码写入线程,而这些线程会被SMP操作系统安排并发运行。
自动并行化包括使用工具发现程序的可并行化,并将代码转化为明晰的并行化程序。某些形式的并行其重点是在循环上。这种方式的合理之处在于,循环常常会成为执行的瓶颈,但有时可以转化为并行的迭代。然而,很多循环是不可并行化的(即使使用十分智能的编译器),因此许多应用程序就不能从这种方式受益。
并行编译器的确存在,但由于编译器的重点放在数据层次的并行性,嵌入式软件并不觉得自动并行化技术十分有用。当然,对于以前在单核平台上运行的嵌入式控制应用程序,开发人员不能期望并行编译器将其转化后就能够在SMP上最优运行。自动并行化在某些方面也许确实能提升性能,特别是当用户加入提示和指示来帮助编译器时(这被称为半自动并行化),但总的来说,还是需要一种全系统方式。未来在自动并行化方面的创新将会更加高效。
POSIX
POSIX(Portable Operating System Interface of Unix,可移植操作系统接口)是由IEEE制订的开放式标准API。POSIX线程(Pthread)是标准中涉及多线程的那部分。Pthread API提供了对线程实施控制的接口、同步原语和进程间通信机制。虽然还有其他多线程标准,Pthread是最常用的、可广泛应用的标准。Pthread被许多嵌入式操作系统支持,如Integrity、LynxOS、QNX。
由于POSIX的普遍性,大量已有的应用程序代码可在嵌入式SMP设计中重用。POSIX的另一个优势是其独立的符合验证。经认证,符合最新POSIX标准的实现可在找到。通过POSIX API编程,开发人员能够写出多线程应用程序,可移植到任何运行POSIX操作系统的多核平台。
在嵌入式系统中,附加的软件组件通常可容易地映射到各个线程。例如,TCP/IP网络栈在一个POSIX线程中就可执行;文件系统服务器、音频应用等也一样。因此,许多嵌入式软件系统可利用SMP,在无需重大程序修改的情况下改进性能。
语言级并发
线程是Java和Ada语言的有机组成部分,用这些语言来设计多线程软件是很自然的事。Java和Ada程序使用语言级线程处理,可以很好地映射到SMP。C和C++仍然是嵌入式系统领域最流行的语言。最近几年的调查显示,C和C++(本身无线程支持)占嵌入式软件的80%,并且这一比例并无下降趋势。
如果你的软件是基于不支持SMP的实时操作系统(RTOS),那么SMP将不适合你。如果你可以自由选择一个新的操作系统,为了以后的兼容性,最好选择同时支持POSIX和SMP的OS。SMP操作系统调度并发的线程,运行在系统中其他核上。这种自动加载均衡是SMP最主要的优点:增加核会提高性能(通常能提高很多),但不用改动软件。
SMP系统多线程应用的自动重用有一个重要例外。多数SMP操作系统允许在多核上同时执行不同优先级的线程。多数实时嵌入式软件则严格按优先级调度。如果软件利用优先级作为同步的方式,就会有麻烦。例如,软件为了让某线程先于另一个线程,可能会手动提高其优先级。SMP系统中,如果这两个线程是双核系统中可运行的最高优先级的线程,这种办法就不可行。嵌入式设计人员必须分析系统以确保SMP调度算法不会产生问题。
核绑定
如果嵌入式系统的实时性要求很高,SMP就会出现一个问题:处理器间中断(IPI)和低效缓存会使上下文切换(context switch)发生延迟。例如,当中断服务程序在一个核上执行并示意某线程开始运行,SMP调度也许会让线程在另一个核上运行,这就产生了IPI。如果线程刚才并不是在同一个核上运行的,因为需要重新向缓存装入代码和数据,就产生了额外开销。SMP操作系统往往会迁移线程,令预测此类开销十分困难。
好消息是,多数SMP操作系统能够映射中断,并将线程与指定核绑定。这样就能达到实时性能要求,而其他软件则按RTOS要求作多核优化。底线是,实时系统可以利用SMP,但设计人员要做好配置系统调度参数的准备。
嵌入式NUMA
相对计算密集型系统,SMP的单存储总线结构也许并不适合存储及I/O限制类型的应用。为确定这一因素的影响大小,唯一方法是在SMP上运行该软件。对SMP还持有不确定态度的工程师们也许会对NUMA(non-uniform memory access,非一致性内存访问)系统的前景感到兴奋。NUMA与SMP类似,但它包含多于一个存储源,访问每个存储源的时间各有不同。
NUMA代表了一种折中的解决办法,这里代码仍可被共享并以SMP方式自动平衡负载。你可以通过在线程存储访问为本地的核上运行该线程,来优化存储访问次数。一种方法是利用前面提到的SMP操作系统的绑定功能。你可以将线程需要的存储定位在核的本地存储体上,并将线程与核绑定。支持NUMA的操作系统能自动进行存储和线程绑定的优化。尽管NUMA在主流嵌入式设备中并不可用,但将来很可能出现可提供SMP替代品的器件。
如果是第一次使用SMP平台,开发人员要做好准备,使用多核开发、调试和优化过程中需要的工具。紧耦合的多核处理器通常提供一个片上调试口(如JTAG),来使与硬件探测设备连接的调试器可以同时调试多核。有了这项功能,开发人员就能对多核实施低级、同步的运行控制。这一解决方案常用于集成电路板和设备驱动的开发。
开发工具让所有系统核可视化,令开发者可以选择任意组合进行调试。同时,工具也提供了对所调试核进行同步运行及停止的控制。
运行模式多核调试
运行模式调试对SMP系统也很有用,因为核从不中断。调试器利用主机和目标调试代理(debug agent)之间的通信信道(通常是以太网)控制应用程序的线程。
SMP操作系统提供集成的调试代理(以及相关通信设备驱动)以及测试系统的灵活选择。例如,操作系统有一个与调试器通信的强大的调试代理,能够调试任意核上用户线程的任意组合。用户可以设定专门的中断点,当另一个线程到达中断点的时候,可令用户定义的线程组暂停。一些类型的bug需要这种精细控制。
通过收集系统执行的历史,并使之在调试工具中可供回放,这使寻找和修复极端困难的多核bug变得容易。对SMP的新手来说,应该选择有片上trace功能的处理器。
多核trace功能刚刚开始在多核处理器上出现。阻碍这一硬件功能实现的主要技术难题是:如何跟上多核同时发出的trace数据脚步。一种新出现的方法是高速串行trace(HSST)。HSST利用高速串行总线技术取代了目前的并行trace口,这使得在减少引脚数的情况下还能够提高数据吞吐量。HSST已经作为提案提交到Nexus标准委员会。此外,ARM已经采用HSST作为其CoreSight的trace解决方案组成。
从降低成本、功耗及提高性能的角度来看,SMP是一项很有前景的技术。然而,SMP并不是能治百病的药。该应用必须具有并发的可能性,设计人员可能需要手动调整软件来解除对并发的锁定。另外,SMP系统管理和调试起来会比单核设计更困难些。