From 1a7ad3388a2781ec818a10ee5b6b37886eac478b Mon Sep 17 00:00:00 2001 From: FeiWongReed Date: Wed, 29 Apr 2015 00:07:32 +0600 Subject: [PATCH] prepared measurement, metrics stub --- .../nohope/test/stress/MeasureProvider.java | 10 +- .../stress/MultiInvocationStatCalculator.java | 11 -- .../test/stress/PooledMeasureProvider.java | 8 +- .../test/stress/PreparedMeasurement.java | 98 ++++++++++++++ ...a => SingleInvocationStatAccumulator.java} | 8 +- ...atCalculator.java => StatAccumulator.java} | 17 +-- .../nohope/test/stress/StressScenario.java | 122 +++++------------- .../{Result.java => result/ActionResult.java} | 37 ++++-- .../test/stress/result/StressMetrics.java | 10 ++ .../stress/{ => result}/StressResult.java | 61 +++++++-- .../test/stress/util/MetricsAccumulator.java | 41 ++++++ .../stresstooltest/StressScenarioTest.java | 72 +++++------ 12 files changed, 310 insertions(+), 185 deletions(-) delete mode 100644 projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MultiInvocationStatCalculator.java create mode 100644 projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PreparedMeasurement.java rename projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/{SingleInvocationStatCalculator.java => SingleInvocationStatAccumulator.java} (69%) rename projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/{StatCalculator.java => StatAccumulator.java} (87%) rename projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/{Result.java => result/ActionResult.java} (93%) create mode 100644 projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressMetrics.java rename projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/{ => result}/StressResult.java (68%) create mode 100644 projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/util/MetricsAccumulator.java diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MeasureProvider.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MeasureProvider.java index d98d15b..7655d89 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MeasureProvider.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MeasureProvider.java @@ -12,18 +12,18 @@ */ public final class MeasureProvider extends MeasureData { private final StressScenario scenario; - private final ConcurrentMap map; - private final Function calculatorFunction; + private final ConcurrentMap map; + private final Function calculatorFunction; protected MeasureProvider(final StressScenario scenario, final int threadId, final int operationNumber, final int concurrency, - final ConcurrentMap map) { + final ConcurrentMap map) { super(threadId, operationNumber, concurrency); this.scenario = scenario; this.map = map; - this.calculatorFunction = newName -> new MultiInvocationStatCalculator( + this.calculatorFunction = newName -> new StatAccumulator( this.scenario.getResolution(), newName, concurrency); } @@ -36,7 +36,7 @@ public void call(final String name, final Invoke invoke) throws Exception { getStat(name).invoke(getThreadId(), invoke); } - private MultiInvocationStatCalculator getStat(final String name) { + private StatAccumulator getStat(final String name) { return map.computeIfAbsent(name, calculatorFunction); } diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MultiInvocationStatCalculator.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MultiInvocationStatCalculator.java deleted file mode 100644 index fcdcc93..0000000 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/MultiInvocationStatCalculator.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.nohope.test.stress; - -/** -* @author ketoth xupack -* @since 2013-12-27 16:18 -*/ -class MultiInvocationStatCalculator extends StatCalculator { - protected MultiInvocationStatCalculator(final TimerResolution resolution, final String name, final int concurrency) { - super(resolution, name, concurrency); - } -} diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PooledMeasureProvider.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PooledMeasureProvider.java index 34cebb8..7296282 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PooledMeasureProvider.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PooledMeasureProvider.java @@ -13,12 +13,12 @@ */ public final class PooledMeasureProvider extends MeasureData { private final LoadingCache poolCache; - private final LoadingCache statCache; + private final LoadingCache statCache; protected PooledMeasureProvider(final int threadId, final int operationNumber, final int concurrency, - final LoadingCache statCache, + final LoadingCache statCache, final LoadingCache poolCache) { super(threadId, operationNumber, concurrency); this.poolCache = poolCache; @@ -31,12 +31,12 @@ public long getThreadId() { } public Future invoke(final String name, final Get getter) throws Exception { - final MultiInvocationStatCalculator calc = statCache.get(name); + final StatAccumulator calc = statCache.get(name); return poolCache.get(name).submit(() -> calc.invoke(getThreadId(), getter)); } public void invoke(final String name, final Invoke invoke) throws Exception { - final MultiInvocationStatCalculator calc = statCache.get(name); + final StatAccumulator calc = statCache.get(name); poolCache.get(name).submit(() -> { try { calc.invoke(getThreadId(), invoke); diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PreparedMeasurement.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PreparedMeasurement.java new file mode 100644 index 0000000..d3ed8c2 --- /dev/null +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/PreparedMeasurement.java @@ -0,0 +1,98 @@ +package org.nohope.test.stress; + +import org.nohope.test.stress.result.ActionResult; +import org.nohope.test.stress.result.StressResult; +import org.nohope.test.stress.util.Memory; +import org.nohope.test.stress.util.MetricsAccumulator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; + +final public class PreparedMeasurement { + private final int threadsNumber; + private final int cycleCount; + private final Iterable executors; + private final Iterable statAccumulators; + private final List threads; + private final TimerResolution timerResolution; + + + PreparedMeasurement(final TimerResolution resolution, final int threadsNumber, final int cycleCount, final Iterable executors, + final Iterable statAccumulators, final List threads) { + this.timerResolution = resolution; + this.threadsNumber = threadsNumber; + this.cycleCount = cycleCount; + this.executors = executors; + this.statAccumulators = statAccumulators; + this.threads = threads; + } + + + public int getThreadsNumber() { + return threadsNumber; + } + + + public int getCycleCount() { + return cycleCount; + } + + + public Iterable getExecutors() { + return executors; + } + + + public Iterable getStatAccumulators() { + return statAccumulators; + } + + + public List getThreads() { + return threads; + } + + public StressResult perform() throws InterruptedException { + return awaitResult(this); + } + + private StressResult awaitResult(final PreparedMeasurement preparedMeasurement) throws InterruptedException { + final MetricsAccumulator metrics = new MetricsAccumulator(); + metrics.start(); + + final Memory memoryStart = Memory.getCurrent(); + final long overallStart = timerResolution.currentTime(); + + preparedMeasurement.getThreads().forEach(java.lang.Thread::start); + + for (final Thread thread : preparedMeasurement.getThreads()) { + thread.join(); + } + + metrics.stop(); + + for (final ExecutorService service : preparedMeasurement.getExecutors()) { + try { + service.shutdown(); + service.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS); + } catch (final InterruptedException ignored) { + } + } + + final long overallEnd = timerResolution.currentTime(); + final Memory memoryEnd = Memory.getCurrent(); + + final double runtime = overallEnd - overallStart; + + final Map results = new HashMap<>(); + for (final StatAccumulator stats : preparedMeasurement.getStatAccumulators()) { + final ActionResult r = stats.getResult(); + results.put(r.getName(), r); + } + + return new StressResult(results, preparedMeasurement.getThreadsNumber(), preparedMeasurement.getCycleCount(), runtime, metrics.getMetrics(), memoryStart, memoryEnd); + } +} diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatCalculator.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatAccumulator.java similarity index 69% rename from projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatCalculator.java rename to projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatAccumulator.java index 14b8330..08d16df 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatCalculator.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/SingleInvocationStatAccumulator.java @@ -6,12 +6,12 @@ * @author ketoth xupack * @since 2013-12-27 16:18 */ -class SingleInvocationStatCalculator extends StatCalculator { +class SingleInvocationStatAccumulator extends StatAccumulator { private final NamedAction action; - public SingleInvocationStatCalculator(final TimerResolution resolution, - final NamedAction action, - final int concurrency) { + public SingleInvocationStatAccumulator(final TimerResolution resolution, + final NamedAction action, + final int concurrency) { super(resolution, action.getName(), concurrency); this.action = action; } diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatCalculator.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatAccumulator.java similarity index 87% rename from projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatCalculator.java rename to projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatAccumulator.java index ffeb6f7..4773827 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatCalculator.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StatAccumulator.java @@ -3,6 +3,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.nohope.test.stress.functors.Get; import org.nohope.test.stress.functors.Invoke; +import org.nohope.test.stress.result.ActionResult; import javax.annotation.Nonnull; import java.util.ArrayList; @@ -11,7 +12,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static java.util.Map.Entry; @@ -20,19 +20,17 @@ * @author ketoth xupack * @since 2013-12-27 16:18 */ -class StatCalculator { +class StatAccumulator { private final ConcurrentHashMap>> timesPerThread = new ConcurrentHashMap<>(); private final ConcurrentHashMap, ConcurrentLinkedQueue> errorStats = new ConcurrentHashMap<>(); - private final ConcurrentHashMap, ConcurrentLinkedQueue> rootErrorStats = new ConcurrentHashMap<>(); - private final AtomicReference result = new AtomicReference<>(); - private final AtomicInteger fails = new AtomicInteger(0); + private final AtomicReference result = new AtomicReference<>(); private final String name; private final TimerResolution resolution; private final int concurrency; - protected StatCalculator(final TimerResolution resolution, - final String name, final int concurrency) { + protected StatAccumulator(final TimerResolution resolution, + final String name, final int concurrency) { this.resolution = resolution; this.name = name; this.concurrency = concurrency; @@ -44,7 +42,7 @@ protected StatCalculator(final TimerResolution resolution, } @Nonnull - public Result getResult() { + public ActionResult getResult() { if (result.get() == null) { calculate(); } @@ -84,7 +82,6 @@ protected final void invoke(final long threadId, private void handleException(final Exception e) { final Class aClass = e.getClass(); errorStats.computeIfAbsent(aClass, clazz -> new ConcurrentLinkedQueue<>()).add(e); - fails.getAndIncrement(); } @@ -114,7 +111,7 @@ private void calculate() { } - result.set(new Result( + result.set(new ActionResult( name, timesPerThread, eStats, diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressScenario.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressScenario.java index 17efc5a..d1fd445 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressScenario.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressScenario.java @@ -7,9 +7,13 @@ import org.nohope.test.stress.actions.Action; import org.nohope.test.stress.actions.NamedAction; import org.nohope.test.stress.actions.PooledAction; +import org.nohope.test.stress.result.ActionResult; +import org.nohope.test.stress.result.StressResult; import org.nohope.test.stress.util.Memory; +import org.nohope.test.stress.util.MetricsAccumulator; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,15 +43,15 @@ public static StressScenario of(final TimerResolution resolution) { return new StressScenario(resolution); } - public StressResult measure(final int threadsNumber, - final int cycleCount, - final NamedAction... actions) + public PreparedMeasurement prepare(final int threadsNumber, + final int cycleCount, + final NamedAction... actions) throws InterruptedException { - final Map stats = new HashMap<>(); + final Map stats = new HashMap<>(actions.length); for (final NamedAction action : actions) { stats.put(action.getName(), - new SingleInvocationStatCalculator(resolution, action, threadsNumber)); + new SingleInvocationStatAccumulator(resolution, action, threadsNumber)); } final List threads = new ArrayList<>(); @@ -56,7 +60,7 @@ public StressResult measure(final int threadsNumber, threads.add(new Thread(() -> { for (int j = k * cycleCount; j < (k + 1) * cycleCount; j++) { try { - for (final SingleInvocationStatCalculator stat : stats.values()) { + for (final SingleInvocationStatAccumulator stat : stats.values()) { stat.invoke(k, j); } } catch (final InvocationException e) { @@ -66,47 +70,25 @@ public StressResult measure(final int threadsNumber, }, "stress-worker-" + k)); } - final Memory memoryStart = Memory.getCurrent(); - final long overallStart = resolution.currentTime(); - threads.forEach(java.lang.Thread::start); - - for (final Thread thread : threads) { - thread.join(); - } - final long overallEnd = resolution.currentTime(); - - final Memory memoryEnd = Memory.getCurrent(); - - - final double runningTime = overallEnd - overallStart; - - final Map results = new HashMap<>(); - int fails = 0; - for (final SingleInvocationStatCalculator stat : stats.values()) { - final Result r = stat.getResult(); - fails += r.getErrors().size(); - results.put(r.getName(), r); - } - - return new StressResult(results, threadsNumber, cycleCount, - fails, runningTime, memoryStart, memoryEnd); + return new PreparedMeasurement(resolution, threadsNumber, cycleCount, Collections.emptyList(), stats.values(), threads); } - public StressResult measure(final int threadsNumber, + public PreparedMeasurement prepare(final int threadsNumber, final int cycleCount, final Action action) throws InterruptedException { - final ConcurrentMap result = + final ConcurrentMap result = new ConcurrentHashMap<>(16, 0.75f, threadsNumber); - final List providers = new ArrayList<>(); + final List providers = new ArrayList<>(threadsNumber * cycleCount); for (int i = 0; i < threadsNumber; i++) { for (int j = i * cycleCount; j < (i + 1) * cycleCount; j++) { providers.add(new MeasureProvider(this, i, j, threadsNumber, result)); } } + final List threads = new ArrayList<>(); for (int i = 0; i < threadsNumber; i++) { final int k = i; @@ -120,34 +102,14 @@ public StressResult measure(final int threadsNumber, } }, "stress-worker-" + k)); } + return new PreparedMeasurement(resolution, threadsNumber, cycleCount, Collections.emptyList(), result.values(), threads); - final Memory memoryStart = Memory.getCurrent(); - final long overallStart = resolution.currentTime(); - threads.forEach(java.lang.Thread::start); - for (final Thread thread : threads) { - thread.join(); - } - final long overallEnd = resolution.currentTime(); - final Memory memoryEnd = Memory.getCurrent(); - - final double runtime = overallEnd - overallStart; - - int fails = 0; - final Map results = new HashMap<>(); - for (final MultiInvocationStatCalculator stats : result.values()) { - final Result r = stats.getResult(); - fails += r.getErrors().size(); - results.put(r.getName(), r); - } - - return new StressResult(results, threadsNumber, cycleCount, - fails, runtime, memoryStart, memoryEnd); } - public StressResult measurePooled(final int threadsNumber, - final int cycleCount, - final int coordinateThreadsCount, - final PooledAction action) + public PreparedMeasurement prepare(final int threadsNumber, + final int cycleCount, + final int coordinateThreadsCount, + final PooledAction action) throws InterruptedException { final LoadingCache threadPools = @@ -157,18 +119,18 @@ public StressResult measurePooled(final int threadsNumber, final int concurrency = threadsNumber * coordinateThreadsCount; - final LoadingCache calcPool = + final LoadingCache calcPool = CacheBuilder.newBuilder() .concurrencyLevel(threadsNumber) - .build(new CacheLoader() { + .build(new CacheLoader() { @Override - public MultiInvocationStatCalculator load(final String key) throws Exception { - return new MultiInvocationStatCalculator(getResolution(), key, - concurrency); + public StatAccumulator load(final String key) throws Exception { + return new StatAccumulator(getResolution(), key, + concurrency); } }); - final List providers = new ArrayList<>(); + final List providers = new ArrayList<>(threadsNumber * cycleCount); for (int i = 0; i < threadsNumber; i++) { for (int j = i * cycleCount; j < (i + 1) * cycleCount; j++) { providers.add(new PooledMeasureProvider(i, j, concurrency, calcPool, threadPools)); @@ -190,35 +152,13 @@ public MultiInvocationStatCalculator load(final String key) throws Exception { }, "stress-worker-" + k)); } - final Memory memoryStart = Memory.getCurrent(); - final long overallStart = resolution.currentTime(); - threads.forEach(java.lang.Thread::start); - for (final Thread thread : threads) { - thread.join(); - } - for (final ExecutorService service : threadPools.asMap().values()) { - try { - service.shutdown(); - service.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS); - } catch (final InterruptedException ignored) { - } - } - final long overallEnd = resolution.currentTime(); - final Memory memoryEnd = Memory.getCurrent(); + return new PreparedMeasurement(resolution, threadsNumber, cycleCount, threadPools.asMap().values(), + calcPool.asMap().values(), threads); + } + - final double runtime = overallEnd - overallStart; - int fails = 0; - final Map results = new HashMap<>(); - for (final MultiInvocationStatCalculator stats : calcPool.asMap().values()) { - final Result r = stats.getResult(); - fails += r.getErrors().size(); - results.put(r.getName(), r); - } - return new StressResult(results, threadsNumber, cycleCount, - fails, runtime, memoryStart, memoryEnd); - } private static class PoolLoader extends CacheLoader { private final int threadsNumber; @@ -229,7 +169,7 @@ private PoolLoader(final int threadsNumber) { @Override public ExecutorService load(final String key) throws Exception { - final String nameFormat = "measure-pool-" + key + "-%d"; + final String nameFormat = "prepare-pool-" + key + "-%d"; final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(nameFormat).build(); return Executors.newFixedThreadPool(threadsNumber, diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/Result.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/ActionResult.java similarity index 93% rename from projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/Result.java rename to projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/ActionResult.java index 46c8f9a..40786bc 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/Result.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/ActionResult.java @@ -1,4 +1,4 @@ -package org.nohope.test.stress; +package org.nohope.test.stress.result; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -25,10 +25,11 @@ * @author ketoth xupack * @since 2013-12-27 16:19 */ -public class Result { +public class ActionResult { private final Map>> timestampsPerThread = new HashMap<>(); private final Map, List> errorStats = new HashMap<>(); private final Map, List> rootErrorStats = new HashMap<>(); + private final Map> startEndForThread; private final String name; @@ -38,18 +39,17 @@ public class Result { private final double totalDeltaNanos; private final long operationsCount; private final int numberOfThreads; - private final Map> startEndForThread; private double avgWastedNanos; private double avgRuntimeIncludingWastedNanos; private final Set percentiles = new TreeSet<>(); private final Percentile percentile = new Percentile(); - public Result(final String name, - final Map>> timestampsPerThread, - final Map, List> errorStats, - final long totalDeltaNanos, - final long minTime, - final long maxTime) { + public ActionResult(final String name, + final Map>> timestampsPerThread, + final Map, List> errorStats, + final long totalDeltaNanos, + final long minTime, + final long maxTime) { this.name = name; this.totalDeltaNanos = totalDeltaNanos; this.minTime = minTime; @@ -113,6 +113,8 @@ public Result(final String name, } + + private static Map, ? extends List> computeRootStats(final Map, List> errorStats) { final Map, List> rStats = new HashMap<>(errorStats.size()); @@ -134,6 +136,7 @@ public Result(final String name, } + public double getAvgWastedNanos() { return avgWastedNanos; } @@ -191,13 +194,25 @@ public double getRuntime() { return totalDeltaNanos; } + + /** + * Per thread timestamps of operation start and end + * @return in nanoseconds + */ + public Map>> getTimestampsPerThread() { + return Collections.unmodifiableMap(timestampsPerThread); + } + + /** + * Operation times per thread * @return in nanoseconds */ public Map> getPerThreadRuntimes() { final Map> times = new HashMap<>(); for (final Entry>> perThreadTime : timestampsPerThread.entrySet()) { - final List perThread = perThreadTime.getValue().stream().map(e -> e.getValue() - e.getKey()) + final List perThread = perThreadTime.getValue().stream() + .map(e -> e.getValue() - e.getKey()) .collect(Collectors.toList()); times.put(perThreadTime.getKey(), perThread); } @@ -231,7 +246,7 @@ public final List getRunTimes() { return times; } - public Result withPercentiles(final double... percentiles) { + public ActionResult withPercentiles(final double... percentiles) { for (final double percentile : percentiles) { if (percentile < 0 || percentile > 100) { throw new IllegalStateException("Percentile " + percentile + " is out of range [0, 100]"); diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressMetrics.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressMetrics.java new file mode 100644 index 0000000..fa3645f --- /dev/null +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressMetrics.java @@ -0,0 +1,10 @@ +package org.nohope.test.stress.result; + +/** + */ +public class StressMetrics { + + public static StressMetrics get() { + return new StressMetrics(); + } +} diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressResult.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressResult.java similarity index 68% rename from projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressResult.java rename to projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressResult.java index 99fb565..8553e31 100644 --- a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/StressResult.java +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/result/StressResult.java @@ -1,49 +1,68 @@ -package org.nohope.test.stress; +package org.nohope.test.stress.result; import org.apache.commons.lang3.StringUtils; import org.nohope.test.stress.util.Memory; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.TreeSet; +import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.nohope.test.stress.util.TimeUtils.throughputTo; -import static org.nohope.test.stress.util.TimeUtils.timeTo; +import static org.nohope.test.stress.util.TimeUtils.*; /** * @author ketoth xupack * @since 2013-12-27 16:19 */ public class StressResult { - private final Map results = new HashMap<>(); + private final Map results; private final double runtime; - private final int fails; + private final int totalExceptionsCount; private final int threadsCount; private final int cycleCount; private final Memory memoryStart; private final Memory memoryEnd; + private final List allExceptions; + private final List metrics; - public StressResult(final Map stats, + + public StressResult(final Map stats, final int threadsCount, final int cycleCount, - final int fails, final double runtime, + final List metrics, final Memory memoryStart, final Memory memoryEnd) { this.runtime = runtime; - this.fails = fails; + this.allExceptions = stats.entrySet().stream() + .flatMap(entry -> entry.getValue().getErrors().stream()) + .collect(Collectors.toList()); + this.totalExceptionsCount = allExceptions.size(); this.threadsCount = threadsCount; this.cycleCount = cycleCount; + results = new HashMap<>(stats.size()); this.results.putAll(stats); + + this.metrics = new ArrayList<>(metrics.size()); + this.metrics.addAll(metrics); this.memoryStart = memoryStart; this.memoryEnd = memoryEnd; } + + public List getMetrics() { + return metrics; + } + + /** * @return per test results */ - public Map getResults() { + public Map getResults() { return results; } @@ -51,7 +70,7 @@ public Map getResults() { * @return approximate overall throughput in op/sec */ public double getApproxThroughput() { - return (threadsCount * cycleCount * 1.0 - fails) / runtime; + return (threadsCount * cycleCount * 1.0 - totalExceptionsCount) / runtime; } /** @@ -64,8 +83,8 @@ public double getRuntime() { /** * @return overall exceptions count */ - public int getFails() { - return fails; + public int getTotalExceptionsCount() { + return totalExceptionsCount; } public Memory getMemoryStart() { @@ -76,6 +95,22 @@ public Memory getMemoryEnd() { return memoryEnd; } + + public int getThreadsCount() { + return threadsCount; + } + + + public int getCycleCount() { + return cycleCount; + } + + + public List getAllExceptions() { + return Collections.unmodifiableList(allExceptions); + } + + @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -100,7 +135,7 @@ public String toString() { return builder.append(separator) .append('\n') .append(pad("Total error count:")) - .append(fails) + .append(totalExceptionsCount) .append('\n') .append(pad("Total running time:")) .append(String.format("%.3f", timeTo(runtime, SECONDS))) diff --git a/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/util/MetricsAccumulator.java b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/util/MetricsAccumulator.java new file mode 100644 index 0000000..7664914 --- /dev/null +++ b/projects/test-utils/test-utils-stress/src/main/java/org/nohope/test/stress/util/MetricsAccumulator.java @@ -0,0 +1,41 @@ +package org.nohope.test.stress.util; + +import org.nohope.test.stress.result.StressMetrics; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + */ +public class MetricsAccumulator { + private final List metrics = new ArrayList<>(); + private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); + + + private void storeMetric() { + metrics.add(StressMetrics.get()); + } + + + public List getMetrics() { + return Collections.unmodifiableList(metrics); + } + + + public void start() { + scheduledThreadPoolExecutor.scheduleAtFixedRate(this::storeMetric, 0, 2, TimeUnit.SECONDS); + } + + + public void stop() { + scheduledThreadPoolExecutor.shutdown(); + try { + scheduledThreadPoolExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS); + } catch (final InterruptedException ignored) { + + } + } +} diff --git a/projects/test-utils/test-utils-stress/src/test/java/org/nohope/test/stresstooltest/StressScenarioTest.java b/projects/test-utils/test-utils-stress/src/test/java/org/nohope/test/stresstooltest/StressScenarioTest.java index ba5aa65..2c742fb 100644 --- a/projects/test-utils/test-utils-stress/src/test/java/org/nohope/test/stresstooltest/StressScenarioTest.java +++ b/projects/test-utils/test-utils-stress/src/test/java/org/nohope/test/stresstooltest/StressScenarioTest.java @@ -5,8 +5,8 @@ import org.nohope.test.stress.MeasureData; import org.nohope.test.stress.MeasureProvider; import org.nohope.test.stress.PooledMeasureProvider; -import org.nohope.test.stress.Result; -import org.nohope.test.stress.StressResult; +import org.nohope.test.stress.result.ActionResult; +import org.nohope.test.stress.result.StressResult; import org.nohope.test.stress.StressScenario; import org.nohope.test.stress.TimerResolution; import org.nohope.test.stress.actions.Action; @@ -31,22 +31,22 @@ public class StressScenarioTest { public void roughTest() throws InterruptedException { final StressResult m1 = StressScenario.of(TimerResolution.MILLISECONDS) - .measure(50, 1000, new NamedAction("test1") { + .prepare(50, 1000, new NamedAction("test1") { @Override public void doAction(final MeasureData p) throws Exception { Thread.sleep(10); } - }); + }).perform(); final StressResult m2 = StressScenario.of(TimerResolution.NANOSECONDS) - .measure(50, 1000, new NamedAction("test2") { + .prepare(50, 1000, new NamedAction("test2") { @Override public void doAction(final MeasureData p) throws Exception { Thread.sleep(10); } - }); + }).perform(); System.err.println(m1); System.err.println(); @@ -55,22 +55,22 @@ public void doAction(final MeasureData p) final StressResult m3 = StressScenario.of(TimerResolution.MILLISECONDS) - .measure(50, 1000, new Action() { + .prepare(50, 1000, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.call("test1", () -> Thread.sleep(10)); } - }); + }).perform(); final StressResult m4 = StressScenario.of(TimerResolution.NANOSECONDS) - .measure(50, 1000, new Action() { + .prepare(50, 1000, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.call("test1", () -> Thread.sleep(10)); } - }); + }).perform(); System.err.println(m3); System.err.println(); @@ -82,7 +82,7 @@ public void counts() throws InterruptedException { { final StressResult m = StressScenario.of(TimerResolution.NANOSECONDS) - .measure(2, 100, new NamedAction("test") { + .prepare(2, 100, new NamedAction("test") { @Override public void doAction(final MeasureData p) throws Exception { @@ -92,13 +92,13 @@ public void doAction(final MeasureData p) } Thread.sleep(1); } - }); + }).perform(); - final Map results = m.getResults(); + final Map results = m.getResults(); assertNotNull(m.toString()); assertEquals(1, results.size()); - final Result testResult = results.get("test"); + final ActionResult testResult = results.get("test"); //System.err.println(testResult); assertNotNull(testResult); final double throughput = testResult.getThroughput(); @@ -123,7 +123,7 @@ public void doAction(final MeasureData p) assertTrue(testResult.getMeanTime() >= testResult.getMinTime()); assertTrue(m.getRuntime() > 0); assertTrue(testResult.getRuntime() > 0); - assertEquals(100, m.getFails()); + assertEquals(100, m.getTotalExceptionsCount()); assertEquals(100, testResult.getErrorsPerClass() .get(IllegalStateException.class) .size() @@ -133,7 +133,7 @@ public void doAction(final MeasureData p) { final StressResult m = StressScenario.of(TimerResolution.NANOSECONDS) - .measure(2, 100, new Action() { + .prepare(2, 100, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { @@ -144,12 +144,12 @@ public void doAction(final MeasureProvider p) Thread.sleep(1); }); } - }); + }).perform(); - final Map results = m.getResults(); + final Map results = m.getResults(); assertNotNull(m.toString()); assertEquals(1, results.size()); - final Result testResult = results.get("test"); + final ActionResult testResult = results.get("test"); assertNotNull(testResult); assertTrue(testResult.getThroughput() <= 2000); assertTrue(testResult.getWorkerThroughput() <= 1000); @@ -163,7 +163,7 @@ public void doAction(final MeasureProvider p) assertTrue(testResult.getAvgRuntimeIncludingWastedNanos() > 0); assertTrue(testResult.getAvgWastedNanos() > 0); assertTrue(testResult.getAvgWastedNanos() < testResult.getAvgRuntimeIncludingWastedNanos()); - assertEquals(100, m.getFails()); + assertEquals(100, m.getTotalExceptionsCount()); assertEquals(100, testResult.getErrorsPerClass() .get(IllegalStateException.class) .size() @@ -173,31 +173,31 @@ public void doAction(final MeasureProvider p) { final StressResult m2 = StressScenario.of(TimerResolution.MILLISECONDS) - .measure(2, 100, new NamedAction("test") { + .prepare(2, 100, new NamedAction("test") { @Override public void doAction(final MeasureData p) throws Exception { Thread.sleep(10); } - }); + }).perform(); assertNotNull(m2.toString()); assertTrue(m2.getRuntime() >= 1); assertTrue(m2.getApproxThroughput() <= 200); final StressResult m3 = StressScenario.of(TimerResolution.MILLISECONDS) - .measure(2, 100, new Action() { + .prepare(2, 100, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.call("test", () -> Thread.sleep(10)); } - }); + }).perform(); assertNotNull(m3.toString()); assertTrue(m3.getRuntime() >= 1); assertTrue(m3.getApproxThroughput() <= 200); final StressResult m4 = StressScenario.of(TimerResolution.MILLISECONDS) - .measure(2, 100, new Action() { + .prepare(2, 100, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.get("test", () -> { @@ -205,7 +205,7 @@ public void doAction(final MeasureProvider p) throws Exception { return null; }); } - }); + }).perform(); assertNotNull(m4.toString()); assertTrue(m4.getRuntime() >= 1); assertTrue(m4.getApproxThroughput() <= 200); @@ -214,12 +214,12 @@ public void doAction(final MeasureProvider p) throws Exception { { final StressResult m2 = StressScenario.of(TimerResolution.MILLISECONDS) - .measurePooled(2, 100, 2, new PooledAction() { + .prepare(2, 100, 2, new PooledAction() { @Override public void doAction(final PooledMeasureProvider p) throws Exception { p.invoke("test", () -> Thread.sleep(10)); } - }); + }).perform(); assertNotNull(m2.toString()); assertTrue(m2.getRuntime() >= 1); assertTrue(m2.getApproxThroughput() <= 200); @@ -227,7 +227,7 @@ public void doAction(final PooledMeasureProvider p) throws Exception { final StressResult m3 = StressScenario.of(TimerResolution.MILLISECONDS) - .measurePooled(2, 100, 2, new PooledAction() { + .prepare(2, 100, 2, new PooledAction() { @Override public void doAction(final PooledMeasureProvider p) throws Exception { p.invoke("test", () -> { @@ -235,7 +235,7 @@ public void doAction(final PooledMeasureProvider p) throws Exception { return null; }); } - }); + }).perform(); assertNotNull(m3.toString()); assertTrue(m3.getRuntime() >= 1); assertTrue(m3.getApproxThroughput() <= 200); @@ -250,7 +250,7 @@ public void pooled() throws InterruptedException { final AtomicLong atomic = new AtomicLong(); final StressResult result = StressScenario.of(TimerResolution.NANOSECONDS) - .measure(500, 100, new Action() { + .prepare(500, 100, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.get("test1", () -> { @@ -265,7 +265,7 @@ public void doAction(final MeasureProvider p) throws Exception { return old; }); } - }); + }).perform(); System.err.println(result); } @@ -276,7 +276,7 @@ public void doAction(final MeasureProvider p) throws Exception { final AtomicLong atomic = new AtomicLong(); final StressResult result = StressScenario.of(TimerResolution.MILLISECONDS) - .measurePooled(500, 100, 10, new PooledAction() { + .prepare(500, 100, 10, new PooledAction() { @Override public void doAction(final PooledMeasureProvider p) throws Exception { p.invoke("test1", () -> { @@ -291,7 +291,7 @@ public void doAction(final PooledMeasureProvider p) throws Exception { return old; }); } - }); + }).perform(); System.err.println(result); } @@ -301,7 +301,7 @@ public void doAction(final PooledMeasureProvider p) throws Exception { @Test public void sortedOutput() throws InterruptedException { final StressResult result = - StressScenario.of(TimerResolution.MILLISECONDS).measure(10, 1, new Action() { + StressScenario.of(TimerResolution.MILLISECONDS).prepare(10, 1, new Action() { @Override public void doAction(final MeasureProvider p) throws Exception { p.call("action4", () -> { @@ -313,7 +313,7 @@ public void doAction(final MeasureProvider p) throws Exception { p.call("action3", () -> { }); } - }); + }).perform(); final int action1 = result.toString().indexOf("action1"); final int action2 = result.toString().indexOf("action2");