diff options
author | 2017-11-21 02:31:25 -0800 | |
---|---|---|
committer | 2017-11-21 02:32:41 -0800 | |
commit | 0fd76922d60bd1a39dd57d56b42c94edc2674243 (patch) | |
tree | 7b872d3aedf1968afb6b268708edb27b27fb0dcb /src/main/java/com/google/devtools/build/lib | |
parent | 6d8b8440d5b013e38827c7ed5c065c52ebe5c7ec (diff) |
UI: distinguish executing actions
When showing the current actions, the most interesting are those
that are currently being executed, not those that are waiting for
resources or otherwise in the process of being scheduled. Therefore,
show the executing actions at the top of the list. Also add more
visual hints to distinguish executing from non executing actions.
Screenshot
(14:51:21) [160 / 230] 32 actions, 11 running
Compiling lotsofwork/true986.c; 0s linux-sandbox
Compiling lotsofwork/true982.c; 0s linux-sandbox
Compiling lotsofwork/true983.c; 0s linux-sandbox
Executing genrule //lotsofwork:true975_c; 0s linux-sandbox
Compiling lotsofwork/true981.c; 0s linux-sandbox
Linking lotsofwork/true_999; 0s linux-sandbox
Linking lotsofwork/true_996; 0s linux-sandbox
Linking lotsofwork/true_998; 0s linux-sandbox
Compiling lotsofwork/true980.c; 0s linux-sandbox
Compiling lotsofwork/true98.c; 0s linux-sandbox
Executing genrule //lotsofwork:true974_c; 0s linux-sandbox
[Sched] Creating runfiles tree bazel-out/k8-fastbuild/bin/lotsofwork/true_974.runfiles
[Sched] Linking lotsofwork/true_997
[Sched] Linking lotsofwork/true_995
[Sched] Linking lotsofwork/true_99
[Sched] Linking lotsofwork/true_991 ...
Improves on #4089.
Change-Id: I1bc6636d5e53a16151023bba595e38259eb1ac88
PiperOrigin-RevId: 176483192
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java | 89 |
1 files changed, 67 insertions, 22 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java index 5df6a8dcdb..1995ebd325 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java @@ -48,6 +48,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.stream.Stream; /** * An experimental state tracker for the new experimental UI. @@ -58,7 +59,8 @@ class ExperimentalStateTracker { static final String ELLIPSIS = "..."; static final String FETCH_PREFIX = " Fetching "; static final String AND_MORE = " ..."; - + static final String NO_STATUS = "-----"; + static final int STATUS_LENGTH = 5; static final int NANOS_PER_SECOND = 1000000000; static final String URL_PROTOCOL_SEP = "://"; @@ -79,7 +81,8 @@ class ExperimentalStateTracker { private final Deque<String> runningActions; private final Map<String, Action> actions; private final Map<String, Long> actionNanoStartTimes; - private final Map<String, String> actionStrategy; + private final Map<String, String> actionStatus; + private final Set<String> executingActions; // running downloads are identified by the original URL they were trying to // access. @@ -112,8 +115,9 @@ class ExperimentalStateTracker { ExperimentalStateTracker(Clock clock, int targetWidth) { this.runningActions = new ArrayDeque<>(); this.actions = new TreeMap<>(); + this.executingActions = new TreeSet<>(); this.actionNanoStartTimes = new TreeMap<>(); - this.actionStrategy = new TreeMap<>(); + this.actionStatus = new TreeMap<>(); this.testActions = new TreeMap<>(); this.runningDownloads = new ArrayDeque<>(); this.downloads = new TreeMap<>(); @@ -248,12 +252,14 @@ class ExperimentalStateTracker { String name = event.getActionMetadata().getPrimaryOutput().getPath().getPathString(); if (strategy != null) { synchronized (this) { - actionStrategy.put(name, strategy); + actionStatus.put(name, strategy); + executingActions.add(name); } } else { String message = event.getMessage(); synchronized (this) { - actionStrategy.put(name, message); + actionStatus.put(name, message); + executingActions.remove(name); } } } @@ -263,9 +269,10 @@ class ExperimentalStateTracker { Action action = event.getAction(); String name = action.getPrimaryOutput().getPath().getPathString(); runningActions.remove(name); + executingActions.remove(name); actions.remove(name); actionNanoStartTimes.remove(name); - actionStrategy.remove(name); + actionStatus.remove(name); if (action.getOwner() != null) { Label owner = action.getOwner().getLabel(); @@ -393,9 +400,22 @@ class ExperimentalStateTracker { } String postfix = ""; + String prefix = ""; long nanoRuntime = nanoTime - actionNanoStartTimes.get(name); long runtimeSeconds = nanoRuntime / NANOS_PER_SECOND; - String strategy = actionStrategy.get(name); + String strategy = null; + if (executingActions.contains(name)) { + strategy = actionStatus.get(name); + } else { + String status = actionStatus.get(name); + if (status == null) { + status = NO_STATUS; + } + if (status.length() > STATUS_LENGTH) { + status = status.substring(0, STATUS_LENGTH); + } + prefix = prefix + "[" + status + "] "; + } // To keep the UI appearance more stable, always show the elapsed // time if we also show a strategy (otherwise the strategy will jump in // the progress bar). @@ -412,10 +432,10 @@ class ExperimentalStateTracker { } if (desiredWidth <= 0) { - return message + postfix; + return prefix + message + postfix; } - if (message.length() + postfix.length() <= desiredWidth) { - return message + postfix; + if (prefix.length() + message.length() + postfix.length() <= desiredWidth) { + return prefix + message + postfix; } // We have to shorten the message to fit into the line. @@ -428,31 +448,56 @@ class ExperimentalStateTracker { if (pathIndex >= 0) { String start = message.substring(0, pathIndex); String end = message.substring(pathIndex + pathString.length()); - int pathTargetLength = desiredWidth - start.length() - end.length() - postfix.length(); + int pathTargetLength = + desiredWidth - start.length() - end.length() - postfix.length() - prefix.length(); // This attempt of shortening is reasonable if what is left from the label // is significantly longer (twice as long) as the ellipsis symbols introduced. if (pathTargetLength >= 3 * ELLIPSIS.length()) { String shortPath = suffix(pathString, pathTargetLength - ELLIPSIS.length()); int slashPos = shortPath.indexOf('/'); if (slashPos >= 0) { - return start + ELLIPSIS + shortPath.substring(slashPos) + end + postfix; + return prefix + start + ELLIPSIS + shortPath.substring(slashPos) + end + postfix; } } } // Second attempt: just take a shortened version of the label. String shortLabel = - shortenedLabelString(action.getOwner().getLabel(), desiredWidth - postfix.length()); - if (shortLabel.length() + postfix.length() <= desiredWidth) { - return shortLabel + postfix; + shortenedLabelString( + action.getOwner().getLabel(), desiredWidth - postfix.length() - prefix.length()); + if (prefix.length() + shortLabel.length() + postfix.length() <= desiredWidth) { + return prefix + shortLabel + postfix; } } } - if (3 * ELLIPSIS.length() + postfix.length() <= desiredWidth) { - message = ELLIPSIS + suffix(message, desiredWidth - ELLIPSIS.length() - postfix.length()); + if (3 * ELLIPSIS.length() + postfix.length() + prefix.length() <= desiredWidth) { + message = + ELLIPSIS + + suffix( + message, desiredWidth - ELLIPSIS.length() - postfix.length() - prefix.length()); } - return message + postfix; + return prefix + message + postfix; + } + + /** + * Stream of actions in decreasing order of importance for the UI. I.e., first have all executing + * actions and then all non-executing actions, each time in order of increasing start time. + */ + private Stream<String> sortedActions() { + return Stream.concat( + runningActions.stream().filter(s -> executingActions.contains(s)), + runningActions.stream().filter(s -> !executingActions.contains(s))); + } + + private String countActions() { + if (runningActions.size() == 1) { + return " 1 action"; + } else if (runningActions.size() == executingActions.size()) { + return "" + runningActions.size() + " actions running"; + } else { + return "" + runningActions.size() + " actions, " + executingActions.size() + " running"; + } } private void sampleOldestActions(AnsiTerminalWriter terminalWriter) throws IOException { @@ -461,7 +506,7 @@ class ExperimentalStateTracker { long nanoTime = clock.nanoTime(); int actionCount = runningActions.size(); Set<String> toSkip = new TreeSet<>(); - for (String action : runningActions) { + for (String action : (Iterable<String>) sortedActions()::iterator) { totalCount++; if (toSkip.contains(action)) { continue; @@ -767,14 +812,14 @@ class ExperimentalStateTracker { if (shortVersion) { String statusMessage = describeAction( - runningActions.peekFirst(), + sortedActions().findFirst().get(), clock.nanoTime(), targetWidth - terminalWriter.getPosition(), null); - statusMessage += " ... (" + runningActions.size() + " actions)"; + statusMessage += " ... (" + countActions() + ")"; terminalWriter.normal().append(" " + statusMessage); } else { - String statusMessage = "" + runningActions.size() + " actions"; + String statusMessage = countActions(); terminalWriter.normal().append(" " + statusMessage); maybeShowRecentTest( terminalWriter, shortVersion, targetWidth - terminalWriter.getPosition()); |