Skip to content

Commit 8c2c4ab

Browse files
author
David Ungar
committed
Fixes for fine-grained dependencies
1 parent 99e60b0 commit 8c2c4ab

File tree

6 files changed

+191
-110
lines changed

6 files changed

+191
-110
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/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: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ namespace driver {
449449
diag::warn_unable_to_load_dependencies,
450450
DependenciesFile);
451451
Comp.disableIncrementalBuild(
452-
Twine("malformed swift dependencies file ' ") + DependenciesFile +
452+
Twine("malformed swift dependencies file '") + DependenciesFile +
453453
"'");
454454
}
455455

@@ -485,10 +485,11 @@ namespace driver {
485485
// other recompilations. It is possible that the current code marks
486486
// things that do not need to be marked. Unecessary compilation would
487487
// result if that were the case.
488-
bool wasKnownToNeedRunning = isMarkedInDepGraph(FinishedCmd, forRanges);
488+
bool wasKnownToCascade = isMarkedInDepGraph(FinishedCmd, forRanges);
489489

490-
switch (loadDepGraphFromPath(FinishedCmd, DependenciesFile,
491-
Comp.getDiags(), forRanges)) {
490+
const auto loadResult = loadDepGraphFromPath(
491+
FinishedCmd, DependenciesFile, Comp.getDiags(), forRanges);
492+
switch (loadResult) {
492493
case CoarseGrainedDependencyGraph::LoadResult::HadError:
493494
if (ReturnCode != EXIT_SUCCESS)
494495
// let the next build handle it.
@@ -501,7 +502,7 @@ namespace driver {
501502
break;
502503

503504
case CoarseGrainedDependencyGraph::LoadResult::UpToDate:
504-
if (!wasKnownToNeedRunning)
505+
if (!wasKnownToCascade)
505506
break;
506507
LLVM_FALLTHROUGH;
507508
case CoarseGrainedDependencyGraph::LoadResult::AffectsDownstream:
@@ -1092,6 +1093,12 @@ namespace driver {
10921093
// using markIntransitive and having later functions call
10931094
// markTransitive. That way markIntransitive would be an
10941095
// implementation detail of CoarseGrainedDependencyGraph.
1096+
//
1097+
// As it stands, after this job finishes, this mark will tell the code
1098+
// that this job was known to be "cascading". That knowledge will
1099+
// any dependent jobs to be run if they haven't already been.
1100+
//
1101+
// TODO: I think this is overly tricky
10951102
markIntransitiveInDepGraph(Cmd, forRanges);
10961103
}
10971104
LLVM_FALLTHROUGH;

0 commit comments

Comments
 (0)