Skip to content

Commit f696aab

Browse files
author
David Ungar
authored
Merge pull request #29246 from davidungar/fine-grained-off-but-w-tests-rb
[Incremental] Fixes for fine-grained dependencies + tests for them, but off-by-default
2 parents 0895235 + 7f4205e commit f696aab

File tree

334 files changed

+11277
-482
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

334 files changed

+11277
-482
lines changed

include/swift/AST/FineGrainedDependencies.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,8 @@ class SourceFileDepGraph {
785785
llvm::StringMap<std::vector<std::pair<std::string, std::string>>>
786786
compoundNamesByRDK);
787787

788+
static constexpr char noncascadingOrPrivatePrefix = '#';
789+
788790
/// Nodes are owned by the graph.
789791
~SourceFileDepGraph() {
790792
forEachNode([&](SourceFileDepGraphNode *n) { delete n; });
@@ -793,7 +795,7 @@ class SourceFileDepGraph {
793795
/// Goes at the start of an emitted YAML file to help tools recognize it.
794796
/// May vary in the future according to version, etc.
795797
std::string yamlProlog(const bool hadCompilationError) const {
796-
return std::string("# Experimental\n") +
798+
return std::string("# Fine-grained v0\n") +
797799
(!hadCompilationError ? ""
798800
: "# Dependencies are unknown because a "
799801
"compilation error occurred.\n");

include/swift/Driver/Compilation.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,9 @@ class Compilation {
529529
/// sequence of inputs the driver was initially invoked with.
530530
///
531531
/// Also use to write out information in a consistent order.
532+
template <typename JobCollection>
532533
void sortJobsToMatchCompilationInputs(
533-
ArrayRef<const Job *> unsortedJobs,
534+
const JobCollection &unsortedJobs,
534535
SmallVectorImpl<const Job *> &sortedJobs) const;
535536

536537
private:

include/swift/Driver/FineGrainedDependencyDriverGraph.h

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@ class ModuleDepGraph {
164164
std::unordered_set<std::string> externalDependencies;
165165

166166
/// The new version of "Marked."
167-
/// Aka "isMarked". Holds the swiftDeps paths for jobs the driver has or will
168-
/// schedule.
169-
/// TODO: Move scheduledJobs out of the graph, ultimately.
170-
std::unordered_set<std::string> swiftDepsOfJobsThatNeedRunning;
167+
/// Aka "isMarked".
168+
/// If job is in here, all of its dependent jobs have already been searched
169+
/// for jobs that depend on them, OR the job is about to be scheduled and
170+
/// we'll need to run all dependent jobs after it completes. (See the call to
171+
/// \c markIntransitive in \c shouldScheduleCompileJobAccordingToCondition.)
172+
std::unordered_set<std::string> swiftDepsOfMarkedJobs;
171173

172174
/// Keyed by swiftdeps filename, so we can get back to Jobs.
173175
std::unordered_map<std::string, const driver::Job *> jobsBySwiftDeps;
@@ -307,6 +309,10 @@ class ModuleDepGraph {
307309
/// For the dot file.
308310
std::string getGraphID() const { return "driver"; }
309311

312+
void forCorrespondingImplementationOfProvidedInterface(
313+
const ModuleDepGraphNode *,
314+
function_ref<void(ModuleDepGraphNode *)>) const;
315+
310316
void forEachUseOf(const ModuleDepGraphNode *def,
311317
function_ref<void(const ModuleDepGraphNode *use)>);
312318

@@ -326,6 +332,8 @@ class ModuleDepGraph {
326332
/// Interface to status quo code in the driver.
327333
bool isMarked(const driver::Job *) const;
328334

335+
bool isSwiftDepsMarked(StringRef swiftDeps) const;
336+
329337
/// Given a "cascading" job, that is a job whose dependents must be recompiled
330338
/// when this job is recompiled, Compute two sets of jobs:
331339
/// 1. Return value (via visited) is the set of jobs needing recompilation
@@ -334,9 +342,9 @@ class ModuleDepGraph {
334342
/// are recompiled. Such jobs are added to the \ref scheduledJobs set, and
335343
/// accessed via \ref isMarked.
336344
///
337-
/// Only return jobs marked that were previously unmarked. Not required for
338-
/// the driver because it won't run a job twice, but required for the unit
339-
/// test.
345+
/// Returns jobs to be run because of changes to any/ever node in the
346+
/// argument. Only return jobs marked that were previously unmarked, assuming
347+
/// previously marked jobs are already scheduled.
340348
std::vector<const driver::Job*> markTransitive(
341349
const driver::Job *jobToBeRecompiled, const void *ignored = nullptr);
342350

@@ -413,7 +421,7 @@ class ModuleDepGraph {
413421
/// Integrate a SourceFileDepGraph into the receiver.
414422
/// Integration happens when the driver needs to read SourceFileDepGraph.
415423
CoarseGrainedDependencyGraphImpl::LoadResult
416-
integrate(const SourceFileDepGraph &);
424+
integrate(const SourceFileDepGraph &, StringRef swiftDepsOfJob);
417425

418426
enum class LocationOfPreexistingNode { nowhere, here, elsewhere };
419427

@@ -431,7 +439,8 @@ class ModuleDepGraph {
431439
bool
432440
integrateSourceFileDepGraphNode(const SourceFileDepGraph &g,
433441
const SourceFileDepGraphNode *integrand,
434-
const PreexistingNodeIfAny preexistingMatch);
442+
const PreexistingNodeIfAny preexistingMatch,
443+
StringRef swiftDepsOfJob);
435444

436445
/// Integrate the \p integrand, a node that represents a Decl in the swiftDeps
437446
/// file being integrated. \p preexistingNodeInPlace holds the node
@@ -442,7 +451,7 @@ class ModuleDepGraph {
442451
/// ModuleDepGraphNode.
443452
std::pair<bool, ModuleDepGraphNode *>
444453
integrateSourceFileDeclNode(const SourceFileDepGraphNode *integrand,
445-
StringRef swiftDepsOfSourceFileGraph,
454+
StringRef swiftDepsOfJob,
446455
const PreexistingNodeIfAny preexistingMatch);
447456

448457
/// Create a brand-new ModuleDepGraphNode to integrate \p integrand.
@@ -463,14 +472,25 @@ class ModuleDepGraph {
463472
/// Given a definition node, and a list of already found dependents,
464473
/// recursively add transitive closure of dependents of the definition
465474
/// into the already found dependents.
475+
///
476+
/// \param foundDependents gets filled out with all dependent nodes found
477+
/// \param definition the starting definition
478+
/// \param shouldConsiderUse returns true if a use should be considered
466479
void findDependentNodes(
467480
std::unordered_set<const ModuleDepGraphNode *> &foundDependents,
468-
const ModuleDepGraphNode *definition);
481+
const ModuleDepGraphNode *definition,
482+
function_ref<bool(const ModuleDepGraphNode *use)> shouldConsiderUse);
469483

470484
/// Givien a set of nodes, return the set of swiftDeps for the jobs those
471485
/// nodes are in.
472-
llvm::StringSet<> computeSwiftDepsFromInterfaceNodes(
473-
ArrayRef<const ModuleDepGraphNode *> nodes);
486+
std::vector<std::string>
487+
computeSwiftDepsFromNodes(ArrayRef<const ModuleDepGraphNode *> nodes) const;
488+
489+
std::vector<const driver::Job *>
490+
getUnmarkedJobsFrom(const ArrayRef<const ModuleDepGraphNode *> nodes) const;
491+
492+
/// Mark any jobs for these nodes
493+
void markJobsFrom(ArrayRef<const ModuleDepGraphNode *>);
474494

475495
/// Record a visit to this node for later dependency printing
476496
size_t traceArrival(const ModuleDepGraphNode *visitedNode);
@@ -483,8 +503,8 @@ class ModuleDepGraph {
483503
const driver::Job *dependentJob);
484504

485505
/// Return true if job was not scheduled before
486-
bool recordJobNeedsRunning(StringRef swiftDeps) {
487-
return swiftDepsOfJobsThatNeedRunning.insert(swiftDeps).second;
506+
bool markJobViaSwiftDeps(StringRef swiftDeps) {
507+
return swiftDepsOfMarkedJobs.insert(swiftDeps).second;
488508
}
489509

490510
/// For debugging and visualization, write out the graph to a dot file.

lib/AST/FineGrainedDependenciesSourceFileDepGraphConstructor.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,17 @@ class SourceFileDepGraphConstructor {
585585
dynamicLookupDepends.push_back(std::make_pair(p.getFirst().userFacingName(), p.getSecond()));
586586

587587
std::vector<std::pair<std::tuple<std::string, std::string, bool>, bool>> memberDepends;
588-
for (const auto &p: SF->getReferencedNameTracker()->getUsedMembers())
588+
for (const auto &p: SF->getReferencedNameTracker()->getUsedMembers()) {
589+
const auto &member = p.getFirst().second;
590+
StringRef emptyOrUserFacingName = member.empty() ? "" : member.userFacingName();
589591
memberDepends.push_back(
590592
std::make_pair(
591593
std::make_tuple(
592594
mangleTypeAsContext(p.getFirst().first),
593-
p.getFirst().second.userFacingName(),
595+
emptyOrUserFacingName,
594596
declIsPrivate(p.getFirst().first)),
595597
p.getSecond()));
598+
}
596599

597600
return SourceFileDepGraphConstructor(
598601
swiftDeps,
@@ -810,7 +813,8 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies(
810813
return false;
811814
});
812815

813-
assert(g.verifyReadsWhatIsWritten(outputPath));
816+
// If path is stdout, cannot read it back, so check for "-"
817+
assert(outputPath == "-" || g.verifyReadsWhatIsWritten(outputPath));
814818

815819
if (alsoEmitDotFile) {
816820
std::string dotFileName = outputPath.str() + ".dot";
@@ -825,44 +829,47 @@ bool swift::fine_grained_dependencies::emitReferenceDependencies(
825829
//==============================================================================
826830
// Entry point from the unit tests
827831
//==============================================================================
832+
static StringRef stripPrefix(const StringRef name) {
833+
return name.ltrim(SourceFileDepGraph::noncascadingOrPrivatePrefix);
834+
}
828835

829836
static std::vector<ContextNameFingerprint>
830837
getBaseNameProvides(ArrayRef<std::string> simpleNames) {
831838
std::vector<ContextNameFingerprint> result;
832839
for (StringRef n : simpleNames)
833-
result.push_back(ContextNameFingerprint("", n.str(), None));
840+
result.push_back(ContextNameFingerprint("", stripPrefix(n).str(), None));
834841
return result;
835842
}
836843

837844
static std::vector<ContextNameFingerprint>
838845
getMangledHolderProvides(ArrayRef<std::string> simpleNames) {
839846
std::vector<ContextNameFingerprint> result;
840847
for (StringRef n : simpleNames)
841-
result.push_back(ContextNameFingerprint(n.str(), "", None));
848+
result.push_back(ContextNameFingerprint(stripPrefix(n).str(), "", None));
842849
return result;
843850
}
844851

845852
static std::vector<ContextNameFingerprint> getCompoundProvides(
846853
ArrayRef<std::pair<std::string, std::string>> compoundNames) {
847854
std::vector<ContextNameFingerprint> result;
848855
for (const auto &p : compoundNames)
849-
result.push_back(ContextNameFingerprint(p.first, p.second, None));
856+
result.push_back(ContextNameFingerprint(stripPrefix(p.first),
857+
stripPrefix(p.second), None));
850858
return result;
851859
}
852860

853-
// Use '_' as a prefix indicating non-cascading
854-
static bool cascades(const std::string &s) { return s.empty() || s[0] != '_'; }
861+
static bool cascades(const std::string &s) { return s.empty() || s[0] != SourceFileDepGraph::noncascadingOrPrivatePrefix; }
855862

856863
// Use '_' as a prefix for a file-private member
857864
static bool isPrivate(const std::string &s) {
858-
return !s.empty() && s[0] == '_';
865+
return !s.empty() && s[0] == SourceFileDepGraph::noncascadingOrPrivatePrefix;
859866
}
860867

861868
static std::vector<std::pair<std::string, bool>>
862869
getSimpleDepends(ArrayRef<std::string> simpleNames) {
863870
std::vector<std::pair<std::string, bool>> result;
864871
for (std::string n : simpleNames)
865-
result.push_back({n, cascades((n))});
872+
result.push_back({stripPrefix(n), cascades((n))});
866873
return result;
867874
}
868875

@@ -881,14 +888,16 @@ getCompoundDepends(
881888
// (On Linux, the compiler needs more verbosity than:
882889
// result.push_back({{n, "", false}, cascades(n)});
883890
result.push_back(
884-
std::make_pair(std::make_tuple(n, std::string(), false), cascades(n)));
891+
std::make_pair(std::make_tuple(stripPrefix(n), std::string(), false), cascades(n)));
885892
}
886893
for (auto &p : compoundNames) {
887894
// Likewise, for Linux expand the following out:
888895
// result.push_back(
889896
// {{p.first, p.second, isPrivate(p.second)}, cascades(p.first)});
890897
result.push_back(
891-
std::make_pair(std::make_tuple(p.first, p.second, isPrivate(p.second)),
898+
std::make_pair(std::make_tuple(stripPrefix(p.first),
899+
stripPrefix(p.second),
900+
isPrivate(p.second)),
892901
cascades(p.first)));
893902
}
894903
return result;

lib/Driver/Compilation.cpp

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,15 @@ namespace driver {
355355
PendingExecution.insert(Cmd);
356356
}
357357

358+
// Sort for ease of testing
359+
template <typename Jobs>
360+
void scheduleCommandsInSortedOrder(const Jobs &jobs) {
361+
llvm::SmallVector<const Job *, 16> sortedJobs;
362+
Comp.sortJobsToMatchCompilationInputs(jobs, sortedJobs);
363+
for (const Job *Cmd : sortedJobs)
364+
scheduleCommandIfNecessaryAndPossible(Cmd);
365+
}
366+
358367
void addPendingJobToTaskQueue(const Job *Cmd) {
359368
// FIXME: Failing here should not take down the whole process.
360369
bool success =
@@ -393,8 +402,7 @@ namespace driver {
393402
<< LogJobArray(AllBlocked) << "\n";
394403
}
395404
BlockingCommands.erase(BlockedIter);
396-
for (auto *Blocked : AllBlocked)
397-
scheduleCommandIfNecessaryAndPossible(Blocked);
405+
scheduleCommandsInSortedOrder(AllBlocked);
398406
}
399407
}
400408

@@ -449,7 +457,7 @@ namespace driver {
449457
diag::warn_unable_to_load_dependencies,
450458
DependenciesFile);
451459
Comp.disableIncrementalBuild(
452-
Twine("malformed swift dependencies file ' ") + DependenciesFile +
460+
Twine("malformed swift dependencies file '") + DependenciesFile +
453461
"'");
454462
}
455463

@@ -485,23 +493,23 @@ namespace driver {
485493
// other recompilations. It is possible that the current code marks
486494
// things that do not need to be marked. Unecessary compilation would
487495
// result if that were the case.
488-
bool wasKnownToNeedRunning = isMarkedInDepGraph(FinishedCmd, forRanges);
496+
bool wasKnownToCascade = isMarkedInDepGraph(FinishedCmd, forRanges);
489497

490-
switch (loadDepGraphFromPath(FinishedCmd, DependenciesFile,
491-
Comp.getDiags(), forRanges)) {
498+
const auto loadResult = loadDepGraphFromPath(
499+
FinishedCmd, DependenciesFile, Comp.getDiags(), forRanges);
500+
switch (loadResult) {
492501
case CoarseGrainedDependencyGraph::LoadResult::HadError:
493502
if (ReturnCode != EXIT_SUCCESS)
494503
// let the next build handle it.
495504
break;
496505
dependencyLoadFailed(DependenciesFile);
497506
// Better try compiling whatever was waiting on more info.
498-
for (const Job *Cmd : DeferredCommands)
499-
scheduleCommandIfNecessaryAndPossible(Cmd);
507+
scheduleCommandsInSortedOrder(DeferredCommands);
500508
DeferredCommands.clear();
501509
break;
502510

503511
case CoarseGrainedDependencyGraph::LoadResult::UpToDate:
504-
if (!wasKnownToNeedRunning)
512+
if (!wasKnownToCascade)
505513
break;
506514
LLVM_FALLTHROUGH;
507515
case CoarseGrainedDependencyGraph::LoadResult::AffectsDownstream:
@@ -695,18 +703,9 @@ namespace driver {
695703
noteBuildingJobs(DependentsInEffect, useRangesForScheduling,
696704
"because of dependencies discovered later");
697705

698-
// Sort dependents for more deterministic behavior
699-
llvm::SmallVector<const Job *, 16> UnsortedDependents;
700-
for (const Job *j : DependentsInEffect)
701-
UnsortedDependents.push_back(j);
702-
llvm::SmallVector<const Job *, 16> SortedDependents;
703-
Comp.sortJobsToMatchCompilationInputs(UnsortedDependents,
704-
SortedDependents);
705-
706-
for (const Job *Cmd : SortedDependents) {
706+
scheduleCommandsInSortedOrder(DependentsInEffect);
707+
for (const Job *Cmd : DependentsInEffect)
707708
DeferredCommands.erase(Cmd);
708-
scheduleCommandIfNecessaryAndPossible(Cmd);
709-
}
710709
return TaskFinishedResponse::ContinueExecution;
711710
}
712711

@@ -1092,6 +1091,12 @@ namespace driver {
10921091
// using markIntransitive and having later functions call
10931092
// markTransitive. That way markIntransitive would be an
10941093
// implementation detail of CoarseGrainedDependencyGraph.
1094+
//
1095+
// As it stands, after this job finishes, this mark will tell the code
1096+
// that this job was known to be "cascading". That knowledge will
1097+
// cause any dependent jobs to be run if it hasn't already been.
1098+
//
1099+
// TODO: I think this is overly tricky
10951100
markIntransitiveInDepGraph(Cmd, forRanges);
10961101
}
10971102
LLVM_FALLTHROUGH;
@@ -2080,17 +2085,22 @@ void Compilation::addDependencyPathOrCreateDummy(
20802085
}
20812086
}
20822087

2088+
template <typename JobCollection>
20832089
void Compilation::sortJobsToMatchCompilationInputs(
2084-
const ArrayRef<const Job *> unsortedJobs,
2090+
const JobCollection &unsortedJobs,
20852091
SmallVectorImpl<const Job *> &sortedJobs) const {
20862092
llvm::DenseMap<StringRef, const Job *> jobsByInput;
20872093
for (const Job *J : unsortedJobs) {
2088-
const CompileJobAction *CJA = cast<CompileJobAction>(&J->getSource());
2089-
const InputAction *IA = CJA->findSingleSwiftInput();
2090-
auto R =
2091-
jobsByInput.insert(std::make_pair(IA->getInputArg().getValue(), J));
2092-
assert(R.second);
2093-
(void)R;
2094+
// Only worry about sorting compilation jobs
2095+
if (const CompileJobAction *CJA =
2096+
dyn_cast<CompileJobAction>(&J->getSource())) {
2097+
const InputAction *IA = CJA->findSingleSwiftInput();
2098+
auto R =
2099+
jobsByInput.insert(std::make_pair(IA->getInputArg().getValue(), J));
2100+
assert(R.second);
2101+
(void)R;
2102+
} else
2103+
sortedJobs.push_back(J);
20942104
}
20952105
for (const InputPair &P : getInputFiles()) {
20962106
auto I = jobsByInput.find(P.second->getValue());
@@ -2099,3 +2109,8 @@ void Compilation::sortJobsToMatchCompilationInputs(
20992109
}
21002110
}
21012111
}
2112+
2113+
template void
2114+
Compilation::sortJobsToMatchCompilationInputs<ArrayRef<const Job *>>(
2115+
const ArrayRef<const Job *> &,
2116+
SmallVectorImpl<const Job *> &sortedJobs) const;

0 commit comments

Comments
 (0)