blob: 35b146724a1ed812ef94a82b169f6c1ff6422f37 [file]
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.dynamic;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.Converters;
import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionDocumentationCategory;
import com.google.devtools.common.options.OptionEffectTag;
import com.google.devtools.common.options.OptionMetadataTag;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsClass;
import com.google.devtools.common.options.OptionsParsingException;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/** Options related to dynamic spawn execution. */
@OptionsClass
public abstract class DynamicExecutionOptions extends OptionsBase {
@Option(
name = "experimental_spawn_scheduler",
documentationCategory = OptionDocumentationCategory.UNCATEGORIZED,
effectTags = {OptionEffectTag.UNKNOWN},
metadataTags = {OptionMetadataTag.DEPRECATED},
defaultValue = "null",
help =
"Enable dynamic execution by running actions locally and remotely in parallel. Bazel "
+ "spawns each action locally and remotely and picks the one that completes first. "
+ "If an action supports workers, the local action will be run in the persistent "
+ "worker mode. To enable dynamic execution for an individual action mnemonic, use "
+ "the `--internal_spawn_scheduler` and `--strategy=<mnemonic>=dynamic` flags "
+ "instead.",
expansion = {
"--internal_spawn_scheduler",
"--spawn_strategy=dynamic",
},
deprecationWarning =
"--experimental_spawn_scheduler is deprecated. Using dynamic execution for everything is"
+ " rarely a good idea (see https://bazel.build/remote/dynamic). If you really want"
+ " to enable dynamic execution globally, pass `--internal_spawn_scheduler "
+ "--spawn_strategy=dynamic`.")
@Deprecated
public abstract Void getExperimentalSpawnScheduler();
public abstract void setExperimentalSpawnScheduler(Void value);
@Option(
name = "internal_spawn_scheduler",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "true",
help =
"Placeholder option so that we can tell in Blaze whether the spawn scheduler was "
+ "enabled.")
public abstract boolean getInternalSpawnScheduler();
public abstract void setInternalSpawnScheduler(boolean value);
@Option(
name = "dynamic_local_strategy",
converter = Converters.StringToStringListConverter.class,
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "null",
allowMultiple = true,
help =
"""
The local strategies, in order, to use for the given mnemonic - the first applicable
strategy is used. For example, `worker,sandboxed` runs actions that support
persistent workers using the worker strategy, and all others using the sandboxed
strategy. If no mnemonic is given, the list of strategies is used as the
fallback for all mnemonics. The default fallback list is `worker,sandboxed`, or
`worker,sandboxed,standalone` if `experimental_local_lockfree_output` is set.
Takes `[mnemonic=]local_strategy[,local_strategy,...]`.
""")
public abstract List<Map.Entry<String, List<String>>> getDynamicLocalStrategy();
public abstract void setDynamicLocalStrategy(List<Map.Entry<String, List<String>>> value);
@Option(
name = "dynamic_remote_strategy",
converter = Converters.StringToStringListConverter.class,
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "null",
allowMultiple = true,
help =
"""
The remote strategies, in order, to use for the given mnemonic - the first applicable
strategy is used. If no mnemonic is given, the list of strategies is used as the
fallback for all mnemonics. The default fallback list is `remote`, so this flag
usually does not need to be set explicitly.
Takes `[mnemonic=]remote_strategy[,remote_strategy,...]`.
""")
public abstract List<Map.Entry<String, List<String>>> getDynamicRemoteStrategy();
public abstract void setDynamicRemoteStrategy(List<Map.Entry<String, List<String>>> value);
@Option(
name = "dynamic_local_execution_delay",
oldName = "experimental_local_execution_delay",
oldNameWarning = false,
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "1000",
help =
"How many milliseconds should local execution be delayed, if remote execution was faster"
+ " during a build at least once?")
public abstract int getLocalExecutionDelay();
public abstract void setLocalExecutionDelay(int value);
@Option(
name = "debug_spawn_scheduler",
oldName = "experimental_debug_spawn_scheduler",
oldNameWarning = false,
documentationCategory = OptionDocumentationCategory.LOGGING,
effectTags = {OptionEffectTag.UNKNOWN},
defaultValue = "false")
public abstract boolean getDebugSpawnScheduler();
public abstract void setDebugSpawnScheduler(boolean value);
@Option(
name = "experimental_dynamic_slow_remote_time",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "0",
help =
"If >0, the time a dynamically run action must run remote-only before we"
+ " prioritize its local execution to avoid remote timeouts."
+ " This may hide some problems on the remote execution system. Do not turn this on"
+ " without monitoring of remote execution issues.")
public abstract Duration getSlowRemoteTime();
public abstract void setSlowRemoteTime(Duration value);
@Option(
name = "experimental_dynamic_local_load_factor",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "0",
help =
"""
Controls how much load from dynamic execution to put on the local machine.
This flag adjusts how many actions in dynamic execution we will schedule
concurrently. It is based on the number of CPUs Blaze thinks is available,
which can be controlled with the `--local_resources=cpu=` flag.
If this flag is `0`, all actions are scheduled locally immediately. If > 0,
the amount of actions scheduled locally is limited by the number of CPUs
available. If < 1, the load factor is used to reduce the number of locally
scheduled actions when the number of actions waiting to schedule is high.
This lessens the load on the local machine in the clean build case, where
the local machine does not contribute much.
""")
public abstract double getLocalLoadFactor();
public abstract void setLocalLoadFactor(double value);
@Option(
name = "experimental_dynamic_exclude_tools",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS},
defaultValue = "true",
help =
"""
When set, targets that are build "for tool" are not subject to dynamic execution. Such
targets are extremely unlikely to be built incrementally and thus not worth
spending local cycles on.
""")
public abstract boolean getExcludeTools();
public abstract void setExcludeTools(boolean value);
@Option(
name = "experimental_dynamic_ignore_local_signals",
documentationCategory = OptionDocumentationCategory.BUILD_TIME_OPTIMIZATION,
converter = SignalListConverter.class,
effectTags = {OptionEffectTag.EXECUTION},
defaultValue = "null",
help =
"Takes a list of OS signal numbers. If a local branch of dynamic execution"
+ " gets killed with any of these signals, the remote branch will be allowed to"
+ " finish instead. For persistent workers, this only affects signals that kill"
+ " the worker process.")
public abstract Set<Integer> getIgnoreLocalSignals();
public abstract void setIgnoreLocalSignals(Set<Integer> value);
@Option(
name = "experimental_dynamic_cancel_remote_branch_on_local_win",
documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY,
effectTags = {OptionEffectTag.EXECUTION},
defaultValue = "true",
help =
"If true, cancels the remote branch when the local branch finishes first in dynamic"
+ " execution. If false, allows the remote branch to continue running to completion"
+ " in the background to populate the remote action cache for future builds.")
public abstract boolean getCancelRemoteBranchOnLocalWin();
public abstract void setCancelRemoteBranchOnLocalWin(boolean value);
/** Converts comma-separated lists of signal numbers into a set of signal numbers. */
public static class SignalListConverter implements Converter<Set<Integer>> {
@Override
public ImmutableSet<Integer> convert(String input, @Nullable Object conversionContext)
throws OptionsParsingException {
if (input == null || "null".equals(input)) {
return ImmutableSet.of();
}
Iterable<String> parts = Splitter.on(",").split(input);
if (!parts.iterator().hasNext()) {
throw new OptionsParsingException("Requires at least one signal number");
}
ImmutableSet.Builder<Integer> signals = new ImmutableSet.Builder<>();
for (String p : parts) {
String trimmed = p.trim();
Integer signalNum = Ints.tryParse(trimmed);
if (signalNum != null && signalNum > 0) {
signals.add(signalNum);
} else {
throw new OptionsParsingException(String.format("No such signal %s", trimmed));
}
}
return signals.build();
}
@Override
public String getTypeDescription() {
return "a comma-separated list of signal numbers";
}
}
}