LabVIEW应用程序性能优化

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

LabVIEW应⽤程序性能优化
7.3 LabVIEW应⽤程序性能优化《上》(LabVIEW Application Performance Optimization)
VERSION 5
Created on: Apr 23, 2011 5:46 AM by jwdz - Last Modified: Apr 23, 2011 8:35 PM by jwdz
LabvIEW图形化系统的最伟⼤之处就是降低了程序设计过程的复杂度,使⽤过它的⼯程师和科学家们已经充分的体会到这⼀点。

它已经使得程序的设计者将关注度放在了待解问题上,⽽不是如何实现程序设计上。

是的,⼤家已经学会了按照LabVIEW数据流的编程思想进⾏了应⽤程序的设计,并且采⽤LabVIEW所提供的设计模式(模版)来设计应⽤程序的架构。

对于这样设计完
成的应⽤程序还需要进⼀步优化吗?答案是肯定的,因为任何设计都不会完美⽆缺。

优化的⽬的和过程
在软件⼯程中,有⼀个著名的法则:80/20法则。

该法则意思说:在应⽤程序中,程序执⾏时间的80%被20%的代码所占⽤。

性能优化的⽬的就是真对20%的这部分程序代码进⾏改进和提⾼。

并且性能优化的过程是⼀个不断循环的过程。

也就是检查——优化,再检查——再优化,直⾄满意为⽌。

图 7.3-1 软件的循环优化过程
⾮常遗憾的是,即使是经验⼗分丰富的程序员要想确定和发现20%这部分代码中的问题仍然是很困难的⼀件事。

显然,选择合适的分析⼯具应该显得更为重要。

7.3.1 性能优化⼯具
有许多可以进⾏程序性能优化的⼯具,⽤来帮助我们查找问题的来源和观察出现问题的现象。

其中,包括来⾃操作系统的和LabVIEW本⾝所⾃带的。

下⾯简单介绍⼏种。

7.3.1.1 Windows任务管理器
Windows任务管理器就是⼀个⾮常简单⽽实⽤的⼯具,并且它是内置在Windows操作系统中,使⽤起来也相当⽅便。

⽆论是学习LabVIEW之初还是现阶段的程序设计中,它都被⽤来做监测和查看CPU使⽤率的⼀个⼯具。

同时,它可以被最⼩化到任务栏中,实时获得监测结果。

假如:我们在While循环或状态机的循环中忘了放置⼀个⼩定时器,程序运⾏起来会使CPU的使⽤率达到100%。

通过查看它,就可以及时发现此类问题的存在。

当然,借助于它还可以查看到内存的使⽤情况,乃⾄发现程序中不良代码导致内存泄露的现象。

由于⼤家对任务管理器都很熟悉,所以关于它的使⽤⽅法就不做更多介绍了。

下⾯谈谈LabVIEW所提供的⼀些测试分析⼯具。

7.3.1.2 查看VI的性能和内存
这个⼯具在前⾯的内容中曾经使⽤过,这是LabVIEW中最常⽤的⼀个⼯具,可以很有效的评价⼀个VI,包括V I的执⾏速度和内存使⽤。

VI分析器提供了对应⽤程序中所有VI的平均执⾏时间进⾏粗略的估计。

但它也仅限于毫秒的时间分辨率。

因为它给出的是应⽤程序中所有VI的平均执⾏时间,所以直接断定哪20%的代码出现问题还是⽐较困难的,主要依靠编程者的经验和判断⼒。

建议,执⾏时间分析和内存分析最好分开进⾏,因为⼆者同时进⾏分析可能会有⼀些相互影响,分析结果未必准确。

⽽对于那些执⾏时间⼩于1毫秒的VI,最好使⽤下⾯的⽅法来测试。

7.3.1.3 查看VI的执⾏时间
利⽤下图所⽰的程序代码就可以测量某个VI的执⾏时间。

被测量VI或程序代码被放置下图中的For循环内,当VI的执⾏时间很⼩时,可以适当加⼤N的数值,利⽤多次测量来获得程序的平均执⾏时间(单位为:秒)。

这样就可以改进和提⾼某些代码的执⾏速度,从⽽进⼀步提⾼程序的执⾏性能。

