Discussion:
Community Nugget 2-19-2007 "Stacked Sequence Exterminator"
(too old to reply)
altenbach
2007-02-19 07:10:08 UTC
Permalink
I am sure everyone with even casual familiarity of LabVIEW has run across older (or newer) code that is just peppered with ...
 
Stacked Sequences from Hell.
 
Stacked sequences (especially the one's containing sequence locals) are the hallmarks of confusing, unreadable and unmaintainable code. Data flows in all directions (mostly right-to-left), a large percentage of code is hidden at any given time, and it is almost impossible to debug and follow what going on. Often there is clear data dependency (or execution order does not matter), so the sequence serves no purpose. Better programmers don't use stacked sequences at all and even keep flat sequences at a minimum.
 


Here is an example:
 
<img src="Loading Image...">
&nbsp;
Since the code seems to work "sort of", and trying to rewire things manually will probably lead to accidental errors, we have no choice than to leave things in place...
&nbsp;
.. or do we??? :o
&nbsp;


If we try to right-click on the sequence, we can only remove individual frames, breaking everything in the process. No go!&nbsp;A dead end!&nbsp; Sigh! :(
&nbsp;
<img src="Loading Image...">
&nbsp;
&nbsp;


But let's not give up just now.... We can easily convert the stacked sequence to a flat sequence, so lets do that as a first step:
&nbsp;
<img src="Loading Image...">
&nbsp;


At this point, we can remove the flat&nbsp;sequence and all connections remain in place. Now we can just cleanup the elements and wires and everything look much better. Ahhh!!! :)
&nbsp;
<img src="Loading Image...">
&nbsp;
In summary:
An easy two-step procedure allows us to exterminate unnecessary stacked sequences without any danger of breaking the code. This method should lower the fear to remove these monstrosities. :) Try it today!
&nbsp;
&nbsp;
&nbsp;


This is a Community Nugget. If you want to contribute, please sign up here: <a href="http://forums.ni.com/ni/board/message?board.id=BreakPoint&amp;message.id=3379#M3379" target="_blank">http://forums.ni.com/ni/board/message?board.id=BreakPoint&amp;message.id=3379#M3379</a>
&nbsp;
&nbsp;
&nbsp;
&nbsp;Message Edited by altenbach on 02-18-2007 10:43 PM


SeqToFlat.gif:
http://forums.ni.com/attachments/ni/170/230714/1/SeqToFlat.gif


SeqStackedA.gif:
http://forums.ni.com/attachments/ni/170/230714/2/SeqStackedA.gif


CannotRemove.gif:
http://forums.ni.com/attachments/ni/170/230714/3/CannotRemove.gif
tst
2007-02-19 11:10:12 UTC
Permalink
Great suggestion, Tomi. Did you file a product suggestion?
Nicely done, Chris. :smileyhappy:
Ben
2007-02-19 14:10:08 UTC
Permalink
Thank you for taking the plunge into Nugget-Land Christian!
Nice start.
For the most part I am with you on not using stacked sequence structures. I teach all of my new hires to not even concider them.
But some years ago I had the oppertunity to work with "The Architect Supreme"* and she pointed out a wonderful use of the stacked seq.
<img src="Loading Image...">
DOCUMENTATION!
It is really handy having the design diagrams just a click or two away.
Ben
*"The Architect Supreme" was the first person to earn cetification as both a LabVIEW and TestStand Architects. In this case it was "May the best WOMAN" win!".Message Edited by Ben on 02-19-2007 07:45 AM


Documentation.JPG:
http://forums.ni.com/attachments/ni/170/230782/1/Documentation.JPG
Ben
2007-02-20 02:10:08 UTC
Permalink
Tomi,
Aren't you asking for a good reason to use a "bad" construct? :smileyindifferent:
Your suggested code construct would look like this.
<img src="Loading Image...">
After wondering how to make it faster, you would concider this.
<img src="Loading Image...">
But the revised version is not possible with a stacked seq. With a State Diagram you have a lot more flexibility, and you have it now.
Now don't get me started because the next thing you know I will be talking about the SDE* and this thread is about exterminating Stacked Sequences..
Wait, I think I just did. :smileyhappy:
Ben
* With a State Diagram you have a lot more flexibility, and you have it now. If you use the SDE the graphic documentaiton comes along for the ride.Message Edited by Ben on 02-19-2007 07:59 PM


Stacked Seq.JPG:
http://forums.ni.com/attachments/ni/170/230908/1/Stacked Seq.JPG


