Skip to content

Commit 69d1060

Browse files
author
David Ungar
authored
Merge pull request #28867 from davidungar/enable-disable-off-by-default
[Driver, Incremental] Add enable- and disable- only-one-dependency-file flags off-by-default
2 parents d59c23f + 0291b36 commit 69d1060

File tree

9 files changed

+298
-92
lines changed

9 files changed

+298
-92
lines changed

include/swift/Driver/Compilation.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,23 @@ class Compilation {
257257
/// limit filelists will be used.
258258
size_t FilelistThreshold;
259259

260+
/// Because each frontend job outputs the same info in its .d file, only do it
261+
/// on the first job that actually runs. Write out dummies for the rest of the
262+
/// jobs. This hack saves a lot of time in the build system when incrementally
263+
/// building a project with many files. Record if a scheduled job has already
264+
/// added -emit-dependency-path.
265+
bool HaveAlreadyAddedDependencyPath = false;
266+
267+
public:
268+
/// When set, only the first scheduled frontend job gets the argument needed
269+
/// to produce a make-style dependency file. The other jobs create dummy files
270+
/// in the driver. This hack speeds up incremental compilation by reducing the
271+
/// time for the build system to read each dependency file, which are all
272+
/// identical. This optimization can be disabled by passing
273+
/// -disable-only-one-dependency-file on the command line.
274+
const bool OnlyOneDependencyFile;
275+
276+
private:
260277
/// Scaffolding to permit experimentation with finer-grained dependencies and
261278
/// faster rebuilds.
262279
const bool EnableFineGrainedDependencies;
@@ -309,6 +326,7 @@ class Compilation {
309326
bool SaveTemps = false,
310327
bool ShowDriverTimeCompilation = false,
311328
std::unique_ptr<UnifiedStatsReporter> Stats = nullptr,
329+
bool OnlyOneDependencyFile = false,
312330
bool EnableFineGrainedDependencies = false,
313331
bool VerifyFineGrainedDependencyGraphAfterEveryImport = false,
314332
bool EmitFineGrainedDependencyDotFileAfterEveryImport = false,
@@ -427,6 +445,16 @@ class Compilation {
427445
return FilelistThreshold;
428446
}
429447

448+
/// Since every make-style dependency file contains
449+
/// the same information, incremental builds are sped up by only emitting one
450+
/// of those files. Since the build system expects to see the files existing,
451+
/// create dummy files for those jobs that don't emit real dependencies.
452+
/// \param path The dependency file path
453+
/// \param addDependencyPath A function to add an -emit-dependency-path
454+
/// argument
455+
void addDependencyPathOrCreateDummy(StringRef path,
456+
function_ref<void()> addDependencyPath);
457+
430458
UnifiedStatsReporter *getStatsReporter() const {
431459
return Stats.get();
432460
}

include/swift/Driver/Job.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ class CommandOutput {
194194
/// first primary input.
195195
StringRef getAdditionalOutputForType(file_types::ID type) const;
196196

197+
/// Assuming (and asserting) that there are one or more input pairs, return true if there exists
198+
/// an _additional_ (not primary) output of type \p type associated with the
199+
/// first primary input.
200+
bool hasAdditionalOutputForType(file_types::ID type) const;
201+
197202
/// Return a vector of additional (not primary) outputs of type \p type
198203
/// associated with the primary inputs.
199204
///

include/swift/Option/Options.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ def enable_fine_grained_dependencies :
139139
Flag<["-"], "enable-fine-grained-dependencies">, Flags<[FrontendOption, HelpHidden]>,
140140
HelpText<"Experimental work-in-progress to be more selective about incremental recompilation">;
141141

142+
143+
def enable_only_one_dependency_file :
144+
Flag<["-"], "enable-only-one-dependency-file">, Flags<[DoesNotAffectIncrementalBuild]>,
145+
HelpText<"Enables incremental build optimization that only produces one dependencies file">;
146+
147+
def disable_only_one_dependency_file :
148+
Flag<["-"], "disable-only-one-dependency-file">, Flags<[DoesNotAffectIncrementalBuild]>,
149+
HelpText<"Disables incremental build optimization that only produces one dependencies file">;
150+
151+
142152
def enable_source_range_dependencies :
143153
Flag<["-"], "enable-source-range-dependencies">, Flags<[]>,
144154
HelpText<"Try using source range information">;

lib/Driver/Compilation.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848

4949
#include "CompilationRecord.h"
5050

51+
#include <fstream>
5152
#include <signal.h>
5253

5354
#define DEBUG_TYPE "batch-mode"
@@ -121,6 +122,7 @@ Compilation::Compilation(DiagnosticEngine &Diags,
121122
bool SaveTemps,
122123
bool ShowDriverTimeCompilation,
123124
std::unique_ptr<UnifiedStatsReporter> StatsReporter,
125+
bool OnlyOneDependencyFile,
124126
bool EnableFineGrainedDependencies,
125127
bool VerifyFineGrainedDependencyGraphAfterEveryImport,
126128
bool EmitFineGrainedDependencyDotFileAfterEveryImport,
@@ -149,14 +151,16 @@ Compilation::Compilation(DiagnosticEngine &Diags,
149151
ShowDriverTimeCompilation(ShowDriverTimeCompilation),
150152
Stats(std::move(StatsReporter)),
151153
FilelistThreshold(FilelistThreshold),
154+
OnlyOneDependencyFile(OnlyOneDependencyFile),
152155
EnableFineGrainedDependencies(EnableFineGrainedDependencies),
153156
VerifyFineGrainedDependencyGraphAfterEveryImport(
154157
VerifyFineGrainedDependencyGraphAfterEveryImport),
155158
EmitFineGrainedDependencyDotFileAfterEveryImport(
156159
EmitFineGrainedDependencyDotFileAfterEveryImport),
157160
FineGrainedDependenciesIncludeIntrafileOnes(
158161
FineGrainedDependenciesIncludeIntrafileOnes),
159-
EnableSourceRangeDependencies(EnableSourceRangeDependencies) {
162+
EnableSourceRangeDependencies(EnableSourceRangeDependencies)
163+
{
160164
if (CompareIncrementalSchemes)
161165
IncrementalComparator.emplace(
162166
// Ensure the references are to inst vars, NOT arguments
@@ -2032,3 +2036,19 @@ unsigned Compilation::countSwiftInputs() const {
20322036
++inputCount;
20332037
return inputCount;
20342038
}
2039+
2040+
void Compilation::addDependencyPathOrCreateDummy(
2041+
StringRef depPath, function_ref<void()> addDependencyPath) {
2042+
2043+
if (!OnlyOneDependencyFile) {
2044+
addDependencyPath();
2045+
return;
2046+
}
2047+
if (!HaveAlreadyAddedDependencyPath) {
2048+
addDependencyPath();
2049+
HaveAlreadyAddedDependencyPath = true;
2050+
} else if (!depPath.empty()) {
2051+
// Create dummy empty file
2052+
std::ofstream(depPath.str().c_str());
2053+
}
2054+
}

lib/Driver/Driver.cpp

Lines changed: 66 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,11 @@ Driver::buildCompilation(const ToolChain &TC,
951951
ArgList->hasArg(options::OPT_driver_time_compilation);
952952
std::unique_ptr<UnifiedStatsReporter> StatsReporter =
953953
createStatsReporter(ArgList.get(), Inputs, OI, DefaultTargetTriple);
954+
955+
const bool OnlyOneDependencyFile =
956+
ArgList->hasFlag(options::OPT_enable_only_one_dependency_file,
957+
options::OPT_disable_only_one_dependency_file, false);
958+
954959
// relies on the new dependency graph
955960
const bool EnableFineGrainedDependencies =
956961
ArgList->hasArg(options::OPT_enable_fine_grained_dependencies);
@@ -984,6 +989,7 @@ Driver::buildCompilation(const ToolChain &TC,
984989
SaveTemps,
985990
ShowDriverTimeCompilation,
986991
std::move(StatsReporter),
992+
OnlyOneDependencyFile,
987993
EnableFineGrainedDependencies,
988994
VerifyFineGrainedDependencyGraphAfterEveryImport,
989995
EmitFineGrainedDependencyDotFileAfterEveryImport,
@@ -2425,60 +2431,74 @@ static bool hasExistingAdditionalOutput(CommandOutput &output,
24252431
return false;
24262432
}
24272433

2428-
static void addAuxiliaryOutput(
2434+
static llvm::SmallString<128> computeAuxiliaryOutputPath(
24292435
Compilation &C, CommandOutput &output, file_types::ID outputType,
24302436
const TypeToPathMap *outputMap, StringRef workingDirectory,
24312437
StringRef outputPath = StringRef(),
24322438
llvm::opt::OptSpecifier requireArg = llvm::opt::OptSpecifier()) {
24332439

24342440
if (hasExistingAdditionalOutput(output, outputType, outputPath))
2435-
return;
2441+
return {};
24362442

2437-
StringRef outputMapPath;
24382443
if (outputMap) {
24392444
auto iter = outputMap->find(outputType);
2440-
if (iter != outputMap->end())
2441-
outputMapPath = iter->second;
2445+
if (iter != outputMap->end()) {
2446+
StringRef outputMapPath = iter->second;
2447+
// Prefer a path from the OutputMap.
2448+
if (!outputMapPath.empty())
2449+
return outputMapPath;
2450+
}
24422451
}
2452+
if (!outputPath.empty())
2453+
return outputPath;
24432454

2444-
if (!outputMapPath.empty()) {
2445-
// Prefer a path from the OutputMap.
2446-
output.setAdditionalOutputForType(outputType, outputMapPath);
2447-
} else if (!outputPath.empty()) {
2448-
output.setAdditionalOutputForType(outputType, outputPath);
2449-
} else if (requireArg.isValid() && !C.getArgs().getLastArg(requireArg)) {
2455+
if (requireArg.isValid() && !C.getArgs().getLastArg(requireArg)) {
24502456
// This auxiliary output only exists if requireArg is passed, but it
24512457
// wasn't this time.
2452-
return;
2453-
} else {
2454-
// Put the auxiliary output file next to "the" primary output file.
2455-
//
2456-
// FIXME: when we're in WMO and have multiple primary outputs, we derive the
2457-
// additional filename here from the _first_ primary output name, which
2458-
// means that in the derived OFM (in Job.cpp) the additional output will
2459-
// have a possibly-surprising name. But that's only half the problem: it
2460-
// also get associated with the first primary _input_, even when there are
2461-
// multiple primary inputs; really it should be associated with the build as
2462-
// a whole -- derived OFM input "" -- but that's a more general thing to
2463-
// fix.
2464-
llvm::SmallString<128> path;
2465-
if (output.getPrimaryOutputType() != file_types::TY_Nothing)
2466-
path = output.getPrimaryOutputFilenames()[0];
2467-
else if (!output.getBaseInput(0).empty())
2468-
path = llvm::sys::path::filename(output.getBaseInput(0));
2469-
else {
2470-
formFilenameFromBaseAndExt(C.getOutputInfo().ModuleName, /*newExt=*/"",
2471-
workingDirectory, path);
2472-
}
2473-
assert(!path.empty());
2474-
2475-
bool isTempFile = C.isTemporaryFile(path);
2476-
llvm::sys::path::replace_extension(
2477-
path, file_types::getExtension(outputType));
2478-
output.setAdditionalOutputForType(outputType, path);
2479-
if (isTempFile)
2480-
C.addTemporaryFile(path);
2458+
return {};
24812459
}
2460+
2461+
// Put the auxiliary output file next to "the" primary output file.
2462+
//
2463+
// FIXME: when we're in WMO and have multiple primary outputs, we derive the
2464+
// additional filename here from the _first_ primary output name, which
2465+
// means that in the derived OFM (in Job.cpp) the additional output will
2466+
// have a possibly-surprising name. But that's only half the problem: it
2467+
// also get associated with the first primary _input_, even when there are
2468+
// multiple primary inputs; really it should be associated with the build as
2469+
// a whole -- derived OFM input "" -- but that's a more general thing to
2470+
// fix.
2471+
llvm::SmallString<128> path;
2472+
if (output.getPrimaryOutputType() != file_types::TY_Nothing)
2473+
path = output.getPrimaryOutputFilenames()[0];
2474+
else if (!output.getBaseInput(0).empty())
2475+
path = llvm::sys::path::filename(output.getBaseInput(0));
2476+
else {
2477+
formFilenameFromBaseAndExt(C.getOutputInfo().ModuleName, /*newExt=*/"",
2478+
workingDirectory, path);
2479+
}
2480+
assert(!path.empty());
2481+
2482+
const bool isTempFile = C.isTemporaryFile(path);
2483+
llvm::sys::path::replace_extension(path,
2484+
file_types::getExtension(outputType));
2485+
if (isTempFile)
2486+
C.addTemporaryFile(path);
2487+
return path;
2488+
}
2489+
2490+
static void addAuxiliaryOutput(
2491+
Compilation &C, CommandOutput &output, file_types::ID outputType,
2492+
const TypeToPathMap *outputMap, StringRef workingDirectory,
2493+
StringRef outputPath = StringRef(),
2494+
llvm::opt::OptSpecifier requireArg = llvm::opt::OptSpecifier()) {
2495+
2496+
const auto path =
2497+
computeAuxiliaryOutputPath(C, output, outputType, outputMap,
2498+
workingDirectory, outputPath, requireArg);
2499+
if (path.empty())
2500+
return;
2501+
output.setAdditionalOutputForType(outputType, path);
24822502
}
24832503

24842504
static void addDiagFileOutputForPersistentPCHAction(
@@ -3057,8 +3077,12 @@ void Driver::chooseDependenciesOutputPaths(Compilation &C,
30573077
llvm::SmallString<128> &Buf,
30583078
CommandOutput *Output) const {
30593079
if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
3060-
addAuxiliaryOutput(C, *Output, file_types::TY_Dependencies, OutputMap,
3061-
workingDirectory);
3080+
auto depPath = computeAuxiliaryOutputPath(
3081+
C, *Output, file_types::TY_Dependencies, OutputMap, workingDirectory);
3082+
C.addDependencyPathOrCreateDummy(depPath, [&] {
3083+
addAuxiliaryOutput(C, *Output, file_types::TY_Dependencies, OutputMap,
3084+
workingDirectory);
3085+
});
30623086
}
30633087
if (C.getIncrementalBuildEnabled()) {
30643088
file_types::forEachIncrementalOutputType([&](file_types::ID type) {

lib/Driver/Job.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ CommandOutput::getAdditionalOutputsForType(file_types::ID Type) const {
236236
return V;
237237
}
238238

239+
bool CommandOutput::hasAdditionalOutputForType(file_types::ID type) const {
240+
return AdditionalOutputTypes.count(type);
241+
}
242+
239243
StringRef CommandOutput::getAnyOutputForType(file_types::ID Type) const {
240244
if (PrimaryOutputType == Type)
241245
return getPrimaryOutputFilename();

lib/Driver/ToolChain.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ bool ToolChain::jobIsBatchable(const Compilation &C, const Job *A) const {
238238
auto const *CJActA = dyn_cast<const CompileJobAction>(&A->getSource());
239239
if (!CJActA)
240240
return false;
241+
// When having only one job output a dependency file, that job is not
242+
// batchable since it has an oddball set of additional output types.
243+
if (C.OnlyOneDependencyFile &&
244+
A->getOutput().hasAdditionalOutputForType(file_types::TY_Dependencies))
245+
return false;
241246
return findSingleSwiftInput(CJActA) != nullptr;
242247
}
243248

0 commit comments

Comments
 (0)