03-26-2012 09:16 PM
Hi all,
I am trying to implement a function that reads a decent amount of udp data (~30 Mb/s) and then based on some characteristics sends it to a queue for further processing. Everything was working fine with the code in my top level vi, but then I moved it to a subvi to try and hide the process. I was hoping that this would allow me to clean up the top level vi and not distract people with a bunch of parrallel loops. To move to the subvi I passed in a reference to a control which quits the program. This obviously introduced a property node into the loop instead of a local variable and made things much worse.
I am familiar with the following thread:
http://forums.ni.com/t5/LabVIEW/local-variable-vs-property-node-value/td-p/292442
Although I must admit I never actually looked at the numbers to realize how bad the difference was. I figured it was a factor of 2 or 3, my tests with a simple system similar to mine showed a factor of ~300 times slower.
I have considered doing a timing difference calculation and only checking to stop the loop if the timing difference is greater than a certain amount. I think that should fix the problem but I wish I didn't have it to begin with.
Other than that, is there any other advice on this topic? I really liked the idea of hiding the details of the implementation and only having documentation at the top level that allowed someone to know what the process was doing.
Also, it is unclear to me what the functional difference is between reading the value from the reference and from the local variable. Perhaps someone could clarify.
Thanks!
Jim
Here's an example of what my code looks. In the subvi implementation the "quit" local variable has been replaced by a reference to a property node, with the reference coming from outside the loop to the property node inside of it.
03-26-2012 09:36 PM
Can you post the snippet of the BD showing how you have passed the control reference and also the sub vi how you have taken the value to stop the loop.
03-26-2012 10:31 PM
I've attached some more images. I'm using LV2009 and my create snippet from code function doesn't seem to be working all that well. The problem menitoned above manifests itself if I simply replace the local variable in the top level vi with a property node.
For the image below, the calling function in the top level vi is on the left. I've encased it in a sequence structure to facilitate dragging and to identify it as a functional unit. The sub vi it is calling is on the right. The vi being called in the loop "Read Cfg Packet" does the udp call and only outputs true if my test is true (similar to above). In the error case it outputs false. NOTE: I just realized the one note on the left in the image might be confusing, that loop it refers to is not shown
03-26-2012 10:59 PM
This is the problem when you are passing into a while loop it will take only the initial value you will not be able to update the value later so it will not at all work. You have to use a global variable to stop the loop in the sub vi.
03-26-2012 11:35 PM
P Anand,
There is nothing wrong with that implementation. Only the reference to the Quit control is passed into the loop. The value of that control is read inside the loop.
Jimbo,
How fast is your subVI's loop running? Could it be running so fast that it is eating up all CPU cycles? If so, it might be starving the UI thread from being able to get the current value of the quit control in the main VI.
Try putting a wait statement in your subVI's while loop and see if it changes the behavior.
03-26-2012 11:44 PM
Yes sorry I missed it.
03-27-2012 01:07 AM
03-27-2012 06:30 AM
Followup:
Here's a link to a good discussion on performance issues with LabVIEW;
http://zone.ni.com/reference/en-XX/help/371361H-01/lvconcepts/vi_execution_speed/
Here's a brief discussion of using references:
Though you can use controls, control references, and Property Nodes to pass data between VIs, they were not designed for use as variables because they work through the user interface. Use local variables and the Value property only when performing user interface actions or when stopping parallel loops.
User interface actions are historically slow on computers. LabVIEW passes a double value through a wire in nanoseconds, and draws a piece of text in hundreds of microseconds to milliseconds. For example, LabVIEW can pass a 100K array through a wire in 0 nanoseconds to a few microseconds. Drawing a graph of this 100K array takes tens of milliseconds. Because controls have a user interface attached, using controls to pass data has the side effect of redrawing controls, which adds memory expense and slows performance. If the controls are hidden, LabVIEW passes the data faster, but because the control can be displayed at anytime, LabVIEW still needs to update the control.
Hope this helps!
Wes
03-27-2012 09:37 AM
Locals have a special backdorr method of getting at the value in a control that bypasses the UI thread.
That is why it ran fast in the top-level VI.
When using a property node, the code will stall when it gets to the property node read while it waits for the OS to do the thread swap to the UI thread to read the value and then it will drop out of the UI thread and finish that cycle of your loop.
I would go for a LV2 Global to as the easiest fix since it will use the UI thread.
Ben
03-27-2012 09:47 AM
Hi all,
Thanks so much for the feedback. I tend to use the process of releasing a queue quite frequently to stop things, it never occured to me to create a queue or notifier for the sole purpose of stopping things. Creating a notifier and then wiring the error status of the "get notifier status" vi into the stop condition of the while loop worked great.
Regarding the loop and implementing a wait timer:
Since I am performing a udp read, it doesn't seem necessary to put in a wait timer. I was incorrect with my previous data estimate as I hadn't turned on one type of data stream. Given a rate that is actually a bit over 100 Mb/s with packet sizes being at most 1500 bytes I expect that I could reach roughly 10000 loops per second (100M/8/1500). My tests seem to indicate that the udp data is read in packets so that unlike a DAQ read there isn't necessarily an advantage in letting the buffer fill a decent amount before reading since I need to do one read per packet anyway. This is in contrast to a program like Matlab which seems to return multiple packets per read, so that running the loop as many times as packets are produced isn't necessary, although there you need to handle partial packets :/. The packet arrival rate seems to thus specify the minimum rate in which my loop must run, and the fact that the udp read waits until data arrives means that this loop can't take up all of the processing power ... I THINK ... someone feel free to correct or clarify as I am new with this.
Regarding the use of a property value to stop the loop:
I am still a bit unclear as to why the property node is so much different than a local variable. Most the comments I see regarding property nodes are with respect to writing to them, in which case I could understand there being issues with respect to redrawing components on write. What I don't understand is why reading a property node is so slow, especially if you are only reading its value. I have attached an image below which I think is somewhat similar to my situation. The references in the image were local variables of the Boolean control but the create snippet has replaced them with the property nodes. I've attached an image using the property node for reference as well. This second case is about 1000x slower than using the control. It seems like this is an optimization issue with the compiler that National Instruments has ignored. Alternatively I am missing something and perhaps someone could clarify what that is. I realize that perhaps property nodes should not be used as a general design feature but it is unclear to me how what seems like two identical situations, in which a user click can change a value that stops the loop, would result in such a huge difference in performance.
Again all, thanks for your help.
This is approximately 1000x slower than above ...