Stacked Seq Rev1.JPG:
http://forums.ni.com/attachments/ni/170/230908/2/Stacked Seq Rev1.JPG
Tomi M
2007-02-20 11:40:07 UTC
Permalink
You are kind of right Ben... However state diagrams toolkit is not part
of LabVIEW language but an add on that most users don't have access to.
So I don't think it solves a general problem of error handling that
should be accessible to everyone. Currently there is no good diagram
that suits well to error handling. I think error handling is such an
important
I'd like to have a single diagram for error handling, that would function in similar (but more advanced) way as three nested diagrams below. It would combine functionality of while loop (allow stopping, shift registers), sequence (limited number of frames in certain order, no going back) and case structure (maching errors against prototypes).- Handle errors that occur before the diagram in one or more cases&nbsp;&nbsp;&nbsp; - Even though errors have occurred before the diagram, allow executing rest of the diagram in special cases defined by "continue" node- Execute the primary code in one single case- Handle errors that occurred after the diagram in error handler cases- Allow stopping the sequence in any of the frames- Allow leaving right hand side shift registers unwired, the previous wired value is used in these cases- Add a new left hand side "pattern matching" dual connector terminal similar to "?" terminal but this terminal would take error cluster and an array of anything as input. The error in error-in is matched against this array of anything. There would be one error handling case for each item in the array of anything. (If you didn't understand this, never mind)Tomi<img src="Loading Image..."> <img src="Loading Image..."> Message Edited by Tomi M on 02-20-2007 01:29 PMMessage Edited by Tomi M on 02-20-2007 01:30 PM


error-handler1.png:
http://forums.ni.com/attachments/ni/170/230968/1/error-handler1.png


