Home AMX User Forum NetLinx Studio

Okay, it happened again today... (old processor content)

I couldn't find the old thread about this. So, sorry for the possible incontinuity of thought.

Howver, a while back I mentioned an instance of events and routines timing out before completion. I was bludgeoned about the head from y'all about it and mocked and riduculed. (okay that's a bit overkill...) :D

The issue was an event timing out before finishing. we had lot's of helpful hints and discussion on the matter and many of you said it wasn't possible. However today I saw it again.

I was on an old NI-3000 by the way and I now know that this was the issue because the same hunk of code works fine on the newer processors. So, it is a processor speed problem, I'm sure. The firmware is the most current non-duet variety.

Here's the gist of the code. Simplified for easy digestion...


My first version was in define_program.

if(do_something_flag)
{
// concantinate a bunch of stuff from a buffer
// about 7 or steps to get 5 or so values.

FOR(x=1; x<18; x++)
  {
  if(array[x]==incoming_result)
    {
    // store value in status_array_var
    //  force x to =99 to get out of loop
    }
  if(x>16 and length_string(incoming_buffer)>5) // there's more in the buffer, repeat process
    {
    do_something_flag=1
    }
  else
    {
    // we're done - the buffer is emplty. go update all the TP feedback
    }
  } // end for loop
do_something_flag=0
} // end if(do_something_flag)

the do_something_flag=0 statement is at the end of the line so that we're sure that all the above commands get addressed before leaving the IF statement. Setting it to zero keeps ti from repeating before the FOR loop has actually finished.

As you can see, the for loop looks for a match in the array. If it finds it, the sets the loop value to 99. This was helpful in debugging to know when it foud a mathc or not.

The buffer regulary gets a whole bunch of stuff 500 or so chars long sometimes. (Lutron Homworks) the routine repeats and chips away at it until the whole buffer is whittled down.

Now, this routine runs fine on the newer-faster stuff. However, on the old NI-3000 it would only make it to about 7 or 8 reps of X before just leaving the statement. So, consequently the routine would only run once or twice and then stop. If the buffer had a length of 400-500 chars I could force it to refire by setting do_something_flag=1. It would run through a couple more times and quit.

What ended up fixing it on the NI-3000 was this:

of course, in simplified form...
if(do_something_flag)
{
// concantinate a bunch of stuff from a buffer
// about 7 or steps to get 5 or so values.

FOR(x=1; x<18; x++)
  {
  if(array[x]==incoming_result)
    {
    // store value in status_array_var
    //  force x to =99 to get out of loop
    }
  [b]if(x>15)
    {
    do_something_flag=0 // this forces do_something_flag to stay 1 almost all the way throgh the FOR loop.  
    }[/b]
  if(x>16 and length_string(incoming_buffer)>5) // there's more in the buffer, keep going
    {
    do_something_flag=1
    }
  else
    {
    // we're done - the buffer is emplty. go update all the TP feedback
    }
  } // end for loop
} // end if(do_something_flag)

Now making this a fuction or placing in within a XYZ_event made no difference. In fact, I couldn't think of a way to keep an event going past it's time out time.

The program running in this NI-3000 is quite large and I asume that has a lot to do with it too. This exact same program with the original routine runs fine on an NI-700


So, I was not crazy....

