Go Back   Cockos Incorporated Forums > REAPER Forums > REAPER Bug Reports

Reply
 
Thread Tools Display Modes
Old 12-11-2018, 09:29 PM   #1
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default Strange JSFX hang... (Can anyone reproduce?) (FIXED)

Had a strange busy-cycle hang happening with a project. After many many hours I have narrowed it down to this absurd demo code. It's bizarrely sensitive to any changes; as far as I've found every line has to be present, and even changes that seem meaningless (e.g. changing the test condition for the first while loop to remove the "-1", or removing pointless assignments, etc.) will make the hang go away and everything work normally.

So I'm thinking this is a bug, unless someone enlightens me as to what is going wrong?

Again, this is nonsensical code just to show the issue, so don't ask why I'm doing some pointless thing. :-) AFAICT, there should be no busy hangs in this code, even though it's crazy.

To reproduce, open a fresh profile [edit: by which I of course mean a new reaper install], make a track, throw it on there. Then start the transport and click around in the arrange window a bunch. Sometimes I need to start/stop a few times, etc. It usually kicks in in 3-10 seconds. The GUI hangs and the program is unresponsive.

This happens in Linux (5.96 and 5.963) and in Windows (5.95).

Code:
slider1:25<10,300,1>

@slider

slidervar=floor((slider1/1000)*srate+.5);

@gfx

function funcA()
(
  index=0;
  while (index+slidervar-1<0)
  (
    result+=1;
    index+=slidervar;
  );
  total=result;

  result=0;
);

function funcB()
(
  counter=total;

  while(counter >= 0)
  (
    idx=0;
    while(idx <= total-counter)
    (
      idx+=1;
    );
 
    counter-=1;
  );
);

funcA();
funcB();

Last edited by clepsydrae; 12-11-2018 at 10:54 PM.
clepsydrae is offline   Reply With Quote
Old 12-11-2018, 11:07 PM   #2
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,776
Default

The @gfx code is called in (quite) regularly timed intervals. Hence when the runtime of such code is greater that the interval time, weird things are bound to happen.

-Michael
mschnell is online now   Reply With Quote
Old 12-11-2018, 11:21 PM   #3
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Quote:
Originally Posted by mschnell View Post
The @gfx code is called in (quite) regularly timed intervals. Hence when the runtime of such code is greater that the interval time, weird things are bound to happen.
Are you saying that the @gfx is potentially entered by multiple threads at once?
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 02:09 AM   #4
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,776
Default

No, AFAIK, @gfx only uses the GUI thread, and there is only one GUI thread (Usually the so called main thread of the program). While @sample and @block use the thread that is assigned to the track, which always is a different thread than the GUI thread.

But if the execution of @gfx takes longer than the interval @gfx is called by Reaper, there is no time left for other stuff to be done in the GUI thread. I don't know how Reaper schedules the multiple activities of the GUI thread (Reaper GUI, every single plugin, ...), but none of these is allowed to take a long time.

A recent version of the Kontakt featured a bug that it's GUI entered a closed loop when the user performs a certain kind of action. This hangs the Reaper GUI. No Mouse activity possible any more. Fortunately I found that Kontakt leaves that loop (or Reaper forces Kontakt to do so) when hitting the Esc key.

So a JSFX should never do more than a few loop cycles in @gfx. If you really need to do a long loop, you need to leave that loop rather soon and re-enter that activity with the next call to @gfx, and display the results only when the task is done. This might result in a jumpy GUI look of that JSFX, but will prevent it from harming other GUI activity.

-Michael
mschnell is online now   Reply With Quote
Old 12-12-2018, 10:42 AM   #5
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Thanks -- I understand that @gfx can hang reaper -- but I think if you look at the code you will see that it should never do that -- none of the loops in those two functions should ever execute anything, ever. It's basically calling two null functions.

And again, if you make the slightest change to the code, it runs fine and never hangs.

E.g. the first while is "while (index+slidervar-1<0)". If you change that to "while (index+slidervar<0)", it never hangs.

