LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Static control references are slow if the UI is busy

This one surprised me and I wanted to post it for anyone else that might make some bad assumptions

 

In my top loop I use some static references. I always imaged those as constants requiring nearly zero resources. As it turns out, if you busy the UI with something like updating a graph, it actually takes easily 300 ms to read 10 references.

static refs.png

0 Kudos
Message 1 of 12
(1,295 Views)

Three things:

  • Static references belong on the toplevel diagram, not inside tight loops.
  • You need to disable debugging. With debugging enabled there is extra code generated so you can probe the reference wires inside the innermost structures. (After you disable debugging, your times will be very short!)
  • Having two tight loops in parallel is not great. You might want to place a small wait in each. Even a 0ms wait allows a task switch to give the other loop a chance. (Your are probably OK here since you have multiple cores, but remember that the UI thread is single threaded and is quite overloaded in your case. Basically, you are just heating the room.)
0 Kudos
Message 2 of 12
(1,261 Views)

Yes, I definitely learned the hard way that static references should go top level. I still don't understand why since they should be like a numeric constant which would be fine in a tight loop right? Putting the references at the top is ugly.

 

No, if you do something with the reference array outside the for loop, we still see code that should be constant folded taking hundreds of miliseconds even if you disable debugging

 

Neither loop is a tight loop. Each has a 5 ms sleep. I don't totally understand the load on the UI thread and how that might slow down my loops. When you write a value to a control like in the bottom loop, you aren't asking for a synchronous draw are you?

0 Kudos
Message 3 of 12
(1,200 Views)

A sorry, I did not see the occurrence timeout. Haven't use that in decades, ever since the event structure was introduced. 😄

 


@nanocyte wrote:

 

No, if you do something with the reference array outside the for loop, we still see code that should be constant folded taking hundreds of miliseconds even if you disable debugging


Can you define "something". I really don't understand what you are trying to say. With debugging disabled, the timing in the original top loop is basically instantaneous in my testing. (i.e. <<microseconds)

 

altenbach_0-1708029678915.png

 

What is the use for the array of references? For example if you use it to iterate over property nodes, each will probably run in the UI thread, I think

 

0 Kudos
Message 4 of 12
(1,193 Views)

Example something.

example somthing.PNG

Without doing "something" to the array of references, I think the compiler identifies the static references as useless and removes them

0 Kudos
Message 5 of 12
(1,187 Views)

Yes, I was just playing with something similar and now that the references are no longer "dead code eliminated" (because if generates an output!), I do see the dramatic slowdown of we build inside the loop.

 

altenbach_1-1708030947257.png

 

 

 

Of course graphing 100k points on a graph that is a few hundred pixels wide is very expensive and is heavily taxing the UI thread. I simply would not do that ever.

 

Only NI can say what's going on here....

 

0 Kudos
Message 6 of 12
(1,176 Views)

@altenbach wrote:

 

 

Only NI can say what's going on here....

 


I am not from NI, but I think this penalty caused by massive threads contexts switching between UI Thread and thread, which is assigned for standard execution system. UI Thread is single, the standard execution system may have up to 24 parallel threads by default as far as I remember.

The references (as well as property nodes) executing in UI thread (this also stated somewhere in documentation). So, every time when we obtaining the reference, it switched us to UI thread, get this reference, then switched back to standard thread and in fast loop (here 32 iterations for 10 references running in while loop) we have lot of such switches (why its not cached, another question). And all 10 references will be obtained sequentially, not parallel.

It is quite simple to demonstrate. Usually if I have some UI loops with references and property nodes mixed together with some loops which should be fast, then to control that I will not block UI thread in such loops by occasionally forgotten reference I placing another while loop which will suspend UI thread execution for some time and see what happened with my loops then:

image-20240216061140389.png

I just put half second Sleep called from kernel32.dll from UI thread (not thread safe!) and another half second by Wait (ms), otherwise you will get troubles to stop this VI. Call the DLL in UI Thread will suspend execution of UI thread for half second, whole UI will be "frozen" and you will see that the loop, where we have Reference is also suspended for that time, we have only around 50 iterations per second, and not 100 as expected to have for the loop with 10 ms delay.

Now, if I will move the reference outside of this loop, then the cycle will be not blocked any longer, and will iterate around 100 times per second, as expected, that the difference:

image-20240216061426728.png

But if I will use Property Node inside of my cycle, then penalty comes back, because Property Node will execute in UI thread and will therefore will wait for Sleep, its cannot be executed in parallel with DLL call in UI Thread as well:

image-20240216061558619.png

So, even if placed references outside of the loop, but when you will start to work with Property Nodes, your "Fast!" loops will slow down again (not checked, but pretty sure).

It is possible to see these context switches in Process Explorer from SysInternals:

image-20240216062640675.png

(you can also suspend the threads and check what happened).

And back to original VI — there lot of threads switches to UI Thread (which is single) and back caused by references, and the overall performance goes down significantly.

Message 7 of 12
(1,156 Views)

When i hear "The UI is slow/sluggish" i immidiately think of UI thread switching, and your example shows it clearly. It should be fairly easy to modify it to use "Get Control Value by Index" and it'd be interesting to see the difference!

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
Message 8 of 12
(1,135 Views)

A static reference is still a reference. Static means that the underlying object is allocated/created at load time, not runtime and the object gets a marker to indicate to the Close Reference that it should do nothing on this object, since it will be deallocated at unload time.

All the rules for accessing VI objects still apply, including having to arbitrate for the UI thread when trying to access it. So the only big difference about static references to normal references is that retrieving such a reference does not increment the object refcount and passing it to a Close Reference node is a NOP! Other rules still apply including that any operation on them requires the UI thread to run it in, to guarantee no race conditions can occur.

 

Property nodes in fast or tight loops is ALWAYS a code smell. In fact I go as far as claiming that property nodes (and methods) in anything but your active UI loop are simply bad. Just don’t do it. If you need UI feedback from such locations, the solution is NOT to use control references but proper queue or similar based messaging to your UI loop! If that feels to cumbersome to implement, the according UI feedback for sure is not important enough to care about. 😀

 

I have long ago decided that the somewhat popular design model of acquiring all UI control references to pass to subVIs for updating of the UI is one of the most ultimate anti patterns. It seems easy to do but promotes terrible application design. It’s often employed by people who know enough about LabVIEW to be dangerous but not enough to know that they are dangerous.

Rolf Kalbermatter
My Blog
Message 9 of 12
(1,128 Views)

@rolfk wrote:

I have long ago decided that the somewhat popular design model of acquiring all UI control references to pass to subVIs for updating of the UI is one of the most ultimate anti patterns. It seems easy to do but promotes terrible application design. It’s often employed by people who know enough about LabVIEW to be dangerous but not enough to know that they are dangerous.


Word!

G# - Award winning reference based OOP for LV, for free! - Qestit VIPM GitHub

Qestit Systems
Certified-LabVIEW-Developer
0 Kudos
Message 10 of 12
(1,102 Views)