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:
David Ungar
2018-03-16 17:38:53 -07:00
committed by GitHub
38 changed files with 696 additions and 358 deletions

View File

@@ -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) {