Jump to content
manigreatus

DVRs within Classes

Recommended Posts

Is it a good practice to keep objects as DVRs within another object as shown below

post-28231-0-10246100-1359645535_thumb.p

 

In this case I am loading different drivers within HAL and I have no intentions to void dataflow by using DVRs rather I want to keep less memory for HAL.

Edited by manigreatus

Share this post


Link to post
Share on other sites

I don't see how this saves memory. If you're using this class strictly ByVal (not branching the HAL.lvclass wire and expecting the DVR contents to be the same on both branches), there are no duplicates of the Config data.

Share this post


Link to post
Share on other sites
Is it a good practice to keep objects as DVRs within another object as shown below

Why not.

This will help you access the same object even if you branch the HAL Wire.

Also it helps you locking the resource.

Memory Wise, I think it could be an advantage, if the Aggregated Object Contains Huge amount of data.

By replacing that with a 4byte DVR reference value, the HAL-Wire don't become so heavy.

So e.g. if you branch the Hal-wire, or when you go into many SubVIs, those SubVIs has to allocate memory for this Huge amount of data.

 

But should you ever branch a ByValue Wire?

If you want to run things in parallel and accessing one object, you have to go with the Actor approach, or...just use ObjectByReference.

//Mike

  • Like 2

Share this post


Link to post
Share on other sites

With the caveat that I consider it a bad practice to use references unless you are backed into a corner and have no other options, then, yes, this is a good practice. Just remember that if *any* data member of your class is by reference then things work much MUCH better if *all* data members of your class are by reference. Trying to mix by value members with by reference members is legal but results in situations that many people screw up easily (i.e. the wire forks and now half of their class is copied and half of their class is the shared reference, leading to confusion about what exactly this object represents).

  • Like 1

Share this post


Link to post
Share on other sites

I don't see how this saves memory. If you're using this class strictly ByVal (not branching the HAL.lvclass wire and expecting the DVR contents to be the same on both branches), there are no duplicates of the Config data.

 

 

With the caveat that I consider it a bad practice to use references unless you are backed into a corner and have no other options, then, yes, this is a good practice. Just remember that if *any* data member of your class is by reference then things work much MUCH better if *all* data members of your class are by reference. Trying to mix by value members with by reference members is legal but results in situations that many people screw up easily (i.e. the wire forks and now half of their class is copied and half of their class is the shared reference, leading to confusion about what exactly this object represents).

 

the reason why I chose this practice is a recent experience with a simple LV action engine being used in a GUI based application with different parallel processes. The application hangs when I tried to look for different parameters in the configuration, and the issue was resolved by using DVRs as shown below. I that case I was just having 100 I/Os with scaling info and in case of HAL I might end up with more than 200 I/Os including scaling info and calibration (a separate object) as well. 

 

post-28231-0-10681900-1359712427_thumb.p

Why not.

This will help you access the same object even if you branch the HAL Wire.

Also it helps you locking the resource.

Memory Wise, I think it could be an advantage, if the Aggregated Object Contains Huge amount of data.

By replacing that with a 4byte DVR reference value, the HAL-Wire don't become so heavy.

So e.g. if you branch the Hal-wire, or when you go into many SubVIs, those SubVIs has to allocate memory for this Huge amount of data.

 

But should you ever branch a ByValue Wire?

If you want to run things in parallel and accessing one object, you have to go with the Actor approach, or...just use ObjectByReference.

//Mike

 

It seems a very valid point to replace heavy HAL-wire with just a 4byte DVR ref. currently I have no intentions of branching if I need then I would go with the Actor approach or simply having an independent process.

Edited by manigreatus

Share this post


Link to post
Share on other sites

Random comments:

1) An “action engine” is a by-ref construct very similar in use to a DVR, so I don’t understand how you could have experience application hang with an action engine.  Having an action engine with a DVR inside it seems redundant and overly complicated.

2) I actually have some mixed by-val/by-ref objects, but they are “naturally” that way, because they are a by-value object that “decorates” or extends a reference.  For example, a “configurable forwarding address” which wraps a communication reference (queue, etc.) with by-val instructions on how to modify messages sent to this reference.  I also have some mixed objects that I would probably have been better off making entirely by-ref.

Share this post


Link to post
Share on other sites
Random comments:

1) An “action engine” is a by-ref construct very similar in use to a DVR, so I don’t understand how you could have experience application hang with an action engine.  Having an action engine with a DVR inside it seems redundant and overly complicated.

 

