Skip to content

Commit babd837

Browse files
authored
Merge pull request #14976 from graydon/rdar-38123690-task-queue-exec-errors
rdar://38123690 (overlarge batches) and rdar://37865437 (task queue exec errors)
2 parents f66dd8e + 6c9029e commit babd837

File tree

3 files changed

+188
-20
lines changed

3 files changed

+188
-20
lines changed

lib/Driver/Compilation.cpp

Lines changed: 67 additions & 20 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,19 +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-
BatchPartition Partition(Comp.NumberOfParallelCommands);
792-
partitionIntoBatches(Batchable.takeVector(), Partition);
818+
// Split the batchable from non-batchable pending jobs.
819+
getPendingBatchableJobs(Batchable, NonBatchable);
793820

794-
// Construct a BatchJob from each batch in the partition.
795-
std::vector<const Job *> Batches;
796-
for (auto const &Batch : Partition) {
797-
formBatchJobFromPartitionBatch(Batches, Batch);
798-
}
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();
799832

800833
// Save batches so we can locate and decompose them on task-exit.
801834
for (const Job *Cmd : Batches)
@@ -810,15 +843,29 @@ namespace driver {
810843
do {
811844
using namespace std::placeholders;
812845
// Ask the TaskQueue to execute.
813-
TQ->execute(std::bind(&PerformJobsState::taskBegan, this,
814-
_1, _2),
815-
std::bind(&PerformJobsState::taskFinished, this,
816-
_1, _2, _3, _4, _5),
817-
std::bind(&PerformJobsState::taskSignalled, this,
818-
_1, _2, _3, _4, _5, _6));
819-
820-
// Returning from TaskQueue::execute should mean either an empty
821-
// TaskQueue or a failed subprocess.
846+
if (TQ->execute(std::bind(&PerformJobsState::taskBegan, this,
847+
_1, _2),
848+
std::bind(&PerformJobsState::taskFinished, this,
849+
_1, _2, _3, _4, _5),
850+
std::bind(&PerformJobsState::taskSignalled, this,
851+
_1, _2, _3, _4, _5, _6))) {
852+
if (Result == EXIT_SUCCESS) {
853+
// FIXME: Error from task queue while Result == EXIT_SUCCESS most
854+
// likely means some fork/exec or posix_spawn failed; TaskQueue saw
855+
// "an error" at some stage before even calling us with a process
856+
// exit / signal (or else a poll failed); unfortunately the task
857+
// causing it was dropped on the floor and we have no way to recover
858+
// it here, so we report a very poor, generic error.
859+
Comp.Diags.diagnose(SourceLoc(), diag::error_unable_to_execute_command,
860+
"<unknown>");
861+
Result = -2;
862+
AnyAbnormalExit = true;
863+
return;
864+
}
865+
}
866+
867+
// Returning without error from TaskQueue::execute should mean either an
868+
// empty TaskQueue or a failed subprocess.
822869
assert(!(Result == 0 && TQ->hasRemainingTasks()));
823870

824871
// Task-exit callbacks from TaskQueue::execute may have unblocked jobs,

test/Driver/bad_exec.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// REQUIRES: OS=macosx
2+
// RUN: %empty-directory(%t)
3+
// RUN: not %swiftc_driver -driver-use-frontend-path /always/searching/never/finding %s 2>&1 | %FileCheck %s
4+
// CHECK: unable to execute command
5+
func thing() {
6+
print(1)
7+
}

0 commit comments

Comments
 (0)