Jump to content

Labview anti-pattern: Action Engines


Recommended Posts

Still willing to play along...

I have some re-use code that I have been re-using since LV 6 that provides Event logging services that can used to track system start-up shut-down and any errors that may have happened. It is based on an AE. All my developers have to do is drop this widget in their error chains and they always have a way to track back an error. It is so simple it isn't worth showing.

It has three actions

Start (Open log file write start-up time and create queue for new messages)

Log if error (post to queue if an error)

Stop (close log and kill queue)

So with three wrapper (one for each) that gives us three VI's the developer has to use.

So how would I write a LVOOP replacement that would actually be a one-to-one replacement?

From what I understand of LVOOP, I'm either going to hide an AE in a LVOOP method, or my developers are going to start running more wires to use the LVOOP version.

Take care,

Ben

OH! OH! - I actually have a useful answer (as opposed to my earlier post) to this one because I do the same thing with classes.

I have an ErrorLogger class that has three public methods - Start Daemon, Stop Daemon, and Enqueue Error. Any time you want to start logging errors, start the daemon, To log an error, just drop the Enqueue Error VI in the error wire. When you want to stop logging errors, just call Stop Daemon. The daemon opens a ref to the error queue and starts waiting for anything on the queue.

The Start Daemon vi has controls that let the user set the path to the log file, the max error log size (it starts throwing away old messages when the max size is reached), and whether or not enable error dialogs.

The Enqueue Error vi just has error in and error out terminals - it gets a ref to the error queue by name and closes it when it exits.

The Stop Daemon just has error terminals (all of my VI's have error terminals)

All of the other stuff (like whether or not the Start Daemon has to create a new directory to create the error log file and the daemon itself) is in the private methods of the class and the user needs never worry about any of that.

The HUGE advantage of this approach over a single action engine is that the Enqueue Error vi is reentrant - one part of the code can be spewing errors and logging them (and my code often does :rolleyes:) while another part of the code that also could log errors isn't blocked waiting on the AE.

Mark

  • Like 1
Link to comment
  • 2 weeks later...

...

The HUGE advantage of this approach over a single action engine is that the Enqueue Error vi is reentrant - one part of the code can be spewing errors and logging them (and my code often does rolleyes.gif) while another part of the code that also could log errors isn't blocked waiting on the AE.

Mark

worshippy.gif

Sorry for the delay, I had lost track of this thread!

That is a wonderful explanation of my Event Logger with some features mine does not have.

I can't ignore the reentrant feature. Nice!

The following is in the interest of learning what others have done about errors on RT tragets...

book.gif

I have never used my Event Loger on a RT target since the strings of the Error Cluster "Source" is of variable size. In an RT environment, dynamically allocating buffers for the strings when code starts "spewing errors" can crash an RT app. "Bad, Bad, Bad".

IN RT apps I force the Source to empty strings and pass the rest off to a WIndows app to log, whenever possible. So...

Have you tried your LVOOP based solution to RT yet?

TO All:

What are your experiences with logging errors on RT targets and what techniques have helped you?

Thanks again Mark!

Ben

Link to comment

worshippy.gif

Sorry for the delay, I had lost track of this thread!

That is a wonderful explanation of my Event Logger with some features mine does not have.

I can't ignore the reentrant feature. Nice!

The following is in the interest of learning what others have done about errors on RT tragets...

book.gif

I have never used my Event Loger on a RT target since the strings of the Error Cluster "Source" is of variable size. In an RT environment, dynamically allocating buffers for the strings when code starts "spewing errors" can crash an RT app. "Bad, Bad, Bad".

IN RT apps I force the Source to empty strings and pass the rest off to a WIndows app to log, whenever possible. So...

Have you tried your LVOOP based solution to RT yet?

TO All:

What are your experiences with logging errors on RT targets and what techniques have helped you?

Thanks again Mark!

Ben

Ben,

Thanks for the compliment - some of my code actually works the way I intend it to, or as we used to say back in Tennessee, "even a blind pig finds an acorn sooner or later". As far as RT targets, I've never actually had an opportunity to work with LabVIEW RT so I can't make any useful comments. I will say that when I've worked with C code on RT targets the errors were always returned as either an index into a lookup table (I16's or such) or as bit arrays so they were always fixed size either way.

Mark

Link to comment

