From 9fc1ce60f285e303058c40d1331712bd01067955 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Fri, 26 Jun 2015 14:56:54 +0000 Subject: Only run the worker if the build is incremental. This feature is tunable through --worker_max_changed_files flag. If unspecified, all builds are considered incremental. -- MOS_MIGRATED_REVID=96968367 --- .../build/lib/actions/ChangedFilesMessage.java | 3 +- .../lib/worker/WorkerActionContextProvider.java | 6 ++- .../devtools/build/lib/worker/WorkerModule.java | 6 ++- .../devtools/build/lib/worker/WorkerOptions.java | 10 +++++ .../build/lib/worker/WorkerSpawnStrategy.java | 45 +++++++++++++++++++++- 5 files changed, 64 insertions(+), 6 deletions(-) (limited to 'src/main/java/com/google/devtools') diff --git a/src/main/java/com/google/devtools/build/lib/actions/ChangedFilesMessage.java b/src/main/java/com/google/devtools/build/lib/actions/ChangedFilesMessage.java index 56f688284c..47c48ec015 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/ChangedFilesMessage.java +++ b/src/main/java/com/google/devtools/build/lib/actions/ChangedFilesMessage.java @@ -19,7 +19,8 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Set; /** - * A message sent conveying a set of changed files. + * A message sent conveying a set of changed files. This is sent over the event bus if a build is + * discovered to have few changed files. If many files have changed, it will not be sent at all. */ public class ChangedFilesMessage { diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java index 6d4e419391..0db3a46595 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerActionContextProvider.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.worker; import com.google.common.collect.ImmutableList; +import com.google.common.eventbus.EventBus; import com.google.devtools.build.lib.actions.ActionContextProvider; import com.google.devtools.build.lib.actions.Executor.ActionContext; import com.google.devtools.build.lib.buildtool.BuildRequest; @@ -24,9 +25,10 @@ import com.google.devtools.build.lib.buildtool.BuildRequest; final class WorkerActionContextProvider extends ActionContextProvider { private final ImmutableList strategies; - public WorkerActionContextProvider(BuildRequest buildRequest, WorkerPool workers) { + public WorkerActionContextProvider( + BuildRequest buildRequest, WorkerPool workers, EventBus eventBus) { this.strategies = - ImmutableList.of(new WorkerSpawnStrategy(buildRequest, workers)); + ImmutableList.of(new WorkerSpawnStrategy(buildRequest, workers, eventBus)); } @Override diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java index 81d5024610..b7de57fee1 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerModule.java @@ -32,6 +32,7 @@ public class WorkerModule extends BlazeModule { private final WorkerPool workers; private BuildRequest buildRequest; + private BlazeRuntime blazeRuntime; public WorkerModule() { GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig(); @@ -41,8 +42,8 @@ public class WorkerModule extends BlazeModule { @Override public Iterable getActionContextProviders() { - return ImmutableList.of(new WorkerActionContextProvider(buildRequest, - workers)); + return ImmutableList.of( + new WorkerActionContextProvider(buildRequest, workers, blazeRuntime.getEventBus())); } @Override @@ -54,6 +55,7 @@ public class WorkerModule extends BlazeModule { @Override public void beforeCommand(BlazeRuntime blazeRuntime, Command command) { + this.blazeRuntime = blazeRuntime; blazeRuntime.getEventBus().register(this); } diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java index 5dd7db01b9..b4471c0400 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java @@ -36,4 +36,14 @@ public class WorkerOptions extends OptionsBase { help = "Enable the experimental persistent Java compiler.", expansion = {"--strategy=Javac=worker", "--strategy=JavaIjar=local"}) public Void experimentalPersistentJavac; + + @Option( + name = "worker_max_changed_files", + defaultValue = "0", + category = "strategy", + help = + "Don't run local worker if more files than this were changed. 0 means always use " + + "workers." + ) + public int workerMaxChangedFiles; } diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java index 697a57de4d..13673ef3ae 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerSpawnStrategy.java @@ -17,17 +17,23 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; import com.google.devtools.build.lib.actions.ActionExecutionContext; +import com.google.devtools.build.lib.actions.ChangedFilesMessage; import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.SpawnActionContext; import com.google.devtools.build.lib.actions.UserExecException; +import com.google.devtools.build.lib.concurrent.ThreadSafety; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest; import com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse; import com.google.devtools.common.options.OptionsClassProvider; +import java.util.concurrent.atomic.AtomicBoolean; + /** * A spawn action context that launches Spawns the first time they are used in a persistent mode and * then shards work over all the processes. @@ -35,18 +41,31 @@ import com.google.devtools.common.options.OptionsClassProvider; @ExecutionStrategy(name = { "worker" }, contextType = SpawnActionContext.class) final class WorkerSpawnStrategy implements SpawnActionContext { private final WorkerPool workers; + private final IncrementalHeuristic incrementalHeuristic; - public WorkerSpawnStrategy(OptionsClassProvider optionsProvider, WorkerPool workers) { + public WorkerSpawnStrategy( + OptionsClassProvider optionsProvider, WorkerPool workers, EventBus eventBus) { + Preconditions.checkNotNull(optionsProvider); WorkerOptions options = optionsProvider.getOptions(WorkerOptions.class); workers.setMaxTotalPerKey(options.workerMaxInstances); workers.setMaxIdlePerKey(options.workerMaxInstances); workers.setMinIdlePerKey(options.workerMaxInstances); this.workers = workers; + this.incrementalHeuristic = new IncrementalHeuristic(options.workerMaxChangedFiles); + eventBus.register(incrementalHeuristic); } @Override public void exec(Spawn spawn, ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException { + if (!incrementalHeuristic.shouldUseWorkers()) { + SpawnActionContext context = actionExecutionContext.getExecutor().getSpawnActionContext(""); + if (context != this) { + context.exec(spawn, actionExecutionContext); + return; + } + } + String paramFile = Iterables.getLast(spawn.getArguments()); // We assume that the spawn to be executed always gets a single argument, which is a flagfile @@ -106,4 +125,28 @@ final class WorkerSpawnStrategy implements SpawnActionContext { public boolean isRemotable(String mnemonic, boolean remotable) { return false; } + + /** + * For installation with remote execution, non-incremental builds may be slowed down by the + * persistent worker system. To avoid this we only use workers for builds where few files + * changed. + */ + @ThreadSafety.ThreadSafe + private static class IncrementalHeuristic { + private final AtomicBoolean fewFilesChanged = new AtomicBoolean(false); + private int limit = 0; + + public boolean shouldUseWorkers() { + return limit == 0 || fewFilesChanged.get(); + } + + IncrementalHeuristic(int limit) { + this.limit = limit; + } + + @Subscribe + public void changedFiles(ChangedFilesMessage msg) { + fewFilesChanged.set(msg.getChangedFiles().size() <= limit); + } + } } -- cgit v1.2.3