summaryrefslogtreecommitdiffstats
path: root/jack
diff options
context:
space:
mode:
authorJean-Philippe Lesot <jplesot@google.com>2015-03-27 12:30:15 +0100
committerJean-Philippe Lesot <jplesot@google.com>2015-03-27 12:30:15 +0100
commit5a2c65c03945ad6aef38a68e64168f031fb845ba (patch)
tree336220ade5bc1031af62845d8760f91642c47418 /jack
parent43e79118b5513baede74735da8d6c744afb2bf0b (diff)
downloadtoolchain_jack-5a2c65c03945ad6aef38a68e64168f031fb845ba.tar.gz
toolchain_jack-5a2c65c03945ad6aef38a68e64168f031fb845ba.tar.bz2
toolchain_jack-5a2c65c03945ad6aef38a68e64168f031fb845ba.zip
Use simple framework to make a simple http server for jack
Also modify script to use this simple http server. Change-Id: Ibcf01b80fd618d58aab0aec111e97af103bde6db
Diffstat (limited to 'jack')
-rwxr-xr-xjack/etc/jack113
-rw-r--r--jack/rsc/debug.jack.logging.properties1
-rw-r--r--jack/rsc/error.jack.logging.properties3
-rw-r--r--jack/rsc/info.jack.logging.properties1
-rw-r--r--jack/rsc/initial.logging.properties2
-rw-r--r--jack/rsc/trace.jack.logging.properties3
-rw-r--r--jack/rsc/warning.jack.logging.properties3
-rw-r--r--jack/src/com/android/jack/server/JackSimpleServer.java704
8 files changed, 763 insertions, 67 deletions
diff --git a/jack/etc/jack b/jack/etc/jack
index 4c07d145..70296568 100755
--- a/jack/etc/jack
+++ b/jack/etc/jack
@@ -23,8 +23,16 @@ if [ -z "$TMPDIR" ]; then
TMPDIR="/tmp"
fi
+if [ -z "$SERVER_PORT" ]; then
+ SERVER_PORT=8072
+fi
+
+if [ -z "$SERVER_COUNT" ]; then
+ SERVER_COUNT=1
+fi
+
if [ -z "$SERVER_NB_COMPILE" ]; then
- SERVER_NB_COMPILE=6
+ SERVER_NB_COMPILE=4
fi
if [ -z "$SERVER_TIMEOUT" ]; then
@@ -35,85 +43,33 @@ fi
# Static setting
#
-set -o nounset
-
-# Release code (3 digits) followed by the sub-release code (3 digits)
-JACK_ID=002009
+#
+# Prepare compilation
+#
-SERVER_PRG="$JACK_VM_COMMAND -cp $JACK_JAR com.android.jack.server.Server"
+SERVER_PRG="$JACK_VM_COMMAND -cp $JACK_JAR com.android.jack.server.JackSimpleServer"
SERVER_DIR="$TMPDIR/jack-$USER"
-SERVER_FIFO="$SERVER_DIR/jack-$JACK_ID.cmd"
-SERVER_LOCK="$SERVER_DIR/jack-$JACK_ID.lock"
-SERVER_LOG="$SERVER_DIR/jack-$JACK_ID.log"
-
JACK_DIR="$SERVER_DIR/jack-task-$$/"
+SERVER_LOG="$SERVER_DIR/jack-$SERVER_PORT.log"
JACK_OUT="$JACK_DIR/out"
JACK_ERR="$JACK_DIR/err"
-JACK_EXIT="$JACK_DIR/exit"
JACK_CLI="$JACK_DIR/cli"
JACK_PWD="$PWD"
-#
-# Prepare server
-#
-
mkdir -m 700 "$SERVER_DIR" 2>/dev/null
-mkfifo -m 600 "$SERVER_FIFO" 2>/dev/null
-
-#
-# Launch the server if needed
-#
-
-SERVER_TMP_LOCK=$SERVER_LOCK.$$
-trap 'rm -f $SERVER_TMP_LOCK 2>/dev/null;' EXIT
-
-while true; do
- echo $$ > "$SERVER_TMP_LOCK" 2>/dev/null
- if ln "$SERVER_TMP_LOCK" "$SERVER_LOCK" 2>/dev/null; then
- rm "$SERVER_TMP_LOCK"
- echo "Launching background server" $SERVER_PRG
- $SERVER_PRG $SERVER_NB_COMPILE $SERVER_TIMEOUT "$SERVER_FIFO" "$SERVER_LOCK" >$SERVER_LOG 2>&1 &
- echo $! > "$SERVER_LOCK"
- break
- else
- CANDIDATE_PID=`cat $SERVER_LOCK`
- if [ $? -eq 0 ]; then
- if kill -0 $CANDIDATE_PID 2>/dev/null; then
- # Server seems to be alive, go ahead
- rm "$SERVER_TMP_LOCK" 2>/dev/null
- break
- else
- # Stale lock, clean and retry again
- # Unfortunately, there is a race condition here leading to launching several
- # servers. We are living with that.
- echo "Stale lock detected, cleaning"
- rm "$SERVER_LOCK" "$SERVER_TMP_LOCK" 2>/dev/null
- fi
- else
- # Someone is removing or echoing inside the lock, try again
- rm "$SERVER_TMP_LOCK" 2>/dev/null
- fi
- # Calm down the retry
- sleep 1
- fi
-done
-
-#
-# Prepare compilation
-#
# Cleanup
-trap 'rm -f $JACK_OUT $JACK_ERR $JACK_EXIT $JACK_CLI 2>/dev/null; rmdir $JACK_DIR 2>/dev/null' EXIT
+trap 'rm -f $JACK_OUT $JACK_ERR $JACK_CLI 2>/dev/null; rmdir $JACK_DIR 2>/dev/null' EXIT
+set -o nounset
+set -o errexit
# Create fifo for a task
mkdir -m 700 "$JACK_DIR"
mkfifo -m 600 "$JACK_OUT"
mkfifo -m 600 "$JACK_ERR"
-mkfifo -m 600 "$JACK_EXIT"
# Try to cleanup if interrupted
-trap 'rm $JACK_EXIT; kill -9 $PID_OUT $PID_ERR; wait $PID_OUT; wait $PID_ERR; exit -1' SIGHUP SIGINT SIGQUIT SIGTERM
-
+trap 'kill -9 $PID_OUT $PID_ERR; exit 255' SIGHUP SIGINT SIGQUIT SIGTERM ERR
# Redirect output and error
cat <"$JACK_OUT" >&1 &
PID_OUT=$!
@@ -127,16 +83,39 @@ for i in "$@"; do
done
echo >>"$JACK_CLI"
+set +o errexit
+trap ERR
+
#
# Launch the compilation
#
# Launch compilation
-echo "+ $JACK_OUT $JACK_ERR $JACK_EXIT $JACK_CLI" >>"$SERVER_FIFO"
-EXIT_CODE=$(cat "$JACK_EXIT")
-if [ -z "$EXIT_CODE" ]; then
- EXIT_CODE=-1;
-fi
+EXIT_CODE=255
+RETRY=3
+while true; do
+ EXIT_CODE=$(curl -f -s -d@- http://127.0.0.1:$SERVER_PORT/jack <<< "+ $JACK_OUT $JACK_ERR $JACK_CLI")
+ CODE=$?
+ if [ -z "$EXIT_CODE" ]; then
+ kill -9 $PID_OUT $PID_ERR
+ exit 255
+ fi
+ if [ $CODE -eq 0 ]; then
+ break;
+ elif [ $CODE -eq 7 ]; then
+ if [ $RETRY -eq 0 ]; then
+ kill -9 $PID_OUT $PID_ERR
+ echo "Cannot lunch background server"
+ exit 255
+ else
+ # Launch the server
+ echo "Launching background server" $SERVER_PRG
+ $SERVER_PRG $SERVER_PORT $SERVER_COUNT $SERVER_NB_COMPILE $SERVER_TIMEOUT >$SERVER_LOG 2>&1 &
+ let RETRY=RETRY-1
+ sleep 3
+ fi
+ fi
+done
# Wait for termination
wait $PID_OUT
diff --git a/jack/rsc/debug.jack.logging.properties b/jack/rsc/debug.jack.logging.properties
index 33d1e0a4..5ca142a5 100644
--- a/jack/rsc/debug.jack.logging.properties
+++ b/jack/rsc/debug.jack.logging.properties
@@ -28,6 +28,7 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
.level= FINE
# configure each logger
+com.android.jack.server.level=INFO
com.android.sched.level= WARNING
# ...
diff --git a/jack/rsc/error.jack.logging.properties b/jack/rsc/error.jack.logging.properties
index 03689645..7bc1f694 100644
--- a/jack/rsc/error.jack.logging.properties
+++ b/jack/rsc/error.jack.logging.properties
@@ -26,3 +26,6 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
# Default level for loggers
.level= SEVERE
+
+# configure each logger
+com.android.jack.server.level=INFO
diff --git a/jack/rsc/info.jack.logging.properties b/jack/rsc/info.jack.logging.properties
index 016e1ffa..09cd9fe1 100644
--- a/jack/rsc/info.jack.logging.properties
+++ b/jack/rsc/info.jack.logging.properties
@@ -28,4 +28,5 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
.level= INFO
# configure each logger
+com.android.jack.server.level=INFO
com.android.sched.level= WARNING
diff --git a/jack/rsc/initial.logging.properties b/jack/rsc/initial.logging.properties
index 7c18e67a..baa12b0f 100644
--- a/jack/rsc/initial.logging.properties
+++ b/jack/rsc/initial.logging.properties
@@ -27,3 +27,5 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
# Default level for loggers
.level= WARNING
+# configure each logger
+com.android.jack.server.level=INFO
diff --git a/jack/rsc/trace.jack.logging.properties b/jack/rsc/trace.jack.logging.properties
index f30e4872..25230e69 100644
--- a/jack/rsc/trace.jack.logging.properties
+++ b/jack/rsc/trace.jack.logging.properties
@@ -26,3 +26,6 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
# Default level for loggers
.level= FINEST
+
+# configure each logger
+com.android.jack.server.level=INFO
diff --git a/jack/rsc/warning.jack.logging.properties b/jack/rsc/warning.jack.logging.properties
index d3731798..baa12b0f 100644
--- a/jack/rsc/warning.jack.logging.properties
+++ b/jack/rsc/warning.jack.logging.properties
@@ -26,3 +26,6 @@ java.util.logging.ConsoleHandler.formatter= com.android.sched.util.log.ConsoleFo
# Default level for loggers
.level= WARNING
+
+# configure each logger
+com.android.jack.server.level=INFO
diff --git a/jack/src/com/android/jack/server/JackSimpleServer.java b/jack/src/com/android/jack/server/JackSimpleServer.java
new file mode 100644
index 00000000..4f27b4ad
--- /dev/null
+++ b/jack/src/com/android/jack/server/JackSimpleServer.java
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.server;
+
+import com.google.common.base.Joiner;
+
+import com.android.sched.util.config.cli.TokenIterator;
+import com.android.sched.util.file.OutputStreamFile;
+import com.android.sched.util.findbugs.SuppressFBWarnings;
+import com.android.sched.util.location.NoLocation;
+import com.android.sched.util.log.tracer.probe.MemoryBytesProbe;
+import com.android.sched.util.log.tracer.probe.TimeNanosProbe;
+
+import org.simpleframework.http.Path;
+import org.simpleframework.http.Request;
+import org.simpleframework.http.Response;
+import org.simpleframework.http.Status;
+import org.simpleframework.http.core.Container;
+import org.simpleframework.http.core.ContainerSocketProcessor;
+import org.simpleframework.http.parse.PathParser;
+import org.simpleframework.transport.connect.Connection;
+import org.simpleframework.transport.connect.SocketConnection;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.management.CompilationMXBean;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Server controlling the number of Jack compilations that are executed simultaneously.
+ */
+public class JackSimpleServer {
+ private static int port;
+
+ @Nonnull
+ private static final ServerTask serviceTest = new ServerTask() {
+ @Nonnull
+ private final Random rnd = new Random();
+
+ @Override
+ public int run(@Nonnull PrintStream out, @Nonnull PrintStream err, @Nonnull File workingDir,
+ @Nonnull TokenIterator args) {
+ String cmd = null;
+ try {
+ args.hasNext();
+ cmd = args.next();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ out.println("Pre-test stdout for '" + workingDir.getPath() + "' from " + port);
+ err.println("Pre-test stderr for '" + cmd + "' from " + port);
+
+ try {
+ Thread.sleep(rnd.nextInt(3000));
+ } catch (InterruptedException e) {
+ // Doesn't matter
+ }
+
+ out.println("Post-test stdout for '" + workingDir.getPath() + "' from " + port);
+ err.println("Post-test stderr for '" + cmd + "' from " + port);
+
+ return rnd.nextInt(30);
+ }
+ };
+
+ @Nonnull
+ private static ServerTask service = new ServerTaskInsideVm();
+
+ @Nonnull
+ private static Logger logger = Logger.getLogger(JackSimpleServer.class.getSimpleName());
+
+ private static final int CMD_IDX_CMD = 0;
+ private static final int CMD_IDX_OUT = 1;
+ private static final int CMD_IDX_ERR = 2;
+ private static final int CMD_IDX_CLI = 3;
+ private static final int CMD_IDX_END = 4;
+
+ private static final int CLI_IDX_PORT = 0;
+ private static final int CLI_IDX_COUNT = 1;
+ private static final int CLI_IDX_MAX = 2;
+ private static final int CLI_IDX_TIEMOUT = 3;
+ private static final int CLI_IDX_END = 4;
+
+ @CheckForNull
+ private static Connection connection;
+ @CheckForNull
+ private static Timer timer;
+ @Nonnull
+ private static Lock lock = new ReentrantLock();
+
+ private static int timeout;
+
+ private static int currentLocal = 0;
+ private static long totalLocal = 0;
+ private static int maxLocal = 0;
+
+ private static int currentForward = 0;
+ private static long totalForward = 0;
+ private static int maxForward = 0;
+
+ public static void main(String[] args) {
+ if (args.length != CLI_IDX_END) {
+ logger.log(Level.SEVERE,
+ "Usage: <port-nb> <server-count> <max-compile> <timeout-s>");
+ abort();
+ }
+
+ port = 0;
+ try {
+ port = Integer.parseInt(args[CLI_IDX_PORT]);
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, "Cannot parse port number '" + args[CLI_IDX_PORT] + "'");
+ abort();
+ }
+
+ logger = Logger.getLogger(JackSimpleServer.class.getSimpleName() + "." + port);
+
+ int count = 0;
+ try {
+ count = Integer.parseInt(args[CLI_IDX_COUNT]);
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, "Cannot parse server count '" + args[CLI_IDX_COUNT] + "'");
+ abort();
+ }
+
+ int nbInstance = 0;
+ try {
+ nbInstance = Integer.parseInt(args[CLI_IDX_MAX]);
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, "Cannot parse instance count '" + args[CLI_IDX_MAX] + "'");
+ abort();
+ }
+
+ try {
+ timeout = Integer.parseInt(args[CLI_IDX_TIEMOUT]) * 1000;
+ } catch (NumberFormatException e) {
+ logger.log(Level.SEVERE, "Cannot parse timeout '" + args[CLI_IDX_TIEMOUT] + "'");
+ abort();
+ }
+
+ InetSocketAddress socket = new InetSocketAddress("127.0.0.1", port);
+
+ logger.log(Level.INFO, "Starting simple server on " + socket);
+ try {
+ JackRouter router = new JackRouter();
+ router.addContainer(new PathParser("/jack"), new JackRun());
+ router.addContainer(new PathParser("/gc"), new JackGc());
+ router.addContainer(new PathParser("/stat"), new JackStat());
+
+ ContainerSocketProcessor processor =
+ new ContainerSocketProcessor(router, nbInstance);
+ connection = new SocketConnection(processor);
+ assert connection != null;
+ connection.connect(socket);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Problem during connection ", e);
+ abort();
+ }
+ }
+
+ private static class JackRouter implements Container {
+ @Nonnull
+ private final Map<String, Container> registry = new HashMap<String, Container>();
+ @Nonnull
+ private final Container primary;
+
+ public JackRouter() {
+ primary = new Container() {
+ @Override
+ public void handle(@Nonnull Request request, @Nonnull Response response) {
+ logger.log(Level.INFO, "Unknown request for '" + request.getPath().getPath() + "'");
+ response.setStatus(Status.NOT_FOUND);
+ }
+ };
+ }
+
+ public JackRouter(@Nonnull Container primary) {
+ this.primary = primary;
+ }
+
+ public void addContainer(@Nonnull Path path, @Nonnull Container container) {
+ registry.put(path.getPath(), container);
+ }
+
+ @Override
+ public void handle(@Nonnull Request request, @Nonnull Response response) {
+ String normalizedPath = request.getPath().getPath();
+
+ logger.log(Level.INFO, "Route request from '" + normalizedPath + "'");
+
+ Container container = registry.get(normalizedPath);
+ if (container != null) {
+ container.handle(request, response);
+ } else {
+ primary.handle(request, response);
+ }
+ }
+ }
+
+ private static class JackRun implements Container {
+ @Override
+ public void handle(@Nonnull Request request, @Nonnull Response response) {
+ try {
+ String line;
+
+ try {
+ line = request.getContent();
+ } catch (IOException e1) {
+ logger.log(Level.SEVERE, "Command read command");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ if (line == null) {
+ logger.log(Level.SEVERE, "Command error: nothing to read");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ String[] command = line.split(" ");
+
+ if (!command[CMD_IDX_CMD].equals("+")) {
+ logger.log(Level.SEVERE, "Command error '" + line + "'");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ logger.log(Level.INFO, "Read command '" + line + "'");
+
+ PrintStream out = null;
+ PrintStream err = null;
+
+ long id;
+
+ lock.lock();
+ try {
+ id = totalLocal;
+ totalLocal++;
+ if (currentLocal == 0) {
+ cancelTimer();
+ }
+ currentLocal++;
+ logger.log(Level.INFO, "Number of concurrent compilations: " + currentLocal);
+ if (currentLocal > maxLocal) {
+ maxLocal = currentLocal;
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ try {
+ if (command.length != CMD_IDX_END) {
+ logger.log(Level.SEVERE, "Command format error '" + line + "'");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ logger.log(Level.INFO, "Open standard output '" + command[CMD_IDX_OUT] + "'");
+ try {
+ out = new OutputStreamFile(command[CMD_IDX_OUT]).getPrintStream();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ logger.log(Level.INFO, "Open standard error '" + command[CMD_IDX_ERR] + "'");
+ try {
+ err = new OutputStreamFile(command[CMD_IDX_ERR]).getPrintStream();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage(), e);
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ logger.log(Level.INFO, "Parse command line");
+ TokenIterator args = new TokenIterator(new NoLocation(), "@" + command[CMD_IDX_CLI]);
+ args.allowFileReferenceInFile();
+ if (!args.hasNext()) {
+ logger.log(Level.SEVERE, "Cli format error");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ String workingDir;
+ try {
+ workingDir = args.next();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Cli format error");
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+
+ int code = -1;
+ long start = System.currentTimeMillis();
+ try {
+ logger.log(Level.INFO, "Run Compilation #" + id);
+ start = System.currentTimeMillis();
+ code = service.run(out, err, new File(workingDir), args);
+ } finally {
+ long stop = System.currentTimeMillis();
+ logger.log(Level.INFO, "Compilation #" + id + " return exit code " + code);
+ logger.log(Level.INFO, "Compilation #" + id + " run in " + (stop - start) + " ms");
+
+ response.setStatus(Status.OK);
+
+ PrintStream printer;
+ try {
+ printer = response.getPrintStream();
+ printer.println(code);
+ printer.close();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Problem to send exit code for compilation #" + id);
+ response.setStatus(Status.BAD_REQUEST);
+ return;
+ }
+ }
+ } finally {
+ if (out != null) {
+ out.close();
+ } else {
+ unblock(command[CMD_IDX_OUT]);
+ }
+
+ if (err != null) {
+ err.close();
+ } else {
+ unblock(command[CMD_IDX_ERR]);
+ }
+
+ lock.lock();
+ try {
+ currentLocal--;
+ if (currentLocal == 0) {
+ startTimer();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ } finally {
+ try {
+ response.close();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Exception during close: ", e);
+ }
+ }
+
+ return;
+ }
+ }
+
+ private static class JackStat implements Container {
+ @Override
+ public void handle(@Nonnull Request request, @Nonnull Response response) {
+ try {
+ response.setStatus(Status.OK);
+ PrintStream printer = response.getPrintStream();
+
+ long time = System.currentTimeMillis();
+ Date date = new Date(time);
+ printer.println("date: " + time + " [" + date + "]");
+
+ try {
+ lock.lock();
+ try {
+ printer.println("server.compilation: " + totalLocal);
+ printer.println("server.compilation.max: " + maxLocal);
+ printer.println("server.compilation.current: " + currentLocal);
+ printer.println("server.forward: " + totalForward);
+ printer.println("server.forward.max: " + maxForward);
+ printer.println("server.forward.current: " + currentForward);
+ } finally {
+ lock.unlock();
+ }
+
+ OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+ printer.println("os.arch: " + os.getArch());
+ printer.println("os.proc.nb: " + Integer.valueOf(os.getAvailableProcessors()));
+ printer.println("os.name: " + os.getName());
+ printer.println("os.version: " + os.getVersion());
+
+ RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+ printer.println("vm.name: " + runtime.getVmName());
+ printer.println("vm.vendor: " + runtime.getVmVendor());
+ printer.println("vm.version: " + runtime.getVmVersion());
+ printer.println("vm_options: "
+ + Joiner.on(' ').skipNulls().join(runtime.getInputArguments()));
+ printer.println("vm.memory.max: " + formatQuatity(Runtime.getRuntime().maxMemory()));
+ printer.println("vm.memory.free: " + formatQuatity(Runtime.getRuntime().freeMemory()));
+ printer.println("vm.memory.total: " + formatQuatity(Runtime.getRuntime().totalMemory()));
+
+ try {
+ CompilationMXBean compilation = ManagementFactory.getCompilationMXBean();
+ printer.println("vm.jit.time: "
+ + formatDuration(compilation.getTotalCompilationTime(), TimeUnit.MILLISECONDS));
+ } catch (UnsupportedOperationException e) {
+ // Do the best
+ }
+
+ for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
+ String suffix = "vm.collector." + tranformString(gc.getName()) + ".";
+ printer.println(suffix + "time: "
+ + formatDuration(gc.getCollectionTime(), TimeUnit.MILLISECONDS));
+ printer.println(suffix + "count: " + gc.getCollectionCount());
+ }
+
+ for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
+ String suffix = "vm.pool." + tranformString(pool.getName()) + ".";
+ printer.println(suffix + "type: " + pool.getType().name());
+
+ printMemoryUsage(printer, suffix + "collection.", pool.getCollectionUsage());
+ try {
+ printer.println(suffix + "collection.threshold: "
+ + formatQuatity(pool.getCollectionUsageThreshold()));
+ } catch (UnsupportedOperationException e) {
+ // Best effort
+ }
+
+ try {
+ printer.println(suffix + "collection.threshold.count: "
+ + pool.getCollectionUsageThresholdCount());
+ } catch (UnsupportedOperationException e) {
+ // Best effort
+ }
+
+ printMemoryUsage(printer, suffix + "peak.", pool.getPeakUsage());
+
+ printMemoryUsage(printer, suffix + "usage.", pool.getUsage());
+ try {
+ printer.println(suffix + "usage.threshold: "
+ + formatQuatity(pool.getUsageThreshold()));
+ } catch (UnsupportedOperationException e) {
+ // Best effort
+ }
+ try {
+ printer.println(suffix + "usage.threshold.count: " + pool.getUsageThresholdCount());
+ } catch (UnsupportedOperationException e) {
+ // Best effort
+ }
+ }
+
+ try {
+ printer.println("host.name: " + InetAddress.getLocalHost().getHostName());
+ } catch (UnknownHostException e1) {
+ // Best effort
+ }
+
+ Method method;
+ try {
+ method = os.getClass().getMethod("getCommittedVirtualMemorySize");
+ method.setAccessible(true);
+ printer.println("os.memory.virtual.committed: "
+ + formatQuatity(((Long) method.invoke(os)).longValue()));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getTotalPhysicalMemorySize");
+ method.setAccessible(true);
+ printer.println("os.memory.physical.total: "
+ + formatQuatity(((Long) method.invoke(os)).longValue()));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getFreePhysicalMemorySize");
+ method.setAccessible(true);
+ printer.println("os.memory.physical.free: "
+ + formatQuatity(((Long) method.invoke(os)).longValue()));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getTotalSwapSpaceSize");
+ method.setAccessible(true);
+ printer.println("os.memory.swap.total: "
+ + formatQuatity(((Long) method.invoke(os)).longValue()));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getFreeSwapSpaceSize");
+ method.setAccessible(true);
+ printer.println("os.memory.swap.free: "
+ + formatQuatity(((Long) method.invoke(os)).longValue()));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getOpenFileDescriptorCount");
+ method.setAccessible(true);
+ printer.println("os.fd.open: " + ((Long) method.invoke(os)).longValue());
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+
+ try {
+ method = os.getClass().getMethod("getProcessCpuLoad");
+ method.setAccessible(true);
+ printer.println("os.process.cpu.load: " + ((Double) method.invoke(os)).doubleValue());
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getProcessCpuTime");
+ method.setAccessible(true);
+ printer.println("os.process.cpu.time: "
+ + formatDuration(((Long) method.invoke(os)).longValue(), TimeUnit.NANOSECONDS));
+ } catch (Throwable t) {
+ // Best effort
+ }
+
+ try {
+ method = os.getClass().getMethod("getSystemCpuLoad");
+ method.setAccessible(true);
+ printer.println("os.system.cpu.load: " + ((Double) method.invoke(os)).doubleValue());
+ } catch (Throwable t) {
+ // Best effort
+ }
+ } catch (Throwable e) {
+ logger.log(Level.SEVERE, "Unexpected exception: ", e);
+ }
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Exception during IO: ", e);
+ } finally {
+ try {
+ response.close();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Exception during close: ", e);
+ }
+ }
+ }
+ }
+
+ static void printMemoryUsage(@Nonnull PrintStream printer, @Nonnull String suffix,
+ @CheckForNull MemoryUsage usage) {
+ if (usage != null) {
+ printer.println(suffix + "commited: " + formatQuatity(usage.getCommitted()));
+ printer.println(suffix + "itnit: " + formatQuatity(usage.getInit()));
+ printer.println(suffix + "max: " + formatQuatity(usage.getMax()));
+ printer.println(suffix + "used: " + formatQuatity(usage.getUsed()));
+ }
+ }
+
+ @Nonnull
+ static String formatDuration(@Nonnull long duration, @Nonnull TimeUnit unit) {
+ String str = Long.toString(duration);
+
+ str += " [";
+ str += TimeNanosProbe.formatDuration(unit.toNanos(duration));
+ str += "]";
+
+ return str;
+ }
+
+ @Nonnull
+ static String formatQuatity(@Nonnull long quantity) {
+ String str = Long.toString(quantity);
+
+ str += " [";
+ str += MemoryBytesProbe.formatBytes(quantity);
+ str += "]";
+
+ return str;
+ }
+
+ @Nonnull
+ static String tranformString(@Nonnull String string) {
+ return string.toLowerCase().replace(' ', '-');
+ }
+
+ @SuppressFBWarnings("DM_GC")
+ private static class JackGc implements Container {
+ @Override
+ public void handle(@Nonnull Request request, @Nonnull Response response) {
+ logger.log(Level.INFO, "Force GC");
+ System.gc();
+ response.setStatus(Status.OK);
+ try {
+ response.close();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Exception during close: ", e);
+ }
+ }
+ }
+
+ private static void abort() {
+ logger.log(Level.SEVERE, "Abort sever");
+ System.exit(1);
+ }
+
+ private static void unblock(@Nonnull String name) {
+ logger.log(Level.INFO, "Trying to unblock '" + name + "'");
+ PrintStream out = null;
+ try {
+ out = new OutputStreamFile(name).getPrintStream();
+ } catch (IOException e) {
+ // Best effort
+ }
+
+ if (out != null) {
+ out.close();
+ }
+ }
+
+ private static void startTimer() {
+ lock.lock();
+ try {
+ if (timer != null) {
+ cancelTimer();
+ }
+
+ logger.log(Level.INFO, "Start timer");
+
+ timer = new Timer("jack-server-timeout");
+ assert timer != null;
+ timer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ cancelTimer();
+
+ Connection conn = connection;
+ assert conn != null;
+
+ logger.log(Level.INFO, "Shutdowning server");
+ logger.log(Level.INFO, "# max of concurrent compilations: " + maxLocal);
+ logger.log(Level.INFO, "# total of compilations: " + totalLocal);
+ logger.log(Level.INFO, "# max of concurrent forward compilations: " + maxForward);
+ logger.log(Level.INFO, "# total of forward compilations: " + totalForward);
+ try {
+ conn.close();
+ logger.log(Level.INFO, "Done");
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Cannot shutdown the server: ", e);
+ }
+ }
+ }, timeout);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private static void cancelTimer() {
+ lock.lock();
+ try {
+ if (timer != null) {
+ logger.log(Level.INFO, "Cancel timer");
+
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+}