LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Global vs Local variables in performance-critical loops

Scenario: my main VI contains two tightly timed loops which must stay in lockstep with the hardware. These are constantly feeding data to the device using Ethernet/IP protocol. The data changes according to what I want the device to do, and I use local variables to send the data changes into the tight loops.

 

The processes I would like to put the device through are sometimes complex, and I would like to make subVIs of them. Preload, Calibrate, Run process, etc. But then they can't feed data to the hardware control loops using local variables! I would have to use global variables instead, and I have read that global variables are a performance hit. Am I right about that? What is the most efficient way to feed data from an executing subVI called from one loop, into the ongoing process of another loop?

 

0 Kudos
Message 1 of 23
(7,701 Views)

Using locals is almost always a bad idea for anything but the quickest code hacks, especially in "time-critical" scenarios (which you probably won't be able to achieve reliably if you are running, say, Windows). Each local variable node call requires the UI thread, and there's only one of those - so your calls will only execute one at a time, as well as sharing time with the UI and other "root loop" house-keeping.

 

You can use Global variables as you suggest; they are just a VI call so they have very little overhead. That probably answers your main question. But you should be careful how you use them; Globals going 'one-way' (eg. Write only, Read only) are a perfectly ok design decision but require a certain amount of diligence. To feed data between loops the best options are typically synchronisation primitives such as Queues, Notifiers. If you are using LV 2016+ Channel wires are another good option (which are just wrappers around the base primitives from an execution perspective). These types of nodes can be configured for a number of scenarios, including limiting your overhead in tight-loops.

 

In the end the best design decision really depends on your platform, timing, re-usability and maintainability requirements. You'll get better advice if you provide more specific information.

0 Kudos
Message 2 of 23
(7,686 Views)

@Ken_Brooks wrote:

I would have to use global variables instead, and I have read that global variables are a performance hit. Am I right about that?  


No.

 

You wouldn't have to (and shouldn't) use global variables.

 

Reading global variables won't be a performance hit either. Each instance of a global or local is a copy in memory of the data. For scalar values, that's probably not going to be noticeable in performance.

 


@Ken_Brooks wrote:

What is the most efficient way to feed data from an executing subVI called from one loop, into the ongoing process of another loop? 


 You should ask yourself if "the most efficient" is needed. I'd go for "efficient enough".

 

Note that locals are probably on a visible front panel, while globals are usually on a closed front panel. Globals probably perform better then most alternatives (even locals!), at least performance-wise. Definitely not when it comes down to maintainability and readability.

 

Functional Globals (FGV), DVR's, Queue's, by reference Classes are all options.

 

 

0 Kudos
Message 3 of 23
(7,651 Views)

@tyk007 wrote:

Each local variable node call requires the UI thread, and there's only one of those - so your calls will only execute one at a time, as well as sharing time with the UI and other "root loop" house-keeping.


Completely WRONG.  A local variable does not have anything to do with the UI thread.  Writing to a local variable acts the same as writing to a terminal, just with more memory usage.  It will put the data into a buffer and when the UI thread is allowed to run again, it reads the data from said buffer to update the graphics.  I think what you were trying to refer to are the Value Property Nodes.  Property Nodes that are referenced to anything on a front panel have to run the the UI thread and force redraws.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 4 of 23
(7,640 Views)

@Ken_Brooks wrote:
I would have to use global variables instead, and I have read that global variables are a performance hit. Am I right about that?

You are not right about that, at least in modern versions of LabVIEW.  Global Variables did get a major performance boost somewhere along the way.

 


@Ken_Brooks wrote:
What is the most efficient way to feed data from an executing subVI called from one loop, into the ongoing process of another loop?

Well, now we have to get into more specifics.  What kind of data are you trying to pass along?  Tag data (only care about the latest value, ignore any missed values) or Streamed data (have to process every value, high throughput)?  I will assume we are not talking about Message data (intermittent, probably care about every value).

 

So, if we assume Tag data, then Global Variables are great.  As with almost all Tag data, make sure there is only 1 place where the values are written.

 