error-handler2.png:
http://forums.ni.com/attachments/ni/170/230968/2/error-handler2.png
Ben
2007-02-20 15:40:13 UTC
Permalink
Hi Tomi,
If a developer has access to the VIA they probably have access to the SDE.
Even without the SDE, State Diagrams (as illustrated in the LV 6.X code shown in reply #8) are still available.
Everything that you proposed can be done in a state diagram.
Maybe when I learn to think "LVOOP-ishly" I may see the benefit of your suggestion.
Please be patient with me! I'm still learning.
Ben
Ben
2007-02-20 21:10:09 UTC
Permalink
"...full of wires that have no meaning ..."
Oh but the do! They say in a very explicit manner that the data associated with those shift register will not be modified by this case (event).
Ben
Tomi M
2007-02-20 21:40:12 UTC
Permalink
Oh but the do! They say in a very explicit manner that the data associated with those shift register will not be modified by this case (event).
Well, an unwired shift register could have exactly the same meaning but it would be easier to read as the information is concentrated on a single point, namely the right hand side shift register. Only the wires having other than default action would be required.
JDave
2007-02-20 21:40:14 UTC
Permalink
Well, an unwired shift register could have
exactly the same meaning but it would be easier to read as the
information is concentrated on a single point, namely the right hand
side shift register. Only the wires having other than default action
would be required.
However, the difference between a purposefully unwired input and a neglectfully unwired input is huge, while at the same time hard to detect.&nbsp; An unwired input also has the connotation of "Use Default in Unwired".&nbsp; It would be confusing to add this meaning in as well.&nbsp; If nothing else it should have a different appearance.
Tomi M
2007-02-21 10:10:08 UTC
Permalink
JDave wrote:
Well, an unwired shift register could have
exactly the same meaning but it would be easier to read as the
information is concentrated on a single point, namely the right hand
side shift register. Only the wires having other than default action
would be required.
However, the difference between a purposefully unwired input and a neglectfully unwired input is huge, while at the same time hard to detect.&nbsp; An unwired input also has the connotation of "Use Default in Unwired".&nbsp; It would be confusing to add this meaning in as well.&nbsp; If nothing else it should have a different appearance.Very good point! How about the following. By default you must wire the the right side shift regsiter. However there is a context menu option "use previous value". Thid option must be set for each frame separately. This guarantees that at least the developer of the structure must explicitly define each shift register in each frame to use previous value. Perhaps such shift register should look a little different. I think this is sufficient to avoid most errors and makes the structure clearer. How at NI R&amp;D owns the stacked sequence and similar structures?Tomi
Ben
2007-02-21 14:10:12 UTC
Permalink
Shane wrote;
" ... why not simply build a cluster in a state machine with all values which need to be preserved and then use unbundle by name to access them?&nbsp;"
AS long as the elements of the cluster are small and the preformance req are low, then OK.
When ever the data elements become large, then explicit storage is called for. What I have in mind when I speak of "large" I am thinking a arrays that are over 10K (approx).
From what I have observed of buffer usage and performance, sticking a large array inside a cluster in a SR casuses beffer copies. If the large arrays are broken out and stored in distinct SR's the buffer can be re-used when an element of the arry is replaced.
I have been toying with "showing my hand" when it comes to the "Data Analysis" phase of application design and trying to put it in a Nugget (or two, or three?) but I have not been able to formalize what exactly "Data Analysis" is! For the time being let me describe it as "an additinal step I insert&nbsp;after the "fuzzy cloud" step and before the "State Diagram" step that defines my data structures and identifies performance risks."
Anyone else do something similar?
Care to team up on a Nugget?
If so e-mail me at
***@dsautomation.com
Ben
&nbsp;
shoneill
2007-02-21 16:40:12 UTC
Permalink
Ben, regarding : "sticking a large array inside a cluster in a SR casuses beffer copies"I just read <a href="http://forums.ni.com/ni/board/message?board.id=170&amp;message.id=151292#M151292" target="_blank">this</a>.&nbsp; Your example assumes that because overwriting a larger array with
itself causes more overhead that the arays are not stored as pointers
within a cluster.&nbsp; I'm not so sure.&nbsp; I thought I'd do some benchmarking of my own.&nbsp; The attached VI has two clusters, each with two arrays.In the first cluster, the second array has 5000000 elements in it, whereas the first is empty.The second has 5 elements in the second array, whereas the first is empty.In the code, I increment the empty array 10,000 times (Read/Write/Append).I find the work on the first array to be independent of the second array's size.&nbsp; This would mean that both arrays within a given cluster must occupy seperate memory spaces, no?Please have a look and comment (VI is LV 8.20),Shane.


Cluster pointers.vi:
http://forums.ni.com/attachments/ni/170/231289/1/Cluster pointers.vi
altenbach
2007-02-21 17:10:09 UTC
Permalink
Did Hell just freeze over or is Shane actually using LabVIEW 8.2??!? :o
Shane, you should make current values to the defaults before saving and posting. All your&nbsp;controls are empty in the posted example.
shoneill
2007-02-22 09:40:10 UTC
Permalink
Sorry, I forgot my &lt;\sarcasm&gt; tag.......Of course the price is at least partially market-defined.&nbsp; That's basic
economics, but there are a lot of man-months go into each version of LV.&nbsp; There's quite a bit of work behind the scenes there.&nbsp; Shane.Message Edited by shoneill on 02-22-2007 10:22 AM
Ben
2007-02-22 14:10:13 UTC
Permalink
Hi Shane Tomi et al,
I do not have the time at the moment to a proper analysis of the code snippets you posted.
LV IS remarkably optimized. The "Inplaceness Algorithm" is amazing.
THe only short-coming I see in it's "shroud of mystery". What I mean by this is that all of the wonders it performs are top notch intelectual property that we do not know the details of and are subject to change when further improvements are implemented.
So lacking a complete set of documentation on its behaviour, we are forced to poke, prod and discuss to learn about it.
I imagine it to be a lot like learing to ride a surf board. There are two extreme approaches that can be taken to learn to surf. I could break books and study all of the physics involved and memorize the equations so that I can solve them as I ride. Another approach is to forget about the physics and just jump on and start riding.
When it comes to ridng the wave of LV, many of just jump on and learn by our falls.
The physics appraoch to learning LV is not possible because the "physics books on LV" are locked up in an ivory tower and are subject to change.
Back to the surf board.
We could take a hybrid approach to learning and combine the book work with the practiacl experience.
Returning to the LV experience
We can do use the same hybrid approach BUT we have to do the research as we go! When we fall off we should stop and analyze "why did that fail?".
When we discover new sublties, we should share. THat is what i tried to do above when pointing out what I had learned from a one of my "wipe-outs".
Still driving the LV is like surfing anaology
In the same way that subtle shifts in weight can influence the behaviour of the surf board, little things in LV can make a big difference in our direction. In your second snippet, you did not wire the cluster into the top of the bundle as you did in the first. This small "wave of the hand" gave the Inplaceness Algorithm the hint it need to know that you were not going to step on everything.
Done rambling. What do YOU think?
Ben
&nbsp;
shoneill
2007-02-22 14:40:11 UTC
Permalink
First things first:Ben, your last post came accross a bit defensive, and I'm sorry if you felt there was any agression implied in my posts.&nbsp; Just in case of anyone feeling irked by any of this: I'm not disagreeing or trying to argue with
anyone here.&nbsp; I agree with Ben's sentiments about clustered arrays
being a lot slower, even if I originally misinterpreted his statement.&nbsp;
After observing it myself, I immediately understood what he'd been saying (I'm a bit like that sometimes).&nbsp; Your observation trumped my assumption.I am certainly one who has tried to learn LabVIEW
through trial and error (man I've had my fair share of error).&nbsp; I've
also learned a huge portion of what I know from these forums.&nbsp; I've (up
to now) not had a single LabVIEW course, even though I cheated once and
went to a NI day in Switzerland.....