Yes you are right, but just see the code inside dvr because of which I had to use dvr (which was not part of my design).

Share this post


Link to post
Share on other sites
Yes you are right, but just see the code inside dvr because of which I had to use dvr (which was not part of my design).

That code should work fine without the DVR.  It shouldn’t hang the application.  

— James

BTW> look into “Variant Attributes” as a higher-performance way of doing look-ups like that.

Share this post


Link to post
Share on other sites
BTW> look into “Variant Attributes” as a higher-performance way of doing look-ups like that.

 

I did consider that but couldn't utilize them. It works very nice when you look-up against the same type of key say you are looking-up a 'data-cluster' against the 'name string' but what if you want to look-up the same 'data-cluster' against another type of key?

Share this post


Link to post
Share on other sites
the reason why I chose this practice is...

As long as you have a reason based on trying alternatives, not based on fear or a knee-jerk "cannot be done otherwise" response, you won't hear objections from me*. :-)

 

* unless your logic strikes me as wildly off base, but that's not applicable here.

I did consider that but couldn't utilize them. It works very nice when you look-up against the same type of key say you are looking-up a 'data-cluster' against the 'name string' but what if you want to look-up the same 'data-cluster' against another type of key?

You do what a SQL database does and double-key it. The first key maps to a second key. The second key maps to the data cluster. You can have as many different types of first keys as you want that all map to the same second key. Include some bit of ref counting in the second key to know how many first keys are pointing at it so that you know when to throw the data cluster away.

Share this post


Link to post
Share on other sites

I agree with Mikael and Stephen; there's nothing wrong with putting an object in a DVR inside another object.  However, I also agree with Todd and James; based on what you've told us I don't see how adding the DVR uses less memory and the action engine example you posted should work fine without the DVR (assuming your vi is set to non-reentrant.)

Share this post


Link to post
Share on other sites

I'm using this technique by storing the ref to the private data of a class. But the problem I'm facing now is that I can not extend the private data by inheriting the class. I have to create a new or a second reference in the child class. Or use variants to store the data.

Share this post


Link to post
Share on other sites
But the problem I'm facing now is that I can not extend the private data by inheriting the class.

 

This is by design.  In Labview, child classes *never* extend the private data of the parent class--they have their own private data.  Parents can make their private data available to children via accessors, but there is no way for a child class to change the set of data types the parent class contains in its private cluster.  If you want the child classes to be by-ref also, the child class should have its own DVR refnum in its private cluster to maintain the child class' data.

 

FWIW, I almost never build classes with built-in by-ref behavior.  I've found I have much more flexibility if the classes are by-value, then if I need to interact with one in a by-ref way, I let the application code put the object in a DVR and pass that around.

  • Like 1

Share this post


Link to post
Share on other sites

Thanx all for your invaluable comments! Now I am almost convinced not to have DVRs for my driver objects but the thing still in my mind is that HAL wire is going be heavy anyways so wont DVRs do better in that case?

 

I also agree with Todd and James; based on what you've told us I don't see how adding the DVR uses less memory and the action engine example you posted should work fine without the DVR (assuming your vi is set to non-reentrant.)

 

For me with DVRs  you can easily play around with arrays since you don't have data copies. The example shown was a non-reentrant vi being called from different parallel processes. As you see there shouldn't be anything wrong without DVRs so did I but the reality was different. Probably I had some other issue but it was resolved when I used DVRs. I will try to re-create the error when I get some time.

Share this post


Link to post
Share on other sites
Now I am almost convinced not to have DVRs for my driver objects but the thing still in my mind is that HAL wire is going be heavy anyways so wont DVRs do better in that case?

 

Like Todd said, if you're not branching the HAL wire at all putting that info in a DVR doesn't save you any memory.  All that HAL data still needs to be stored in memory somewhere.  Having a 4-byte reference instead of a multi-kb data structure on the wire only saves you memory if copies are created.

 

If you are branching the HAL wire there are times when LV will make copies of the data.  However, *even if* you are creating data copies, 200 i/o channels with associated scaling and calibration info isn't that much data for a modern computer to copy.  I'd be surprised if it was noticable.

Share this post


Link to post
Share on other sites

My rule is that if the data in the attribute is huge, I use Reference based objects, just like NI does for the NI-IMAQ VIs. It helps the user not to accidentally use too much memory.

Or sometime I use a GDS design pattern “Add reference variable to class” to a normal ByValue class.

post-941-0-75669000-1359957434_thumb.png

post-941-0-23490200-1359957444_thumb.png

