You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/03/19 10:47:42 UTC

[commons-rng] branch master updated: Report exit value of stress test subprocess programs

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git


The following commit(s) were added to refs/heads/master by this push:
     new 6d08881  Report exit value of stress test subprocess programs
6d08881 is described below

commit 6d08881815ac0a7d582cd570bfc35194938ecced
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Mar 19 10:47:38 2019 +0000

    Report exit value of stress test subprocess programs
---
 .../commons/rng/examples/stress/BridgeTester.java  | 42 ++++++++++++++++-
 .../rng/examples/stress/RandomStressTester.java    | 52 ++++++++++++++++++++--
 2 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/BridgeTester.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/BridgeTester.java
index bbfc560..d4eef10 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/BridgeTester.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/BridgeTester.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Class that can be used for testing that {@code int} values can be piped to a
@@ -48,6 +49,8 @@ public class BridgeTester {
         "1000", "1001", "1010", "1011",
         "1100", "1101", "1110", "1111",
     };
+    /** The timeout to wait for a process to end (1 second in milliseconds). */
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(1);
 
     /** Command line. */
     private final List<String> cmdLine;
@@ -143,7 +146,17 @@ public class BridgeTester {
                 }
             }
 
-        } catch (IOException e) {
+            if (waitFor(testingProcess)) {
+                final int exitValue = testingProcess.exitValue();
+                if (exitValue != 0) {
+                    System.out.printf("[ERROR] %s exit code = %d%n", cmdLine.get(0), exitValue);
+                }
+            } else {
+                System.out.printf("[ERROR] %s did not exit, killing the subprocess%n", cmdLine.get(0));
+                testingProcess.destroy();
+            }
+
+        } catch (IOException | InterruptedException e) {
             throw new RuntimeException("Failed to run process: " + e.getMessage());
         }
     }
@@ -198,8 +211,33 @@ public class BridgeTester {
     private static void writeByte(BufferedWriter data,
                                   int value) throws IOException {
         // This matches the functionality of:
-        // data.write(String.format("%8s", Integer.toBinaryString(value & 0xff)).replace(' ', '0'));
+        // data.write(String.format("%8s", Integer.toBinaryString(value & 0xff)).replace(' ', '0'))
         data.write(BIT_REP[value >>> 4]);
         data.write(BIT_REP[value & 0x0F]);
     }
+
+    /**
+     * Wait until the given {@code Process} object has terminated, waiting at most for 1 second.
+     *
+     * @param process the process.
+     * @return {@code true} if the process has exited, {@code false} otherwise.
+     * @throws InterruptedException if interrupted while waiting.
+     */
+    private static boolean waitFor(Process process) throws InterruptedException {
+        // TODO - use Java 1.8 Process.waitFor(long, TimeUnit) instead
+        long startTime = System.currentTimeMillis();
+        long remaining = TIMEOUT;
+
+        while (remaining > 0) {
+            try {
+                // Poll the exit value
+                process.exitValue();
+                return true;
+            } catch (IllegalThreadStateException ex) {
+                Thread.sleep(Math.min(remaining + 1, 100));
+            }
+            remaining = TIMEOUT - (System.currentTimeMillis() - startTime);
+        }
+        return false;
+    }
 }
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RandomStressTester.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RandomStressTester.java
index 2b95afe..4de2395 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RandomStressTester.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/RandomStressTester.java
@@ -186,6 +186,10 @@ public class RandomStressTester {
      * Pipes random numbers to the standard input of an analyzer.
      */
     private class Task implements Runnable {
+        /** The timeout to wait for the process exit value in milliseconds. */
+        private final long TIMEOUT = 1000000L;
+        /** The default exit value to use when the process has not terminated. */
+        private final int DEFAULT_EXIT_VALUE = -808080;
         /** Directory for reports of the tester processes. */
         private final File output;
         /** RNG to be tested. */
@@ -205,7 +209,7 @@ public class RandomStressTester {
 
         /** {@inheritDoc} */
         @Override
-            public void run() {
+        public void run() {
             try {
                 // Write header.
                 printHeader(output, rng);
@@ -213,6 +217,7 @@ public class RandomStressTester {
                 // Start test suite.
                 final ProcessBuilder builder = new ProcessBuilder(cmdLine);
                 builder.redirectOutput(ProcessBuilder.Redirect.appendTo(output));
+                builder.redirectErrorStream(true);
                 final Process testingProcess = builder.start();
                 final DataOutputStream sink = new DataOutputStream(
                     new BufferedOutputStream(testingProcess.getOutputStream()));
@@ -229,13 +234,49 @@ public class RandomStressTester {
 
                 final long endTime = System.nanoTime();
 
+                // Get the exit value
+                final int exitValue = getExitValue(testingProcess);
+
                 // Write footer.
-                printFooter(output, endTime - startTime);
+                printFooter(output, endTime - startTime, exitValue);
 
             } catch (IOException e) {
                 throw new RuntimeException("Failed to start task: " + e.getMessage());
             }
         }
+
+        /**
+         * Get the exit value from the process, waiting at most for 1 second, otherwise kill the process
+         * and return a dummy value.
+         *
+         * @param process the process.
+         * @return the exit value.
+         * @see Process#destroy()
+         */
+        private int getExitValue(Process process) {
+            long startTime = System.currentTimeMillis();
+            long remaining = TIMEOUT;
+
+            while (remaining > 0) {
+                try {
+                    return process.exitValue();
+                } catch (IllegalThreadStateException ex) {
+                    try {
+                        Thread.sleep(Math.min(remaining + 1, 100));
+                    } catch (InterruptedException e) {
+                        // Reset interrupted status and stop waiting
+                        Thread.currentThread().interrupt();
+                        break;
+                    }
+                }
+                remaining = TIMEOUT - (System.currentTimeMillis() - startTime);
+            }
+
+            // Not finished so kill it
+            process.destroy();
+
+            return DEFAULT_EXIT_VALUE;
+        }
     }
 
     /**
@@ -278,17 +319,22 @@ public class RandomStressTester {
     /**
      * @param output File.
      * @param nanoTime Duration of the run.
+     * @param exitValue The process exit value.
      * @throws IOException if there was a problem opening or writing to
      * the {@code output} file.
      */
     private void printFooter(File output,
-                             long nanoTime)
+                             long nanoTime,
+                             int exitValue)
         throws IOException {
         final StringBuilder sb = new StringBuilder();
         sb.append(C).append(N);
 
         appendDate(sb, "End");
 
+        sb.append(C).append("Exit value: ").append(exitValue).append(N);
+        sb.append(C).append(N);
+
         final double duration = nanoTime * 1e-9 / 60;
         sb.append(C).append("Test duration: ").append(duration).append(" minutes").append(N);