Skip to content

Commit

Permalink
Experimentally support remote persistent workers.
Browse files Browse the repository at this point in the history
Add a new `--experimental_remote_mark_tool_inputs` flag, which makes Bazel tag tool inputs when executing actions remotely, and also adds a tools input key to the platform proto sent as part of the remote execution request.

This allows a remote execution system to implement persistent workers, i.e., to keep worker processes around and reuse them for subsequent actions. In a trivial example, this improves build performance by ~3x.

We use "persistentWorkerKey" for the platform property, with the value being a hash of the tool inputs, and "bazel_tool_input" as the node property name, with an empty string as value—this is just a boolean tag.

Fixes bazelbuild#10091.

Co-authored-by: Ulf Adams <ulf@engflow.com>

Closes bazelbuild#16362.

PiperOrigin-RevId: 482433908
Change-Id: I2a80834731fd0169c08d4beea348f61a323ca028
  • Loading branch information
benjaminp authored and dan-huenecke committed Jun 5, 2024
1 parent e6af231 commit adb42cd
Show file tree
Hide file tree
Showing 11 changed files with 704 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import build.bazel.remote.execution.v2.Platform;
import build.bazel.remote.execution.v2.Platform.Property;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Ordering;
import com.google.devtools.build.lib.actions.Spawn;
Expand Down Expand Up @@ -64,41 +65,48 @@ public static Platform buildPlatformProto(Map<String, String> executionPropertie
@Nullable
public static Platform getPlatformProto(Spawn spawn, @Nullable RemoteOptions remoteOptions)
throws UserExecException {
return getPlatformProto(spawn, remoteOptions, ImmutableMap.of());
}

@Nullable
public static Platform getPlatformProto(
Spawn spawn, @Nullable RemoteOptions remoteOptions, Map<String, String> additionalProperties)
throws UserExecException {
SortedMap<String, String> defaultExecProperties =
remoteOptions != null
? remoteOptions.getRemoteDefaultExecProperties()
: ImmutableSortedMap.of();

if (spawn.getExecutionPlatform() == null
&& spawn.getCombinedExecProperties().isEmpty()
&& defaultExecProperties.isEmpty()) {
&& defaultExecProperties.isEmpty()
&& additionalProperties.isEmpty()) {
return null;
}

Platform.Builder platformBuilder = Platform.newBuilder();

Map<String, String> properties;
if (!spawn.getCombinedExecProperties().isEmpty()) {
Map<String, String> combinedExecProperties;
// Apply default exec properties if the execution platform does not already set
// exec_properties
if (spawn.getExecutionPlatform() == null
|| spawn.getExecutionPlatform().execProperties().isEmpty()) {
combinedExecProperties = new HashMap<>();
combinedExecProperties.putAll(defaultExecProperties);
combinedExecProperties.putAll(spawn.getCombinedExecProperties());
properties = new HashMap<>();
properties.putAll(defaultExecProperties);
properties.putAll(spawn.getCombinedExecProperties());
} else {
combinedExecProperties = spawn.getCombinedExecProperties();
}

for (Map.Entry<String, String> entry : combinedExecProperties.entrySet()) {
platformBuilder.addPropertiesBuilder().setName(entry.getKey()).setValue(entry.getValue());
properties = spawn.getCombinedExecProperties();
}
} else if (spawn.getExecutionPlatform() != null
&& !Strings.isNullOrEmpty(spawn.getExecutionPlatform().remoteExecutionProperties())) {
properties = new HashMap<>();
// Try and get the platform info from the execution properties.
try {
Platform.Builder platformBuilder = Platform.newBuilder();
TextFormat.getParser()
.merge(spawn.getExecutionPlatform().remoteExecutionProperties(), platformBuilder);
for (Property property : platformBuilder.getPropertiesList()) {
properties.put(property.getName(), property.getValue());
}
} catch (ParseException e) {
String message =
String.format(
Expand All @@ -108,12 +116,23 @@ public static Platform getPlatformProto(Spawn spawn, @Nullable RemoteOptions rem
e, createFailureDetail(message, Code.INVALID_REMOTE_EXECUTION_PROPERTIES));
}
} else {
for (Map.Entry<String, String> property : defaultExecProperties.entrySet()) {
platformBuilder.addProperties(
Property.newBuilder().setName(property.getKey()).setValue(property.getValue()).build());
properties = defaultExecProperties;
}

if (!additionalProperties.isEmpty()) {
if (properties.isEmpty()) {
properties = additionalProperties;
} else {
// Merge the two maps.
properties = new HashMap<>(properties);
properties.putAll(additionalProperties);
}
}

Platform.Builder platformBuilder = Platform.newBuilder();
for (Map.Entry<String, String> entry : properties.entrySet()) {
platformBuilder.addPropertiesBuilder().setName(entry.getKey()).setValue(entry.getValue());
}
sortPlatformProperties(platformBuilder);
return platformBuilder.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* probably should not exist, but is currently necessary for our local MacOS support.
*/
public interface LocalEnvProvider {
LocalEnvProvider NOOP = (env, binTools, fallbackTmpDir) -> ImmutableMap.copyOf(env);

/**
* Creates a local environment provider for the current OS.
Expand Down
Loading

0 comments on commit adb42cd

Please sign in to comment.