diff options
author | Jean-Philippe Lesot <jplesot@google.com> | 2015-03-27 12:30:15 +0100 |
---|---|---|
committer | Jean-Philippe Lesot <jplesot@google.com> | 2015-03-27 12:30:15 +0100 |
commit | 5a2c65c03945ad6aef38a68e64168f031fb845ba (patch) | |
tree | 336220ade5bc1031af62845d8760f91642c47418 /jack | |
parent | 43e79118b5513baede74735da8d6c744afb2bf0b (diff) | |
download | toolchain_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-x | jack/etc/jack | 113 | ||||
-rw-r--r-- | jack/rsc/debug.jack.logging.properties | 1 | ||||
-rw-r--r-- | jack/rsc/error.jack.logging.properties | 3 | ||||
-rw-r--r-- | jack/rsc/info.jack.logging.properties | 1 | ||||
-rw-r--r-- | jack/rsc/initial.logging.properties | 2 | ||||
-rw-r--r-- | jack/rsc/trace.jack.logging.properties | 3 | ||||
-rw-r--r-- | jack/rsc/warning.jack.logging.properties | 3 | ||||
-rw-r--r-- | jack/src/com/android/jack/server/JackSimpleServer.java | 704 |
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(); + } + } +} |