Host Engineering Forum

General Category => Do-more CPUs and Do-more Designer Software => Topic started by: CReese on September 19, 2013, 11:01:06 AM

Title: Loops vs Program/stage
Post by: CReese on September 19, 2013, 11:01:06 AM
Hello all.

I'm trying to evaluate program simplicity vs. execution speed for the following scenario:

I've got a series of operations that perform math, move data around, do some copying, etc., on one element of a bunch of arrays. So something like:

SETNUMR
Myarray1[index] = Myarray2[index] + Myarray3[index]

but obviously much more involved.

Currently I have it set up in a loop where index goes from 0 to length of Myarray1.

For another set of operations, however (memory read operations), I have a two-stage program to do a single operation. I call this from a supervisory program. When the single operation read completes, it goes to the second stage, where it exits to signal completion and this initiates an index increment in the supervisory program and the single operation is again carried out.

My questions:
1. Which is more efficient?
2. How does the loop work in the context of scans? Does it simply span as many scans as necessary to complete the loop operation?

Thanks,
Colin
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 11:29:49 AM
Looping is discussed in the Help Topic Programs and Tasks Overview DMD0231.  Look under the section Code-block Configuration Options where it discusses the .TimeSlice member of the code-block element.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 11:38:24 AM
That was helpful. So the default time slice will punish the loop performance-wise if it is too low, and the overhead of all other scan operations would punish the per-scan staged operation, if I am reading this correctly.

One more question - why don't PD, ND, and Differential contact instructions work in loops properly? This is another reason I'm considering trying my loop operations in a different fashion. Although I prefer state logic, in this case it is resulting in significantly larger code blocks.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 11:59:06 AM
"Efficient" is a relative term here.

Minimize Scan Time
Get all the work done as fast as possible (even if my I/O does not update for 3 seconds)

The two are diametrically opposed.  Usually, something between the two is "optimal".  What's good about Do-more is that once you have the basic "algorithm" working, tweaking the .TimeSlice (in micro seconds) is the best way to optimize it.

I've generally seen that .TimeSlice around 100 - 500 uSec for general MATH/MOVE type operations does a good enough job at minimizing scan time, but getting a lot of work done on each scan, thus taking less total number of scans to do all the "looping".

A .TimeSlice of 0 means only iterate the loop once and move on to the next code-block ("always yield" - this minimizes scan time).

A .TimeSlice of 65535 is "DirectLOGIC" mode where you will stay in the loop and no other instructions, no other I/O is done until the loop is done (e.g. FOR/NEXT loop in 260), "never yield".  If it's 1000 iterations, your PLC literally will loop those instructions 1000 times (better make sure your watchdog timer is high enough for lengthy operations, otherwise it will kick you out of RUN mode - you can even manipulate it programatically in DST23, $WatchdogTimeVal).

We just posted an overview of Programs vs. Tasks in the Do-more Example forum.  Look here http://forum.hosteng.com/index.php/board,20.0.html) and click on the "Overview of Programs Vs. Tasks" topic.  Inside there is an attached .PDF of slides that give a good overview of all these details (and many others).  I recommend looking at all of those slides to get a good understanding of how Programs and Tasks work inside Do-more.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 12:02:14 PM
One more question - why don't PD, ND, and Differential contact instructions work in loops properly? This is another reason I'm considering trying my loop operations in a different fashion. Although I prefer state logic, in this case it is resulting in significantly larger code blocks.

They work fine, it's just that the conditions required to define an edge are harder to manage in loops. An edge is defined as power ON following power OFF on successive invocations of the instruction. That says that, at best, a differential contact can only be true every other pass through the loop.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 12:06:47 PM
One more question - why don't PD, ND, and Differential contact instructions work in loops properly?
The Pgm vs. Tasks Overview may help explain that.  But if you are looping, you are executing no other ladder logic.  So unless the state of the differential contact is being manipulated from WITHIN YOUR LOOP, you will NOT see an "edge" while within the loop (because you are looping, so STRPD X0 will NEVER EVER change because you are not executing any I/O cycle while you stay within the loop).  Sometimes changing .TimeSlice to 0 helps, but usually you must rewrite code within a loop to NOT be dependent upon "edge" triggers (loops and edges do not work well together).
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 12:21:22 PM
you must rewrite code within a loop to NOT be dependent upon "edge" triggers (loops and edges do not work well together).

