Jump to content

DVRs within Classes


Recommended Posts

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
Link to comment

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
Link to comment

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
Link to comment

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.

Link to comment
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).

Link to comment
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.

Link to comment
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?

Link to comment
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.

Link to comment

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.)

Link to comment

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.

Link to comment
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
Link to comment

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.

Link to comment
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.

Link to comment

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

 

Link to comment
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.

Link to comment
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.

Link to comment
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.

Link to comment
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.  

Link to comment
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.

Link to comment
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.

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
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.

  • Similar Content

    • By Axelwlt
      Hi
      I am reading big TDMS files (~1GB) and I try to minimize memory usage.
      I read a signal once and I want to keep it for later usage, so I tried to write it to a DVR in the hope that I have only one instance of the data in memory.

      However the task manager tells me that uses 2 times more memory than it should.
      I think the problem is that the array is not deallocated although I don't need it after writing it to the DVR.
      Is there a solution to make sure I don't have copies of data?
    • By Ram Prakash
      Can anyone please tell what a DVR [ Data value reference ] is ? I want to know at what situation it will be used and what are the advantages we get by using DVR. I am really confused in this topic . If someone has any code in which they have worked with DVRs. kindly share it to me.
       
      Thank you.
    • By Zyl
      Hi everybody,
       
      I'm running into something I don't really understand. Maybe you can help me here !
      I've got a LVLIB that is used as an 'Interface': it exposes public VIs which wrap around public functions of a private class (see code attached) . The class is private because I want to force the users to use the 'interface' functions.
      In one of my interface VI, I create a DVR on the private class (Interface_init). The DVR is stored into a typedef (FClass_DVR.ctl) and this typedef is the 'reference' that link all the interface public functions.
      In TestCode.vi (which is not part of the lvlib and illustrates the standard code that a user can create to use my driver), I can call my public interface functions and link them without any problem.

      But as soon as I create an indicator on that reference (to create a state-machine-context-cluster for example), my TestCode VI breaks !

      The error returned is : This VI cannot use the LabVIEW class control because of library access scope. The LabVIEW class is a private library item and can only be accessed from inside the same library or libraries contained in that library.
      I understand that the class is private. But the DVR is contained into a public control. Using an In Place structure on that DVR into TestCode would not work, since the class is private. So why is the DVR control problematic at that point ? Creating it do not breaks any access protection...
      Am I missing something ?
      DVR Private POC.zip
    • By IpsoFacto
      I've got some weird stuff going on with a cRIO project I'm working on wanted to get some opinions on it. The basic architecture is a set of classes that do some process. That process registers with a server. The internal data of the process is held in a DVR and the server get's access to that DVR. Clients use TCP to ask the server to do something, the server makes a call against the classes DVR and returns a response to the client.
      To simplify the issues I'm seeing I created a class that internally just increments an integer every 500ms. The client asks the server what's the current count, the server asks the Counter class and returns the answer to the client. This works perfectly fine when running the VI in the IDE. When built it connects, will get the JSON message back, but always gets a default value from the DVR call (zero, in this case). As soon as I open a remote debug panel to the cRIO, everything is working. The count is correct, the client calls work, just like normal. As soon as I right-click, close debug, it goes back to zero. Open debug works, close debug, back to zero. I know the DVR isn't getting dropped because the count continues to increment while not in debug, the process is still running happily with no issues.
      Here's a few screenshots of the code;
      Count Class process (get the count, increment, write it back to the DVR) - Counter Class process
      You can see the DVR vi's are actually vim's using a cast. I can't imagine that's the issue.
      Server Side call - Server Side calls
      All this does is get the count from the DVR (same as above) and wraps it in JSON and passes it back to the client as a JSON string.
      I also implemented an Echo class that ignores the process and DVR's, it just takes whatever string you sent form the client to the server and passes it back with a prepended "@echo". This works when running as an executable with the debug turned off so I know the client, server, and the server/class calls are all working as expected.
      Any thoughts here would be welcome, thanks.
      edit: I added the any possible errors coming from the variant cast to the JSON reply. When the debug is open there are no errors, when the debugger is closed it throws error 91, but the in-place element structure reading the DVR does not throw any errors. How can a variant not exist until a debugger is opened and than it magically exists?
      edit: the internal data dictionary is a wrapper around a variant attribute, I wired out the "found?" terminal all the way out to the JSON reply and if the debugger is open the attribute is found, but not if the debugger is closed. Anyone have issues with Variant Attributes in Real-Time?
    • By the_mitten
      The introduction of parallel, read-only access for DVRs in LabVIEW 2017 adds a great deal of flexibility to using DVRs to monitor values in parallel executions of code. Fo\The downside of this, of course, is the necessity of using the In Place Element (IPE) throughout your code simply to read the value. Having IPEs throughout your code just to read a value both takes up block diagram real estate and also takes more clicks than desirable to insert.
      Similarly, though less frequently, there are times when you only need to update the value within a DVR without actually performing any logic inside of the IPE.  This situation is less frequent, at least for me, as I am usually using arrays or classes with DVRs such that I actually need to modify the existing data rather than simply replacing it.
      A more preferable solution to the above situations would be to have Read/Get and Write/Set VIs for the DVRs to simplify the process of working with them. This way, and IPE on the block diagram would only be needed when you were actually modifying the existing data within the DVR, rather than simply overwriting or returning the current value.
      Thanks to the power of malleable VIs and the type specialization structure that is now officially released in LabVIEW 2018, a better solution is now available. I’ve created two malleable VIs, Read  DVR Value (Parallel) and Write DVR Value that allow you to perform a write and a parallel read on any DVR data type.
       Now, you can use a single VI that you can insert via Quick Drop to read or to write DVR values.  
      Download the attached ZIP file to access the two malleable VIs and example code, and please let me know your thoughts in the comments!
       


      DVR Read and Write VIs 1.0.0.zip
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.