www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 20219] New: Idle D programs keep consuming CPU in

https://issues.dlang.org/show_bug.cgi?id=20219

          Issue ID: 20219
           Summary: Idle D programs keep consuming CPU in
                    Gcx.scanBackground
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: regression
          Priority: P2
         Component: druntime
          Assignee: nobody puremagic.com
          Reporter: dlang-bugzilla thecybershadow.net
                CC: r.sagitario gmx.de

This program will keep consuming CPU cycles in the background, when it should
be completely idle:

/////////////// test.d ///////////////
import core.memory;
import core.stdc.stdio;
import core.sys.posix.unistd;

void main()
{
    printf("Creating garbage...\n");
    foreach (n; 0 .. 1_000)
        new uint[1_000_000];
    printf("Collecting garbage...\n");
    GC.collect();
    printf("Sleeping...\n");
    sleep(uint.max);
}
//////////////////////////////////////

Examining the program's state with a debugger reveals that the CPU consumption
comes from a loop in Gcx.scanBackground. This function will wake up every 10
milliseconds to check if it has any work to do, then go back to sleep, until
the garbage collector is deinitialized.

Even though the CPU consumption is small (about 0.5% per core on my machine),
it can still add up when many otherwise-idle D programs are running, which
would otherwise have no load impact on the system other than RAM usage.

More importantly, the timer is causing the CPU to wake up and thus exit a low
power state frequently. This can significantly affect power consumption of
portable / low-power devices. For this reason, I consider this to be a
significant regression. If possible, the implementation should be changed so
that the garbage collector notifies background threads that they have work to
do using synchronization primitives like semaphores, and timers should not be
used at all anywhere.

I should also note that it is atypical for system programming language runtimes
to create runtime threads and leave them around, even if they are idle when the
program is. These still consume some resources like PIDs, which are finite.
Unless an uncompromising solution can be found, perhaps it would be appropriate
to make parallel marking opt-in rather than opt-out.

To illustrate and extrapolate on the above: on a Linux machine, open htop, make
sure that threads are visible (toggled with H) and kernel threads are hidden
(toggled with K). Note that even though some processes (lines in white or black
text) have threads attached to them (lines in green text), most do not. If all
of the software on the system were to be hypothetically rewritten in D, every
process would have a dozen threads attached to it, which to me doesn't seem
like a great outcome.

--
Sep 16 2019