From a706994ac69e3f3fed361c61378de847b50d3b12 Mon Sep 17 00:00:00 2001 From: Tom Cnops <60213975+tom-cnops@users.noreply.github.com> Date: Thu, 27 Oct 2022 03:10:10 -0700 Subject: [PATCH] Remove logic that increases delay between progress updates over time Removes a bit of undocumented behavior that increases the delay between progress updates the longer the build is running. Potentially resolves https://github.com/bazelbuild/bazel/issues/16119 Also renamed `MAXIMAL_UPDATE_DELAY_MILLIS` to `MINIMAL_UPDATE_INTERVAL_MILLIS` because it is used as a minimum and doesn't affect the delay between messages. Fixes #16119. Closes #16221. RELNOTES[INC]: Bazel no longer increases the delay between progress updates when there is no cursor control. PiperOrigin-RevId: 484203851 Change-Id: I33f7302ca85b75135744eb6093b618196199a49f --- site/en/docs/user-manual.md | 12 +++-- .../lib/buildtool/BuildRequestOptions.java | 6 ++- .../build/lib/runtime/UiEventHandler.java | 50 +++++++------------ 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/site/en/docs/user-manual.md b/site/en/docs/user-manual.md index eca68974a84247..ac25620d87055f 100644 --- a/site/en/docs/user-manual.md +++ b/site/en/docs/user-manual.md @@ -790,6 +790,9 @@ The default is 0, that means an incremental algorithm: the first report will be printed after 10 seconds, then 30 seconds and after that progress is reported once every minute. +When bazel is using cursor control, as specified by +[`--curses`](#curses), progress is reported every second. + #### `--local_{ram,cpu}_resources {{ "" }}resources or resource expression{{ "" }}` {:#local-resources} These options specify the amount of local resources (RAM in MB and number of CPU logical cores) @@ -1129,11 +1132,10 @@ default. When disabled, progress messages are suppressed. #### `--show_progress_rate_limit={{ "" }}n{{ "" }}` {:#show-progress-rate} -This option causes bazel to display only -one progress message per `n` seconds, where {{ "" }}n{{ "" }} is a real number. -If `n` is -1, all progress messages will be displayed. The default value for -this option is 0.02, meaning bazel will limit the progress messages to one per every -0.02 seconds. +This option causes bazel to display at most one progress message per `n` seconds, +where {{ "" }}n{{ "" }} is a real number. +The default value for this option is 0.02, meaning bazel will limit the progress +messages to one per every 0.02 seconds. #### `--show_result={{ "" }}n{{ "" }}` {:#show-result} diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java index 3db5ed194fc6a0..5b9b24f3e88b56 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java @@ -73,8 +73,10 @@ public class BuildRequestOptions extends OptionsBase { effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, converter = ProgressReportIntervalConverter.class, help = - "The number of seconds to wait between two reports on still running jobs. The " - + "default value 0 means to use the default 10:30:60 incremental algorithm.") + "The number of seconds to between reports on still running jobs. The " + + "default value 0 means the first report will be printed after 10 " + + "seconds, then 30 seconds and after that progress is reported once every minute. " + + "When --curses is enabled, progress is reported every second.") public int progressReportInterval; @Option( diff --git a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java index 379ae364969415..0c6c85a074ad37 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java @@ -81,19 +81,12 @@ public final class UiEventHandler implements EventHandler { private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - /** Latest refresh of the progress bar, if contents other than time changed */ - private static final long MAXIMAL_UPDATE_DELAY_MILLIS = 200L; + /** Minimal time between scheduled updates */ + private static final long MINIMAL_UPDATE_INTERVAL_MILLIS = 200L; /** Minimal rate limiting (in ms), if the progress bar cannot be updated in place */ private static final long NO_CURSES_MINIMAL_PROGRESS_RATE_LIMIT = 1000L; - /** - * Minimal rate limiting, as fraction of the request time so far, if the progress bar cannot be - * updated in place - */ - private static final double NO_CURSES_MINIMAL_RELATIVE_PROGRESS_RATE_LMIT = 0.15; /** Periodic update interval of a time-dependent progress bar if it can be updated in place */ private static final long SHORT_REFRESH_MILLIS = 1000L; - /** Periodic update interval of a time-dependent progress bar if it cannot be updated in place */ - private static final long LONG_REFRESH_MILLIS = 20000L; private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("(HH:mm:ss) "); @@ -101,7 +94,6 @@ public final class UiEventHandler implements EventHandler { private final boolean cursorControl; private final Clock clock; - private final long uiStartTimeMillis; private final AnsiTerminal terminal; private final boolean debugAllEvents; private final UiStateTracker stateTracker; @@ -111,7 +103,7 @@ public final class UiEventHandler implements EventHandler { private final boolean showTimestamp; private final OutErr outErr; private final ImmutableSet filteredEvents; - private long minimalDelayMillis; + private long progressRateLimitMillis; private long minimalUpdateInterval; private long lastRefreshMillis; private long mustRefreshAfterMillis; @@ -175,7 +167,6 @@ public UiEventHandler( this.progressInTermTitle = options.progressInTermTitle && options.useCursorControl(); this.showTimestamp = options.showTimestamp; this.clock = clock; - this.uiStartTimeMillis = clock.currentTimeMillis(); this.debugAllEvents = options.experimentalUiDebugAllEvents; this.locationPrinter = new LocationPrinter(options.attemptToPrintRelativePaths, workspacePathFragment); @@ -200,14 +191,15 @@ public UiEventHandler( this.stateTracker.setProgressSampleSize(options.uiActionsShown); this.numLinesProgressBar = 0; if (this.cursorControl) { - this.minimalDelayMillis = Math.round(options.showProgressRateLimit * 1000); + this.progressRateLimitMillis = Math.round(options.showProgressRateLimit * 1000); } else { - this.minimalDelayMillis = + this.progressRateLimitMillis = Math.max( Math.round(options.showProgressRateLimit * 1000), NO_CURSES_MINIMAL_PROGRESS_RATE_LIMIT); } - this.minimalUpdateInterval = Math.max(this.minimalDelayMillis, MAXIMAL_UPDATE_DELAY_MILLIS); + this.minimalUpdateInterval = + Math.max(this.progressRateLimitMillis, MINIMAL_UPDATE_INTERVAL_MILLIS); this.stdoutLineBuffer = new ByteArrayOutputStream(); this.stderrLineBuffer = new ByteArrayOutputStream(); this.dateShown = false; @@ -854,7 +846,7 @@ private void doRefresh(boolean fromUpdateThread) { return; } long nowMillis = clock.currentTimeMillis(); - if (lastRefreshMillis + minimalDelayMillis < nowMillis) { + if (lastRefreshMillis + progressRateLimitMillis < nowMillis) { if (updateLock.tryLock()) { try { synchronized (this) { @@ -863,17 +855,6 @@ private void doRefresh(boolean fromUpdateThread) { clearProgressBar(); addProgressBar(); terminal.flush(); - if (!cursorControl) { - // If we can't update the progress bar in place, make sure we increase the update - // interval as time progresses, to avoid too many progress messages in place. - minimalDelayMillis = - Math.max( - minimalDelayMillis, - Math.round( - NO_CURSES_MINIMAL_RELATIVE_PROGRESS_RATE_LMIT - * (clock.currentTimeMillis() - uiStartTimeMillis))); - minimalUpdateInterval = Math.max(minimalDelayMillis, MAXIMAL_UPDATE_DELAY_MILLIS); - } } } } catch (IOException e) { @@ -901,7 +882,7 @@ private void refreshSoon() { // a future update scheduled. long nowMillis = clock.currentTimeMillis(); if (mustRefreshAfterMillis <= lastRefreshMillis) { - mustRefreshAfterMillis = Math.max(nowMillis + minimalUpdateInterval, lastRefreshMillis + 1); + mustRefreshAfterMillis = Math.max(nowMillis + 1, lastRefreshMillis + minimalUpdateInterval); } startUpdateThread(); } @@ -911,22 +892,25 @@ private synchronized boolean timeBasedRefresh() { if (!stateTracker.progressBarTimeDependent()) { return false; } + // Don't do more updates than are requested through events when there is no cursor control. + if (!cursorControl) { + return false; + } long nowMillis = clock.currentTimeMillis(); - long intervalMillis = cursorControl ? SHORT_REFRESH_MILLIS : LONG_REFRESH_MILLIS; if (lastRefreshMillis < mustRefreshAfterMillis - && mustRefreshAfterMillis < nowMillis + minimalDelayMillis) { - // Within the small interval from now, an update is scheduled anyway, + && mustRefreshAfterMillis < nowMillis + progressRateLimitMillis) { + // Within a small interval from now, an update is scheduled anyway, // so don't do a time-based update of the progress bar now, to avoid // updates too close to each other. return false; } - return lastRefreshMillis + intervalMillis < nowMillis; + return lastRefreshMillis + SHORT_REFRESH_MILLIS < nowMillis; } private void ignoreRefreshLimitOnce() { // Set refresh time variables in a state such that the next progress bar // update will definitely be written out. - lastRefreshMillis = clock.currentTimeMillis() - minimalDelayMillis - 1; + lastRefreshMillis = clock.currentTimeMillis() - progressRateLimitMillis - 1; } private void startUpdateThread() {