图 7.3.1.3-1 测试代码的执⾏时间
如果安装了MGI的VI库,它也给出了⼀个代码执⾏时间的测试VI,它使⽤的是层叠式顺序结构。

7.3.1.4 LabVIEW VI Analyzer
如果你是NI 开发者套件⽤户,便会获得LabVIEW VI Analyzer⼯具。

否者那就必须购买该⼯具包。

安装该⼯具包后,在LabVIEW开发环境下,选择:⼯具》VI分析器》分析VI,就可以打开这个⼯具包,对某个VI进⾏基本性能分析。

NI LabVIEW
VI分析器可以⾃动实现VI的代码分析、测试,测试内容多达60多种,包括代码性能和样式的测试。

从⽽能够轻松地找出VI中潜在存在的问题。

⼤致与VI性能相关的基本测试分析:
循环中的数组和字符串
数据强制转换点
启⽤调试
While循环中的Wait
VI的⼤⼩
数组的默认值
结构中隐藏的对象
全局变量和局部变量
未曾使⽤的代码
⼦框图中的接线端
顺序结构的⽤法
当然,它的分析中有些提⽰(警告)也是可以忽略的,主要注意查看红⾊惊叹号所标明的问题。

7.3.1.5 LabVIEW Desktop Execution Trace Toolkit
这是⼀个需要付费的⼯具包。

它可以实现动态的代码分析和代码调试。

由于笔者也没有使⽤过这个⼯具包,所以这⾥也仅仅是提名形式的介绍。

具体可参考该⼯具包的相关⽂档。

7.3.2 代码性能优化的⼏个⽅式
如果在程序设计之初,就能够有意识的避免某些潜在问题的出现,那肯定是最好不过的事情了。

换句话说,如果能够了解更多的简单错误产⽣的原因,届时就可以避免常见的错误出现在程序设计中。

下⾯谈谈常见的⼏个问题。

7.3.2.1 避免数据强制转换
数据强制转换这是⼀个⽼⽣常谈的话题,最令⼤家记忆犹新的就是那个强制转换标志:⼩红点。

1、U8与I8、U16与I16、U32与I32相对应所发⽣的数据强制转换
下⾯还是以Memory Test(2010-
Mac).vi为例,看看数据强制转换发⽣时,VI的内存使⽤情况将如何发⽣变化。

图 7.3.2.1-1 Memory Test(2010-Mac).vi程序框图(均为U8数据类型)在图 7.3.2.1-1
中,设定:常数“2”和数组显⽰控件都是由U8的数据类型构成,因为⼆者的数据类型⼀致,所以并没有看到数据的强制转换发⽣。

如果将常数“2”的数据类型改变为:I8,⽽数组显⽰控件的数据类型还是使⽤U8。

在这种情况下,会发⽣那些变化呢?参见下图。

图 7.3.2.1-2 Memory Test(2010-Mac).vi程序框图(I8与U8)
很明显,此时由于所使⽤的数据类型不同,这⾥已经发⽣了数据的强制转换,因为那个⼩红点已经给出了提⽰。

问题是内存的使⽤情况也会发⽣变化吗?下⾯来看看!
图 7.3.2.1-3 Memory Test(2010-Mac).vi程序框图(I8与U8)的内存使⽤情况
尽管此时已经发⽣了数据的强制转换,但是内存使⽤情况没有发⽣变化或改变,与数据类型同是U8的情况⼀样(2M)。

此时,即便是使⽤To Unsigned Byte
Integer函数进⾏转换,消除了那个⼩红点,内存使⽤情况依然没有变化,参见下图。

图 7.3.2.1-4 Memory Test(2010-Mac).vi (I8与U8)消除强制转换
图 7.3.2.1-5 Memory Test(2010-Mac).vi (I8与U8)消除强制转换后内存使⽤情况
即便是再将常数“2”的数据类型设定为U8,⽽数组显⽰控件数据类型改为I8,同样也发⽣了数据的强制转换,但内存使⽤情况的结果也是与上图⼀样。

实际上,⽆论使⽤U8还是I8的数据类型,内存的使⽤情况都没有发⽣本质上的改变(U8的内存使⽤情况与上图⼀样,所以这⾥并没有给出)。

