Skip to content

Commit 4f49b6a

Browse files
authored
Merge pull request #34231 from CodaFi/skippy
Skip Merge-Modules When We Can
2 parents cb70220 + cecb7c8 commit 4f49b6a

File tree

7 files changed

+194
-57
lines changed

7 files changed

+194
-57
lines changed

include/swift/Driver/Action.h

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,23 +130,40 @@ class JobAction : public Action {
130130
class IncrementalJobAction : public JobAction {
131131
public:
132132
struct InputInfo {
133-
enum Status {
133+
/// The status of an input known to the driver. These are used to affect
134+
/// the scheduling decisions made during an incremental build.
135+
///
136+
/// \Note The order of cases matters. They are ordered from least to
137+
/// greatest impact on the incremental build schedule.
138+
enum class Status {
139+
/// The input to this job is up to date.
134140
UpToDate,
135-
NeedsCascadingBuild,
141+
/// The input to this job has changed in a way that requires this job to
142+
/// be rerun, but not in such a way that it requires a cascading rebuild.
136143
NeedsNonCascadingBuild,
144+
/// The input to this job has changed in a way that requires this job to
145+
/// be rerun, and in such a way that all jobs dependent upon this one
146+
/// must be scheduled as well.
147+
NeedsCascadingBuild,
148+
/// The input to this job was not known to the driver when it was last
149+
/// run.
137150
NewlyAdded
138151
};
139152

140153
public:
141-
Status status = UpToDate;
154+
Status status = Status::UpToDate;
142155
llvm::sys::TimePoint<> previousModTime;
143156

144157
InputInfo() = default;
145158
InputInfo(Status stat, llvm::sys::TimePoint<> time)
146159
: status(stat), previousModTime(time) {}
147160

148161
static InputInfo makeNewlyAdded() {
149-
return InputInfo(Status::NewlyAdded, llvm::sys::TimePoint<>::max());
162+
return {Status::NewlyAdded, llvm::sys::TimePoint<>::max()};
163+
}
164+
165+
static InputInfo makeNeedsCascadingRebuild() {
166+
return {Status::NeedsCascadingBuild, llvm::sys::TimePoint<>::min()};
150167
}
151168
};
152169

@@ -166,7 +183,8 @@ class IncrementalJobAction : public JobAction {
166183

167184
public:
168185
static bool classof(const Action *A) {
169-
return A->getKind() == Action::Kind::CompileJob;
186+
return A->getKind() == Action::Kind::CompileJob ||
187+
A->getKind() == Action::Kind::MergeModuleJob;
170188
}
171189
};
172190

@@ -263,12 +281,12 @@ class REPLJobAction : public JobAction {
263281
}
264282
};
265283

266-
class MergeModuleJobAction : public JobAction {
284+
class MergeModuleJobAction : public IncrementalJobAction {
267285
virtual void anchor() override;
268286
public:
269-
MergeModuleJobAction(ArrayRef<const Action *> Inputs)
270-
: JobAction(Action::Kind::MergeModuleJob, Inputs,
271-
file_types::TY_SwiftModuleFile) {}
287+
MergeModuleJobAction(ArrayRef<const Action *> Inputs, InputInfo input)
288+
: IncrementalJobAction(Action::Kind::MergeModuleJob, Inputs,
289+
file_types::TY_SwiftModuleFile, input) {}
272290

273291
static bool classof(const Action *A) {
274292
return A->getKind() == Action::Kind::MergeModuleJob;

lib/Driver/Compilation.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ namespace driver {
446446

447447
std::vector<const Job*>
448448
reloadAndRemarkDeps(const Job *FinishedCmd, int ReturnCode,
449-
const bool forRanges) {
449+
const bool forRanges) {
450450
const CommandOutput &Output = FinishedCmd->getOutput();
451451
StringRef DependenciesFile =
452452
Output.getAdditionalOutputForType(file_types::TY_SwiftDeps);
@@ -458,7 +458,8 @@ namespace driver {
458458
// coarse dependencies that always affect downstream nodes), but we're
459459
// not using either of those right now, and this logic should probably
460460
// be revisited when we are.
461-
assert(FinishedCmd->getCondition() == Job::Condition::Always);
461+
assert(isa<MergeModuleJobAction>(FinishedCmd->getSource()) ||
462+
FinishedCmd->getCondition() == Job::Condition::Always);
462463
return {};
463464
}
464465
const bool compileExitedNormally =
@@ -907,6 +908,7 @@ namespace driver {
907908
return everyIncrementalJob;
908909
};
909910

911+
const Job *mergeModulesJob = nullptr;
910912
CommandSet jobsToSchedule;
911913
CommandSet initialCascadingCommands;
912914
for (const Job *cmd : Comp.getJobs()) {
@@ -915,6 +917,11 @@ namespace driver {
915917
continue;
916918
}
917919

920+
if (isa<MergeModuleJobAction>(cmd->getSource())) {
921+
assert(!mergeModulesJob && "multiple scheduled merge-modules jobs?");
922+
mergeModulesJob = cmd;
923+
}
924+
918925
const Optional<std::pair<bool, bool>> shouldSchedAndIsCascading =
919926
computeShouldInitiallyScheduleJobAndDependendents(cmd, forRanges);
920927
if (!shouldSchedAndIsCascading)
@@ -936,6 +943,15 @@ namespace driver {
936943
collectIncrementalExternallyDependentJobsFromDependencyGraph(
937944
forRanges))
938945
jobsToSchedule.insert(cmd);
946+
947+
// The merge-modules job is special: it *must* be scheduled if any other
948+
// job has been scheduled because any other job can influence the
949+
// structure of the resulting module. Additionally, the initial scheduling
950+
// predicate above is only aware of intra-module changes. External
951+
// dependencies changing *must* cause merge-modules to be scheduled.
952+
if (!jobsToSchedule.empty() && mergeModulesJob) {
953+
jobsToSchedule.insert(mergeModulesJob);
954+
}
939955
return jobsToSchedule;
940956
}
941957

@@ -1031,6 +1047,13 @@ namespace driver {
10311047
/// But returns None if there was a dependency read error.
10321048
Optional<std::pair<Job::Condition, bool>>
10331049
loadDependenciesAndComputeCondition(const Job *const Cmd, bool forRanges) {
1050+
// merge-modules Jobs do not have .swiftdeps files associated with them,
1051+
// however, their compilation condition is computed as a function of their
1052+
// inputs, so their condition can be used as normal.
1053+
if (isa<MergeModuleJobAction>(Cmd->getSource())) {
1054+
return std::make_pair(Cmd->getCondition(), true);
1055+
}
1056+
10341057
// Try to load the dependencies file for this job. If there isn't one, we
10351058
// always have to run the job, but it doesn't affect any other jobs. If
10361059
// there should be one but it's not present or can't be loaded, we have to
@@ -1163,7 +1186,12 @@ namespace driver {
11631186
continue;
11641187
}
11651188

1166-
// Can we run a cross-module incremental build at all? If not, fallback.
1189+
// Is this module out of date? If not, just keep searching.
1190+
if (Comp.getLastBuildTime() >= depStatus.getLastModificationTime())
1191+
continue;
1192+
1193+
// Can we run a cross-module incremental build at all?
1194+
// If not, fall back.
11671195
if (!Comp.getEnableCrossModuleIncrementalBuild()) {
11681196
fallbackToExternalBehavior(external);
11691197
continue;
@@ -1609,8 +1637,8 @@ namespace driver {
16091637
CompileJobAction::InputInfo info;
16101638
info.previousModTime = entry.first->getInputModTime();
16111639
info.status = entry.second ?
1612-
CompileJobAction::InputInfo::NeedsCascadingBuild :
1613-
CompileJobAction::InputInfo::NeedsNonCascadingBuild;
1640+
CompileJobAction::InputInfo::Status::NeedsCascadingBuild :
1641+
CompileJobAction::InputInfo::Status::NeedsNonCascadingBuild;
16141642
inputs[&inputFile->getInputArg()] = info;
16151643
}
16161644
}
@@ -1627,7 +1655,7 @@ namespace driver {
16271655

16281656
CompileJobAction::InputInfo info;
16291657
info.previousModTime = entry->getInputModTime();
1630-
info.status = CompileJobAction::InputInfo::UpToDate;
1658+
info.status = CompileJobAction::InputInfo::Status::UpToDate;
16311659
inputs[&inputFile->getInputArg()] = info;
16321660
}
16331661
}

lib/Driver/CompilationRecord.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,12 @@ inline static StringRef getName(TopLevelKey Key) {
5959
inline static StringRef
6060
getIdentifierForInputInfoStatus(CompileJobAction::InputInfo::Status Status) {
6161
switch (Status) {
62-
case CompileJobAction::InputInfo::UpToDate:
62+
case CompileJobAction::InputInfo::Status::UpToDate:
6363
return "";
64-
case CompileJobAction::InputInfo::NewlyAdded:
65-
case CompileJobAction::InputInfo::NeedsCascadingBuild:
64+
case CompileJobAction::InputInfo::Status::NewlyAdded:
65+
case CompileJobAction::InputInfo::Status::NeedsCascadingBuild:
6666
return "!dirty";
67-
case CompileJobAction::InputInfo::NeedsNonCascadingBuild:
67+
case CompileJobAction::InputInfo::Status::NeedsNonCascadingBuild:
6868
return "!private";
6969
}
7070

@@ -76,11 +76,11 @@ getIdentifierForInputInfoStatus(CompileJobAction::InputInfo::Status Status) {
7676
/// compilation record file (.swiftdeps file).
7777
inline static Optional<CompileJobAction::InputInfo::Status>
7878
getInfoStatusForIdentifier(StringRef Identifier) {
79-
return llvm::StringSwitch<Optional<
80-
CompileJobAction::InputInfo::Status>>(Identifier)
81-
.Case("", CompileJobAction::InputInfo::UpToDate)
82-
.Case("!dirty", CompileJobAction::InputInfo::NeedsCascadingBuild)
83-
.Case("!private", CompileJobAction::InputInfo::NeedsNonCascadingBuild)
79+
using InputStatus = CompileJobAction::InputInfo::Status;
80+
return llvm::StringSwitch<Optional<InputStatus>>(Identifier)
81+
.Case("", InputStatus::UpToDate)
82+
.Case("!dirty", InputStatus::NeedsCascadingBuild)
83+
.Case("!private", InputStatus::NeedsNonCascadingBuild)
8484
.Default(None);
8585
}
8686

0 commit comments

Comments
 (0)