Skip to content

Commit 199fa51

Browse files
author
David Ungar
committed
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
1 parent fda4dfc commit 199fa51

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,
@@ -2421,60 +2427,74 @@ static bool hasExistingAdditionalOutput(CommandOutput &output,
24212427
return false;
24222428
}
24232429

2424-
static void addAuxiliaryOutput(
2430+
static llvm::SmallString<128> computeAuxiliaryOutputPath(
24252431
Compilation &C, CommandOutput &output, file_types::ID outputType,
24262432
const TypeToPathMap *outputMap, StringRef workingDirectory,
24272433
StringRef outputPath = StringRef(),
24282434
llvm::opt::OptSpecifier requireArg = llvm::opt::OptSpecifier()) {
24292435

24302436
if (hasExistingAdditionalOutput(output, outputType, outputPath))
2431-
return;
2437+
return {};
24322438

2433-
StringRef outputMapPath;
24342439
if (outputMap) {
24352440
auto iter = outputMap->find(outputType);
2436-
if (iter != outputMap->end())
2437-
outputMapPath = iter->second;
2441+
if (iter != outputMap->end()) {
2442+
StringRef outputMapPath = iter->second;
2443+
// Prefer a path from the OutputMap.
2444+
if (!outputMapPath.empty())
2445+
return outputMapPath;
2446+
}
24382447
}
2448+
if (!outputPath.empty())
2449+
return outputPath;
24392450

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

24802500
static void addDiagFileOutputForPersistentPCHAction(
@@ -3053,8 +3073,12 @@ void Driver::chooseDependenciesOutputPaths(Compilation &C,
30533073
llvm::SmallString<128> &Buf,
30543074
CommandOutput *Output) const {
30553075
if (C.getArgs().hasArg(options::OPT_emit_dependencies)) {
3056-
addAuxiliaryOutput(C, *Output, file_types::TY_Dependencies, OutputMap,
3057-
workingDirectory);
3076+
auto depPath = computeAuxiliaryOutputPath(
3077+
C, *Output, file_types::TY_Dependencies, OutputMap, workingDirectory);
3078+
C.addDependencyPathOrCreateDummy(depPath, [&] {
3079+
addAuxiliaryOutput(C, *Output, file_types::TY_Dependencies, OutputMap,
3080+
workingDirectory);
3081+
});
30583082
}
30593083
if (C.getIncrementalBuildEnabled()) {
30603084
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)