slidervar is 1103. If instead of "slidervar=floor((slider1/1000)*srate+.5);" you say "slidervar=1103;", it never hangs.

So the "it should never ever do anything" plus "it's weirdly sensitive" make me think a bug (or PEBKAC) is afoot.

If there was a multithreading bug between @slider and @gfx, where @gfx was sometimes seeing sliderval as 0, that might explain it. I'd still scratch my head a little about why it's so sensitive to any code changes in funcB, but perhaps some kind of pileup effect of semi-busy @gfx calls is in play.

But JSFX/EEL2 has confused me 100 times and then I learn something new about its nuances, hence my query here about something I'm overlooking.
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 11:08 AM   #6
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,776
Default

Quote:
Originally Posted by clepsydrae View Post
E.g. the first while is "while (index+slidervar-1<0)". If you change that to "while (index+slidervar<0)", it never hangs.
Seemingly, in eel, "<" binds stronger than "-". Hence
while(index+slidervar-1<0) means
while(index+slidervar-(1<0)) and as (1<0) is false and false is 0 this is
while(index+slidervar) and this is the same as
while((index+slidervar)!=0) and this close to always is true.

I suppose what you mean is
while((index+slidervar-1)<0) .

-Michael
mschnell is online now   Reply With Quote
Old 12-12-2018, 11:54 AM   #7
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Thanks for the brainstorming --

Quote:
Originally Posted by mschnell View Post
Seemingly, in eel, "<" binds stronger than "-".
...but I don't think so (see here -- subtraction is above < and >).

E.g. this:
Code:
5+4-1<0 ? yes=1 : no=1;
...gives us "no=1" in the debugger, as expected.

And even if that were the case, it wouldn't explain why setting "sliderval=1103" makes the above code work without issue.
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 12:50 PM   #8
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,737
Default

(edit) Ah I think it's possible for @slider to be executed with srate=0 or slider1=0 initially (you could check for this I imagine)

Last edited by Justin; 12-12-2018 at 01:01 PM.
Justin is online now   Reply With Quote
Old 12-12-2018, 01:00 PM   #9
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

[Edit: just saw your edit... contemplating... I did see that checking for sliderval being 0 did trigger, so that's at least happening as you suggested previously.]

Thanks -- so there is no guarantee that the @slider that comes after the @init will be called before @gfx, I take it?

Is @init guaranteed to be called before any @gfx?
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 01:03 PM   #10
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,737
Default

Quote:
Originally Posted by clepsydrae View Post
Thanks -- so there is no guarantee that the @slider that comes after the @init will be called before @gfx, I take it?

Is @init guaranteed to be called before any @gfx?

@init is guaranteed to be called before @slider, which is guaranteed to be called before @block, which is guaranteed to be called before @sample.

@gfx runs asynchronously from the others (meaning it could run at the same time as any of them) and should be careful about that
Justin is online now   Reply With Quote
Old 12-12-2018, 01:23 PM   #11
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Thanks!

Quote:
Ah I think it's possible for @slider to be executed with srate=0 or slider1=0 initially (you could check for this I imagine)
Ah, I am indeed detecting srate==0 in the @slider section sometimes, yeah. (No detection of slider1==0 yet.) Is that a bug, then?

Re: concurrency -- I know this is totally already in the JSFX docs, but maybe a slight clarification would be nice; e.g. in the @init section an extra "Note: the @gfx section (see below) could start running immediately, and may execute before or simultaneous to the @init."

Or maybe it's just me. :-) I was aware that @gfx was its own thread, but fooled by my instinctual assumption that "@init" happened before anything else. I.e. that "on effect load" for the @init thread would always happen before "when the plug-ins GUI is open" for the @gfx thread, since it would seem like the effect must be loaded before the GUI can be shown.
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 03:08 PM   #12
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,776
Default

Additionally there also is a point in time when variables (but seemingly not the content of arrays) is set to zero, which might or might not be just before @init (after loading and e.g. when starting "play"). Hopefully @gfx will never see completely uninitialized variables when starting concurrently to that implicit initialization.-

-Michael
mschnell is online now   Reply With Quote
Old 12-12-2018, 03:12 PM   #13
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Quote:
Originally Posted by mschnell View Post
Additionally there also is a point in time when variables (but seemingly not the content of arrays) is set to zero, which might or might not be just before @init (after loading and e.g. when starting "play").
Yeah, I did see the caveat in the docs about everything getting zeroed out on @init, and knowing that @gfx doesn't wait for @init certainly explains a lot (and I'll need to go over all my JSFX scripts to check for this issue.)

