mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
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.
173 lines
4.6 KiB
Java
173 lines
4.6 KiB
Java
//
|
|
// Copyright (C) 2014 The Mercury Team
|
|
// This file may only be copied under the terms of the GNU Library General
|
|
// Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
//
|
|
|
|
package jmercury.runtime;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Getopt style option passing.
|
|
* This is currently very simple, it does only what is necessary.
|
|
*/
|
|
public class Getopt implements Iterable<Getopt.Option>
|
|
{
|
|
String option_string;
|
|
List<Option> options;
|
|
List<String> arguments;
|
|
|
|
/**
|
|
* Create a Getopt object to process the command line options.
|
|
*/
|
|
public Getopt(String option_string)
|
|
{
|
|
this.option_string = option_string;
|
|
this.options = null;
|
|
}
|
|
|
|
public Iterator<Option> iterator()
|
|
{
|
|
if (options == null) {
|
|
process();
|
|
}
|
|
|
|
return options.iterator();
|
|
}
|
|
|
|
/**
|
|
* Process the options. This is called automatically and the result is
|
|
* cached.
|
|
*/
|
|
public void process()
|
|
{
|
|
StringTokenizer tok = new StringTokenizer(option_string);
|
|
Option option = null;
|
|
|
|
options = new LinkedList<Option>();
|
|
arguments = new LinkedList<String>();
|
|
|
|
while (tok.hasMoreTokens()) {
|
|
String str;
|
|
|
|
str = tok.nextToken();
|
|
if (str.startsWith("--")) {
|
|
if (option != null) {
|
|
options.add(option);
|
|
option = null;
|
|
}
|
|
option = new Option(str.substring(2));
|
|
} else if (str.startsWith("-")) {
|
|
if (option != null) {
|
|
options.add(option);
|
|
option = null;
|
|
}
|
|
option = new Option(str.substring(1));
|
|
} else {
|
|
if (option != null) {
|
|
option.setValue(str);
|
|
options.add(option);
|
|
option = null;
|
|
} else {
|
|
arguments.add(str);
|
|
/*
|
|
* The token we've got is an argument not an option,
|
|
* Store the remaining strings as arguments and stop
|
|
* processing.
|
|
*/
|
|
while (tok.hasMoreTokens()) {
|
|
str = tok.nextToken();
|
|
arguments.add(str);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the arguments from the command line. Arguments are not options,
|
|
* they occur after the options list.
|
|
*/
|
|
public List<String> getArguments() {
|
|
return arguments;
|
|
}
|
|
|
|
/**
|
|
* An option. Call getopt.nextOption() to get each option.
|
|
*/
|
|
public static class Option
|
|
{
|
|
// the name of the option. This is stored without either the - or
|
|
// -- that may proceed option names.
|
|
private String option;
|
|
// the value of the option or null.
|
|
private String value;
|
|
|
|
/**
|
|
* Create a new option.
|
|
* @param option The name of the option, excluding any leading - or
|
|
* -- substring.
|
|
* @param value The value of the option.
|
|
*/
|
|
public Option(String option, String value)
|
|
{
|
|
this.option = option;
|
|
this.value = value;
|
|
}
|
|
|
|
/**
|
|
* Create a new option.
|
|
* The option's value will be initialised to null.
|
|
* @param option The name of the option, excluding any leading - or
|
|
* -- substring.
|
|
*/
|
|
public Option(String option)
|
|
{
|
|
this(option, null);
|
|
}
|
|
|
|
public void setValue(String value)
|
|
{
|
|
this.value = value;
|
|
}
|
|
|
|
/**
|
|
* True if this option matches the given option name.
|
|
* @param option The option name for comparison without leading --
|
|
* or -.
|
|
*/
|
|
public boolean optionIs(String option)
|
|
{
|
|
return this.option.equals(option);
|
|
}
|
|
|
|
public int getValueInt()
|
|
throws NumberFormatException
|
|
{
|
|
return Integer.parseInt(value);
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
// Add dashes.
|
|
if (option.length() == 1) {
|
|
builder.append("-");
|
|
} else {
|
|
// This must be a double dash argument.
|
|
builder.append("--");
|
|
}
|
|
builder.append(option);
|
|
builder.append(" ");
|
|
builder.append(value);
|
|
|
|
return builder.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
|