mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #15013 from davidungar/PR-18-11-fileMap
[Batch mode] Write supplementary output file map. rdar://problem/38157859
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
#include "swift/Driver/Job.h"
|
||||
#include "swift/Driver/ParseableOutput.h"
|
||||
#include "swift/Driver/ToolChain.h"
|
||||
#include "swift/Frontend/OutputFileMap.h"
|
||||
#include "swift/Option/Options.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
@@ -37,12 +39,14 @@
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/YAMLParser.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "CompilationRecord.h"
|
||||
|
||||
#define DEBUG_TYPE "batch-mode"
|
||||
|
||||
// Batch-mode has a sub-mode for testing that randomizes batch partitions,
|
||||
// by user-provided seed. That is the only thing randomized here.
|
||||
#include <random>
|
||||
@@ -103,6 +107,7 @@ Compilation::Compilation(DiagnosticEngine &Diags,
|
||||
bool EnableIncrementalBuild,
|
||||
bool EnableBatchMode,
|
||||
unsigned BatchSeed,
|
||||
bool ForceOneBatchRepartition,
|
||||
bool SkipTaskExecution,
|
||||
bool SaveTemps,
|
||||
bool ShowDriverTimeCompilation,
|
||||
@@ -119,12 +124,14 @@ Compilation::Compilation(DiagnosticEngine &Diags,
|
||||
EnableIncrementalBuild(EnableIncrementalBuild),
|
||||
EnableBatchMode(EnableBatchMode),
|
||||
BatchSeed(BatchSeed),
|
||||
ForceOneBatchRepartition(ForceOneBatchRepartition),
|
||||
SaveTemps(SaveTemps),
|
||||
ShowDriverTimeCompilation(ShowDriverTimeCompilation),
|
||||
Stats(std::move(StatsReporter)) {
|
||||
};
|
||||
|
||||
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags);
|
||||
static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
|
||||
DiagnosticEngine &diags);
|
||||
|
||||
using CommandSet = llvm::SmallPtrSet<const Job *, 16>;
|
||||
using CommandSetVector = llvm::SetVector<const Job*>;
|
||||
@@ -254,7 +261,8 @@ namespace driver {
|
||||
|
||||
void addPendingJobToTaskQueue(const Job *Cmd) {
|
||||
// FIXME: Failing here should not take down the whole process.
|
||||
bool success = writeFilelistIfNecessary(Cmd, Comp.Diags);
|
||||
bool success =
|
||||
writeFilelistIfNecessary(Cmd, *Comp.TranslatedArgs.get(), Comp.Diags);
|
||||
assert(success && "failed to write filelist");
|
||||
(void)success;
|
||||
|
||||
@@ -787,12 +795,20 @@ namespace driver {
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: at the moment we're not passing OutputFileMaps to frontends, so
|
||||
// due to the multiplication of the number of additional files and the
|
||||
// Due to the multiplication of the number of additional files and the
|
||||
// number of files in a batch, it's pretty easy to construct too-long
|
||||
// command lines here, which will then fail to exec. We address this crudely
|
||||
// by re-forming batches with a finer partition when we overflow.
|
||||
//
|
||||
// Now that we're passing OutputFileMaps to frontends, this should never
|
||||
// happen, but keep this as insurance, because the decision to pass output
|
||||
// file maps cannot know the exact length of the command line, so may
|
||||
// possibly fail to use the OutputFileMap.
|
||||
//
|
||||
// In order to be able to exercise as much of the code paths as possible,
|
||||
// take a flag to force a retry, but only once.
|
||||
bool shouldRetryWithMorePartitions(std::vector<const Job *> const &Batches,
|
||||
bool &PretendTheCommandLineIsTooLongOnce,
|
||||
size_t &NumPartitions) {
|
||||
|
||||
// Stop rebatching if we can't subdivide batches any further.
|
||||
@@ -801,10 +817,14 @@ namespace driver {
|
||||
|
||||
for (auto const *B : Batches) {
|
||||
if (!llvm::sys::commandLineFitsWithinSystemLimits(B->getExecutable(),
|
||||
B->getArguments())) {
|
||||
B->getArguments()) ||
|
||||
PretendTheCommandLineIsTooLongOnce) {
|
||||
PretendTheCommandLineIsTooLongOnce = false;
|
||||
// To avoid redoing the batch loop too many times, repartition pretty
|
||||
// aggressively by doubling partition count / halving size.
|
||||
NumPartitions *= 2;
|
||||
DEBUG(llvm::dbgs()
|
||||
<< "Should have used a supplementary output file map.\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -827,6 +847,8 @@ namespace driver {
|
||||
size_t NumPartitions = Comp.NumberOfParallelCommands;
|
||||
CommandSetVector Batchable, NonBatchable;
|
||||
std::vector<const Job *> Batches;
|
||||
bool PretendTheCommandLineIsTooLongOnce =
|
||||
Comp.getForceOneBatchRepartition();
|
||||
do {
|
||||
// We might be restarting loop; clear these before proceeding.
|
||||
Batchable.clear();
|
||||
@@ -845,7 +867,8 @@ namespace driver {
|
||||
formBatchJobFromPartitionBatch(Batches, Batch);
|
||||
}
|
||||
|
||||
} while (shouldRetryWithMorePartitions(Batches, NumPartitions));
|
||||
} while (shouldRetryWithMorePartitions(
|
||||
Batches, PretendTheCommandLineIsTooLongOnce, NumPartitions));
|
||||
PendingExecution.clear();
|
||||
|
||||
// Save batches so we can locate and decompose them on task-exit.
|
||||
@@ -1089,7 +1112,8 @@ static void writeCompilationRecord(StringRef path, StringRef argsHash,
|
||||
}
|
||||
}
|
||||
|
||||
static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
|
||||
static bool writeFilelistIfNecessary(const Job *job, const ArgList &args,
|
||||
DiagnosticEngine &diags) {
|
||||
bool ok = true;
|
||||
for (const FilelistInfo &filelistInfo : job->getFilelistInfos()) {
|
||||
if (filelistInfo.path.empty())
|
||||
@@ -1121,18 +1145,29 @@ static bool writeFilelistIfNecessary(const Job *job, DiagnosticEngine &diags) {
|
||||
}
|
||||
break;
|
||||
case FilelistInfo::WhichFiles::PrimaryInputs:
|
||||
for (const Action *A : job->getSource().getInputs()) {
|
||||
const auto *IA = cast<InputAction>(A);
|
||||
out << IA->getInputArg().getValue() << "\n";
|
||||
// Ensure that -index-file-path works in conjunction with
|
||||
// -driver-use-filelists. It needs to be the only primary.
|
||||
if (Arg *A = args.getLastArg(options::OPT_index_file_path))
|
||||
out << A->getValue() << "\n";
|
||||
else {
|
||||
// The normal case for non-single-compile jobs.
|
||||
for (const Action *A : job->getSource().getInputs()) {
|
||||
const auto *IA = cast<InputAction>(A);
|
||||
out << IA->getInputArg().getValue() << "\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FilelistInfo::WhichFiles::Output:
|
||||
case FilelistInfo::WhichFiles::Output: {
|
||||
const CommandOutput &outputInfo = job->getOutput();
|
||||
assert(outputInfo.getPrimaryOutputType() == filelistInfo.type);
|
||||
for (auto &output : outputInfo.getPrimaryOutputFilenames())
|
||||
out << output << "\n";
|
||||
break;
|
||||
}
|
||||
case FilelistInfo::WhichFiles::SupplementaryOutput:
|
||||
job->getOutput().writeOutputFileMap(out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1171,7 +1206,7 @@ int Compilation::performSingleCommand(const Job *Cmd) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!writeFilelistIfNecessary(Cmd, Diags))
|
||||
if (!writeFilelistIfNecessary(Cmd, *TranslatedArgs.get(), Diags))
|
||||
return 1;
|
||||
|
||||
switch (Level) {
|
||||
|
||||
Reference in New Issue
Block a user