What are your experiences with logging errors on RT targets and what techniques have helped you?

What we do is write the error code (I32) to a shared variable (I32). Hence the communication is fixed size so we can use RT-FIFO enabled SVs. We keep the error text in a LabVIEW error code database so we can get the error explanation on the PC. (This does mean that we don't get the name of the VI where the error occurred.) We configure the shared variable to log (the error code) to the Citadel database.

We only use this for serious errors that we don't anticipate. For warnings or errors we can anticipate (really anything but coding or hardware bugs) we create Booleans (for example, measuredForceOutOfRangeIsTrue), and again write these to Boolean shared variables. Then we can subscribe to this information on a UI front panel (as we can the errorCode), and again we log to the Citadel database. (For appropriate types of warnings and errors we can use the SV alarming capabilities.) What this means in practice is that we almost never see an error code.

This works for us, but it may not be the solution you were seeking....

Link to comment

worshippy.gif

I can't ignore the reentrant feature. Nice!

What are your experiences with logging errors on RT targets and what techniques have helped you?

While I understand the reentrant advantage I'm not sure that is such a big deal here. I use a similar error/event logger scheme as yours (from like written 12 years ago or so) (and yes I wanted to redesign it a few times since but it just sits there and works so the need never really pressed itself upon me).:lol:

In general if you happen to have an application that produces errors so fast that the non-reentrancy of the AE starts to be an issue, of course assuming that you did decouple the actual action properly, then I feel one has a much bigger problem to solve than the possible blocking of other threads by the still busy AE from earlier errors.

That said I use the same silly AE based event/error logging system on all my systems including RT apps.

  • Like 1
Link to comment

In general if you happen to have an application that produces errors so fast that the non-reentrancy of the AE starts to be an issue, of course assuming that you did decouple the actual action properly, then I feel one has a much bigger problem to solve than the possible blocking of other threads by the still busy AE from earlier errors.

I agree with you with respect to errors. Wouldn't reentrancy really be a big benefit if you're logging a lot of events to debug your application? Especially in an RT environment, where you want to have as little impact on the timing as possible? (I haven't done Labview RT, so I'm speculating here.)

Link to comment

I agree with you with respect to errors. Wouldn't reentrancy really be a big benefit if you're logging a lot of events to debug your application? Especially in an RT environment, where you want to have as little impact on the timing as possible? (I haven't done Labview RT, so I'm speculating here.)

My experience with logging lots of events is that it is almost impossible to find the interesting needle in the haystack. Logging events and especially errors should be normally the exception, not the rule, otherwise you can just as well throw them away anyway, since nobody is ever going to try to look at the log. :yes:

Link to comment
  • 1 month later...

While I understand the reentrant advantage I'm not sure that is such a big deal here. I use a similar error/event logger scheme as yours (from like written 12 years ago or so) (and yes I wanted to redesign it a few times since but it just sits there and works so the need never really pressed itself upon me).:lol: ...

That said I use the same silly AE based event/error logging system on all my systems including RT apps.

In the same boat. I've been reusing the same General Logging Library so long it is still in a *.llb and seems fossilized.

My version is queue based with a handler that is started by calling the Startup method. Lets be clear that this is not OO based, or classes. The Methods VI is called with a "Logger Method" ENUM.

I have a few extra "Methods" beyond those mentioned by others above,

ENABLE / DISABLE - turns logging temporarily on/off

OPEN / CLOSE - The background Manager is also a GUI showing the last 20 events, a new event alert flasher with Ack button. Open/Close methods make the GUI appear and disappear.

The log files are closed and a new one opened on the first log entry after midnight, so each day has it's own log file.

Several things I'd like to add or upgrade, but it's fairly simple and as Rolf said, just works, so it's never been a high enough priority to rewrite or make OO. I've also used it "as is" on several RT apps, with no problems, but they were fairly slow RT, log rates of 100 mSec. If I had to log a lot faster I'd add in some number and lookup tables like Paul uses. Haven't needed it so far.

I've given quite a few copies away over the years, so I'll post it here.

(LabVIEW 8.2.1, if someone needs it I could probably dig further down and find 7.1 somewhere)GLOG_General_Log.llb

  • Like 1
Link to comment
  • 8 years later...
On 12/11/2009 at 10:34 AM, Daklu said:

...

From my point of view, AE's have not always been anti-patterns since it was the only way to create the necessary behavior. It's the recent development of classes that relegate AE's to the anti-pattern category. To address the idea of embedding AE's in libraries and exposing public methods, you can get many, but not all, of the benefits of classes by doing that. My question is, if you're going to go to all that effort, why didn't you just make it a class in the first place? That's what it's for.

...

I had the same thought. Whenever I discuss OO with my LV developer friends, I hear, "yeah, but I can do all that stuff without OO". Sure, you can do just about anything OO can do without OO. This applies to every programming language. You can do everything in C (without objects) that you can do in C++ (with objects), but why would you want to?

For me, it comes down to this: Do you want to learn a bunch of tricks to get around the (former) limitations of a (formerly-non-OO) language (which may or may not be portable to other languages), or do you just want to learn OOP and code like everyone else in the developed world? :lol:

-Jamie

Link to comment
35 minutes ago, jfalesi said:

For me, it comes down to this: Do you want to learn a bunch of tricks to get around the (former) limitations of a (formerly-non-OO) language (which may or may not be portable to other languages), or do you just want to learn OOP and code like everyone else in the developed world? :lol:

-Jamie

Or do you want a compile time of 7 hours instead of 20 minutes ;)

  • Like 1
