Skip to content

Commit 6c9029e

Browse files
committed
[BatchMode] Fix rdar://38123690 a little more robustly.
1 parent eb315e7 commit 6c9029e

File tree

4 files changed

+55
-21
lines changed

4 files changed

+55
-21
lines changed

include/swift/Driver/ToolChain.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ namespace driver {
2929
class Job;
3030
class OutputInfo;
3131

32-
/// The limit for passing a list of files on the command line.
33-
const size_t TOO_MANY_FILES = 128;
34-
3532
/// A ToolChain is responsible for turning abstract Actions into concrete,
3633
/// runnable Jobs.
3734
///

lib/Driver/Compilation.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,6 @@ namespace driver {
688688
NonBatchable.insert(Cmd);
689689
}
690690
}
691-
PendingExecution.clear();
692691
}
693692

694693
/// If \p Batch is nonempty, construct a new \c BatchJob from its
@@ -770,6 +769,30 @@ namespace driver {
770769
}
771770
}
772771

772+
// FIXME: at the moment we're not passing OutputFileMaps to frontends, so
773+
// due to the multiplication of the number of additional files and the
774+
// number of files in a batch, it's pretty easy to construct too-long
775+
// command lines here, which will then fail to exec. We address this crudely
776+
// by re-forming batches with a finer partition when we overflow.
777+
bool shouldRetryWithMorePartitions(std::vector<const Job *> const &Batches,
778+
size_t &NumPartitions) {
779+
780+
// Stop rebatching if we can't subdivide batches any further.
781+
if (NumPartitions > PendingExecution.size())
782+
return false;
783+
784+
for (auto const *B : Batches) {
785+
if (!llvm::sys::commandLineFitsWithinSystemLimits(B->getExecutable(),
786+
B->getArguments())) {
787+
// To avoid redoing the batch loop too many times, repartition pretty
788+
// aggressively by doubling partition count / halving size.
789+
NumPartitions *= 2;
790+
return true;
791+
}
792+
}
793+
return false;
794+
}
795+
773796
/// Select jobs that are batch-combinable from \c PendingExecution, combine
774797
/// them together into \p BatchJob instances (also inserted into \p
775798
/// BatchJobs), and enqueue all \c PendingExecution jobs (whether batched or
@@ -783,23 +806,29 @@ namespace driver {
783806
return;
784807
}
785808

786-
// Split the batchable from non-batchable pending jobs.
809+
size_t NumPartitions = Comp.NumberOfParallelCommands;
787810
CommandSetVector Batchable, NonBatchable;
788-
getPendingBatchableJobs(Batchable, NonBatchable);
811+
std::vector<const Job *> Batches;
812+
do {
813+
// We might be restarting loop; clear these before proceeding.
814+
Batchable.clear();
815+
NonBatchable.clear();
816+
Batches.clear();
789817

790-
// Partition the batchable jobs into sets.
791-
// FIXME: at present we set a maximum batch size of TOO_MANY_FILES
792-
// so that we don't overflow command-line lengths. This can go away
793-
// when we're passing OFMs to the frontend processes.
794-
BatchPartition Partition(std::max(size_t(Comp.NumberOfParallelCommands),
795-
Batchable.size() / TOO_MANY_FILES));
796-
partitionIntoBatches(Batchable.takeVector(), Partition);
818+
// Split the batchable from non-batchable pending jobs.
819+
getPendingBatchableJobs(Batchable, NonBatchable);
797820

798-
// Construct a BatchJob from each batch in the partition.
799-
std::vector<const Job *> Batches;
800-
for (auto const &Batch : Partition) {
801-
formBatchJobFromPartitionBatch(Batches, Batch);
802-
}
821+
// Partition the batchable jobs into sets.
822+
BatchPartition Partition(NumPartitions);
823+
partitionIntoBatches(Batchable.takeVector(), Partition);
824+
825+
// Construct a BatchJob from each batch in the partition.
826+
for (auto const &Batch : Partition) {
827+
formBatchJobFromPartitionBatch(Batches, Batch);
828+
}
829+
830+
} while (shouldRetryWithMorePartitions(Batches, NumPartitions));
831+
PendingExecution.clear();
803832

804833
// Save batches so we can locate and decompose them on task-exit.
805834
for (const Job *Cmd : Batches)

lib/Driver/ToolChains.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ using namespace swift;
3737
using namespace swift::driver;
3838
using namespace llvm::opt;
3939

40+
/// The limit for passing a list of files on the command line.
41+
static const size_t TOO_MANY_FILES = 128;
42+
4043
static void addInputsOfType(ArgStringList &Arguments,
4144
ArrayRef<const Action *> Inputs,
4245
types::ID InputType,

test/Driver/batch_mode_overlong_argv.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// REQUIRES: OS=macosx
12
// RUN: %empty-directory(%t)
23
// RUN: touch %t/f_1_1.swift %t/f_1_2.swift %t/f_1_3.swift %t/f_1_4.swift %t/f_1_5.swift %t/f_1_6.swift %t/f_1_7.swift %t/f_1_8.swift %t/f_1_9.swift %t/f_1_10.swift
34
// RUN: touch %t/f_2_1.swift %t/f_2_2.swift %t/f_2_3.swift %t/f_2_4.swift %t/f_2_5.swift %t/f_2_6.swift %t/f_2_7.swift %t/f_2_8.swift %t/f_2_9.swift %t/f_2_10.swift
@@ -99,11 +100,15 @@
99100
// RUN: touch %t/f_98_1.swift %t/f_98_2.swift %t/f_98_3.swift %t/f_98_4.swift %t/f_98_5.swift %t/f_98_6.swift %t/f_98_7.swift %t/f_98_8.swift %t/f_98_9.swift %t/f_98_10.swift
100101
// RUN: touch %t/f_99_1.swift %t/f_99_2.swift %t/f_99_3.swift %t/f_99_4.swift %t/f_99_5.swift %t/f_99_6.swift %t/f_99_7.swift %t/f_99_8.swift %t/f_99_9.swift %t/f_99_10.swift
101102
// RUN: touch %t/f_100_1.swift %t/f_100_2.swift %t/f_100_3.swift %t/f_100_4.swift %t/f_100_5.swift %t/f_100_6.swift %t/f_100_7.swift %t/f_100_8.swift %t/f_100_9.swift %t/f_100_10.swift
102-
// RUN: %swiftc_driver -driver-show-job-lifecycle -c -module-name foo -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode %t/f_*.swift >%t/out.txt 2>&1
103+
// RUN: mkdir -p %t/additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/
104+
// RUN: %swiftc_driver -driver-show-job-lifecycle -v -c -module-name foo -o %t/additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/foo.o -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode %t/f_*.swift >%t/out.txt 2>&1
103105
// RUN: %FileCheck %s <%t/out.txt
104106
// CHECK-NOT: unable to execute command
105-
// CHECK: Found 1000 batchable jobs
106-
// CHECK: Forming into 7 batches
107+
// CHECK: Forming into 1 batches
108+
// CHECK: Forming batch job from 1000 constituents
109+
// CHECK: Forming into 2 batches
110+
// CHECK: Forming batch job from 500 constituents
111+
// CHECK: Forming batch job from 500 constituents
107112
func thing() {
108113
print(1)
109114
}

0 commit comments

Comments
 (0)