But what I have learned is that certain actions lead to certain
results.&nbsp; Just like the scientist I'm trained to be.&nbsp; This "Array in a
cluster" thing seems to be out-of-line to previous experiences with
LabVIEW, hence my originally not grasping your original point, Ben.

Regarding your last post, I agree 100%.&nbsp; But when we, by observing, get
a bit of a picture of the inner workings (hi Rolf!) and this seems odd,
I too think we need to discuss it.&nbsp; I've no problem with someone
showing me that what I've thought / done / said is a load of baloney,
but it's important to note the subltle differences.&nbsp; I simply don't
understand the performance penalty in these examples.Back to the problem at hand:Ben wrote: "In your second snippet, you did not wire the
cluster into the top of the bundle as you did in the first. This small
"wave of the hand" gave the Inplaceness Algorithm the hint it need to
know that you were not going to step on everything."Exactly, that's what I thought when I wired it up.&nbsp; However, it appears that that solution is DRAMATICALLY SLOWER than the other, which surprised me quite a lot (I suggest re-reading <a href="http://forums.ni.com/ni/board/message?board.id=170&amp;message.id=231408#M231408" target="_blank">the post</a>).&nbsp; It seems that even wiring to an unbundle output terminal creates a copy automatically, no matter what you do with it.&nbsp; It seems that the bundle/unbundle is a go : no go thing.&nbsp; If the output terminal isn't wired, fine.&nbsp; If it's wired, make a copy and proceed as normal.&nbsp; This "create a copy" flies in the fact of the "in-placeness" of LV.&nbsp; It seems that the "In-placeness" stopped short of clusters, which is a terrible shame and I'm actually amazed it took me so long to notice this (and without Ben, I probably never would). I think I see the chance to "correct" something in LabVIEW which may lead to a possible solution to the "sometimes unwired shift registers" we have been discussing.&nbsp; Being able to cluster all elements required in a state machine without performance penalty would be a benefit to anyone who programs this way I reckon.....&nbsp; This is how I thought it worked when I originally suggested this, but Ben has changed my mind rather dramatically.&nbsp; And I think (bearing in mind my complete noob status on compiler technology) it would be less complicated to implement this "correction" than a "new feature".I remember doing a report as an undergrad on LV way back (1992 or something) and reading a quote from once of the LV founders, and I paraphrase here : "The in-place array operations belong to some of the most complex code present in the LabVIEW source."&nbsp; I think they were peferring to a "sieve" benchmark.....&nbsp; Sounds familiar somehow ;)Ben, if you get some time to have a look at the code, I'd be grateful for your input to see if I'm really off on a mad trip again.Shane.PS Shouldn't we start a new thread on this??Message Edited by shoneill on 02-22-2007 03:21 PMMessage Edited by shoneill on 02-22-2007 03:23 PM
Ben
2007-02-22 14:40:18 UTC
Permalink
Abosultely no problem Shane!
LV is my sweetheart. When ever her beauties and virtues are called into question, I feel moved to defind her honour.
I'll see if I can back to your examples when I have time to do a proper job.
Ben
detached
2008-08-14 12:10:05 UTC
Permalink
I've dived right into an old but functional test system ~300 VI's. Flow and structure is pretty hard to follow and I'm thinking of breaking it up into state machines. Any ideas on how to approach a stacked sequence beast in 6.1? Flat sequence seems crucial to this method...
JoeLabView
2008-08-14 15:10:05 UTC
Permalink
You should probably start a new thread since this is a Community Nugget thread.&nbsp;When you post the new thread, also include (attach) an example code so that we can provide appropriate suggestions.&nbsp;R
Ben
2007-02-21 17:10:09 UTC
Permalink
Hi Shane,
Please take a look at the attached.
I get a factor of 10 difference in performance when I use distinct SR instead of using the cluster.
How does this run on your machine?
Ben


