Showing results for 
Search instead for 
Did you mean: 

Community Nugget 4/08/2007 Action Engines

Go to solution

Well it looks like my concern about addinga section on performance was un justified.

Thank you for point out the placement of control and how they affect the performance.

Others have touched on the idea of passing an array through a VI (hopefully by reference) to allow the buffer to be "inspected" by the sub-VI. After the sub-VI completes another function can use the same buffer.

Christian wrote;


Also the "Numeric out" should be renamed to "mean out" and should produce e.g. NaN in all actions except "calculate mean".


Good point! ...

unless the AE also offers a "Min" and "Max" function (which this examples does not). Smiley Wink


Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 11 of 161
Bravo, Ben!  Very nice.  Thanks.

Message 12 of 161

Very nicely-done nugget!  FG's and AE's are *very* useful constructs indeed.

Most of my apps involve heavy doses of data acq and I almost always implement an AE around each data acq task (or small set of closely-coupled tasks).  This sets me up with 1 common interface to each logical unit of hardware.  It has proved to be a pretty effective strategy for re-use as well.  The data acq tasks naturally turn into pretty self-contained modules needing relatively little modification from app to app.  (Sometimes none at all.)

Like altenbach mentioned, I also almost always use the "First Call?" primitive in any FG to guarantee some kind of initialization.  Typically, if the first call performs a "Read" action, I'll catch that fact and provide sensible initialization values.  Depending on the FG in question, I may just pass through the default inputs, or I may use special values like NaN, "<undefined>" enum values, or even assert the error cluster -- depending on how crucial it is to have initialized *explicitly*.

-Kevin P.

Message 13 of 161
Some of my early (~LV3) functional globals (had not heard the term Action Engine then) had a Valid output. It remained False until a Write had occurred and was reset to False if the Reset action was performed.

Nice job, Ben.

Message 14 of 161
Nice job, Ben.  I have one more performance improvement that only is worth considering if you are using the AE to store a dynamic array and you are adding data to or subtracting data from the array frequently.  It results in code which is quite a bit more complex.

Build array is a very expensive operation due to using the memory manager and, if used repeatedly, can fragment memory, causing more performance issues.  You need to create some sort of memory management so you don't keep hitting the build array primitive, and the AE allows you to do this.  The executive summary - when you initialize the array, always create twice as many data points as you need, and a minimum of 8 to 16 points.  Keep track of the number of points actually used and the number available.  When you add points to the array, if you need more space, double the array size.  If you subtract data from the array, halve the size if you get to less than one quarter of the points actually used.  Note that actual increases and decreases should be tweaked for your application.  Operations such as min, max, and average may be more efficiently done when points are added (although that is a performance issue each application will need to work out).

If I have a chance, I will code it up and post it.  I have used this in the past with dramatically better performance, but details count, and any particular problem may or may not benefit from such an approach.  The time you save adding points may be lost when processing them, since you cannot use the array operations without creating a subset of the array, which hits the memory manager and may cause a copy.  The best way around this issue is processing the points as you add them, but you can easily end up losing any performance gain you got by not hitting the memory manager.  Of course, you sort of get the performance back on the read, since the values already exist.

Your mileage may vary...
This account is no longer active. Contact ShadesOfGray for current posts and information.
Message 15 of 161

Hi All,

I will try to reply to the replies in chronological order as time permits.


Now that this Nugget is out of my head I will look into harnessing the LVOOP ideas you have been pushing. I'll reply back with this.


I WILL have to follow-up on your link. Concidering how much time I spend with AE's your comments are very tempting!

I will reply to the other posting when I get a break.

Thank you!


Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 16 of 161

Tomi Stephan and others,

To get my head around how to think LVOOPishly, I appreciate a little help.

In my Action Engines...

Should I understand the data in the USR to be a class or is the cluster that defines the USR contents that I should think of as a "Class"?

If I perform an action that modifies the USR, is that a "method"?

If I just read out the "average" is that a "property"?


Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 17 of 161
To follow up on DFGray's comments, I usually keep a pointer (in the AE) to the next available location in the AE array.
When the pointer = array size, time to go get more array elements.  If you allocate in 100 entry chunks your memory
manager overhead is decreased by ~99%, with modest over-allocation.  Works very well for typical AE array sizes we
work with, hundreds to low tens-of-thousands elements.

Message 18 of 161
It seems to me the entire FG would constitute a class, since a class is not only stored data but the functions that operate on that data. The cluster in the USR is your private data, since it obviously can't be accessed outside the FG without accessor methods.

Reading a property would simply be outputting a data value that is stored in the USRs. This could include one element out of a cluster. If you are storing your average in the USR and you just want to output it without recalculating it, then yes, that could be a property. If you include the act of calculating it, that sounds more like a method.

The analogy with LV2-style Functional Globals and classes seems to break down when you start talking about inheritance, because there's no automatic way to inherit a FG and get all its data and methods along with your own new child data and methods. You would have to modify the original functional global to extend its functionality in such a way.
Jarrod S.
National Instruments
Message 19 of 161

Should I understand the data in the USR to be a class or is the cluster that defines the USR contents that I should think of as a "Class"?

I haven't had time to take a look for Stephens example so I will not talk for Stephen but only for myself. The USR could be but would not neet to be an object in LabVOOP. It can as well be anything else such like in pre-LabVOOP LabVIEW. The more relevant question is if the USR containst the class type the VI (method) belongs to or something else. However the story is too long to be replied here wihtout much too many references to undefined issues. I'd rather go on my introduction to LabVIEW object-oriented programming in my blog at expressionflow. When the time is right I'll talk about functional globals and action engines in contexto of object-oriented programming.

My advice, it's very hard to wrap you head around object-oriented programming without actually reading something. The easiest way would be to follow my blog for some time. The more challenging way would be to read one or more books on OOP in the context of some other programming language such as Java.

Tomi Maila
Message 20 of 161