sclass BenchForNSeconds { settable Runnable action; settable double seconds; // how many seconds to run the benchmark volatile bool done; long iterations; long startTime, endTime; gettable new AverageAndMinMax stats; *() {} *(double *seconds, Runnable *action) {} run { startTime = sysNanos(); endTime = lround(startTime+secondsToNanos(seconds)); long time = sysNanos(); while (time < endTime) { action?.run(); ++iterations; long time2 = sysNanos(); long runTook = time2-time; stats.add(runTook); time = time2; } endTime = time; set done; } S formatNanos(double nanos) { ret n2_round(stats.avg()) + " ns"; } toString { ret stats.isEmpty() ? "Not run" : "min/avg/max=" + n2_round(stats.min()) + "/" + n2_round(stats.avg()) + "/" + n2_round(stats.max()) + " ns" + appendRoundBracketed(nRuns((long) stats.n())); } }