package bsh; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; public class TestUtil { /** * Serializes and then deserializes the given instance - should be not null. * * @param orgig this instance is serialized and then deserialized * @return the instance after serialization and deserialization */ @SuppressWarnings({"unchecked"}) public static <T extends Serializable> T serDeser(final T orgig) { try { final ByteArrayOutputStream byteOS = new ByteArrayOutputStream(); new ObjectOutputStream(byteOS).writeObject(orgig); return (T) new ObjectInputStream(new ByteArrayInputStream(byteOS.toByteArray())).readObject(); } catch (Exception e) { throw new RuntimeException(e); } } static void cleanUp() { System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); System.gc(); } /** * Measure the time of concurrent executions of the provided runnable instance - the first error or runtime exceptions * during execution is populated to the caller. The provided runnable is executed {@code taskCount * iterationCount} * times. */ public static long measureConcurrentTime(final Runnable runnable, final int threadCount, final int taskCount, final int iterationCount) throws InterruptedException { final long duration = _measureConcurrentTime(runnable, threadCount, taskCount, iterationCount); cleanUp(); return duration; } static long _measureConcurrentTime(final Runnable runnable, final int threadCount, final int taskCount, final int iterationCount) throws InterruptedException { if (threadCount < 1) { throw new IllegalArgumentException("thread count must be at least 1"); } if (taskCount < threadCount) { throw new IllegalArgumentException("task count below thread count"); } @SuppressWarnings({"ThrowableInstanceNeverThrown"}) final Exception callerStack = new Exception("called from"); final CountDownLatch countDownLatch = new CountDownLatch(threadCount + 1); final AtomicReference<Throwable> exceptionHolder = new AtomicReference<Throwable>(); final MeasureRunnable toMeasure = new MeasureRunnable(countDownLatch, runnable, iterationCount, exceptionHolder); final ExecutorService executorService = Executors.newFixedThreadPool(threadCount); for (int i = 0; i < taskCount; i++) { executorService.submit(toMeasure); } cleanUp(); final long startTime = System.nanoTime(); countDownLatch.countDown(); // start all executorService.shutdown(); executorService.awaitTermination(60 * 60, TimeUnit.SECONDS); final Throwable throwable = exceptionHolder.get(); if (throwable instanceof RuntimeException) { throw combineTraces((RuntimeException) throwable, callerStack); } if (throwable instanceof Error) { throw combineTraces((Error) throwable, callerStack); } if (throwable != null) { //noinspection ThrowableInstanceNeverThrown throw combineTraces(new RuntimeException(throwable), callerStack); } return System.nanoTime() - startTime; } /** * Adds {@code cause} as root-cause to {@code throwable} and returns {@code throwable}. * * @param throwable exception which root-cause should be extended. * @param cause new root-cause, usually a caller-stack. * @param <T> type of given throwable. * @return {@code throwable} extended with the given {@code cause}. */ static <T extends Throwable> T combineTraces(final T throwable, final Exception cause) { Throwable rootCause = throwable; while (rootCause.getCause() != null) { rootCause = rootCause.getCause(); } rootCause.initCause(cause); return throwable; } public static Object eval(final String ... code) throws Exception { StringBuffer buffer = new StringBuffer(); for (String s : code) { buffer.append(s).append('\n'); } return new Interpreter().eval(buffer.toString()); } static class MeasureRunnable implements Runnable { private final CountDownLatch _countDownLatch; private final Runnable _task; private final int _iterationCount; private final AtomicReference<Throwable> _exception; private MeasureRunnable(final CountDownLatch countDownLatch, final Runnable task, final int iterationCount, final AtomicReference<Throwable> exception) { _countDownLatch = countDownLatch; _task = task; _iterationCount = iterationCount; _exception = exception; } public void run() { try { _countDownLatch.countDown(); for (int i = 0; i < _iterationCount; i++) { _task.run(); } } catch (RuntimeException e) { _exception.compareAndSet(null, e); throw e; } catch (Error e) { _exception.compareAndSet(null, e); throw e; } } } }