Support multiplex workers in ResourceProcessorBusyBox Adding support for multiplex workers inside of `ResourceProcessorBusyBox` and moving it's worker implementation over to the generic work request handler. These PRs need to land for this to work: - https://github.com/bazelbuild/bazel/pull/14424 - https://github.com/bazelbuild/bazel/pull/14425 - https://github.com/bazelbuild/bazel/pull/14427 For those not on rolling releases, the other required PRs that have already merged are: - https://github.com/bazelbuild/bazel/pull/14144 - https://github.com/bazelbuild/bazel/pull/14145 - https://github.com/bazelbuild/bazel/pull/14146 Closes #14428. PiperOrigin-RevId: 456561596 Change-Id: I098d5a323ac6558ad0f5f8190e29f45a7a37b4d4
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java b/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java index ffcc82d..db9f08e 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java +++ b/src/main/java/com/google/devtools/build/lib/actions/ExecutionRequirements.java
@@ -176,6 +176,9 @@ public static final ImmutableMap<String, String> WORKER_MODE_ENABLED = ImmutableMap.of(SUPPORTS_WORKERS, "1"); + public static final ImmutableMap<String, String> WORKER_MULTIPLEX_MODE_ENABLED = + ImmutableMap.of(SUPPORTS_MULTIPLEX_WORKERS, "1"); + /** * Requires local execution without sandboxing for a spawn. *
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java index 99d1be0..d517723 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -883,6 +883,17 @@ public boolean persistentBusyboxTools; @Option( + name = "experimental_persistent_multiplex_busybox_tools", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = { + OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS, + OptionEffectTag.EXECUTION, + }, + defaultValue = "false", + help = "Tracking flag for when multiplex busybox workers are enabled.") + public boolean experimentalPersistentMultiplexBusyboxTools; + + @Option( name = "experimental_remove_r_classes_from_instrumentation_test_jar", defaultValue = "true", documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, @@ -1007,6 +1018,8 @@ host.oneVersionEnforcementUseTransitiveJarsForBinaryUnderTest = oneVersionEnforcementUseTransitiveJarsForBinaryUnderTest; host.persistentBusyboxTools = persistentBusyboxTools; + host.experimentalPersistentMultiplexBusyboxTools = + experimentalPersistentMultiplexBusyboxTools; // Unless the build was started from an Android device, host means MAIN. host.configurationDistinguisher = ConfigurationDistinguisher.MAIN; @@ -1052,6 +1065,7 @@ private final boolean dataBindingUpdatedArgs; private final boolean dataBindingAndroidX; private final boolean persistentBusyboxTools; + private final boolean experimentalPersistentMultiplexBusyboxTools; private final boolean filterRJarsFromAndroidTest; private final boolean removeRClassesFromInstrumentationTestJar; private final boolean alwaysFilterDuplicateClassesFromAndroidTest; @@ -1111,6 +1125,8 @@ this.dataBindingUpdatedArgs = options.dataBindingUpdatedArgs; this.dataBindingAndroidX = options.dataBindingAndroidX; this.persistentBusyboxTools = options.persistentBusyboxTools; + this.experimentalPersistentMultiplexBusyboxTools = + options.experimentalPersistentMultiplexBusyboxTools; this.filterRJarsFromAndroidTest = options.filterRJarsFromAndroidTest; this.removeRClassesFromInstrumentationTestJar = options.removeRClassesFromInstrumentationTestJar; @@ -1363,6 +1379,11 @@ } @Override + public boolean persistentMultiplexBusyboxTools() { + return experimentalPersistentMultiplexBusyboxTools; + } + + @Override public boolean incompatibleUseToolchainResolution() { return incompatibleUseToolchainResolution; }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java index ef60365..cadedbd 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDataContext.java
@@ -64,6 +64,7 @@ private final FilesToRunProvider busybox; private final AndroidSdkProvider sdk; private final boolean persistentBusyboxToolsEnabled; + private final boolean persistentMultiplexBusyboxTools; private final boolean optOutOfResourcePathShortening; private final boolean optOutOfResourceNameObfuscation; private final boolean throwOnShrinkResources; @@ -90,6 +91,7 @@ ruleContext, ruleContext.getExecutablePrerequisite("$android_resources_busybox"), androidConfig.persistentBusyboxTools(), + androidConfig.persistentMultiplexBusyboxTools(), AndroidSdkProvider.fromRuleContext(ruleContext), hasExemption(ruleContext, "allow_raw_access_to_resource_paths", false), hasExemption(ruleContext, "allow_resource_name_obfuscation_opt_out", false), @@ -114,6 +116,7 @@ RuleContext ruleContext, FilesToRunProvider busybox, boolean persistentBusyboxToolsEnabled, + boolean persistentMultiplexBusyboxTools, AndroidSdkProvider sdk, boolean optOutOfResourcePathShortening, boolean optOutOfResourceNameObfuscation, @@ -126,6 +129,7 @@ boolean includeProguardLocationReferences, ImmutableMap<String, String> executionInfo) { this.persistentBusyboxToolsEnabled = persistentBusyboxToolsEnabled; + this.persistentMultiplexBusyboxTools = persistentMultiplexBusyboxTools; this.ruleContext = ruleContext; this.busybox = busybox; this.sdk = sdk; @@ -222,6 +226,10 @@ return persistentBusyboxToolsEnabled; } + public boolean isPersistentMultiplexBusyboxTools() { + return persistentMultiplexBusyboxTools; + } + public boolean optOutOfResourcePathShortening() { return optOutOfResourcePathShortening; }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java index 0a1e76b..e055566 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/BusyBoxActionBuilder.java
@@ -344,10 +344,12 @@ if (dataContext.isPersistentBusyboxToolsEnabled()) { commandLine.add("--logWarnings=false"); - spawnActionBuilder - .addCommandLine(commandLine.build(), WORKERS_FORCED_PARAM_FILE_INFO); - + spawnActionBuilder.addCommandLine(commandLine.build(), WORKERS_FORCED_PARAM_FILE_INFO); executionInfo.putAll(ExecutionRequirements.WORKER_MODE_ENABLED); + + if (dataContext.isPersistentMultiplexBusyboxTools()) { + executionInfo.putAll(ExecutionRequirements.WORKER_MULTIPLEX_MODE_ENABLED); + } } else { spawnActionBuilder.addCommandLine(commandLine.build(), FORCED_PARAM_FILE_INFO); }
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidConfigurationApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidConfigurationApi.java index 197d3c1..0eb1a2a 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidConfigurationApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/android/AndroidConfigurationApi.java
@@ -232,6 +232,13 @@ boolean persistentBusyboxTools(); @StarlarkMethod( + name = "experimental_persistent_multiplex_busybox_tools", + structField = true, + doc = "", + documented = false) + boolean persistentMultiplexBusyboxTools(); + + @StarlarkMethod( name = "get_output_directory_name", structField = true, doc = "",
diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD b/src/tools/android/java/com/google/devtools/build/android/BUILD index 592451e..be017fb 100644 --- a/src/tools/android/java/com/google/devtools/build/android/BUILD +++ b/src/tools/android/java/com/google/devtools/build/android/BUILD
@@ -76,6 +76,8 @@ ":dependency_info", "//src/java_tools/singlejar/java/com/google/devtools/build/singlejar:libSingleJar", "//src/java_tools/singlejar/java/com/google/devtools/build/zip", + "//src/main/java/com/google/devtools/build/lib/worker", + "//src/main/java/com/google/devtools/build/lib/worker:work_request_handlers", "//src/main/java/com/google/devtools/common/options", "//src/main/protobuf:worker_protocol_java_proto", "//src/tools/android/java/com/google/devtools/build/android/junctions",
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java index 2b84123e..58e3b48 100644 --- a/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java +++ b/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox.java
@@ -14,10 +14,12 @@ package com.google.devtools.build.android; +import static java.nio.charset.StandardCharsets.UTF_8; + import com.google.devtools.build.android.aapt2.Aapt2Exception; import com.google.devtools.build.android.resources.JavaIdentifierValidator.InvalidJavaIdentifier; -import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; -import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; +import com.google.devtools.build.lib.worker.ProtoWorkerMessageProcessor; +import com.google.devtools.build.lib.worker.WorkRequestHandler; import com.google.devtools.common.options.EnumConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionDocumentationCategory; @@ -30,7 +32,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; +import java.io.PrintWriter; import java.nio.file.FileSystems; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Properties; @@ -183,36 +187,24 @@ PrintStream ps = new PrintStream(buf, true); PrintStream realStdOut = System.out; PrintStream realStdErr = System.err; + + // Redirect all stdout and stderr output for logging. + System.setOut(ps); + System.setErr(ps); try { - // Redirect all stdout and stderr output for logging. - System.setOut(ps); - System.setErr(ps); - - while (true) { - try { - WorkRequest request = WorkRequest.parseDelimitedFrom(System.in); - if (request == null) { - break; - } - - int exitCode = processRequest(request.getArgumentsList()); - ps.flush(); - - WorkResponse.newBuilder() - .setExitCode(exitCode) - .setRequestId(request.getRequestId()) - .setOutput(buf.toString()) - .build() - .writeDelimitedTo(realStdOut); - - realStdOut.flush(); - buf.reset(); - } catch (IOException e) { - logger.severe(e.getMessage()); - e.printStackTrace(realStdErr); - return 1; - } - } + WorkRequestHandler workerHandler = + new WorkRequestHandler.WorkRequestHandlerBuilder( + new WorkRequestHandler.WorkRequestCallback( + (request, pw) -> processRequest(request.getArgumentsList(), pw, buf)), + realStdErr, + new ProtoWorkerMessageProcessor(System.in, realStdOut)) + .setCpuUsageBeforeGc(Duration.ofSeconds(10)) + .build(); + workerHandler.processRequests(); + } catch (IOException e) { + logger.severe(e.getMessage()); + e.printStackTrace(realStdErr); + return 1; } finally { System.setOut(realStdOut); System.setErr(realStdErr); @@ -220,6 +212,31 @@ return 0; } + /** + * Processes the request for the given args and writes the captured byte array buffer to the + * WorkRequestHandler print writer. + */ + private static int processRequest(List<String> args, PrintWriter pw, ByteArrayOutputStream buf) { + int exitCode; + try { + // Process the actual request and grab the exit code + exitCode = processRequest(args); + } catch (Exception e) { + e.printStackTrace(pw); + exitCode = 1; + } finally { + // Write the captured buffer to the work response. We synchronize to avoid race conditions + // while reading from and calling reset on the shared ByteArrayOutputStream. + synchronized (buf) { + String captured = buf.toString(UTF_8).trim(); + buf.reset(); + pw.print(captured); + } + } + + return exitCode; + } + private static int processRequest(List<String> args) throws Exception { OptionsParser optionsParser = OptionsParser.builder()