Jump to content

LabVOOP Performance Issue: To More Specific function


Recommended Posts

"When you have eliminated the impossible, whatever is left, however improbable, must be the truth."

-- Sherlock Holmes

Or, in my case, whatever is left must be the bug.

I've been digging for the source of the performance problem with Map.lvclass (posted here). Various LAVA users posted performance graphs that showed significantly unexpected results: the class implementation of a map came in behind the array implementation. That flies in the face of every bit of computer science theory that I know. So there had to be something strange going on.

I now have the answer. The problem is the To More Specific node. Now, if you're like me, you're probably asking, "How the heck could such a simple node be the source of performance problems? It barely does any work!" And that's the problem -- that node is doing way too much work.

This node has a bug in LV8.2 and 8.5 that forces a full copy of the object to be made whenever the data successfully downcasts. A correct implementation of the node would not make any data copy -- the class data that was traveling on one type of wire should be the same data now traveling on a new type of wire. As a result of this bug, the Map was making hundreds of copies of itself needlessly. With the refnum data types, this really isn't a big deal -- they're just 32-bit numbers and duplicating one is pretty low overhead. But with a class, with all of its private data, it's a huge deal.

What are the ramifications of this bug? First of all, whenever possible, LV class developers should avoid using the To More Specific node to do type testing -- use dynamic dispatch subVIs instead. That's just good programming practice anyway*, but this bug makes it even more important. Second, any LV class developer who is writing a nested data type -- one where the child class includes an instance of the parent class -- needs to be aware of potential performance problems if your data structure gets large. These problems will persist until this bug is fixed in a future version of LabVIEW. Some data types, such as a simple linked list, may be implementable without using To More Specific. But I have not yet managed to do this with the Map class -- at some point in every test implementation, I had to use a To More Specific node. There's just no way to get a parent wire changed into a child wire without using the To More Specific node, and those extra copies slow stuff down considerably.

This was reported to R&D (#121514) for further investigation.

* Why is type testing bad? If you use multiple To More Specific nodes to figure out which class an object is and then use a case structure to execute specific code, you'll create code that requires maintenance every time a new child class is created. And the type testing is done multiple times: "Is it this one? No. Is it this one? No. ...". Dynamic dispatching tests the class once and calls the right function directly, and if you have a new child class, there's no code to update.

Link to comment

Ouch !

The VariantType utility functions in vi.lib include a vi that will give you the class filename of the class 'on the wire'. Does that do some horrible memory copy as well, and if not, could it be used to test for the 'true' class of the wire (if the testing code had enough intelligence to know that class A.lvclass was in fact a descendent of class B...) or is the problem that you always actually need the wire of the descendent class ?

Edit: oops, reread the original post and realised my question is stupid. It's been a long day.

Link to comment

QUOTE (Aristos Queue @ Jul 29 2008, 02:24 PM)

I'm glad you caught this :thumbup:

I noticed having performance problems (especially for classes with a large amount of data -- such as a picture control with a large image on it) but never knew why... I use this node all the time in my LVClass code so I think I now have the answer.

I don't know if I like the workaround though:

QUOTE (Aristos Queue @ Jul 29 2008, 02:24 PM)

LV
class developers should avoid using the To More Specific node to do type testing -- use dynamic dispatch subVIs instead

One thing I've been meaning to do for a while but not had a chance to do is to understand exactly 'when' a LabVIEW class becomes locked. For example, if I have a plugin system, I don't want my class to be locked until the class has been 'plugged in'... (because I want to be able to edit the class for as long as possible). However if I have a Dynamic Dispatch VI, the class is immediately locked in my project (whether or not I have instantiated it) as soon as the plugin-loader runs. This behavior makes it hard to work on plug-in classes while the plug-in loader is running (if you're using Dynamic Dispatching). Hence, I've been avoiding dynamic dispatching on plug-ins... (I know, that sounds like a silly statement but my plug-in interface is pretty simple).

Am I basically stuck now having to go back to the dynamic dispatching world and having my classes getting locked un-necessarily just because they happen to be in my .lvproj file? Or is there some way for me to get a class to become 'unlocked' while the plug-in loader is running?

Link to comment

QUOTE (Omar Mussa @ Jul 31 2008, 11:05 AM)

Well, you can load your top-level VI without loading a project. Then the child classes would not be loaded into memory. If you wanted to edit a child class while the framework was running, you could load the child in its own project (which is a separate application instance). To open a class' tree without loading a project, just pop up on any FP control of the class or BD constant of the class and select "Show Class Library".

But other than that, yes, you're stuck.

LabVIEW cannot predict when data of your child class will be unflattened from a string, loaded as part of a VI coming into memory, instantiated through the latest hack you've invented, etc. Once there's data, there can be function calls, and the dynamic dispatch node has to be ready to go. We can't delay the reservation because reservation must occur in the UI thread for safety, and that would force all LV class operations to be capable of swapping to the UI thread, which would eliminate a lot of our optimizations, even if it was a feature that was never used in your particular app.

I wish that the project only listed the classes instead of loading them. But the architecture decision for that goes way beyond the needs of LV classes, affecting all library types (.lvlib, .xctl, .lvsc, .lvclass, etc). Not something I can get changed easily, though it has been discussed.

QUOTE (Tomi Maila @ Jul 31 2008, 03:50 AM)

Thanks for catching this major bug AQ!
:)
Do you already know if you manage to fix it for the maintenance release of winter 2009?

I guarantee it will be fixed in a future version of LabVIEW. Beyond that, I cannot guess myself, and even if I could, I wouldn't be allowed to post the answer here. Sorry.

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
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
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.