Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exec_group_compatible_with attribute #24964

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 47 additions & 13 deletions site/en/extending/exec-groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ that execution group in the action declaration, that may potentially cause
issues. A mismatch like this may not immediately cause failures, but is a latent
problem.

### Default execution groups {:#exec-groups-for-native-rules}

The following execution groups are predefined:

* `test`: Test runner actions, available on all test rules.
* `cpp_link`: C++ linking actions.

## Using execution groups to set execution properties {:#using-exec-groups-for-exec-properties}

Execution groups are integrated with the
Expand All @@ -126,12 +133,43 @@ All actions with `exec_group = "link"` would see the exec properties
dictionary as `{"mem": "16g"}`. As you see here, execution-group-level
settings override target-level settings.

### Execution groups for native rules {:#exec-groups-for-native-rules}
## Using execution groups to set platform constraints {:#using-exec-groups-for-platform-constraints}

The following execution groups are available for actions defined by native rules:
Execution groups are also integrated with the
[`exec_compatible_with`](/reference/be/common-definitions#common-attributes) and
[`exec_group_compatible_with`](/reference/be/common-definitions#common-attributes)
attributes that exist on every rule and allow the target writer to specify
additional constraints that must be satisfied by the execution platforms
selected for the target's actions.

* `test`: Test runner actions.
* `cpp_link`: C++ linking actions.
For example, if the rule `my_test` defines the `link` execution group in
addition to the default and the `test` execution group, then the following
usage of these attributes would run actions in the default execution group on
a platform with a high number of CPUs, the test action on Linux, and the link
action on the default execution platform:

```python
# BUILD
constraint_setting(name = "cpu")
constraint_value(name = "high_cpu", constraint_setting = ":cpu")

platform(
name = "high_cpu_platform",
constraint_values = [":high_cpu"],
exec_properties = {
"cpu": "256",
},
)

my_test(
name = "my_test",
exec_compatible_with = ["//constraints:high_cpu"],
exec_group_compatible_with = {
"test": ["@platforms//os:linux"],
},
...
)
```

### Execution groups and platform execution properties {:#platform-execution-properties}

Expand All @@ -141,17 +179,14 @@ properties for unknown execution groups are rejected). Targets then inherit the
execution platform's `exec_properties` that affect the default execution group
and any other relevant execution groups.

For example, suppose running a C++ test requires some resource to be available,
but it isn't required for compiling and linking; this can be modelled as
follows:
For example, suppose running tests on the exec platform requires some resource
to be available, but it isn't required for compiling and linking; this can be
modelled as follows:

```python
constraint_setting(name = "resource")
constraint_value(name = "has_resource", constraint_setting = ":resource")

# BUILD
platform(
name = "platform_with_resource",
constraint_values = [":has_resource"],
name = "exec_platform",
exec_properties = {
"test.resource": "...",
},
Expand All @@ -160,7 +195,6 @@ platform(
cc_test(
name = "my_test",
srcs = ["my_test.cc"],
exec_compatible_with = [":has_resource"],
)
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class PredefinedAttributes {
"templates/attributes/common/deprecation.html",
"templates/attributes/common/distribs.html",
"templates/attributes/common/exec_compatible_with.html",
"templates/attributes/common/exec_group_compatible_with.html",
"templates/attributes/common/exec_properties.html",
"templates/attributes/common/features.html",
"templates/attributes/common/package_metadata.html",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ private static Type<?> getAttributeInfoType(AttributeInfo attributeInfo, String
case LABEL_STRING_DICT -> BuildType.LABEL_KEYED_STRING_DICT;
case STRING_DICT -> Types.STRING_DICT;
case STRING_LIST_DICT -> Types.STRING_LIST_DICT;
case LABEL_LIST_DICT -> BuildType.LABEL_LIST_DICT;
case OUTPUT -> BuildType.OUTPUT;
case OUTPUT_LIST -> BuildType.OUTPUT_LIST;
default ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
<p>
A list of
<code><a href="platforms-and-toolchains.html#constraint_value">constraint_values</a></code>
that must be present in the execution platform for this target. This is in
addition to any constraints already set by the rule type. Constraints are used
to restrict the list of available execution platforms. For more details, see
the description of
<a href="/docs/toolchains#toolchain-resolution">toolchain resolution</a>.
that must be present in the execution platform of this target's default exec
group. This is in addition to any constraints already set by the rule type.
Constraints are used to restrict the list of available execution platforms.
For more details, see the description of
<a href="/docs/toolchains#toolchain-resolution">toolchain resolution</a>
and <a href="/extending/exec-groups">exec groups</a>.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<p>Dictionary of strings to lists of <a href="${link build-ref#labels}">labels</a>;
<a href="#configurable-attributes">nonconfigurable</a>; default is <code>{}</code>
</p>

<p>
A dictionary of exec group names to lists of
<code><a href="platforms-and-toolchains.html#constraint_value">constraint_values</a></code>
that must be present in the execution platform for the given exec group. This
is in addition to any constraints already set on the exec group's definition.
Constraints are used to restrict the list of available execution platforms.
For more details, see the description of
<a href="/docs/toolchains#toolchain-resolution">toolchain resolution</a>
and <a href="/extending/exec-groups">exec groups</a>.
</p>
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
<p> A dictionary of strings that will be added to the <code>exec_properties</code> of a platform selected for this target. See <code>exec_properties</code> of the <a href="platforms-and-toolchains.html#platform">platform</a> rule.</p>

<p>If a key is present in both the platform and target-level properties, the value will be taken from the target.</p>

<p>Keys can be prefixed with the name of an execution group followed by a <code>.</code> to apply them only to that particular exec group.</p>
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/packages:exec_group",
"//src/main/java/com/google/devtools/build/lib/skyframe:sane_analysis_exception",
"//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/java/net/starlark/java/spelling",
"//src/main/protobuf:failure_details_java_proto",
"//third_party:auto_value",
"//third_party:guava",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

package com.google.devtools.build.lib.analysis;

import static com.google.devtools.build.lib.analysis.test.ExecutionInfo.DEFAULT_TEST_RUNNER_EXEC_GROUP;
import static com.google.devtools.build.lib.packages.RuleClass.DEFAULT_TEST_RUNNER_EXEC_GROUP;
import static com.google.devtools.build.lib.packages.RuleClass.DEFAULT_TEST_RUNNER_EXEC_GROUP_NAME;
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.DISTRIBUTIONS;
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
Expand Down Expand Up @@ -214,7 +215,8 @@ public static final class TestBaseRule implements RuleDefinition {
@Override
public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
builder
.addExecGroup(DEFAULT_TEST_RUNNER_EXEC_GROUP)
.addExecGroups(
ImmutableMap.of(DEFAULT_TEST_RUNNER_EXEC_GROUP_NAME, DEFAULT_TEST_RUNNER_EXEC_GROUP))
.requiresConfigurationFragments(TestConfiguration.class)
// TestConfiguration only needed to create TestAction and TestProvider
// Only necessary at top-level and can be skipped if trimmed.
Expand Down Expand Up @@ -536,6 +538,14 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env)
"exec_compatible_with exists for constraint checking, not to create an"
+ " actual dependency")
.value(ImmutableList.of()))
.add(
attr(RuleClass.EXEC_GROUP_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST_DICT)
.allowedFileTypes()
.nonconfigurable("Used in toolchain resolution")
.tool(
"exec_group_compatible_with exists for constraint checking, not to create an"
+ " actual dependency")
.value(ImmutableMap.of()))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement;
Expand All @@ -36,6 +38,7 @@
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.Nullable;
import net.starlark.java.spelling.SpellChecker;

/**
* A container class for groups of {@link ExecGroup} instances. This correctly handles exec group
Expand All @@ -52,6 +55,7 @@ public abstract class ExecGroupCollection {
public static ImmutableMap<String, ExecGroup> process(
ImmutableMap<String, ExecGroup> execGroups,
ImmutableSet<Label> defaultExecWith,
ImmutableMultimap<String, Label> execGroupExecWith,
ImmutableSet<ToolchainTypeRequirement> defaultToolchainTypes,
boolean useAutoExecGroups) {
var processedGroups =
Expand All @@ -70,18 +74,36 @@ public static ImmutableMap<String, ExecGroup> process(
.toolchainTypes(defaultToolchainTypes)
.build();
}
Collection<Label> extraExecWith = execGroupExecWith.get(name);
if (!extraExecWith.isEmpty()) {
execGroup =
execGroup.toBuilder()
.execCompatibleWith(
ImmutableSet.<Label>builder()
.addAll(execGroup.execCompatibleWith())
.addAll(extraExecWith)
.build())
.build();
}

processedGroups.put(name, execGroup);
}

if (useAutoExecGroups) {
// Creates one exec group for each toolchain (automatic exec groups).
for (ToolchainTypeRequirement toolchainType : defaultToolchainTypes) {
ImmutableSet<Label> execCompatibleWith = defaultExecWith;
Collection<Label> extraExecWith =
execGroupExecWith.get(toolchainType.toolchainType().getUnambiguousCanonicalForm());
if (!extraExecWith.isEmpty()) {
execCompatibleWith =
ImmutableSet.<Label>builder().addAll(defaultExecWith).addAll(extraExecWith).build();
}
processedGroups.put(
toolchainType.toolchainType().toString(),
ExecGroup.builder()
.addToolchainType(toolchainType)
.execCompatibleWith(defaultExecWith)
.execCompatibleWith(execCompatibleWith)
.build());
}
}
Expand Down Expand Up @@ -134,7 +156,10 @@ private static ImmutableTable<String, String, String> computeCombinedExecPropert
.filter(name -> !execGroupNames.contains(name))
.collect(toImmutableSet());
if (!unknownTargetExecGroupNames.isEmpty()) {
throw new InvalidExecGroupException(unknownTargetExecGroupNames);
throw new InvalidExecGroupException(
"exec_properties",
unknownTargetExecGroupNames,
Iterables.concat(execGroupNames, ImmutableSet.of(DEFAULT_EXEC_GROUP_NAME)));
}
}

Expand Down Expand Up @@ -257,11 +282,18 @@ private static ImmutableTable<String, String, String> parseExecProperties(
/** An error for when the user tries to access a non-existent exec group. */
public static final class InvalidExecGroupException extends AbstractSaneAnalysisException {

public InvalidExecGroupException(Collection<String> invalidNames) {
public InvalidExecGroupException(
String what, Collection<String> invalidNames, Iterable<String> validNames) {
super(
String.format(
"Tried to set properties for non-existent exec groups: %s.",
String.join(",", invalidNames)));
"Tried to set %s for non-existent exec groups: %s%s",
what,
String.join(",", invalidNames),
invalidNames.stream()
.map(invalidName -> SpellChecker.didYouMean(invalidName, validNames))
.filter(s -> !s.isEmpty())
.findFirst()
.orElse("")));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.devtools.build.lib.analysis.constraints.ConstraintConstants.OS_TO_CONSTRAINTS;
import static com.google.devtools.build.lib.analysis.test.ExecutionInfo.DEFAULT_TEST_RUNNER_EXEC_GROUP;
import static com.google.devtools.build.lib.packages.RuleClass.DEFAULT_TEST_RUNNER_EXEC_GROUP_NAME;
import static com.google.devtools.build.lib.packages.ExecGroup.DEFAULT_EXEC_GROUP_NAME;

import com.google.common.annotations.VisibleForTesting;
Expand Down Expand Up @@ -435,7 +435,7 @@ public ActionOwner getTestActionOwner() {
testExecProperties = testExecutionPlatform.execProperties();
} else {
testExecutionPlatform = null;
testExecProperties = getExecGroups().getExecProperties(DEFAULT_TEST_RUNNER_EXEC_GROUP);
testExecProperties = getExecGroups().getExecProperties(DEFAULT_TEST_RUNNER_EXEC_GROUP_NAME);
}

ActionOwner actionOwner =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/analysis:configured_target_value",
"//src/main/java/com/google/devtools/build/lib/analysis:constraints/incompatible_target_checker",
"//src/main/java/com/google/devtools/build/lib/analysis:dependency_kind",
"//src/main/java/com/google/devtools/build/lib/analysis:exec_group_collection",
"//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_aspect_order_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:inconsistent_null_config_exception",
"//src/main/java/com/google/devtools/build/lib/analysis:invalid_visibility_dependency_exception",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static com.google.common.base.Preconditions.checkState;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.ExecGroupCollection;
import com.google.devtools.build.lib.analysis.PlatformConfiguration;
import com.google.devtools.build.lib.analysis.PlatformOptions;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
Expand Down Expand Up @@ -148,15 +149,20 @@ public StateMachine step(Tasks tasks) throws InterruptedException {
unloadedToolchainContextsInputs = UnloadedToolchainContextsInputs.empty();
} else {
platformConfiguration = new PlatformConfiguration(platformOptions);
unloadedToolchainContextsInputs =
ToolchainContextUtil.getUnloadedToolchainContextsInputs(
target,
preRuleTransitionKey.getConfigurationKey().getOptions().get(CoreOptions.class),
platformConfiguration,
preRuleTransitionKey.getExecutionPlatformLabel(),
computeToolchainConfigurationKey(
preRuleTransitionKey.getConfigurationKey().getOptions(),
targetAndConfigurationData.getToolchainTaggedTrimmingTransition()));
try {
unloadedToolchainContextsInputs =
ToolchainContextUtil.getUnloadedToolchainContextsInputs(
target,
preRuleTransitionKey.getConfigurationKey().getOptions().get(CoreOptions.class),
platformConfiguration,
preRuleTransitionKey.getExecutionPlatformLabel(),
computeToolchainConfigurationKey(
preRuleTransitionKey.getConfigurationKey().getOptions(),
targetAndConfigurationData.getToolchainTaggedTrimmingTransition()));
} catch (ExecGroupCollection.InvalidExecGroupException e) {
emitErrorMessage(e.getMessage());
return runAfter;
}
}

if (unloadedToolchainContextsInputs.targetToolchainContextKey() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.StructImpl;
import com.google.devtools.build.lib.packages.StructProvider;
import com.google.devtools.build.lib.packages.Type;
Expand Down Expand Up @@ -230,6 +231,13 @@ public static Object convertAttributeValue(
return null;
}

// Don't expose exec_group_compatible_with to Starlark. There is no reason for it to be used
// by the rule implementation function and its type (LABEL_LIST_DICT) is not available to
// Starlark.
if (a.getName().equals(RuleClass.EXEC_GROUP_COMPATIBLE_WITH_ATTR)) {
return null;
}

if (type == BuildType.DORMANT_LABEL) {
return val == null
? Starlark.NONE
Expand Down
Loading
Loading