Jump to content

Why would one VI reading from a global always be slower than other VI's reading the same global?


Recommended Posts

Hi All,

After some trouble shooting the engineer I was working with looked at me and said "WHY?"

"Why questions are always the hardest Q's to answer.

Warning! I am going to be asking about normal LV globals NOT LV2 globals. Using LV 7.1.

I have to admit that I have very little experience using globals and this is probably my first attempt to use them.

I am using them in this application because I found that a simple boolean global can be read a lot faster than the best LV2 version I could think of. In my application, the "Stop Boolean" global is only written one place but read in about 250 sepearte loops to indicate it is time to stop.

About 30 of those loops are timed loops and we noticed that two of the timed loops were asserting the "Finished Late" flag. The actual finish time was about 1 msec after what was expected.

We found that if we ran the application without the two loops that were flaging the "Finished Late", none of the other loops had problems. If we added either of the two loops that were finishing late, they would again finish late but the others never had trouble.

Running either of the two loops by themselves never give an error. Add any of the other non-late-finishers, BINGO we start seeing the finished late again. Oh bother!

I removed ALL of the code inside the loops that finished late except the read from the global boolean and still the loops finish late.

At this point I had to question the global!

I replaced the global boolean read with a LV2 style boolean and the finished late erros stopped! :o

We could not make (dragging a window around on the desktop helped produce the error) that loop to finish late as long as it was using the LV2.

I restored the global boolean and >>>> Finished late!

More background info.

The application dynamically loads all the VI's required to operate. A timed loop is used in every loaded module. This is how I am quickly including and excluding the offending code. Continuing....

Changing the order in which the modules (timed loops) are loaded did not make a difference.

So.....

Why would 2 timed loops always take longer to read a global boolean than any of the other timed loops?

Do gloabl reads have to execute in the UI thread?

Thank you for reading,

Ben

Link to comment
Do gloabl reads have to execute in the UI thread?