This is what I've done. I have a redundant logic bit so that if the logic fails, a change has been made. Essentially equivalent to creating a 'previous value' to compare to, but I don't need one for each piece of data.

If result != logic formula(data, data, data, data, data):
    // something changed, so act accordingly.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 12:37:25 PM
One more question - why don't PD, ND, and Differential contact instructions work in loops properly?
The Pgm vs. Tasks Overview may help explain that.  But if you are looping, you are executing no other ladder logic.  So unless the state of the differential contact is being manipulated from WITHIN YOUR LOOP, you will NOT see an "edge" while within the loop (because you are looping, so STRPD X0 will NEVER EVER change because you are not executing any I/O cycle while you stay within the loop).  Sometimes changing .TimeSlice to 0 helps, but usually you must rewrite code within a loop to NOT be dependent upon "edge" triggers (loops and edges do not work well together).

The state of the contact does change within one iteration, and it does not work.

Pseudocode:

For Alarm in Alarmlist:
   if conditionA & conditionB, SET alarmactive

   if differential(alarmactive), log alarm
next

I change no conditions and am watching the differential contact flicker and a counter counting ... while the state logic remains quiet.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 12:41:35 PM
Are you using arrays on any of the differentials?
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 12:42:54 PM
Actually, do you RST within the loop (I saw the SET).  You need to RST the alarm state at the top of the loop?
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 12:47:47 PM
Actually, do you RST within the loop (I saw the SET).  You need to RST the alarm state at the top of the loop?
And even THEN, you need to evaluate the alarm condition EVERY-OTHER time in the loop (to give the differential contact a chance to see the OFF state.  This is where it gets hard.  If you can rewrite without differentials, that would be best.  Edge detection within loops requires at least two iterations of the loop.  PLCNut has tried that and it gets ugly very quickly.  I think Mr. Nut ended up using an inner FOR/NEXT loop that goes from 0 to 1 to make sure all the inner logic is scanned twice so that edges can be detected.  It is not "straight forward" to say the least.

Try to rewrite to eliminate all edge-triggers, if you can.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 12:56:40 PM
Pseudocode:

For AlarmIndex
From 0 to NumAlarms-1

   if AlarmValue[AlarmIndex] != AlarmNormValue[AlarmIndex]
       set AlarmStatus[AlarmIndex]

   if Diff(AlarmStatus[AlarmIndex])
       run LogEvent

next

Could I trick it with something like a SETNUM(AlarmStatus[AlarmIndex] AlarmStatus[AlarmIndex]) ?

The alarmstatus needs to be retained between loops. The statuses are being published to MC registers for read by external systems.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 01:27:56 PM
A couple interesting notes:

I found two code blocks that had been set to never yield, despite being copied from code blocks that had standard 100ms yield values.

I changed these values, and now the program refuses to copy, freezing at Monitoring ROM Update status in PLC.

If I turn everything off and on again I can read, but the program runs at a snail's pace, and if I try to update again it freezes. Awesome.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 01:32:41 PM
Scan time is going through the roof due to the work. Go to program and figure out what is causing the high scan time.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 01:35:32 PM
More to the point...comm is handled at the bottom of each scan. If you wind up with a 100ms scan time because something isn't yielding, it will kill comm. The controller hasn't crashed, but it might look like it externally because it becomes very unresponsive. Worst case get to program mode using the switch on the front...
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 01:37:06 PM
What I don't understand is that it was working fine and I changed it to MAKE it yield, as opposed to vice-versa. Stopped it and brought it back to term and can read/write, but no looping is happening.

What's the easiest way to see what's eating up the scan time?
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 01:40:22 PM
and we're back...
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 02:10:06 PM
What's the easiest way to see what's eating up the scan time?

Great question...a utility that doesn't exist yet.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 02:11:04 PM
   if Diff(AlarmStatus[AlarmIndex])
       run LogEvent

1. LogEvent will not run until after the loop has yielded, possibly on the next scan if LogEvent code-block is before your loop code-block.
2. Differentials and Arrays do not mix.  The differential contact only saves the ON/OFF state from the previous time it executed, so if AlarmIndex is 7, you are not "differentiating" AS7 vs. the previous I/O scan's AS7, but AS6 state compared to AS7's state (assuming the index went from 6 to 7).
3. Say your loop finds 3 alarms that changed state within one time slice, do you expect LogEvent to run 3 times, or just once?  Remember, RUN is NOT CALL.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 02:23:28 PM
Another key point...Tasks and Programs are not subroutines, and are not run in context. We will be adding functions and subroutines in a future version, the technology is already in the controller and is proven, it's just lacking the UI needed to create and manage.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 02:26:28 PM

3. Say your loop finds 3 alarms that changed state within one time slice, do you expect LogEvent to run 3 times, or just once?  Remember, RUN is NOT CALL.

This is a very good question. I see that as I have it programmed, it will only handle the last event, as it throws the Log Message that is created into a temporary variable. I suppose the way to do this better is to create a message queue and then have the logger process the queue.

Or, as I proposed previously, change this into a staged program that runs one array item per scan.

Or, can I just have it exit the loop on LogEvent and resume the program on the next scan? This way it is guaranteed to only have to process one event. It has the added bonus of logging the event as quickly as possible without finishing the loop.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 02:44:30 PM
Yes, so how about just adding 'exit' after 'LogEvent'? Will this resume the loop where it left off? Even if not, it's an easy way to avoid the possibility of not handling an event.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 02:45:21 PM
Or, can I just have it exit the loop on LogEvent and resume the program on the next scan? This way it is guaranteed to only have to process one event. It has the added bonus of logging the event as quickly as possible without finishing the loop.
I honestly think you need to eliminate all LOOPs and use the natural scan of the PLC as your "loop", but using events to
1. Increment the processing index
2. Log the event

Make all of this event driven.  I would stick this all in a stage program code block.  Since this is probably something that you want to do all the time, I would only have $Main kick it off "RUN MonitorAlarms" and MonitorAlarms intializes itself in its first SG (say SG0, hence you never JMP back to SG0), and it auto-resets the index whenever it reaches the end

SG S0 Initialize (set index to 0, etc.)
SG S1 See if alarm state @index has changed (you will need a duplicate array of alarm bits to save previous alarm state); if it has, jmp to S2, otherwise jmp to S3
SG S2 Log Alarm Event, once that is done, jmp to S3
SG S3 Put current alarm state (Alarm[index] into PrevAlarm[index]
   Increment index; if index exceeds length, reset index to 0, unconditionally JMP to S1 (NOT S0)

This will minimize scan time.

What are you doing to "Log Alarm Event"?  Sending an EMAIL?  That can take seconds per alarm.  If you have no alarms, this will take N scans where N is the number of alarms.  If N is 100, with a 1ms scan time, that's 100ms "calendar time".  But if "Log Alarm Event" takes 3 seconds, and all alarms turn ON, that will take 300 seconds (5 minutes) of "calendar time" to process all 100 alarms.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 02:58:31 PM
Or, can I just have it exit the loop on LogEvent and resume the program on the next scan? This way it is guaranteed to only have to process one event. It has the added bonus of logging the event as quickly as possible without finishing the loop.
I honestly think you need to eliminate all LOOPs and use the natural scan of the PLC as your "loop", but using events to
1. Increment the processing index
2. Log the event

This is possible, and I may end up doing it. I just don't think it is necessary.

Quote
SG S1 See if alarm state @index has changed (you will need a duplicate array of alarm bits to save previous alarm state); if it has, jmp to S2, otherwise jmp to S3

I've got this handled without a duplicate array, and it would be more. We log on many different event changes, so I don't want duplicates of everything

Quote
What are you doing to "Log Alarm Event"?  Sending an EMAIL?  That can take seconds per alarm.  If you have no alarms, this will take N scans where N is the number of alarms.  If N is 100, with a 1ms scan time, that's 100ms "calendar time".  But if "Log Alarm Event" takes 3 seconds, and all alarms turn ON, that will take 300 seconds (5 minutes) of "calendar time" to process all 100 alarms.

I create a string based on the type of the event, alarm name, and current time. I mash them into a string and process them through a FIFO Alarm Log in the MIR registers for read by other network devices, such as screens and our datalogging server that sends the data across the intertubes. I've about filled the memory of the DoMore, but I keep about 100 events logged at 40 characters per message, if I remember correctly.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 03:01:30 PM
Yes, so how about just adding 'exit' after 'LogEvent'? Will this resume the loop where it left off? Even if not, it's an easy way to avoid the possibility of not handling an event.

Please pay close attention to what Mark just described. To answer the question, no, EXIT terminates the program completely...a YIELD would kick out for one scan and let something else run. Fine if your logging will take no more than one scan...but...as Mark suggested, make it more event-centric and eliminate the time dependence. More work, but guaranteed to work all the time...anywhere.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 03:03:56 PM
This is possible, and I may end up doing it. I just don't think it is necessary.

You would still use a logical loop, just not a looping instruction. By creating the loop in stages, and making the sequencing event based, you solve a multitude of headaches that you may not have had yet. Trust us on this one.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 04:00:41 PM
I refactored it, and it's noticeably slower. Is there an obvious reason I cannot get a timer to work properly in my staged process?

I have a timer reset in stage 0, and I only return to stage 0 when my index needs to be reset. The rest of the times it goes back to stage 1. The timer never starts running.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 04:09:22 PM
Timers aren't standalone hardware entities that run independent of the PLC scan, they are software functions performed by the timer instruction. If a timer instruction is not being invoked, it doesn't accumulate time. If you are timing a stage, put the TMR in that stage. If you are timing globally, put the TMR in something that is constantly being executed...perhaps before the first stage of the program block.
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 04:31:49 PM
This works fine, but now I can't seem to get it to reset. Is it not possible to reset the timer from a single stage to see how often it reaches that stage?
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 04:33:15 PM
RSTT
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 05:14:20 PM
Okey doke,

So I've got it refactored in both stage programs and in loop programs.

Stage takes about 1.9s for 1024 alarms, even though those not enabled skip almost all of the logic elements (all but about 15 of them).

Loop (even with a much larger set of logic to process), takes <590ms.

Either I've really screwed up the stage program, or there is a lot of overhead somewhere. I've disabled all other code blocks, so it's just those in question running, so it's not a scan overhead issue with other processes that I have programmed.

Pretty interesting ... but disappointing.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 05:26:42 PM
Stage takes about 1.9s for 1024 alarms, even though those not enabled skip almost all of the logic elements (all but about 15 of them).

Loop (even with a much larger set of logic to process), takes <590ms.

The stage implementation is basically doing 1 loop per scan. My guess is that the loop implementation would be about the same if you changed the time slice to 0. The problem here is that you have conflicting needs, in that you need to bulk process the alarms, but an alarm event may not be something that can be processed synchronously. If the loop implementation works, and you are sure that you won't run into trouble when multiple alarms fire at the same time, there is no problem using a loop.

Our motivation is to keep you from doing things that may bite you down the road, not to keep you from doing the app in the way that you feel is best. We've simply seen too many folks hurt themselves...
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 05:58:40 PM
Worst I can get is a second, and now it seems to hover just under a second whether I'm yielding at 0 or never.
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 06:04:34 PM
Depending on stage ordering in the program, it's possible that it ends up being more than one scan per pass. There are a large number of variables to consider.

The point is the same though...a loop is a very efficient way to run though large numbers of things, but of marginal use for more asynchronous operations...whereas stages are optimal for asynchronous events, but not the most efficient for rapidly churning through blocks of data. Your app is a hybrid and you have to balance the needs. If engineering was easy, they wouldn't pay us as well, right? ;)
Title: Re: Loops vs Program/stage
Post by: franji1 on September 19, 2013, 06:36:43 PM
Worst I can get is a second, and now it seems to hover just under a second whether I'm yielding at 0 or never.
You also want to look at your max scan time to help determine optimal .TimeSlice value, in addition to "calendar time" to process one "alarm cycle".

BobO and I were talking, and you previously mentioned this, but possibly looping within the "into alarm" SG as long as you have NO alarm events to process.  This would be implemented as a WHILE, not a FOR/NEXT, and you maintain the index across ladder scans.  This way, as long as you have no alarms, they are "monitored" at a fast(er) pace.  Once alarms start showing up, you slow down, but only to "process" the alarm.

I don't want to get into the logic just yet, but does that make sense to you?
Title: Re: Loops vs Program/stage
Post by: CReese on September 19, 2013, 06:41:07 PM
Yes. My brain, however, has decided to call it a day. I'm not in the office Fridays, so I'll pick this up again on Monday. Thanks for being online and helping out. Support is important.

Colin
Title: Re: Loops vs Program/stage
Post by: BobO on September 19, 2013, 07:03:10 PM
Support is important.


Hey, if we can't be engineers, at least we can be engineer supporters! ;)
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 10:28:04 AM
Worst I can get is a second, and now it seems to hover just under a second whether I'm yielding at 0 or never.
You also want to look at your max scan time to help determine optimal .TimeSlice value, in addition to "calendar time" to process one "alarm cycle".

BobO and I were talking, and you previously mentioned this, but possibly looping within the "into alarm" SG as long as you have NO alarm events to process.  This would be implemented as a WHILE, not a FOR/NEXT, and you maintain the index across ladder scans.  This way, as long as you have no alarms, they are "monitored" at a fast(er) pace.  Once alarms start showing up, you slow down, but only to "process" the alarm.

I don't want to get into the logic just yet, but does that make sense to you?

Is this functionally any different than yielding on an alarm log event?
Title: Re: Loops vs Program/stage
Post by: BobO on September 23, 2013, 10:56:08 AM
Is this functionally any different than yielding on an alarm log event?

Very much so. What we were thinking was something like this:

Stage 1: Initializes a "loop", which is really just a loop counter. Jumps to stage 2.
Stage 2: Uses a WHILE/WEND loop to cycle through all alarms. If it finds one, it jumps to stage 3, the alarm handler.
Stage 3: Processes the alarm and jumps back to Stage 2. The handler may well be several stages.
Back at stage 2: Continue cycling alarms and processing as appropriate until you hit the end of the list. Jump back to stage 1.

This should give you the benefit of both fast and sequential. This is exactly how I would do it.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 23, 2013, 12:05:31 PM
Our idea is only helpful for one key feature, to reduce the latency (i.e. calendar time) from when an alarm occurs to when it gets reported.  If the current "calendar time" of a 2 second delay (or more?) is acceptable, then this isn't that important.  However, if you can get that down to 100ms or less, and that makes a big difference, then this idea should be looked at.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 12:09:42 PM
What is most important is the loop cycle time. The log rate is not terribly important.

I want each alarm (value vs. norm value) translated into a status as quickly as possible.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 01:27:54 PM
Ok, so:

SG0:
SETNUMR DAlarmIndex=0

SG1:
WHILE DummyVariable:
IF DAlarmIndex>=NumDAlarms
    JMP SG0

<< Process Alarm with index DAlarmIndex >>

MATH DAlarmIndex=DAlarmIndex+1
IF LogEvent:
    JMP SG2
JMP SG1

SG2:
<< LogEvent actions >>
JMP SG1

Question : The LogEvent actions can be in a task since it will be executed before the next Log Event, correct?
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 01:57:13 PM
This is an important line I missed:

Quote
When the Jump To Stage (JMP) instruction is executed, it does NOT cause an immediate jump to the target Stage logic, it only disables the current Stage and enables the target Stage. The effect of this instruction will occur the next time those Stages are normally processed as part of the controller's scan. This means that any ladder logic instructions between the Jump To Stage (JMP) instruction and the end of the Stage will still be executed.

Sorry guys, not used to having to read instructions for basic logic.
Title: Re: Loops vs Program/stage
Post by: franji1 on September 23, 2013, 02:18:37 PM
Question : The LogEvent actions can be in a task since it will be executed before the next Log Event, correct?
I would NOT stick it in a separate code-block, but do all the logic from within S2.  That way, if you DO have anything that takes more than 1 scan, you will stay in S2 until it finishes, then once the work inside S2 is done, JMP back to S1.  Hence, your JMP S1 from within your S2 should have a contact driving it.  You could make it unconditional ONLY IF there are no multi-scan instructions inside S2 (no edge triggers, no async/device instructions, no tmr, no cnt, only "combinatorial" logic that runs to completion within its execution).
Title: Re: Loops vs Program/stage
Post by: franji1 on September 23, 2013, 02:26:30 PM
When the Jump To Stage (JMP) instruction is executed, it does NOT cause an immediate jump to the target Stage logic, it only disables the current Stage and enables the target Stage. The effect of this instruction will occur the next time those Stages are normally processed as part of the controller's scan. This means that any ladder logic instructions between the Jump To Stage (JMP) instruction and the end of the Stage will still be executed.
One way around that is to use the current stage as an enabling condition

SG S1
...

some terminating condition
JMP S2 (this turns ON S2's bit but also turns OFF S1's bit, but the program pointer is still within S1 on this scan)

S1 contact AND ...  // if the JMP S2 happened, this logic will not be "enabled" because S1 will be OFF
S1 contact AND ...  // ditto
S1 contact AND ...  // ditto

There are other ways around this:
SG S1
...
(termination condition)
OUT Terminate_S1

Terminate_S1 NOT contact AND ...
Termiante_S1 NOT contact AND ...
...
Terminate_S1 NOT contact AND ...
Terminate_S1 contact JMP S2
SG S2


FYI, the EXIT instruction does NOT behave this way - it tweaks the processors program counter to the end of the code-block.  So if you have a conditional EXIT condition, the rest of the code in that code-block WILL be skipped (that implies the remainder of the code within that Stage).
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 02:28:47 PM
Question : The LogEvent actions can be in a task since it will be executed before the next Log Event, correct?
I would NOT stick it in a separate code-block, but do all the logic from within S2.  That way, if you DO have anything that takes more than 1 scan, you will stay in S2 until it finishes, then once the work inside S2 is done, JMP back to S1.  Hence, your JMP S1 from within your S2 should have a contact driving it.  You could make it unconditional ONLY IF there are no multi-scan instructions inside S2 (no edge triggers, no async/device instructions, no tmr, no cnt, only "combinatorial" logic that runs to completion within its execution).


Or I could make the jump back into the WHILE conditional upon a completion bit set by the LogEvent Task.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 02:48:31 PM
This would maximize speed, correct? (Skipping the remainder of the stage). Please take a look below and let me know what you think. It seems from what you have said that if I put an EXIT below the RST in the DAlarmIndex >= DAlarmCount block that I could skip the remainder of that stage's logic, which could be a minimal improvement.

What I currently have is the following. It is currently running at ~900ms for the whole alarm stack. This is quite fast.

SG0:
MATH DAlarmReadTime=TICKms()
DATAINFO DAlarmCount=Length(DAlarmNames)
SETNUMR DAlarmIndex=0
SET RunAlarmLoop
JMP SG1

SG1:
WHILE RunAlarmLoop
   IF DAlarmIndex >= DAlarmCount:
      DAlarmReadTimer=TICKms()-DAlarmReadTime
      RST RunAlarmLoop
      JMP S0

   << Alarm Processing Code >>

   MATH DAlarmIndex= DAlarmIndex+1

   IF LogEvent:
      RST RunAlarmLoop
      JMP S2

WEND

S2:

<< Alarm logging preprocessing >>

ENTASK CopyElementToLog
IF LogDone:
   SET RunAlarmLoop
   JMP S1

Title: Re: Loops vs Program/stage
Post by: franji1 on September 23, 2013, 03:52:51 PM
Do NOT use EXIT.  Monitoring Alarms is a continuously running program that never ends.

I only mentioned that anomaly to show how EXIT does what you THOUGHT JMP did.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 04:59:46 PM
Do NOT use EXIT.  Monitoring Alarms is a continuously running program that never ends.

I only mentioned that anomaly to show how EXIT does what you THOUGHT JMP did.

Yes I since tested it. Break does what I want.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 05:00:21 PM
although I suppose BREAK should start another scan, which is what I was trying to avoid in the first place.
Title: Re: Loops vs Program/stage
Post by: CReese on September 23, 2013, 05:01:53 PM
CONTINUE is what I want!