Cluster pointers_2.vi:
http://forums.ni.com/attachments/ni/170/231300/1/Cluster pointers_2.vi
Ben
2007-02-21 14:10:15 UTC
Permalink
Tomi,
Here is a SIMPLE&nbsp;example of how I handle errors.
<img src="Loading Image...">
Kevin,
I have a Nugget to handle the SR issue. Stay tuned!
Ben
&nbsp;Message Edited by Ben on 02-21-2007 08:02 AM


handelError.JPG:
http://forums.ni.com/attachments/ni/170/231237/1/handelError.JPG
tst
2007-02-21 14:40:08 UTC
Permalink
Ben wrote:


Kevin,
I have a Nugget to handle the SR issue. Stay tuned!


Ben, allow me to make your life harder -&nbsp;Kevin, in the LAVA forums you can find the tunnel wiring wizard, written by David Boyd.&nbsp;It uses scripting&nbsp;to allow you to select any two tunnels and it will automatically connect them in all the cases where the output tunnel is not wired.
Ben
2007-02-21 15:40:15 UTC
Permalink
tst wrote "...Ben, allow me to make your life harder ..."
&nbsp;
Trying to cut off my Nuggets eh? :smileysurprised:
&nbsp;
Sorry did not work. that was only the foot note. :smileywink:
&nbsp;
Ben
Kevin Price
2007-02-21 14:10:14 UTC
Permalink
Tomi M wrote:
I personally hate it when my event structures are full of wires that have no meaning in that particular event. Hence the idea of allowing unwired shift registers, to make diagrams clearer and allow users to better use the space of the diagram (no need to reserve space for wires without meaning).


One of the things I dread most is when I have a state machine with 15+ states, and decide that I need to add a shift register or two to the loop.&nbsp;
Click to next case.&nbsp; Wire from RH SR to case. Wire from case to LH SR.&nbsp; Wire from other RH SR to case.&nbsp; Wire from case to LH SR.&nbsp; Repeat.&nbsp; 20 times or so.&nbsp; Arrrrgggghhh!
It'd be really great to have an SR option for "retain prior value if unwired" which would grey out the SR icon in a manner analogous to "use default if unwired" tunnels.&nbsp; The option would have to be non-default to avoid breaking existing code.
-Kevin P.
altenbach
2007-02-21 16:10:18 UTC
Permalink
Kevin Price wrote: It'd be really great to have an SR option for "retain prior value if unwired" which would grey out the SR icon in a manner analogous to "use default if unwired" tunnels.&nbsp; The option would have to be non-default to avoid breaking existing code.


Kevin,
Mnay years ago (fall 2002)&nbsp;we had a discussion on info-labVIEW about very similar issues. I made a suggestion to add a special "case" to explicitely define the default behavior of unwired tunnels in event and case structures. I still think that would be a very useful addition. :)
The full story has been recorded in the <a href="http://forums.lavag.org/index.php?s=59da918cb17b2f8b0f2baa094ca717c2&amp;showtopic=473&amp;pid=1223&amp;st=0&amp;#entry1223" target="_blank">LAVA forum</a>
Here's what I wrote back then:


I would prefer a even more flexible solution: Make a special, usually hidden case with a name such as "_default outputs_". For example, you would right-click on the case and select "define default outputs". Now you see a case that has a different color. Here you can wire away and define what the output terminals should receive in all the "regular" cases *if* they are not wired. Only outputs you don't wire here would receive the default for the data type as we have now. By default, this case is empty, duplicating the current behavior for unwired outputs.

In your very special case, you would connect the desired input and output tunnels across, but now the possibilities are truly endless. Now you also have the opportunity to do math, e.g. insert a [+1], [-1], etc as often needed. One output tunnel could receive a special wired constant (1, -100, Inf, NaN, etc.) that would be more suitable for the particular situation than the default for the data type we have now. One output tunnel could receive a mathematical result of multiple input tunnels.
Just some ideas ... (We can dream) Christian Altenbach




Only cases that need a special treatment for an output need to be wired. For example if one case does not need the "+1" we have defined, you would wire across to override the default behavior in that single case only.
In your case you would wire all tunnels accross in the "_default outputs_"&nbsp;case and from now on you only need to wire to the output tunnels&nbsp;in the rare cases where you actually modify the tunnel data. :)
Loading...