sclass MultiBencher { settable Runnable action; settable double seconds = 10; settable double interval = 0.001; double elapsedSeconds; //settable double improvementThreshold = 0.05; settable double improvementOverPrintedThreshold = 0.10; new L benchers; *() {} *(Runnable *action) {} run { ensureCapacity(benchers, iceilRatio(seconds, interval)+2); long start = nanoTime(), endTime = lround(start+secondsToNanos(seconds)); while (nanoTime() < endTime) { var bencher = addAndReturn(benchers, new BenchForNSeconds(interval, action)); bencher.run(); } } long startTime() { ret empty(benchers) ? 0 : first(benchers).startTime; } long legMS(int i) { ret lround(nanosToMilliseconds(benchers.get(i).startTime-startTime())); } S renderLegMS(int i) { ret n2(legMS(i)) + " ms"; } S renderLegIndex(int i) { ret "Leg " + (i+1) + "/" + l(benchers) + " (T+" + renderLegMS(i) + ")"; } toString { ret lines(mapWithIndex(benchers, (i, b) -> renderLegIndex(i) + ": " + b)); } // "min records" are the times when a new minimum iteration time is reached S renderMinRecords() { new LS lines; long best = 0, iterations = 0, compileTime = 0, compileIterations = 0; long printedBest = 0; int improvements = 0; for i, b over benchers: { long time = lround(b.min()); iterations += b.iterations(); if (i == 0) { best = printedBest = time; lines.add("First leg: " + n2(time) + " ns"); } else { //double improvement = doubleRatio(best, time)-1; double improvementOverPrinted = doubleRatio(printedBest, time)-1; if (time < best) best = time; if (/*improvement >= improvementThreshold ||*/ improvementOverPrinted >= improvementOverPrintedThreshold) { //printVars(+i, +best, +time, +ratio, +improvement); ++improvements; S percent = formatDouble1(improvementOverPrinted*100); printedBest = time; lines.add("Improved " + convertToSpacesIf(improvements == 1, "another ") + pad(percent, 7) + "% after " + pad(renderLegMS(i), 8) + pad(appendBracketed(nIterations(iterations)), 22) + " - new time: " + pad(b.formatNanos(time), 12)); //lines.add("New best time in " + firstToLower(renderLegIndex(i)) + ": " + n2(time) + " ns"); compileIterations = iterations; compileTime = legMS(i); } } } if (!isEmpty()) lines.add("\nFully compiled after " + n2(compileTime) + " ms" + appendBracketed(nIterations(compileIterations)) + ". Waited for " + formatDouble1(msToSeconds(legMS(l(benchers)-1))) + " s in total"); ret lines(lines); } bool isEmpty() { ret empty(benchers); } }