package de.is24.util.monitoring; import junit.framework.TestCase; import java.text.NumberFormat; import java.util.Random; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; public class CounterAndTimerTest extends TestCase { private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(); static { NUMBER_FORMAT.setGroupingUsed(true); NUMBER_FORMAT.setMinimumFractionDigits(3); NUMBER_FORMAT.setMaximumFractionDigits(3); } private static final int THREADS = 10, RUNS = 50, ITERATIONS = 1000, OVERALL = RUNS * ITERATIONS; private ThreadPoolExecutor executor; private Counter counter; private Timer timer; private Job counterJob, timerJob; private Random rnd; private AtomicLong timerSum; protected void setUp() throws Exception { this.counter = new Counter("test"); this.timer = new Timer("test"); this.counterJob = new CounterJob(); this.timerJob = new TimerJob(); this.rnd = new Random(); this.timerSum = new AtomicLong(); } public void testAddMeasurement() throws Exception { createExecutor(THREADS); executeJob(timerJob); assertEquals(OVERALL, timer.getCount()); assertEquals(timerSum.get(), timer.getTimerSum()); System.out.println("Timer measured " + timer.getCount() + " times."); System.out.println("Timer measured a total of " + timer.getTimerSum() + " ms."); System.out.println("Timer measured an average of " + timer.getTimerAvg() + " ms."); System.out.println("Timer measured a standard deviance of " + timer.getTimerStdDev() + " ms."); waitASecond(); setUp(); executePerformanceTest(timerJob); } public void testIncrement() throws Exception { createExecutor(THREADS); executeJob(counterJob); assertEquals(OVERALL, counter.getCount()); System.out.println("Counter measured " + counter.getCount() + " times."); waitASecond(); setUp(); executePerformanceTest(counterJob); } private void waitASecond() throws InterruptedException { System.gc(); Thread.sleep(1000); System.gc(); } private void executePerformanceTest(Job job) throws InterruptedException { for (int threads = 8; threads >= 1; threads -= 1) { createExecutor(threads); job.reset(); executeJob(job); System.out.println("Executed " + job.getClass().getSimpleName() + " test (" + RUNS + "x" + ITERATIONS + " times using " + threads + " threads) in avg. " + NUMBER_FORMAT.format(job.getTimerAvgMs()) + " (std. deviance " + NUMBER_FORMAT.format(job.getTimerStdDevMs()) + ") ms."); } } private void createExecutor(int threads) { this.executor = new ScheduledThreadPoolExecutor(threads); this.executor.setMaximumPoolSize(threads); } private void executeJob(Runnable job) throws InterruptedException { for (int i = 0; i < RUNS; i++) { executor.execute(job); } executor.shutdown(); executor.awaitTermination(100, TimeUnit.SECONDS); } private abstract class Job implements Runnable { private final AtomicInteger executions = new AtomicInteger(); private final AtomicLong timerSum = new AtomicLong(); private final AtomicLong timerSumOfSquares = new AtomicLong(); public void run() { final long start = System.nanoTime(); doJob(); final long time = System.nanoTime() - start; executions.incrementAndGet(); timerSum.addAndGet(time); timerSumOfSquares.addAndGet(time * time); } protected abstract void doJob(); public double getTimerAvgMs() { return Math.average(executions.get(), timerSum.get()) / (1000 * 1000d); } public double getTimerStdDevMs() { return Math.stdDeviation(executions.get(), timerSum.get(), timerSumOfSquares.get()) / (1000 * 1000d); } public void reset() { executions.set(0); timerSum.set(0); timerSumOfSquares.set(0); } } private class CounterJob extends Job { protected void doJob() { try { for (int i = 0; i < ITERATIONS; i++) { final long millis = (long) java.lang.Math.pow(rnd.nextInt(10), 3); counter.increment(); timerSum.addAndGet(millis); } } catch (RuntimeException e) { e.printStackTrace(); } } } private class TimerJob extends Job { protected void doJob() { try { for (int i = 0; i < ITERATIONS; i++) { final long millis = (long) java.lang.Math.pow(rnd.nextInt(10), 3); timerSum.addAndGet(millis); timer.addMeasurement(millis); } } catch (RuntimeException e) { e.printStackTrace(); } } } }