Yes they do (from "VI Execution Speed" on NI's website):

How Multithreading Affects User Interface Actions

When you write to a local or global variable, LabVIEW does not switch to the user interface thread immediately. LabVIEW instead writes the value to the transfer buffer. The user interface updates at the next scheduled update time. It is possible to update a variable multiple times before a single thread switch or user interface update occurs. This is possible because variables operate solely in the execution thread. Functional global variables can be more efficient than ordinary global variables because they do not use transfer buffers. Functional global variables exist only within the execution thread and do not use transfer buffers, unless you display their values on an open front panel.

Link to comment
Yes they do (from "VI Execution Speed" on NI's website):

How Multithreading Affects User Interface Actions

When you write to a local or global variable, LabVIEW does not switch to the user interface thread immediately. LabVIEW instead writes the value to the transfer buffer. The user interface updates at the next scheduled update time. It is possible to update a variable multiple times before a single thread switch or user interface update occurs. This is possible because variables operate solely in the execution thread. Functional global variables can be more efficient than ordinary global variables because they do not use transfer buffers. Functional global variables exist only within the execution thread and do not use transfer buffers, unless you display their values on an open front panel.

You are fast Chris!

Lacking any more info I will have to read that as aplying to BOTH read and writes.

Now I have to wonder why the two loops in question are always "low man on the totem pole" when trying to get at the UI thread.

Well, I did give the globals a chance!

Maybe this will be better in the long run. It was going to get tough deciding to use LV2's or globals for those "single writer, multiple readers" situations.

Ben

Globals are evil! :nono:

Do the loops have the same priority? Do the VIs have the same priority, execution thread, common non-reentrant code? Did it happen before the Spring Equinoxe?

Come to think of it, we never saw the issue before yesterday!

All of the timed loops are clones each other (before I started hacking).

They are given unique names based on which module they are in. I can try ruling that out tomorow.

Yes I agree they are evil, but I try to give people (and LV functions) another chance.

Are the new LV8 shared globals just as evil?

Ben

Link to comment
It is possible to update a variable multiple times before a single thread switch or user interface update occurs. This is possible because variables operate solely in the execution thread.

Come to think of it - that means that you could write to a global and then read from it again before it's updated. I know that globals inherently lead to race conditions, but the statement above means that even if you force dataflow so a global is written on your BD and then later read, there is no gaurantee that the write happened before the read... :unsure:

Link to comment
Come to think of it - that means that you could write to a global and then read from it again before it's updated. I know that globals inherently lead to race conditions, but the statement above means that even if you force dataflow so a global is written on your BD and then later read, there is no gaurantee that the write happened before the read... :unsure:

Chris,

Experimenting indicates that the global reads are probably executing in the UI thread.

Switching all of the globals (in the timed loops) over to LV2 versions has dropped my CPU loads from 75% and 50% to 4% and 4%.

Ben

Link to comment
Switching all of the globals... over to LV2 versions has dropped my CPU loads from 75% and 50% to 4% and 4%.

Crikey! You must have a lot of global accesses in there - looks like most of your CPU was being taken up by obtaining mutexes and thread swapping :blink: A great demonstration of another reason why globals are evil!

Link to comment
You must have a lot of global accesses in there - looks like most of your CPU was being taken up by obtaining mutexes and thread swapping :blink: A great demonstration of another reason why globals are evil!

hmm ... but then he must have REALLY a lot of globals in his software. I usually use about 20 - 30 globals in a project. Most of them contain "system variables", which are written once at the programm start with things like: application path, path to database, is an exe, path to the ini file, and other programm specific configuration settings read from the ini.file ... and I never experienced any of the problems mentioned in the initial post.

But I can imagine, if you make massive usage of globals to pass data between parallel while loops, there could be a problem. Besides: if you mention, that the CPU load goes up to 75% and you can reduce it to 4%, when using old style globals, my question is: are you shure you haven't programmed a race condition? I mean, the switch to the OSG foreces labview to call the OSG-instances one by one, and as far as I know LV makes it sure, that all instances are called in the one iteration before the next iteration starts, which inherentely prevents from race conditions.

(did I make it clear what the point is? sorry, can't explain better [the coffee is bad this morning]...)

Link to comment
hmm ... but then he must have REALLY a lot of globals in his software. I usually use about 20 - 30 globals in a project. Most of them contain "system variables", which are written once at the programm start with things like: application path, path to database, is an exe, path to the ini file, and other programm specific configuration settings read from the ini.file ... and I never experienced any of the problems mentioned in the initial post.

But I can imagine, if you make massive usage of globals to pass data between parallel while loops, there could be a problem. Besides: if you mention, that the CPU load goes up to 75% and you can reduce it to 4%, when using old style globals, my question is: are you shure you haven't programmed a race condition? I mean, the switch to the OSG foreces labview to call the OSG-instances one by one, and as far as I know LV makes it sure, that all instances are called in the one iteration before the next iteration starts, which inherentely prevents from race conditions.

(did I make it clear what the point is? sorry, can't explain better [the coffee is bad this morning]...)

CORRECTION!

The revised CPU load of 4% were BAD numbers!

After concentratitng getting rid of the finished late errors and watching the CPU loads we found that we were not getting updates. WE eventually found that all o the timed loops were exeting prematuturly.

Running a preliminary test WITHOUT GLOBALS show only a small reduction in CPU.

We are still seeing the FINISHED LATE issues with only two of the 30 Timed Loops. Same two.

We are going to have to retrace our steps but globals are NOT involved anymore.

It is currently looking like an issue with the two timed loops.

I WILL update this thread when I know more.

Thanks for acting as a sounding board!

It really helps.

Ben

Link to comment

Update:

After reviewing our notes and more testing, our observations indicate that the problems may have been the timed loop itself.

We replaced the timed loop with a while loop and then replaced that with a Timed Loop and now that module is not repoting any "Finished Late" events.

I have asked for four more test runs to confirm the fix.

I have no plans to return to using the global "Stop Boolean".

I will update more when the testing is complete.

Again thank you for your "processing time".

Ben

Link to comment

Final Update (?):

After testing and personally witnessing the results this is what I found.

1) Globals are still evil. Eliminating these got rid of "Finished Late" issue due to dragging windows around.

2) One of the 600+ VI's passing a bad "Period" value into one of the timed loop sub-VI's.

3) The remaining failing module will be restructured to stream line its processing.

Once again, I thank you for sharing your ideas.

Ben

Link to comment
:blink: Oops! :D

There are a limited number of thoughts that I have had in my life that are worth repeating. For the most part they warrent a "Duh" and not a wow.

Three that come to mind are.

1) People always find things in the last place they look because after they find it, they stop looking.

2) If you are always early you are never late. (Einstien says I'm wrong on this one when the speed of light is involved).

3) I can do nothing in less time than you can do something. (Works well for optimizing code).

Thanks for your help Chris!

Ben

Link to comment
People always find things in the last place they look because after they find it, they stop looking.

That's got to be one of my favourites!

An optimist says the glass is half full, a pessimst says the glass is half empty, and an engineer says the glass is twice as big as it needs to be.

Link to comment
That's got to be one of my favourites!

An optimist says the glass is half full, a pessimst says the glass is half empty, and an engineer says the glass is twice as big as it needs to be.

Hi Chris,

I managed to get an official answer to my question re:which thread does a global READ occur in?

The official answer is....

"

Ok, the official word is that local and global variable reads do NOT cause a thread swap to the user interface thread.

"

See reply #29 in this thread

http://forums.ni.com/ni/board/message?boar...76661&jump=true

on the NI Dev-Exchange.

This contrary to what I had thought.

Ben

Link to comment
Local and global?!? Wow - this is completely the opposite of what I'd been previously told...

But it's truth. The big performance problem is not in thread switching here (thread switching while costly isn't usually where things go completely bad) but it is in copying the data. In order for the data flow paradigma to work without race conditions LabVIEW needs to make a copy of the data whenever a global or local is read. This is no problem for scalars but some people like to store x MB arrays in a global and read it every second to append a new subset to it and write it back. This is about the worst scenario you can think of in using globals.

Thread switching however does occur when using the Value property since properties are executed in the UI context. So here in addition to possible performance loss because of data copy the additional two context switches will further increase the performance problem.

Rolf Kalbermatter

  • Like 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.