根据上⾯的现象,现在也只能这样认定:在数据类型内存使⽤相同的情况下(数据存储时使⽤的字节相同),尽管发⽣了数据的强制转换,但是这⾥似乎并没有发⽣内存的重新再分
配或通常所说的数据拷贝。

为什么会这样呢?
是否可以这样来解释:U8和I8的数据都只占⽤⼀个字节的内存,所以尽管发⽣了数据的强制转换但内存的使⽤情况并没有发⽣任何改变(似乎没有发⽣新的数据拷贝,或者说数
据拷贝使⽤了原有的部分内存)。

⾄少LabVIEW2010是这样的。

其实,将U16和I16(4096k);U32和I32(8192k)对应测试,结果也是⼀样的,并不增加内存的实际使⽤量。

2、其它数据类型的强制转换
U8-I16
现在将“常数2”的数据类型设定为:U8,将数组显⽰控件的数据类型设定为:I16。

再来看看内存使⽤情况的变化,参见下图。

图 7.3.2.1-6 Memory Test(2010-Mac).vi (U8-I16)的数据强制转换
此时的内存使⽤情况参见下图。

图 7.3.2.1-7 Memory Test(2010-Mac).vi (U8-I16)的数据强制转换内存使⽤情况
显然,内存的使⽤情况发⽣了变化(5M)。

前⾯谈到过,U16-I16或I16-
U16时内存使⽤为:4M,⽽现在为:5M。

这⾥显然发⽣了数据的拷贝。

那就消除强制转换再试试,参见下图。

图 7.3.2.1-8 Memory Test(2010-Mac).vi 消除(U8-I16)数据强制转换
在上图中,将“常数2”的后⾯加⼊⼀个数据转换函数(转换成I16),实现了预先的数据转换。

此时内存使⽤情况如何呢?参见下图。

图 7.3.2.1-9 Memory Test(2010-Mac).vi 消除(U8-I16)数据强制转换后内存的使⽤情况
预先数据转换不仅消除了数据强制转换(消除了⼤量的数据拷贝),实现了所期待的内存使⽤结果(4M)。

其实,消除强制转换有两种⽅式,⼀个是上⾯所谈到的预先数据类型转换;如果我们将转换函数放置在数组显⽰控件之前,也可以实现消除数据强制转换的作⽤。

但是这并不改善内存的使⽤情况,参见下图。

图 7.3.2.1-10 Memory Test(2010-Mac).vi 事后消除(U8-I16)数据强制转换
图 7.3.2.1-11 Memory Test(2010-Mac).vi 事后消除(U8-I16)数据强制转换不改善内存的使⽤情况
从这⾥可以看出,解决数据拷贝的问题,必须在前端处理(注意:这⾥不是没有数据拷贝发⽣,⽽是数据拷贝的数量极⼩);事后处理虽然好像也解决了强制状换的问题(消除了⼩
红点),但是没有解决数据⼤量拷贝的问题。

I16-U8
如果“常数2”为:I16数据类型,⽽数组显⽰控件仍为:U8数据类型;那会⼜发⽣什么情况?参见下图。

图 7.3.2.1-12 Memory Test(2010-Mac).vi (I16-U8)的数据强制转换
图 7.3.2.1-13 Memory Test(2010-Mac).vi (I16-U8)数据强制转换的内存使⽤情况显然,这⾥发⽣了数据的⼤量拷贝(4M)。

试着消除强制转换再看看,参见下图。

图 7.3.2.1-14 Memory Test(2010-Mac).vi 消除(I16-U8)的数据强制转换
图 7.3.2.1-15 Memory Test(2010-Mac).vi 消除(I16-U8)的数据强制转换后内存的使⽤情况
显然,这回到了U8或U8已及U8与I8时的情况下(2M)。

⾃⼰试试在后端进⾏消除数据强制转换会是如何?结论不会改善数据拷贝的问题,不信就试试看。

关于其它数据类型间出现的强制转换问题,因为篇幅的关系,这⾥就不⼀⼀的进⾏讨论了,感兴趣的可以⾃⼰做做试试。

针对数据强制转换这个话题,这⾥想说明的是(仅对于LabVIEW 2010):
——
依据数据流的关系,当数据源端与数据终端的数据类型不⼀致时会发⽣数据的强制转换。