And here are a couple of articles/presentations you should really look at:

A Look At Race Conditions

Are Global Variables Truly Evil?


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 5 of 23
(7,636 Views)

@crossrulz wrote:

@tyk007 wrote:

Each local variable node call requires the UI thread, and there's only one of those - so your calls will only execute one at a time, as well as sharing time with the UI and other "root loop" house-keeping.


Completely WRONG.  A local variable does not have anything to do with the UI thread.  Writing to a local variable acts the same as writing to a terminal, just with more memory usage.  It will put the data into a buffer and when the UI thread is allowed to run again, it reads the data from said buffer to update the graphics.  I think what you were trying to refer to are the Value Property Nodes.  Property Nodes that are referenced to anything on a front panel have to run the the UI thread and force redraws.


Agreed.

 

Locals probably have a little overhead (over closed globals), because the values will get updated at some point (e.g. when updating the UI, the copies of the data need to be compared, and the last update needs to be visualized). This update will happen in the UI thread, but it will not stall the thread that sets the local (, as the UI thread has the copy to work on). This overhead will be tiny for scalars. I would no worry about that at all. 

 

A memory copy for each local is the price for not being linked to the UI thread. Indeed, value property doesn't require a data copy, but the execution thread will synchronize with the UI thread as a consequence.

0 Kudos
Message 6 of 23
(7,634 Views)

@crossrulz...ongoing process of another loop?

Well, now we have to get into more specifics.  What kind of data are you trying to pass along?  Tag data (only care about the latest value, ignore any missed values) or Streamed data (have to process every value, high throughput)?  I will assume we are not talking about Message data (intermittent, probably care about every value).

...


Yes, to be able to properly suggest a solution we need to know exactly what the problem is that you are facing.

 

I agree with much of what has been offered but will offer another approach that let control the throttle level setting of a jet engine simulator running in LV RT 6.1.

 

At that time is was suggested that Action Engines be used to transfer info into a time critical loop. Action Engines were mentioned above under the title of Functional Globals. The detail I want to highlight with this contribution to the thread is the "Skip if Busy" option if an Action Engine is set as "Subroutine" priority. That option can be set for each instance of the AE.

 

That setting allows for a violation of the data flow paradigm in that if the AE is executing when it comes time to invoke that call of the AE the call will be skipped and the calling loop/function will not be stalled. When the call is skipped, the default values returned by the AE are used instead of the actual return data. In my case I returned a Boolean that was set true by the AE. When the Boolean was found to be "True" by the caller, I would use the values returned by the AE. If the Boolean was false I would ignore the default data and use the data I had cached from a previous call of the AE.

 

Summarizing...

 

An Action Engine configured as subroutine can leverage the Skip If Busy" option to be able to pass data into a time critical loop without stalling the Time Critical loop.

 

So add that option to the list of options and choose what best fits your needs.

 

Ben 

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
Message 7 of 23
(7,613 Views)

Note: the OP is using TCP/IP, and is thus nowhere near "tightly timed" enough for the relative overhead of the various techniques to matter.

Message 8 of 23
(7,603 Views)

@drjdpowell wrote:

Note: the OP is using TCP/IP, and is thus nowhere near "tightly timed" enough for the relative overhead of the various techniques to matter.


Here is a link to an old thread where I was questioning why one read of a global would be slower than other reads of the same global.

 

In that situation I was using a Global as a "stop" flag that was checked by about 250 timed loops that were synced to hardware clock in LV 7.1.

 

When I used the "Global" some of the loops would return "Finished Late". Replacing the Global with an AE fixed the problem.

 

There was very definitive fast nailed down in that thread... if you are interested.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 9 of 23
(7,599 Views)

@drjdpowell wrote:

Note: the OP is using TCP/IP, and is thus nowhere near "tightly timed" enough for the relative overhead of the various techniques to matter.


Not all of EthernetIP is TCP/IP.

 

Datagrams can be very fast.

 

Ben

Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 10 of 23
(7,593 Views)