Jump to content

DVR Error Handling


mje

Recommended Posts

I'm just finally getting enough time on my hands that I can explore DVRs. I think I'm missing something with respect to error handling and I'm hoping someone can enlighten me. See below:

post-11742-126892283135_thumb.png

My first thought when I tried wiring this up was of the whiskey tango foxtrot variety, and well...it still is.

The process of taking in a DVR, checking for an error, deserializing contained value, operating, then reversing the process is inherently...serial. Why is the error handling so discontinuous? Why doesn't anything have error in terminals which forces me to bundle 3 values together each time I need to operate on the DVR? This seems unnecessarily messy and inelegant. Am I missing something?

Link to comment

I'm just finally getting enough time on my hands that I can explore DVRs. I think I'm missing something with respect to error handling and I'm hoping someone can enlighten me. See below:

post-11742-126892283135_thumb.png

My first thought when I tried wiring this up was of the whiskey tango foxtrot variety, and well...it still is.

The process of taking in a DVR, checking for an error, deserializing contained value, operating, then reversing the process is inherently...serial. Why is the error handling so discontinuous? Why doesn't anything have error in terminals which forces me to bundle 3 values together each time I need to operate on the DVR? This seems unnecessarily messy and inelegant. Am I missing something?

I agree it's terrible usability. But I think the reasoning behind it may be functionality-related. Usually nodes that have an error passed in are a no-op. What happens if the left DVR node has an error passed into it? Does it dereference the value? Does it output a default value and leave the reference alone? Even more questionable is what happens if the right DVR node has an error passed into it. What happens then? Do we leave the DVR open, because the close operation doesn't happen? Is the value ignored?

Ideally I would like these nodes to have error inputs, but they have no change in behavior when an error is passed in. From a usability and inplaceness perspective that is best. That, however, is completely different than any other function.

Link to comment

I'm just finally getting enough time on my hands that I can explore DVRs. I think I'm missing something with respect to error handling and I'm hoping someone can enlighten me. See below:

post-11742-126892283135_thumb.png

My first thought when I tried wiring this up was of the whiskey tango foxtrot variety, and well...it still is.

The process of taking in a DVR, checking for an error, deserializing contained value, operating, then reversing the process is inherently...serial. Why is the error handling so discontinuous? Why doesn't anything have error in terminals which forces me to bundle 3 values together each time I need to operate on the DVR? This seems unnecessarily messy and inelegant. Am I missing something?

Well technically you don't have to merge the error in wire as you have the case structure catching any errors... but I know what you mean.

I would like a single class method to accept DVRs.

That way I would only have to create one method for ByVal that I can use ByRef

If I wanted to string together a bunch of methods inplace then I would use the IPE and suffer the wrath of size on the BD and the error handing :)

Right now I have create another VI just if I want to read one method and it is a PITA.

I understand about the consequences, and I want the option.

Please vote here to get this one through into 2010!

Link to comment

Well, even though there's no error for the input, I still merge because if I recall there are some legacy VIs can issue a warning...error is false but a code exists. Hence I think it's always important to propagate a no error condition (or am I imagining things?).

Jarrod's comments make sense though, I think I might have to agree now with the current design. However:

If the left DVR node fails to get the value for whatever reason, I'd expect a default value to be returned, analogous to overstepping an array. I don't think it would be a big stretch to expect the same behavior with respect to an error condition. BUT...as Jarrod said, the real question is what happens on the right node. This node must always attempt to execute, otherwise all sorts of bad synchronization things can happen. The error in functionality makes no sense for this node...if you don't replace the value, most programs would enter an undefined state, probably a deadlock since NO task would ever be able to retrieve the value afterwords if the value is never re-referenced.

So I guess after more careful consideration, I think the nodes are designed exactly the way they have to be designed.

Link to comment

Well, even though there's no error for the input, I still merge because if I recall there are some legacy VIs can issue a warning...error is false but a code exists. Hence I think it's always important to propagate a no error condition (or am I imagining things?).

Great point, but for me I don't normally have a system in place for trapping, reporting and logging warnings though, only errors.

So I guess after more careful consideration, I think the nodes are designed exactly the way they have to be designed.

Yes, there are designed correctly, IMO that same design should be used when a DVR is connected to a class method, but (the merging etc) should all take place behind the scenes. This is a specific use case, but that has come up frequently for me.

Link to comment

The process of taking in a DVR, checking for an error, deserializing contained value, operating, then reversing the process is inherently...serial.

FYI, when DVRs were first released there was an example posted by an NI employee and some discussion about the error handling. As I recall the example completely ignored one of the IPE error outputs because it would never generate one in that code. The details (and the a link to the thread) escape me at the moment.

I did find this thread with DVR error information from AQ...

> I'm not sure what kind of errors will be generated by the IPE read and write node.