换句话说,数据转换时伴随数据拷贝的发⽣,对于使⽤数据量很⼤的地⽅,⽐如:数组、
字符串等,尽可能的消除数据转换所带来的数据拷贝。

——
当数据源端与数据终端的数据类型相类似时,如:U8与I8、U16与I16、U32与I32等,数据强制转换或数据拷贝虽然发⽣,但并不会增加内存的使⽤量。

——
依据数据流的关系,消除数据拷贝应该在源端进⾏。

也就是说,在数据拷贝的发⽣地进⾏,尽管事后(后端)也可以消除数据的强制转换,但并不改善内存的使⽤。

7.3 LabVIEW应⽤程序性能优化《下》(LabVIEW Application Performance Optimization)
VERSION 3
Created on: Apr 23, 2011 8:33 PM by jwdz - Last Modified: May 15, 2011 11:38 AM by jwdz
7.3.2.2 避免数据拷贝
尽管通过节点上“⼩红点”的提⽰可以消除数据类型的强制转换,从⽽避免数据拷贝所占⽤⼤量的内存。

但是,数据拷贝并不是仅仅发⽣在数据类型的强制转换⽅⾯。

1、分⽀产⽣数据拷贝
先来看看没有数据分⽀时的情况。

下图中,内存的使⽤量为:8M。

图 7.3.2.2-1 创建数组(I32)使⽤8M内存
如果创建⼀个数组的分⽀,也会产⽣数据拷贝(这是LabVIEW所特有的特性),参见下图。

图 7.3.2.2-2 创建数组并产⽣分⽀(I32)
同样,会查看到内存的使⽤情况,参见下图。

图 7.3.2.2-3 创建数组并产⽣分⽀(I32)内存使⽤增加了4M
图 7.3.2.2-4 创建数组并产⽣分⽀(I32)改变连接⽅式内存使⽤也是增加4M
2、局部变量(全局变量)产⽣数据拷贝
现在,为数组Array创建⼀个局部变量,然后将局部变量连接到数组显⽰控件Array2,参见下图。

图 7.3.2.2-5 创建数组并⽤局部变量代替分⽀(I32)
此时的内存使⽤情况如何呢?
图 7.3.2.2-6 创建数组并⽤局部变量代替分⽀(I32)内存使⽤增加8M
这⾥所说的内存使⽤增加8M,是相⽐与图 7.3.2.2-
1⽽⾔。

显然使⽤局部变量会导致⽐直接连线产⽣更多的数据拷贝。

同样,使⽤属性节点传递数据亦如此。

并且因为属性节点⼯作在⽤户界⾯的线程,所以会引起
线程交换会导致执⾏速度降低。

⽽局部变量可以⼯作在任意线程中,所以它的执⾏速度会较快。

这也就意味着,尽可能的采⽤直接连线的⽅式来传递数据。

Case结构也可以有效的降低内存的使⽤量,参见下图。

图 7.3.2.2-7 Case结构=T,内存使⽤8M; Case结构=F,内存使⽤4M
如果将图 7.3.2.2-1所⽰的VI做为⼦VI使⽤,在它的前⾯版不打开时,其内存使⽤量也是4M。

7.3.2.3 避免过多的缓存区分配
避免过多缓存器分配的最好⽅法就是使⽤“In Place Element Structrure”。

该函数在函数选板》结构》In Place Element Structrure。

右键该结构可以选择如下所⽰的功能。

图 7.3.2.3-1 In Place Element Structrure的基本功能
这⾥通过展⽰⼀个来⾃NI的例⼦进⼀步说明该结构的作⽤。

例⼦中每个⼦VI都包含了波形数据数组。

通过查看缓存器分配,可以获得下图所⽰的结果。

图 7.3.2.3-2 查看到的缓存器分配关系
现在,对第⼀个VI进⾏“In Place”处理,参见下图。

图 7.3.2.3-3 对第⼀个VI进⾏“In Place”处理
图 7.3.2.3-4 对第⼆个VI进⾏“In Place”处理
图 7.3.2.3-5 对第三个VI进⾏“In Place”处理
图 7.3.2.3-6 对⽐图 7.3.2.3-2会发现少了许多内存分配的⼩⿊点。

相关文档
最新文档