Skip to content

Commit 73255ab

Browse files
authored
Merge pull request #84265 from hamishknight/tracksuit
[Frontend] Only enable request reference tracking when needed
2 parents 864e450 + cdfab78 commit 73255ab

File tree

5 files changed

+29
-6
lines changed

5 files changed

+29
-6
lines changed

docs/RequestEvaluator.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,8 @@ To define a request as a dependency source, it must implement an accessor for th
6666

6767
## Open Projects
6868

69-
The request-evaluator is relatively new to the Swift compiler, having been introduced in mid-2018. There are a number of improvements that can be made to the evaluator itself and how it is used in the compiler:
69+
There are a number of improvements that can be made to the evaluator itself and how it is used in the compiler:
7070

71-
* The evaluator uses a `DenseMap<AnyRequest, AnyValue>` as its cache: we can almost certainly do better with per-request-kind caches that don't depend on so much type erasure.
7271
* Explore how best to cache data structures in the evaluator. For example, caching `std::vector<T>` or `std::string` implies that we'll make copies of the underlying data structure each time we access the data. Could we automatically intern the data into an allocation arena owned by the evaluator, and vend `ArrayRef<T>` and `StringRef` to clients instead?
7372
* Cycle diagnostics are far too complicated and produce very poor results. Consider replacing the current `diagnoseCycle`/`noteCycleStep` scheme with a single method that produces summary information (e.g., a short summary string + source location information) and provides richer diagnostics from that string.
7473
* The `isCached()` check to determine whether a specific instance of a request is worth caching may be at the wrong level, because one generally has to duplicate effort (or worse, code!) to make the decision in `isCached()`. Consider whether the `evaluator()` function could return something special to say "produce this value without caching" vs. the normal "produce this value with caching".

include/swift/AST/Evaluator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/EvaluatorDependencies.h"
2323
#include "swift/AST/RequestCache.h"
2424
#include "swift/Basic/AnyValue.h"
25+
#include "swift/Basic/Assertions.h"
2526
#include "swift/Basic/Debug.h"
2627
#include "swift/Basic/LangOptions.h"
2728
#include "swift/Basic/Statistic.h"
@@ -208,6 +209,7 @@ class Evaluator {
208209
void enumerateReferencesInFile(
209210
const SourceFile *SF,
210211
evaluator::DependencyRecorder::ReferenceEnumerator f) const {
212+
ASSERT(recorder.isRecordingEnabled() && "Dep recording should be enabled");
211213
return recorder.enumerateReferencesInFile(SF, f);
212214
}
213215

@@ -414,6 +416,8 @@ class Evaluator {
414416
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
415417
void handleDependencySinkRequest(const Request &r,
416418
const typename Request::OutputType &o) {
419+
if (!recorder.isRecordingEnabled())
420+
return;
417421
evaluator::DependencyCollector collector(recorder);
418422
r.writeDependencySink(collector, o);
419423
}
@@ -425,6 +429,8 @@ class Evaluator {
425429
template <typename Request,
426430
typename std::enable_if<Request::isDependencySource>::type * = nullptr>
427431
void handleDependencySourceRequest(const Request &r) {
432+
if (!recorder.isRecordingEnabled())
433+
return;
428434
auto source = r.readDependencySource(recorder);
429435
if (!source.isNull() && source.get()->isPrimary()) {
430436
recorder.handleDependencySourceRequest(r, source.get());

include/swift/AST/EvaluatorDependencies.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class DependencyRecorder {
9494
public:
9595
DependencyRecorder(bool shouldRecord) : shouldRecord(shouldRecord) {}
9696

97+
/// Whether dependency recording is enabled.
98+
bool isRecordingEnabled() const { return shouldRecord; }
99+
97100
/// Push a new empty set onto the activeRequestReferences stack.
98101
template<typename Request>
99102
void beginRequest();

lib/Frontend/Frontend.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,16 @@ void CompilerInstance::recordPrimaryInputBuffer(unsigned BufID) {
308308
PrimaryBufferIDs.insert(BufID);
309309
}
310310

311+
static bool shouldEnableRequestReferenceTracking(const CompilerInstance &CI) {
312+
// Enable request reference dependency tracking when we're either writing
313+
// dependencies for incremental mode, verifying dependencies, or collecting
314+
// stats.
315+
auto &opts = CI.getInvocation().getFrontendOptions();
316+
return opts.InputsAndOutputs.hasReferenceDependenciesFilePath() ||
317+
opts.EnableIncrementalDependencyVerifier ||
318+
!opts.StatsOutputDir.empty();
319+
}
320+
311321
bool CompilerInstance::setUpASTContextIfNeeded() {
312322
if (FrontendOptions::doesActionBuildModuleFromInterface(
313323
Invocation.getFrontendOptions().RequestedAction) &&
@@ -318,10 +328,8 @@ bool CompilerInstance::setUpASTContextIfNeeded() {
318328
return false;
319329
}
320330

321-
// For the time being, we only need to record dependencies in batch mode
322-
// and single file builds.
323-
Invocation.getLangOptions().RecordRequestReferences
324-
= !isWholeModuleCompilation();
331+
Invocation.getLangOptions().RecordRequestReferences =
332+
shouldEnableRequestReferenceTracking(*this);
325333

326334
Context.reset(ASTContext::get(
327335
Invocation.getLangOptions(), Invocation.getTypeCheckerOptions(),

test/Driver/createCompilerInvocation.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,10 @@
4040
// NOOUTPUT_ARGS-DAG: -typecheck
4141
// NOOUTPUT_ARGS-DAG: -module-name
4242
// NOOUTPUT_ARGS: Frontend Arguments END
43+
44+
// Make sure that '-incremental' is ignored, we don't want SourceKit to run with
45+
// reference dependency tracking enabled. The legacy driver simply doesn't
46+
// implement incremental compilation, but make sure when we switch to the new
47+
// driver this doesn't start failing.
48+
// RUN: %swift-ide-test_plain -test-createCompilerInvocation -incremental %S/Input/main.swift | %FileCheck --check-prefix INCREMENTAL %s
49+
// INCREMENTAL-NOT: emit-reference-dependencies

0 commit comments

Comments
 (0)