-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[blitz.mod] Debug builds secretly reactivate the GC even once GCSuspend()-ed #317
Comments
According to gc.h:
Does this not work as documented? |
Thanks for that hint... it should do what it says in the documentation. bdwgc's misc.c contains this: GC_API void GC_CALL GC_enable(void)
{
LOCK();
GC_ASSERT(GC_dont_gc != 0); /* ensure no counter underflow */
GC_dont_gc--;
if (!GC_dont_gc && GC_heapsize > GC_heapsize_on_gc_disable)
WARN("Heap grown by %" WARN_PRIuPTR " KiB while GC was disabled\n",
(GC_heapsize - GC_heapsize_on_gc_disable) >> 10);
UNLOCK();
}
GC_API void GC_CALL GC_disable(void)
{
LOCK();
if (!GC_dont_gc)
GC_heapsize_on_gc_disable = GC_heapsize;
GC_dont_gc++;
UNLOCK();
}
GC_API int GC_CALL GC_is_disabled(void)
{
return GC_dont_gc != 0;
} So that "75% of the additional runtime" are surely connected to the locking and unlocking of a mutex. And checking the above code there is no reason for the "nesting" not working as it should. But ... if it "nests", is the logic in our
This means that each time you call This means to provoke an issue one could do this:
This exposes that the "nesting" only works if done in the correct order (suspend only if running). Calls like "OnDebugEnterScope()" will "suspend" and "resume" in the correct order - and this is OK as long as nothing expects the "GC" to be actually resumed afterwards (it will still be suspended if it was suspended before). So it looks OK to me. |
What do you think about adding a "GCIsSuspended()" thing - so a getter interpreting Why? Because this would allow to skip "GCSuspend()" and "GCResume()" calls if there won't be a change -> and thus avoiding to lock a mutex up to 2 times. It depends on how "costly" it is to retrieve an atomic value if the gc is suspended or not (already). |
Reading still needs a lock, otherwise you might not get the latest value if it's been changed by a different thread.
Then what if another thread calls |
In our case it should just lead to more locks than needed (so up to 2) ("I need to gcsuspend, nobody else did before" because it missed, that someone else suspended too meanwhile).
These function all do "suspend ...something else ... resume". So as long as you store the "have to wrap my 'something else' in suspend + resume" flag at the beginning of your function, it does not matter what "others" do meanwhile - as others have to take care of their "suspend + resume" on their own. think of the code being similar to:
(of course you would do differently). It does not matter if others also GCSuspend/Resume() somewhere. It is not right that it does NOT matter ... it matters. Because the current code is already not acting threadsafe then. See this function:
(must not be this one - just some function doing "GCSuspend" + "GCResume"). thread 1 calls Voila GC is now set to continue working while thread 1 assumes it is safe to do things now (it just suspended the GC - right?). So either it does not matter if others do their gcsuspend()/gcresume() somewhere - or the current implementation is not guaranteeing thread safety (did not check when or how these debug-functions are called, but someone doing similar stuff in their code has to take care then). The older debugger part (blitz.mod/debugger.stdio.bmx) only called above functions from the main thread - the current implemention (blitz.mod/debugger_mt.stdio.bmx) does not care in which thread it runs. Dunno how threadsafe it is at the end. |
No, because thread 2 also called |
Ah yes you are right ... I somehow already forgot about the "counter" and just had an "on/off" toggle in my mind. Too much computer time today. Will close now. If you can imagine of a way to avoid "two locks" somehow (maybe something like the atomicadd() stuff ... ) then feel free to write to me at discord.. Most people won't run 1.000.000 for loops in debug - but some might do, and optimizing their "debug build experience" isn't the worst we could do. |
While investigating why "for loops" require so much longer in debug builds (1000000 loops release <1ms, debug 3000ms) I have seen that
blitz.mod/debugger_mt.stdio.bmx does a lot of GCSuspend() and GCResume().
as
GCSuspend
simply callsGC_disable();
andGCResume
simply callsGC_enable();
each of these debugger-functions directly affects the GC.These now bears two issues:
Edit:
PS: Just keeping the GCSuspend() and GCResume() calls in the Enter/Leave-Functions (disabling the rest of their function logic) cuts down the execution time from 3000 to 700ms for me. Means the GCResume/Suspend alone does 75% of the additional runtime.
The text was updated successfully, but these errors were encountered: