You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/10/11 13:28:20 UTC
[commons-rng] 08/16: Progress tracker to estimate time remaining.
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git
commit 55c7c83b9d9214c4e6bc806edaf94a3deff7f0a8
Author: aherbert <ah...@apache.org>
AuthorDate: Mon Oct 7 11:51:04 2019 +0100
Progress tracker to estimate time remaining.
---
.../rng/examples/stress/StressTestCommand.java | 111 +++++++++++++++++++--
1 file changed, 102 insertions(+), 9 deletions(-)
diff --git a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
index 286f825..84b4ac3 100644
--- a/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
+++ b/commons-rng-examples/examples-stress/src/main/java/org/apache/commons/rng/examples/stress/StressTestCommand.java
@@ -18,6 +18,7 @@ package org.apache.commons.rng.examples.stress;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.core.source64.RandomLongSource;
+import org.apache.commons.rng.examples.stress.LogUtils.LogLevel;
import org.apache.commons.rng.simple.RandomSource;
import picocli.CommandLine.Command;
@@ -35,6 +36,7 @@ import java.nio.file.StandardOpenOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
+import java.util.Formatter;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
@@ -338,7 +340,7 @@ class StressTestCommand implements Callable<Void> {
LogUtils.info("Running stress test ...");
LogUtils.info("Shutdown by creating stop file: %s", stopFile);
- final ProgressTracker progressTracker = new ProgressTracker(countTrials(stressTestData));
+ final ProgressTracker progressTracker = new ProgressTracker(countTrials(stressTestData), taskCount);
// Run tasks with parallel execution.
final ExecutorService service = Executors.newFixedThreadPool(taskCount);
@@ -461,7 +463,7 @@ class StressTestCommand implements Callable<Void> {
// Log the decision
LogUtils.info("%s existing output file: %s", outputMode, output);
if (outputMode == StressTestCommand.OutputMode.SKIP) {
- progressTracker.incrementProgress();
+ progressTracker.incrementProgress(0);
continue;
}
}
@@ -517,23 +519,38 @@ class StressTestCommand implements Callable<Void> {
private int count;
/** The timestamp of the last progress report. */
private long timestamp;
+ /** The level of parallelisation. */
+ private final int parallelTasks;
+ /** The total time of all completed tasks (in milliseconds). */
+ private long totalTime;
+ /** The number of tasks completed with a time (i.e. were not skipped). */
+ private int completed;
/**
* Create a new instance.
*
* @param total The total progress.
+ * @param parallelTasks The number of parallel tasks.
*/
- ProgressTracker(int total) {
+ ProgressTracker(int total, int parallelTasks) {
this.total = total;
+ this.parallelTasks = parallelTasks;
showProgress();
}
/**
- * Increment the progress.
+ * Signal that a task has completed in a specified time.
+ *
+ * @param taskTime The time for the task (milliseconds).
*/
- void incrementProgress() {
+ void incrementProgress(long taskTime) {
synchronized (this) {
count++;
+ // Used to compute the average task time
+ if (taskTime != 0) {
+ totalTime += taskTime;
+ completed++;
+ }
showProgress();
}
}
@@ -551,8 +568,85 @@ class StressTestCommand implements Callable<Void> {
final long current = System.currentTimeMillis();
if (current - timestamp > REPORT_INTERVAL) {
timestamp = current;
- LogUtils.info("Progress %d / %d (%.2f%%)", count, total, 100.0 * count / total);
+ final StringBuilder sb = new StringBuilder(80);
+ try (Formatter formatter = new Formatter(sb)) {
+ formatter.format("Progress %d / %d (%.2f%%)", count, total, 100.0 * count / total);
+ LogUtils.info(appendRemaining(sb).toString());
+ }
+ }
+ }
+
+ /**
+ * Compute an estimate of the time remaining and append to the progress.
+ *
+ * @param sb String Builder.
+ * @return the string builder
+ */
+ private StringBuilder appendRemaining(StringBuilder sb) {
+ if (completed == 0) {
+ // No estimate possible.
+ return sb;
+ }
+
+ final int remaining = total - count;
+ if (remaining < parallelTasks) {
+ // No more tasks to submit so the last estimate was as good as we can make it.
+ return sb;
+ }
+
+ // Estimate time remaining using the average runtime per task
+ // multiplied by the number of parallel remaining tasks (rounded down).
+ // Parallel remaining is the number of batches required to execute the
+ // remaining tasks in parallel.
+ final long parallelRemaining = remaining / parallelTasks;
+ final long millis = (totalTime * parallelRemaining) / completed;
+
+ // HH:mm:ss format
+ if (LogUtils.isLoggable(LogLevel.DEBUG)) {
+ sb.append(". Average task time = ");
+ hms(sb, totalTime / completed);
+ }
+ sb.append(". Remaining = ");
+ return hms(sb, millis);
+ }
+
+ /**
+ * Append the milliseconds using {@code HH::mm:ss} format.
+ *
+ * @param sb String Builder.
+ * @param millis Milliseconds.
+ * @return the string builder
+ */
+ static StringBuilder hms(StringBuilder sb, final long millis) {
+ final long hours = TimeUnit.MILLISECONDS.toHours(millis);
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
+ // Truncate to interval [0,59]
+ seconds -= TimeUnit.MINUTES.toSeconds(minutes);
+ minutes -= TimeUnit.HOURS.toMinutes(hours);
+
+ append00(sb, hours).append(':');
+ append00(sb, minutes).append(':');
+ return append00(sb, seconds);
+ }
+
+ /**
+ * Append the ticks to the string builder in the format {@code %02d}.
+ *
+ * @param sb String Builder.
+ * @param ticks Ticks.
+ * @return the string builder
+ */
+ static StringBuilder append00(StringBuilder sb, long ticks) {
+ if (ticks == 0) {
+ sb.append("00");
+ } else {
+ if (ticks < 10) {
+ sb.append('0');
+ }
+ sb.append(ticks);
}
+ return sb;
}
}
@@ -624,15 +718,14 @@ class StressTestCommand implements Callable<Void> {
return;
}
+ long nanoTime = 0;
try {
printHeader();
Object exitValue;
- long nanoTime;
if (cmd.dryRun) {
// Do not do anything
exitValue = "N/A";
- nanoTime = 0;
} else {
// Run the sub-process
final long startTime = System.nanoTime();
@@ -645,7 +738,7 @@ class StressTestCommand implements Callable<Void> {
} catch (final IOException ex) {
throw new ApplicationException("Failed to run task: " + ex.getMessage(), ex);
} finally {
- progressTracker.incrementProgress();
+ progressTracker.incrementProgress(TimeUnit.NANOSECONDS.toMillis(nanoTime));
}
}