Link to comment
3 minutes ago, ShaunR said:

Or do you want a compile time of 7 hours instead of 20 minutes ;)

Sure that is annoying that it takes 2 hours to build an exe file of my larger OO based projects.
But I just make sure I have a few copies of the LabVEW.exe file so I can start another LV instance while the other copy of LabVIEW.exe is building.
For me to handle >100s of IOs/Motors/Sensors/Benchtop instruments without OO feels impossible.

Link to comment
9 hours ago, smithd said:

You have a 2-hour build? I would die. I think my worst single-exe build time has only ever hit 15 minutes, and thats for classes on RT (truly, a mistake).

It's not necessarily a mistake but if you go down that path you have to make double and triple sure to not create circular references and similar stuff in your class hierarchy. While this can work on a Windows system (albeit with horrendous load times when loading the top level VI and according compile times) an executable on RT usually simply dies on startup with such a hierarchy.

  • Like 1
Link to comment

When we first deployed object-oriented applications (using by-value objects) on RT targets (quite a few years ago now) we encountered long build times (10 or 15 minutes) that were not repeatable (repeated deployment using the same build specification was successful only a small fraction of the time). This situation was unworkable. We learned that the problems we encountered were due to the tangle of relationships between elements (Rolf's "similar stuff" above). Consequently, we implemented interfaces in the manner I have described elsewhere to reduce interdependencies between elements. Builds since then have been reliable and quite quick. We use objects for all our RT applications. (Caveat: There is one specific issue we encountered and we strategically avoid that.)

Link to comment
  • 4 years later...

@sprezzaturon it does not really make sense to compare LVOOP to a FGV, they are totally different concepts. Pure LVOOP by itself does not give you any kind of parallel access, enum action driven shift-register type actions you will be used to with an AE. 

(and a AE is just a FGV with some methods).

I think a more apt comparison is to compare an AE to say some kind of Actor (or parallel process etc)

Edited by Neil Pate
Link to comment
1 hour ago, Neil Pate said:

I think a more apt comparison is to compare an AE to say some kind of Actor (or parallel process etc)

I disagree.

A FGV is a number of methods around some sort of global variable. An AE is usually (but not exclusively) an extension of that around some sort of global resource which may or may not be a global variable.

A LVPOOP class is a number methods around a local variable (the class cluster).

Therefore I think the question in this context is "how do I make a class with a number of methods around a global variable/resource"? (A.K.A Singleton Pattern)

Edited by ShaunR
Link to comment
On 7/22/2022 at 4:02 AM, sprezzaturon said:

Does anyone have examples of LVOOP vs FGV?  I've been using AE for several years now and, after reading this thread, I think I need to rethink what I've been doing.  Thanks.

So always use Singletons instead of FGV when I know I only need one instance of an object, i.e. one memory space that should be shared in my application.
Just like a global variable, but using the class to control access to the global data.
I've attached a Singleton example that should get you going.
The OpenGDS toolkit generates these classes and Access VIs (methods) to make it easy for you.
Also I talk a bit about the Singleton pattern and how to create that here:

 

Singletons.zip

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.