..and sometimes I even spell ...Aray... with 2 Rs

 

Share this post


Link to post
Share on other sites
I use Reference based objects, just like NI does for the NI-IMAQ VIs.

 

Citing the NI VIs as a template to follow is silly. All the modules like this date from a time when by value objects did not exist. To achieve encapsulation of data, references was the only option. I am not saying they wouldn't be references if they were designed from scratch today... they might be. But the engineering evaluation was never made, so citing them as your reason for using references reads too much into their design. And they all have established patterns of usage that make converting to a by value style today impossible as there's really no way to do such a conversion and maintain backward compatibility.

 

Very large waveforms, arrays, strings, and clusters have been used quite successfully by many people for many years in LabVIEW. Becoming a class does not change the calculus of what should be by value and what should be by reference.  If you are branching the wire, LabVIEW *may* make copies of the data. The majority of the time -- and the LV compiler keeps getting smarter about this with every release -- when it makes a copy, it is because a copy is needed, and would be needed even if you are working with references, only in the reference case, you'd be dropping an explicit "do a deep copy of this reference" node.

 

In my book, leaning on the LV compiler to give you better data copy control is a best practice. Trying to take control of that for yourself just burns up lots of processor cycles uselessly on memory constructs that add expensive thread synchronization when none is needed for the data accesses and cuts you off from all the compiler optimizations that come with dataflow.

Share this post


Link to post
Share on other sites

I was just recently sorely wishing NI-IMAQ had by-value image frames.

 

— James

 

PS to manigreatus> have you considered turning it inside out; make a by-value object and keep it in a DVR if (and only if) your application needs it?

Share this post


Link to post
Share on other sites
I was just recently sorely wishing NI-IMAQ had by-value image frames.

 

I know what you mean.  Their by-ref nature is kind of a PITA in Labview.  In my IMAQ app I had to pipeline the image processing and I ended up copying the image from one buffer to the next for each stage.

Share this post


Link to post
Share on other sites
In my book, leaning on the LV compiler to give you better data copy control is a best practice. Trying to take control of that for yourself just burns up lots of processor cycles uselessly on memory constructs that add expensive thread synchronization when none is needed for the data accesses and cuts you off from all the compiler optimizations that come with dataflow.

Not to hijack the thread, but are you referring to the IPE structure here? I still use that a lot to minimize copies when manipulating large structures.

Share this post


Link to post
Share on other sites
Not to hijack the thread, but are you referring to the IPE structure here? I still use that a lot to minimize copies when manipulating large structures.

More than that.  The IPE makes explicit what the compiler tries to do anyway: minimize copies.  In fact, the IPE’s real benefit is as a guide to the programmer in writing code that can be done in place, rather than actually allowing in-placeness.  

Share this post


Link to post
Share on other sites
Not to hijack the thread, but are you referring to the IPE structure here? I still use that a lot to minimize copies when manipulating large structures.

Nope. The IPE is you telling LV what you are doing, not necessarily how to do it. Yes, it was named for asserting inplaceness, but that really only applies to the "Element In"/"Element Out" pair, and we never really came up with a better name for the structure. It simply provides a better way of saying "I am doing this complex operation of taking a value out, modifying it, and putting it back...LV, you figure out how to lay out the memory more effectively now that you have more information." I am referring to the overuse of the DVRs just to avoid copies where you're taking information away from LabVIEW so you can control the copies entirely. In some cases, yes, that's what you have to do, but with every rev of the compiler, those situations become rarer. Doing it knee-jerk just because you have a large data structure isn't good practice, IMHO.

More than that.  The IPE makes explicit what the compiler tries to do anyway: minimize copies.  In fact, the IPE’s real benefit is as a guide to the programmer in writing code that can be done in place, rather than actually allowing in-placeness.  

Exactly! Like what I wrote in the blog post about the Swap Values primitive. Yes, it can reduce data copies because LV knows that swapping is your intent, but it also makes it much clearer what you're doing with all those crossing wires, and that has benefit all its own.

Share this post


Link to post
Share on other sites
In fact, the IPE’s real benefit is as a guide to the programmer in writing code that can be done in place, rather than actually allowing in-placeness.  

Yeah, I like to use it for the "magic pattern" of unbundling/bundling exactly the same elements in a cluster, or for double-splitting arrays to operate on an entire row at a time (which I don't think you can do sans-IPE). Seeing the structure in my code six months later gives me a reminder that I need to tread carefully with edits.

Share this post


Link to post
Share on other sites

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.