Commit Graph

2 Commits

Author SHA1 Message Date
Paul Bone
a2879c6837 Make MercuryThreadPool (java) notice when a thread blocks on a semaphore.
If threads are blocked while there is work in the queue extra threads may be
spawned to keep the processors busy.

Beginning now, tasks created with thread.spawn are use the thread pool.
(thread.spawn_native does not use the thread pool.)

java/runtime/Semaphore.java:
    Wrap Java's Semaphore class which call the current thread's blocked()
    and running() methods when a thread blocks and then runs after being
    blocked.

library/thread.semaphore.m:
    Use our own Semaphore class.

java/runtime/MercuryThread.java:
java/runtime/MercuryWorkerThread.java:
    Define blocked() and running() on our threads.

java/runtime/NativeThread.java:
    This class is used by spawn_native/4 and is required to define blocked()
    and running(), however it implements them as no-ops as it isn't included
    in the thread pool.

java/runtime/ThreadStatus.java:
    Define the BLOCKED status.

java/runtime/MercuryThreadPool.java:
    Count blocked threads seperatly and allow the creation of new threads
    when existing threads become blocked.

    Add some tracing code to help debug the thread management code.  This is
    disabled by default.

library/thread.m:
    Implement spawn for Java using the thread pool.  This was not enabled
    earlier because without using java/runtime/Semaphore.java it was
    possible to deadlock the system.

java/runtime/Task.java:
    Add some tracing code to debug thread state changes, this is disabled by
    default.
2014-10-03 19:22:32 +10:00
Paul Bone
496952e5ab Use a thread pool to manage threads on the Java backend
Thread pools are often used to reduce poor performance on embarrassingly
parallel work loads.  This isn't immediately necessary on the Java backend
however I've implemented it because:
    + It will be required when we implement parallel conjunctions for the
      Java backend.
    + I want to implement parallel profiling on the Java backend and don't
      want to have to implement this once now, and then re-implement it after
      introducing thread pools later.

We want the thread pool to generally restrict the number of threads that are
in use, this reduces overheads.  However, when one or more tasks become
blocked then it can be desirable to create extra threads, this helps ensure
that all processors are kept busy and that thread pooling doesn't contribute
to any deadlocks itself.  The implementation is a work in prograss and
currently does not implement this second feature.

Java's API provides several different thread pools, see
java.util.concurrent.Executors, none of which are suitable.  Specifically
the fixed thread pool is unsuitable as we want to be able to temporarily
exceed the normal number of threads as explained above; and the cached
thread pools, which are also very similar to the ThreadPoolExecutor class,
do not implement the correct algorithm for determining when a new thread
should be created (they can still perform poorly for embarassingly parallel
workloads).  Additionally we cannot instrument this code as easily for
parallel profiling.

These changes alter the behaviour of Mercury threads on the Java backend in
two ways, they now behave more correctly and more like threads on the C
backends.
    + If a thread throws an exception it is now reported and the program is
      aborted.  Previously it was ignored and let pass to the Java runtime
      where I assume it was reported.
    + The program now exits only after all threads have exited.

The ThreadPool will automatically detect the number of threads to use, or if
the -P flag is given in the MERCURY_OPTIONS environment variable it will
honor that.

java/runtime/MercuryThread.java:
java/runtime/MercuryThreadPool.java:
java/runtime/MercuryWorkerThread.java:
java/runtime/Task.java:
java/runtime/ThreadStatus.java:
    These new classes make up the thread pool.  A MercuryThread is an
    abstract class for Mercury threads, MercuryWorkerThread is a concrete
    subclass of MercuryThread which includes the worker thread behaviour.
    A Task is a computation/closure that has not yet been started, it
    provides some methods not available in Java's generic Runnable and
    Callable classes.  The others should be self-explanatory and all files
    contain documentation.

java/runtime/Getopt.java:
java/runtime/MercuryOptions.java:
    Parse the MERCURY_OPTIONS environment variable for the -P flag.

java/runtime/JavaInternal.java:
    Add support for handling Mercury exceptions, this is used in case a
    worker thread's task (a Mercury thread) throws an exception.

compiler/mlds_to_java.m:
    The main method of the main Java class of an application now starts and
    uses the thread pool to execute main/2.

library/exception.m:
    Export exception reporting code to the Java runtime system.

library/thread.m:
    Use the thread pool for thread.spawn.
2014-08-01 12:32:51 +10:00