Comments

  • Thomas HayesThomas Hayes Posts: 1,164
    Okay, so I'm not nuts either. I spent the last 2 days looking for a ghost in my code. The code has worked fine for a longggggggg time but the latest controller I installed it on has given me nothing but grief. I think I have it tracked down the speed which the code is now being handled. It looks like part of the code is already completed before the other part jas even time to start. I've completely re-written the code and I'll know in a day or two if this does the trick.
  • Spire_JeffSpire_Jeff Posts: 1,917
    I am curious, have you tried using a while loop instead of a for loop? The only reason I ask is that it seems they go out of their way to document the fact that while loops no longer have a timeout period. (Also, I use a while loop to parse data from the homeworks and, until I made this post, everything has been working fine.)

    Also, shouldn't you be able to set the do_something flag to 0 as the first line of the if() statement, then set it as 1 after the routine has completed? Otherwise, (in a mutlithreaded line of thought) the if(statement could be entered multiple times before finishing. You shouldn't have to worry about the if() statement terminating in the middle of operation because the value changed from true to false during execution. The value is only checked at the beginning of the code block (at least in my mind).

    Now, I do recall there being some sort of timeout enforced on the mainline so as to prevent the processor from missing button events and other events, but I thought that execution of the mainline resumed where it was.

    Jeff

    P.S.
    I am starting to go through my code and optimize it for more efficient running, so I would be interested in hearing about anything you do to make the code run faster if that is the only way to avoid the problem. My guess is there might be a faster way to handle string comparisons as it seems that string processing in NetLinx is one of it's slower functions. Maybe I'll run some benchmarks on various string parsing routines....
  • Joe HebertJoe Hebert Posts: 2,159
    ericmedley wrote:
    The issue was an event timing out before finishing.
    What do you mean an event was timing out before finishing? I?m not following you, there is no such thing as an event time out time. It sounds like you saying the IF statement in DEFINE_PROGRAM gets reentered before the code is finished spinning around in the FOR loop inside the IF. That?s not going to happen. If it did there would be pure anarchy.
    Spire_Jeff wrote:
    Also, shouldn't you be able to set the do_something flag to 0 as the first line of the if() statement, then set it as 1 after the routine has completed? Otherwise, (in a mutlithreaded line of thought) the if(statement could be entered multiple times before finishing.
    You guys are making me second guess myself. No one else is questioning this line of reasoning? I?m just having a hard to believing the IF will be reentered before finishing the FOR loop. It just can?t be. Can it?
    ericmedley wrote:
    it is a processor speed problem, I'm sure
    No offense intended but if code breaks due to processor speed then I think it sounds like a coding problem not a processor problem. Code will run slower or faster but if the logic is sound it shouldn?t break. You can never count on code that relies on something like the timing of how fast a FOR loop is going to spin. That?s just playing coding roulette.
    ericmedley wrote:
    the do_something_flag=0 statement is at the end of the line so that we're sure that all the above commands get addressed before leaving the IF statement.
    Sorry that doesn?t make any sense either, the IF condition is evaluated once upon entering and that?s it.
    wrote:
    Now making this a fuction or placing in within a XYZ_event made no difference. In fact, I couldn't think of a way to keep an event going past it's time out time.
    What exactly is this so called event time out time?? I?ve never heard of such a thing. I?ve written plenty of functions that take 10s of seconds or a minute or more to complete and I?ve never had it ?time out.? The only instance I can think of was back in the Axcess days when one or more of the WHILE loop types would drop out after a half second or second or whatever it was.
    ericmedley wrote:
    So, I was not crazy....
    Sure you are. We all are or we wouldn?t be in this business. :D
  • Thomas HayesThomas Hayes Posts: 1,164
    Okay, looks like my code upgrades worked. Note to self, when upgrading code remember to move all the code to the new button_event that is being executed.
  • Spire_JeffSpire_Jeff Posts: 1,917
    Joe Hebert wrote: »
    You guys are making me second guess myself. No one else is questioning this line of reasoning? I?m just having a hard to believing the IF will be reentered before finishing the FOR loop. It just can?t be. Can it?

    I don't think it can happen, but if it only takes one line of code to insure that it doesn't, I am inclined to include it.
    Joe Hebert wrote: »
    No offense intended but if code breaks due to processor speed then I think it sounds like a coding problem not a processor problem. Code will run slower or faster but if the logic is sound it shouldn?t break. You can never count on code that relies on something like the timing of how fast a FOR loop is going to spin. That?s just playing coding roulette.

    I would tend to agree with this line of thinking, but for some reason, I thought there was some discussion about mainline code being subjected to interruption to insure that events are not missed. The problem is that we don't really know how the processor is handling event queuing and priorities within code. This should not cause problems, but speaking from experience with very large programs, occasionally weird problems come up. Most of the problems seem to be related to memory management and/or queues filling up.

    Jeff
  • ericmedleyericmedley Posts: 4,177
    Spire_Jeff wrote: »
    I don't think it can happen, but if it only takes one line of code to insure that it doesn't, I am inclined to include it.



    I would tend to agree with this line of thinking, but for some reason, I thought there was some discussion about mainline code being subjected to interruption to insure that events are not missed. The problem is that we don't really know how the processor is handling event queuing and priorities within code. This should not cause problems, but speaking from experience with very large programs, occasionally weird problems come up. Most of the problems seem to be related to memory management and/or queues filling up.

    Jeff

    I tried this little experiment and what I understood to be true was indeed true. It was an ME-260 (old skool)
    if(flag)
    {
    x=0
    y=0
    for(x=1;x<30000;x++
      {
      if(x=15000 and y>1)
        {send_command dvTP,'adbeep'}  // this is to prove that the Y loop has not started.
      }
    for(y=1;y<30000;y++)
      {
    
      }
    
    flag=0
    } // end IF(flag)
    

    This runs as expected.

    x and y get set to zero.

    x runs up to 30,000, then y follows afterward.
    flag then goes to zero.
    the beep never happens.

    I'm beginning to think the anomoly happens whenever string functions are involved. I know strings are more processor spendy. Perhaps that has something to do with it.

    The program that this occurs in is pretty large.


    I was not trying to argue about how it works. I understand how it's supposed to work. I am confused as to why the program I'm having the issue with does this only on the slower processors and not on the quicker ones.

    the logic of the function is not rocket surgery.

    To make blanket statements that these things will do and won't do things is overstepping our bounds a bit. We don't have a full working knowledge of how these things work under the hood. I've seen plenty of things that fall under the catagory of 'X-Files whacky' before.
  • Joe HebertJoe Hebert Posts: 2,159
    Sorry, I'm not following your train of thought. What is the experiment proving? Care to post an entire program to prove whatever you are trying to prove so we can all play along. Is this supposed to prove that there is an event time out?
    ericmedley wrote: »
    I tried this little experiment and what I understood to be true was indeed true. It was an ME-260 (old skool)
    if(flag)
    {
    x=0
    y=0
    for(x=1;x<30000;x++
      {
      if(x=15000 and y>1)
        {send_command dvTP,'adbeep'}  // this is to prove that the Y loop has not started.
      }
    for(y=1;y<30000;y++)
      {
    
      }
    
    flag=0
    } // end IF(flag)
    

    This runs as expected.

    x and y get set to zero.

    x runs up to 30,000, then y follows afterward.
    flag then goes to zero.
    the beep never happens.

    I'm beginning to think the anomoly happens whenever string functions are involved. I know strings are more processor spendy. Perhaps that has something to do with it.

    The program that this occurs in is pretty large.


    I was not trying to argue about how it works. I understand how it's supposed to work. I am confused as to why the program I'm having the issue with does this only on the slower processors and not on the quicker ones.

    the logic of the function is not rocket surgery.

    To make blanket statements that these things will do and won't do things is overstepping our bounds a bit. We don't have a full working knowledge of how these things work under the hood. I've seen plenty of things that fall under the catagory of 'X-Files whacky' before.
  • ericmedleyericmedley Posts: 4,177
    Joe Hebert wrote: »
    Sorry, I'm not following your train of thought. What is the experiment proving? Care to post an entire program to prove whatever you are trying to prove so we can all play along. Is this supposed to prove that there is an event time out?

    No, I cannot do that. It's too big to post and it has a ton of includes and modules and whatnot. I guess I'm not trying to prove anything. It's just a curiosity, nothing more.
  • Joe HebertJoe Hebert Posts: 2,159
    ericmedley wrote: »
    No, I cannot do that. It's too big to post and it has a ton of includes and modules and whatnot. I guess I'm not trying to prove anything. It's just a curiosity, nothing more.
    I wasn?t referring to your entire program; I was trying to find out what your last snippet of code was supposed to prove or disprove. All I got out of it is that it works as expected.

    If you don't want to discuss what you've brought up for discussion that's okay with me. :)
  • Spire_JeffSpire_Jeff Posts: 1,917
    I think the code snippet was to illustrate that the if(flag) statement only runs one instance at a time. This would be exploring the comment I made about mainline being interrupted to insure no events are missed and I raised the thought the maybe the if() statement was reentered causing problems.

    The only problem is that with a couple of tests I did, simple math like you show does not seem take long enough to hit the interruption times.

    If I thought there was a good chance of this being a problem, I might be motivated to develop some code to test this further. As of right now, it was only a thought I had and it doesn't make much logical sense when dealing with a single thread of execution.

    Jeff
  • ericmedleyericmedley Posts: 4,177
    Spire_Jeff wrote: »
    I think the code snippet was to illustrate that the if(flag) statement only runs one instance at a time. This would be exploring the comment I made about mainline being interrupted to insure no events are missed and I raised the thought the maybe the if() statement was reentered causing problems.

    The only problem is that with a couple of tests I did, simple math like you show does not seem take long enough to hit the interruption times.

    If I thought there was a good chance of this being a problem, I might be motivated to develop some code to test this further. As of right now, it was only a thought I had and it doesn't make much logical sense when dealing with a single thread of execution.

    Jeff

    My point exactly. I am over it already as I have a work-around. It was just a curiosity, nothing more. I'm moving on. :)
  • Joe HebertJoe Hebert Posts: 2,159
    Spire_Jeff wrote:
    I think the code snippet was to illustrate that the if(flag) statement only runs one instance at a time. This would be exploring the comment I made about mainline being interrupted to insure no events are missed and I raised the thought the maybe the if() statement was reentered causing problems.
    The existence of the flag does not mean that it blocked any type of reentrance. If there was some sort of ?event time out? that didn?t allow the FOR loop to finish its thing then who?s to say that this ?time out? can?t happen before the flag is reset and therefore never allow the IF condition to be satisfied again?
    Spire_Jeff wrote:
    The only problem is that with a couple of tests I did, simple math like you show does not seem take long enough to hit the interruption times.
    Here is complete code that can be loaded and tested as is and is the best I can do to prove that there is no such thing as an event time out or an interruption time. I sure hope there is no such thing because programming would be utter chaos if functions could just willy nilly time out and not complete themselves in the expected order.

    This test takes about 9 minutes to complete on my NI-700 but it can be easily modified to last longer.
    DEFINE_DEVICE
    
    dvTP = 10001:1:0
    
    DEFINE_VARIABLE
    
    INTEGER nDoTestFlag
    LONG X
    LONG Y
    
    DEFINE_FUNCTION Loopy() {
    
       LONG A
    
       SEND_STRING 0, 'Entered Loopy'
       FOR (A=1; A<=10000000; A++) {IF (1){}}
       SEND_STRING 0, "'End of A FOR Loop, A=',ITOA(A),' - Exiting Loopy'"   
    
    }
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          SEND_STRING 0, 'Button 1 Pushed'
       }
    }
    
    BUTTON_EVENT[dvTP,2] {
    
       PUSH: {
          SEND_STRING 0, 'Button 2 Pushed - Start your engines'
          ON[nDoTestFlag]
       }
    }
    
    BUTTON_EVENT[dvTP,3] {
    
       PUSH: {
          
          SEND_STRING 0, 'Button 3 Pushed'
          Loopy()
       }
    }
    
    BUTTON_EVENT[dvTP,4] {
    
       PUSH: {
          SEND_STRING 0, 'Button 4 Pushed'
       }
    }
    
    
    DEFINE_PROGRAM
    
    IF (nDoTestFlag) {
    
       SEND_STRING 0, 'Entering IF - Starting X FOR loop'
       FOR (X=1; X<=10000000; X++) {IF (1){}}
       SEND_STRING 0, "'End of X FOR Loop, X=',ITOA(X),' - Starting Y FOR Loop'"   
       FOR (Y=1; Y<=10000000; Y++) {IF (1){}}
       SEND_STRING 0, "'End of Y FOR Loop, Y=',ITOA(Y),' - Exiting IF'"   
       OFF[nDoTestFlag]
    }
    
    After the code is loaded turn on Diagnostics in Netlinx Studio. Open up Emulate a Device and push buttons 1, 2, 3, and 4 in that order. Sit back and observe (or walk away and come back 10 minutes later to check out the results)

    What the program does:

    Pushing button 1 will generate a SEND_STRING 0 to print immediately.

    Pushing button 2 will generate a SEND_STRING 0 and set the flag to allow the code in DEFINE_PROGRAM to run one time.

    Pushing button 3 will queue up the SEND_STRING 0 and the Loopy function to run after the 2 FOR loops in DEFINE_PROGRAM spin around 10 million times each. (Each loop took about 3 minutes with my setup)

    And pushing button 4 will queue up the SEND_STRING 0 that will print out after the FOR loops in DEFINE_PROGRAM are finished and the Loopy function is completed.

    You can see by the output and the time stamps that nothing gets interrupted. All FOR loops complete their thing. Everything is done in the order one would expect them to be done. Time does not appear to be an issue.

    Here is the output after pushing buttons 1-4
    Line      1 :: Button 1 Pushed - 16:58:18
    Line      2 :: Button 2 Pushed - Start your engines - 16:58:20
    Line      3 :: Entering IF - Starting X FOR loop - 16:58:20
    Line      4 :: End of X FOR Loop, X=10000001 - Starting Y FOR Loop - 17:01:19
    Line      5 :: End of Y FOR Loop, Y=10000001 - Exiting IF - 17:04:19
    Line      6 :: Button 3 Pushed - 17:04:19
    Line      7 :: Entered Loopy - 17:04:19
    Line      8 :: End of A FOR Loop, A=10000001 - Exiting Loopy - 17:06:41
    Line      9 :: Button 4 Pushed - 17:06:41
    
    ericmedley wrote:
    I've seen plenty of things that fall under the catagory of 'X-Files whacky' before.
    I worked with a programmer who was having real problems with his code and when I approached him to ask if I could be of help he insisted that his code was perfect and that the ?A Accumulator? of his CPU must be bad. I thought he was joking but he was dead serious. Now that?s wacky!

    If something doesn?t work correctly I always look in the mirror first to make sure I didn?t screw something up and I usually discover I?m at fault. But every once in a while you run into cases where the firmware people screw things up. Stuff happens.
    ericmedley wrote:
    I'm moving on
    I think this horse has been pulverized.
Sign In or Register to comment.