12-11-2018, 09:29 PM | #1 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
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();
__________________
Free blind ABX testing software | Audio illusions / psychoacoustics video series Music Theory Distilled -- a rapid crash course | How to do a portable install Last edited by clepsydrae; 12-11-2018 at 10:54 PM. |
12-11-2018, 11:07 PM | #2 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 16,268
|
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 |
12-11-2018, 11:21 PM | #3 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Are you saying that the @gfx is potentially entered by multiple threads at once?
|
12-12-2018, 02:09 AM | #4 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 16,268
|
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 |
12-12-2018, 10:42 AM | #5 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
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. |
12-12-2018, 11:08 AM | #6 | |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 16,268
|
Quote:
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 |
|
12-12-2018, 11:54 AM | #7 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Thanks for the brainstorming --
...but I don't think so (see here -- subtraction is above < and >). E.g. this: Code:
5+4-1<0 ? yes=1 : no=1; And even if that were the case, it wouldn't explain why setting "sliderval=1103" makes the above code work without issue. |
12-12-2018, 12:50 PM | #8 |
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 16,117
|
(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. |
12-12-2018, 01:00 PM | #9 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
[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? |
12-12-2018, 01:03 PM | #10 | |
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 16,117
|
Quote:
@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 |
|
12-12-2018, 01:23 PM | #11 | |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Thanks!
Quote:
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. |
|
12-12-2018, 03:08 PM | #12 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 16,268
|
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 |
12-12-2018, 03:12 PM | #13 | |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Quote:
But srate not being dependable seems like a different thing? |
|
12-12-2018, 06:30 PM | #14 | |
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 16,117
|
Quote:
(as a note: num_ch can also be 0 for periods of time). Last edited by Justin; 12-12-2018 at 06:58 PM. |
|
12-12-2018, 06:56 PM | #15 | |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Quote:
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? |
|
12-12-2018, 07:06 PM | #16 | |
Administrator
Join Date: Jan 2005
Location: NYC
Posts: 16,117
|
Quote:
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... |
|
12-12-2018, 07:27 PM | #17 |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
I'm just a part-time JSFX tinkerer, so I won't opine, and as usual I trust that we are in good hands. :-)
|
12-12-2018, 10:50 PM | #18 |
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 16,268
|
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 |
12-13-2018, 01:49 AM | #19 | |
Human being with feelings
Join Date: Nov 2011
Posts: 3,440
|
Quote:
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...) |
|
Thread Tools | |
Display Modes | |
|
|