But srate not being dependable seems like a different thing?
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 06:30 PM   #14
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,737
Default

Quote:
Originally Posted by clepsydrae View Post
Yeah, I did see the caveat in the docs about everything getting zeroed out on @init, and knowing that @gfx doesn't wait for @init certainly explains a lot (and I'll need to go over all my JSFX scripts to check for this issue.)

But srate not being dependable seems like a different thing?
Edit: ah, historically it would get set to 0 very briefly, then reset to the actual samplerate, but in 5.9x mainthread changes, it can sometimes end up as 0 for longer periods. Fixing this!

(as a note: num_ch can also be 0 for periods of time).

Last edited by Justin; 12-12-2018 at 06:58 PM.
Justin is online now   Reply With Quote
Old 12-12-2018, 06:56 PM   #15
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Quote:
Originally Posted by Justin View Post
Edit: ah, historically it would get set to 0 very briefly, then reset to the actual samplerate, but in 5.9x mainthread changes, it can sometimes end up as 0 for longer periods. Fixing this!
Woohoo!

So, once fixed, will srate never be zero, or back to the previous behavior? I.e. should we still be guarding against a 0-value sometimes happening?
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 07:06 PM   #16
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,737
Default

Quote:
Originally Posted by clepsydrae View Post
Woohoo!

So, once fixed, will srate never be zero, or back to the previous behavior? I.e. should we still be guarding against a 0-value sometimes happening?
It's probably safest to guard against it... Also num_ch will temporarily be set to 0 for a short time when starting playback, this will probably remain though...

Hmm, on second thought, the current behavior has one perk:

If you bypass the plug-in, and stop/start playback, srate is 0. So plug-ins can theoretically detect if they are bypassed that way. Though I guess they could just check to see if their @block code was run recently, too...
Justin is online now   Reply With Quote
Old 12-12-2018, 07:27 PM   #17
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

I'm just a part-time JSFX tinkerer, so I won't opine, and as usual I trust that we are in good hands. :-)
clepsydrae is offline   Reply With Quote
Old 12-12-2018, 10:50 PM   #18
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,776
Default

Quote:
Originally Posted by clepsydrae View Post
But srate not being dependable seems like a different thing?
I did come across this issue multiple times and in my scripts I always check for srate not being zero when using it outside of @block and @sample.

In fact I set a variable to the srate value in @block and use same in other callbacks, to make sure that it does not have a weird value (not zero and not the correct srate value) there. Maybe this is not really necessary, but according to the docs, it might be...

-Michael
mschnell is online now   Reply With Quote
Old 12-13-2018, 01:49 AM   #19
clepsydrae
Human being with feelings
 
clepsydrae's Avatar
 
Join Date: Nov 2011
Posts: 3,409
Default

Quote:
Originally Posted by mschnell View Post
In fact I set a variable to the srate value in @block and use same in other callbacks, to make sure that it does not have a weird value (not zero and not the correct srate value) there. Maybe this is not really necessary, but according to the docs, it might be...
Yeah, I've also been doing this:

mysrate=srate;
mysrate==0?
(
mylastsrate>0?(mysrate=mylastsrate):mysrate=44100;
):mylastsrate=mysrate;

...so that if it's ever 0, it will at least try to use the last known sample rate before defaulting to 44100. (It'd be better of course to just not use the sample rate until it's present, but too much bother for the stuff I'm doing...)
clepsydrae is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 10:08 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.