package net.tuis.ubench; import java.util.Arrays; /** * Class containing the in-flight details of the execution of a single task. * This class allows the class to be run in spurts, and to collect the results * in a single place * * @author rolf * */ final class TaskRunner { /** * Compute the length of the results array with some space for growth * * @param length * the current length * @return the desired length */ private static int expandTo(int length) { // add 25% + 100 - limit to Integer.Max int toAdd = 100 + (length >> 2); toAdd = Math.min(UBench.MAX_RESULTS - length, toAdd); return toAdd == 0 ? -1 : toAdd + length; } /** * Compute whether any of the values in times exceed the given bound, * relative to the minimum value in times. * * @param times * the times to compute the bounds on * @param bound * the bound is represented as a value like 1.10 for 10% greater * than the minimum * @return true if all values are in bounds. */ private static final boolean inBounds(final long[] times, final double bound) { long min = times[0]; long max = times[0]; long limit = (long) (min * bound); for (int i = 1; i < times.length; i++) { if (times[i] < min) { min = times[i]; limit = (long) (min * bound); if (max > limit) { return false; } } if (times[i] > max) { max = times[i]; // new max, is it slower than the worst allowed? if (max > limit) { return false; } } } return true; } private final Task task; private final String name; private final int index; private final long[] stable; private final int limit; private final double stableLimit; private long[] results; private boolean complete = false; private long remainingTime = 0L; private int iterations = 0; TaskRunner(String name, Task task, int index, final int iterations, final int stableSpan, final double stableLimit, final long timeLimit) { this.name = name; this.task = task; this.index = index; this.stableLimit = stableLimit; limit = Math.min(UBench.MAX_RESULTS, iterations > 0 ? iterations : UBench.MAX_RESULTS); stable = new long[Math.min(stableSpan, limit)]; results = new long[Math.min(limit, 10000)]; remainingTime = timeLimit > 0 ? timeLimit : Long.MAX_VALUE; } /** * Perform a single additional iteration of the task. * * @return true if this task is now complete. */ boolean invoke() { if (complete) { return complete; } if (iterations >= results.length) { int newlen = expandTo(results.length); if (newlen < 0) { complete = true; return complete; } results = Arrays.copyOf(results, newlen); } long res = Math.max(task.time(), 1); results[iterations] = res; if (stable.length > 0) { stable[iterations % stable.length] = res; if (iterations > stable.length && inBounds(stable, stableLimit)) { complete = true; } } remainingTime -= res; iterations++; if (iterations >= limit || remainingTime < 0) { complete = true; } return complete; } /** * Collect all statistics in to a single public UStats instance. * * @param suite * the name of the test suite this task is part of. * @return the UStats instance containing the data for statistical analysis */ UStats collect(String suite) { return new UStats(suite, name, index, Arrays.copyOf(results, iterations)); } }