LabVIEW 对多核 CPU 的支持

    以前,在计算机领域有个摩尔定律,是说每一年半,CPU 的主频都会提高一倍。但是近几年这个定律在CPU主频上已经失效了,我 4 年前用的计算机 CPU 主频是 2G,我前几天换了一台新电脑,CPU 主频还是 2G。
    现在主要两个 CPU 生产商都意识到单纯通过提高处理器主频来提升性能的办法行不通了。他们的新策略是通过增加 CPU 的内核来提升系统整体性能。

    现在双核 CPU 是商用电脑的主流配置,也有高端电脑采用了四核 CPU。Intel 更是宣称他们用不了5年就会做出有 80 个核的 CPU 来。
    多个 CPU 同时工作,效率固然是高。但是,为了充分发挥多核的优势,为了发挥多核的威力,还要你的软件针对多核进行一定的优化才行。首先,你的程序至少是多线程运行的。

    使用常用的文本语言,比如 C++ 编写一个多线程的程序并不是一项简单的工作。除了要非常熟悉 C++
的基本编程方法,程序员还需要了解 Windows 多线程的运行机制,熟悉 Windows API 的调用方法,或者 MFC 的架构等等。在
C++ 上调试多线程程序,更是被许多程序员视为噩梦。
    但如果使用 LabVIEW 编写多线程程序,情况就大为不同了。LabVIEW 是自动多线程的编程语言,LabVIEW
程序员可以不需要了解任何与多线程相关概念与知识。只要他在 VI 的程序框图上,并排放上两段没有先后关系的代码,LabVIEW
就会自动把这两段代码放在不同的线程中,并行运行。而在多核 CPU 的计算机上,操作系统会自动为这两个线程分配两个 CPU
内核。这样就有效地利用了多核 CPU 可以并行运算的优势。LabVIEW 的程序员不知不觉中就完成了一段支持多核系统的程序。

    有操作系统来分配 CPU 也许效率还不是最高的。
   
比如我现在有这样一个程序(图1),有数据采集、显示和分析三个模块。三个模块是并行执行的。我的电脑是双核的,于是操作系统分配 CPU0
先做数据采集,CPU1 先做数据显示,等数据采集做完了,CPU0
又会去做数据处理(图2)。数据处理是个相对任务较为繁重的线程,而电脑一个CPU做数据处理时,另一个 CPU
却空闲在那里。这种负载不均衡就造成了程序对于整体系统的CPU利用率不高。

 
图1, 2:操作系统为多线程程序自动分配CPU

    对于效率要求极为苛刻的程序,还需要更高效的解决方案。LabVIEW 8.5 提供了一种解决方案,就是利用它的定时结构来有程序员人为指定 CPU 的分配方案。
   
定时结构包括定时循环结构(Time Loop)和定时顺序结构(Time
Sequence),他们的主要用于在程序中精确的定时执行某段代码,但是在 LabVIEW 8.5
中它们又多了一个新的功能,就是指定结构内的代码运行在哪一个 CPU
上。在图3中,定时顺序结构左边四边带小爪的黑方块所代表的接线柱就是用来指定哪一个CPU或CPU内核的。


图3:一个时间数序结构


图2:时间顺序结构的输入配置面板

    这个CPU设置可以在配置面板(图2)中静态的指定好,也可以像图1这样,在程序运行时指定。执行图1所示的程序,在0和1之间切换结构内代码运行的CPU,就可以在系统监视器中看到指定的CPU被占用的情况了。

    还是以刚才那段程序为例,这一次我手工为每个任务指定他们运行的 CPU。


图4:手工指定每个任务运行的 CPU

    这样一来,两个耗时较少的任务占用同一个 CPU,耗时较多的任务单独占用一个 CPU。不同 CPU 被分配到的任务比较均衡,程序整体运行速度大大加快,如图5所示:


图5:两个CPU负载均衡

阮奇桢

《我和 LabVIEW》

Advertisements

2 thoughts on “LabVIEW 对多核 CPU 的支持

  1. Hongbo, 非常感谢你分享的经验。对于读者来说,你的实际经验比我的理论推导更加有价值。再次表示感谢,并希望我们以后能多多交流。

  2. 阮前辈您好!小弟潜水了一段时间,从您的blog里面学到了很多实用的东西。在这里发表一点个人关于多核CPU的拙见。现在(2009年10月)的电脑主流恐怕不只2个或4个核了,如何用多核CPU实时采集和处理大流量的数据是个很有意义的话题,这里我提供一点自己的经验。我的实验系统用一块PXI-5122 digitizer采集图像数据(这个图像比较特别,是由光电倍增管产生的连续信号,需要在软件里重新组合像素位置并生成二维图像)。两个通道各25MHz的采样频率,8比特,这样PXI总线数据流量50MB/S,这个任务只能用一个CPU核作。有个瓶颈是PXI总线传输速率虽然很快(800MB/S)但是启动传输需要一个固定的时间,这样就只能尽可能连续的传输多幅图像*(每幅25毫秒)然后再作像素重建。问题就来自这里,重建像素需要大量的计算时间,单独一个CPU核是没法实时完成这个任务的。还好我有8个CPU,我一开始也尝试按您这里描述的模式手动分工,但是效果并不理想,好像Vista系统自动又重新分配了任务。而且Time loop我的感觉是要比while loop耗费更多的绝对CPU时间,实际测试每个CPU都几乎全负载,还是不能完全实时完成任务。最后我的解决方案是把重建像素的VI的execution属性设置成reentrant和high priority,还有要单独分配内存空间preallocate clone for each instance,编成使用8个同样的VI(也就是8个instance),然后把数据流按图像幅拆成8幅送给这8个VI(同在一个while loop里)并设置好index,输出的图像按index统一放在另开辟好的image序列里(IMAQ create image,循环n次可创建n个image的内存空间)。然后另一个while loop按照index从序列里面依次取出每幅图像并连续显示。这样做的结果是每个CPU都均匀的负载50%左右,除了一个CPU因为要读PXI数据占用了将近90%。我本来想用分7个CPU的方法,另一个单独只作数据采集。但是index看起来就不那么整齐了,所以就让vista自己去分配好了。实际上整个程序除了这部分之外还有很多其他实时处理的内容,不过耗CPU并不多。还有就是把重建好的图像写入AVI格式文件,这个也是通过从image序列里面依次取出图像来完成的,只取决于写硬盘速度。总结一下上面的经验,以下几点可供参考,当然这只是从这一个特例引出来的:1. 对于多核CPU,在Windows系列操作系统里面尽量不要手动指定任务,相信微软做的更好。2. 除了需要严格定时并且有相应的硬件的情况外,尽量用while loop而不是time loop3. 如果一个CPU不能实时完成某个处理大流量数据的VI,把数据平均分拆成n部分,开n个相同的reentrant VI,设置好接受输出数据的内存空间并作好index(非常重要,否则即便VI可以由不同的CPU执行,写内存却要冲突),放在同一个while loop里面。4. 尽量把多个不同的VI放在同一个while loop里面,但是运算周期不一样的VI不要放在同个while loop里以免造成资源浪费。通常情况下,用于界面控制的各种运算处理的VI不需要很高的重复执行率,因此不要和处理数据的VI放一起。多谢砖家点评!

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s