The only one is "invalid reference". The Close Reference node actually waits for all current IPE structures, so there is no async delete to worry about, but you can have a Not A Refnum or a refnum that has already been Close, or a refnum that was created by someone casting some random integer into a refnum -- any case where the unlock tries to unlock an invalid refnum creates an error that needs reporting.

Link to comment

The two error terminals of the read/write (lock/unlock) dvr border nodes deliver identical errors. Thus, it is never necessary to "tunnel out" the errors from the lock/read border node as done in the first post's code. Also, technically the write/unlock node does nothing but release the DVR's lock and thus cannot return any new error.

As for the lack of input error terminals, there was confusion as to what the behavior would be if an error were wired into the read/lock DVR border node (the write/unlock would continue to simply release the lock). Should the nodes ignore the error but add it to the error out? Should they not lock the reference but instead create a default value on the wire? mje has a good discussion. In the end, even if perhaps it wasn't the most usable design, we wanted the behavior to be clear for the nodes, so we omitted the error-in terminal.

Link to comment

To add to DJed's post:

In the particular example posted, you don't need the Merge Errors.vi at all because there's no reason to merge a guaranteed "no error" with the other error stream.

Also, technically the write/unlock node does nothing but release the DVR's lock and thus cannot return any new error.
Or, to phrase it another way: BOTH "ERROR OUT" TERMINALS RETURN THE SAME VALUE. So you never have to merge these two error streams. Automatic error handling is satisfied if you wire either one of these two error terminals.
  • Like 1
Link to comment

...technically the write/unlock node does nothing but release the DVR's lock and thus cannot return any new error.

Very good to know. So essentially the only time the unlock fails is if the lock has previously failed (with the same error). Thanks for clarifying.

Automatic error handling is satisfied if you wire either one of these two error terminals.

I find this statement however implies behavior I'd not expect from LabVIEW...are you implying that in this case, if auto handling is enabled and you have an unwired error terminal on an IPE node whose mated side *is* wired, LV won't automagically halt execution when an error is generated? Does this apply for variants as well as DVR nodes?

Link to comment

I find this statement however implies behavior I'd not expect from LabVIEW...are you implying that in this case, if auto handling is enabled and you have an unwired error terminal on an IPE node whose mated side *is* wired, LV won't automagically halt execution when an error is generated? Does this apply for variants as well as DVR nodes?

Variants? I have no idea what you're talking about. But, yes, you have the behavior correct. Those two error terminals are the same error, just available at two different locations on the node -- where "node" in this case means the combined pair of the DVR read and DVR write.
Link to comment

To add to DJed's post:

In the particular example posted, you don't need the Merge Errors.vi at all because there's no reason to merge a guaranteed "no error" with the other error stream.

Or, to phrase it another way: BOTH "ERROR OUT" TERMINALS RETURN THE SAME VALUE. So you never have to merge these two error streams. Automatic error handling is satisfied if you wire either one of these two error terminals.

Cool - I did not know that.

If we only have to merge once - should we choose the In or the Out (is there any benefit of one over the other)?

And what about the case with multiple DVRs on a single IPE?

Link to comment

Yes, I believe the variant bordernodes treat errors in the same way (for the same reason as DVRs).

No, I don't think it makes any difference on LabVIEW's side which error-out terminal you wire. All things being equal, I'd recommend using the one inside the structure if you are doing something inside the structure, and the one outside the IPE structure if you are just merging the error (or presumably the warning) from outside.

Each bordernode (whether data value reference or other) on the IPE structure acts independently (with the exception of order of execution which is ordered to prevent deadlocks). Thus, each pair of bordernodes generates a single, unique error which may or may not be handled. If you wire one pair of bordernodes, but not the error terminals for the other pair, you could trigger auto error handling. Each read/write pair can generate its own errors depending on the state of THAT reference.

Since any number of bordernodes could be present, as well as any number of calculations could be done inside the IPE structure, we do not "fail" out on the IPE. If a data value reference has an error accessing the reference (a fail other than just a wait until the lock is available), a default value is placed on the de-referenced wire. All other calculations in the IPE are performed as usual and we simply discard the value wired to the write/unlock bordernode for the DVR with an error. If you are doing a calculation that takes time or referencing a data value reference that is likely to fail, I highly recommend putting a case structure inside the IPE and act according to whether the border nodes have an error. Actually, this is part of why we don't have an error-in terminal on the bordernodes, because even if they individually fail, the structure continues. Forcing one of them to "take a fall" because of an external error didn't seem to be the appropriate behavior.

Edited by Djed
  • Like 1
Link to comment

If a data value reference has an error accessing the reference..., a default value is placed on the de-referenced wire.

Does that mean that there's a new buffer allocation?

Presumably such an allocation won't be a big hit, since default data usually doesn't take up much space, but it is a thing to consider if handling large data structures.

Link to comment
Does that mean that there's a new buffer allocation?
I went and asked. Here's the details:

The Read Reference node of the IPE always has a buffer allocation standing by in case the data value reference coming in is invalid. So the code inside the structure is pointed either at the data brought in by the reference or the local allocation. The local allocation is initialized with the type's default value whenever it is needed. If we did an on-the-fly allocation, we'd have two problems: data allocations in RT (where, believe it or not, DVRs are actually safe to use as long as you guarantee there's no contention for them, so you can use them for the "guarantee no data copies use case") and complex logic for tracking when to deallocate an on-the-fly allocation.

Top-level data size for the default value is generally small, so it really isn't worth worrying about most of the time -- you'd have to have a giant cluster of many many doubles to get significant top-level data size.

Link to comment

...you'd have to have a giant cluster of many many doubles to get significant top-level data size.

Or a typedef with a large default value? I don't think I would have one, but I could envision someone creating this data as default to avoid having to allocate it explicitly.

Link to comment

Or a typedef with a large default value? I don't think I would have one, but I could envision someone creating this data as default to avoid having to allocate it explicitly.

Although, and I right in presuming that if one were using an object instead of a regular cluster, even if the defaults were large strings / arrays, the additional memory allocation would only be 1 pointer-sized int?

Edited by Shaun Hayward
Link to comment

Or a typedef with a large default value? I don't think I would have one, but I could envision someone creating this data as default to avoid having to allocate it explicitly.

No. A terminal whose type is a typedef does not get the typedef's default value as its default value. So if you have a typedef of an Int32 whose default value is 5 and you put that inside a For Loop and tell it to execute zero times, the value you'll get out is 0, not 5. Typedefs define a type, but they do not define all the behaviors of that type. The default value set on the FP of the control editor is just the default value of any controls of the typedef. If you need a type where the default value is actually defined as part of the type, you need a LabVIEW class.

Although, and I right in presuming that if one were using an object instead of a regular cluster, even if the defaults were large strings / arrays, the additional memory allocation would only be 1 pointer-sized int?

Yes. And that one pointer would point back to the master copy of the class' default value.

Link to comment
  • 8 years later...
On 3/22/2010 at 4:19 PM, Aristos Queue said:

To add to DJed's post:

In the particular example posted, you don't need the Merge Errors.vi at all because there's no reason to merge a guaranteed "no error" with the other error stream.

Or, to phrase it another way: BOTH "ERROR OUT" TERMINALS RETURN THE SAME VALUE. So you never have to merge these two error streams. Automatic error handling is satisfied if you wire either one of these two error terminals.

The comment that the automatic error handling is satisfied if one of the two terminals is connected seems incorrect. Please see the image below. I have tested this both in 2015 and 2017.

 

The errors are the same at this point in time, but I don't think there's any guarantee that that will not change in the future. I plan to always connect both.

DVR_Read_Error.png

  • Like 1
Link to comment
Quote

The errors are the same at this point in time, but I don't think there's any guarantee that that will not change in the future. I plan to always connect both.

Yes, there is a guarantee: both a statement from R&D and also just how much code we'd break if that ever changed. But if you want to continue connecting both, it's just your own programming time and run-time performance you're wasting, so go for it. 

Quote

The comment that the automatic error handling is satisfied if one of the two terminals is connected seems incorrect. Please see the image below. I have tested this both in 2015 and 2017.

I'll file the bug report. Definitely worked when the feature was first introduced (thanks to TomOrr0W for checking back to 2009). *head bang*

This has not been a good LabVIEW day. 

Link to comment
11 hours ago, Aristos Queue said:

Yes, there is a guarantee: both a statement from R&D...

As we have already seen, a statement from R&D is not a strong guarantee.

11 hours ago, Aristos Queue said:

But if you want to continue connecting both, it's just your own programming time and run-time performance you're wasting, so go for it. 

I also plan to connect both not because I like wasting my own programming time (as negligible as connecting an extra terminal might be) but because LV's behavior here is _inconsistent_ between versions and _silently_ changed. What guarantees do we have that it will not change again?

Link to comment
50 minutes ago, Ernesto Aneiros said:

As we have already seen, a statement from R&D is not a strong guarantee.

I also plan to connect both not because I like wasting my own programming time (as negligible as connecting an extra terminal might be) but because LV's behavior here is _inconsistent_ between versions and _silently_ changed. What guarantees do we have that it will not change again?

I think NI is quite a bit better these days at keeping behaviour consistent between versions, except when there is clearly "buggy" behaviour.

Given the focus on NXG I suspect it is pretty safe to say not too much is going to change in current gen LabVIEW going forwards.

Link to comment
2 hours ago, Ernesto Aneiros said:

What guarantees do we have that it will not change again?

None.  There is no guarantee that the Add function doesn't start acting like the subtract if there is a full moon out.  It is just in NI's best interest to keep users of their software and hardware happy and that generally means consistent behavior, but bugs happen.

9 minutes ago, Michael Aivaliotis said:

Automatic error handling is for noobs.

I missed you Michael.

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.

×
×
  • Create New...

Important Information

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