LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Performance of LVclass "Children in memory" node

I'm making an application that uses what is pretty much a factory pattern.  Rather than predefine all possible objects in multiple places, I want to programatically get a list of all descendants of a particular object, and then be able to choose from them on the fly.

 

LabVIEW helpfully comes pre-loaded with the Children In Memory[] Property for the LVClassLibrary reference.  However, when I tried using it, it ends up being pretty slow. (~230 ms to make a list of 9 classes).

 

I've created a workaround that seems to be about 5x faster (~40 ms on the same list) but it's also a bit of a hack in that it just parses the "All VIs in memory" node to find all currently loaded classes, and then checks to see if it can be cast to the parent class.

 

Neither of these options feel like they're the "best" option.  I could probably speed up the parsing on the "All VIs in memory" results some, but it doesn't feel like it ought to be the quickest method.  For compiled applications I can add in a cache check to avoid running the same check twice, but for live code I want to be able to load in classes dynamically.

 

Screenshots for a quick peek:

Time test LabVIEW node.PNGTime test All VIs search and test.PNG

Those were both with the same 10 classes in memory, all with a common ancestor, and about 30 VIs in memory.  I also tried it with the full application loaded in memory, which raised that to 3400 VIs and 96 classes in memory, and the run times increased to 60-70 ms for the "All VIs search" method and changed to 250-300 ms for the ChildrenInMemory[] node method, so neither has a particularly bad scaling issue.

 

Does anyone have a method either more "proper", faster, or (hopefully) both?

 

This is all in LV 2018 SP1 32-bit with the f3 patch applied.  

The sample code is attached.  It was originally a proof of concept LVOOP project that I picked to re-use because each class only has 1 or zero methods, and the classes involved were all descendants of a common "Animal" ancestor (cats, birds, etc.).

0 Kudos
Message 1 of 8
(941 Views)

Have you benchmarked the "Get All Descendents" invoke node on the parent class? It sounds more like the function you are looking for....

 

EDIT: Ah, i see. The Get All Descendents doesn't list the child classes, but their items (methods, controls). So it obviously doesn't work out for you.

So another consideration: Did you try recursive VI search rather than looping?

Norbert
----------------------------------------------------------------------------------------------------
CEO: What exactly is stopping us from doing this?
Expert: Geometry
Marketing Manager: Just ignore it.
0 Kudos
Message 2 of 8
(908 Views)

If I switch the NI implementation to paralellize the loop, it drops from ~240 ms down to ~200 ms.  Due to the rather simple nature of what I'm doing I think that would be the same if not better than it would be to set up a bunch of recursive VI calls.  So a slight improvement, but not much.

 

Even if the delay from the "Get All Descendents" was completely eliminated, the delay that comes from the "LVClass.Open" method is longer than the other method.  Just opening the class reference seems to take a minimum of 50 ms.

0 Kudos
Message 3 of 8
(893 Views)

As an additional note, if I change this example to actually include all the classes I actually may use in my project (10 direct descendants, with those descendants having 0 to 3 descendants each, and occasionally a single sub-descendant after that, for a total of 43) then the time for the "LabVIEW node" version goes up to over 2000 ms (even with full parallelism enabled), while the time for the "All VIs in memory" workaround remains at ~50 ms.

0 Kudos
Message 4 of 8
(890 Views)

I usually make my factories a bit different...

 

Simply try create a new default class with a given name (e.g. from an ini file). Then cast to the parent. It this works, I have my fabricated classobject, if not, the name wasn't valid...

 

Then make sure all children are in memory when building an executable. I use a pre-build script to add those classes (class constants) in a blank VI, and then put that VI in my code, or add it the the top level VIs in the build (always include doesn't work IIRC). This is done pretty much like your code, that is slow. During compilation, the speed will not be a problem though.

0 Kudos
Message 5 of 8
(875 Views)

I guess this is when you create descendant you also add it to a list or named queue so you have easy access to them.

Part of G#'s garbage collection is to do such a thing, so there is always named queues with all instances of specific objects. Maybe that is a solution?

/Y

G# - Award winning reference based OOP for LV, for free! ADDQ VIPM Now on GitHub
"Only dead fish swim downstream" - "My life for Kudos!" - "Dumb people repeat old mistakes - smart ones create new ones."
Certified-LabVIEW-Developer
0 Kudos
Message 6 of 8
(867 Views)

It's the enumeration of available children that is slow.

 

I don't think the creation is that slow, although it might help a bit...

0 Kudos
Message 7 of 8
(862 Views)

wiebe@CARYA wrote:

Then make sure all children are in memory when building an executable. I use a pre-build script to add those classes (class constants) in a blank VI, and then put that VI in my code, or add it the the top level VIs in the build (always include doesn't work IIRC). This is done pretty much like your code, that is slow. During compilation, the speed will not be a problem though.


Note that you'd need to do something similar no matter how your factory works. Unless you put the child constants in the factory. But if that's acceptable, you might as well refactor the factory completely (put the children in an array and use a for loop to get their names)… There will be a moment that you forget to add the child, and send it to the customer without it.

0 Kudos
Message 8 of 8
(858 Views)