Skip to content

Commit 880e9e6

Browse files
authored
Merge pull request swiftlang#29089 from slavapestov/request-eval-perf-hack-5.2
Fix some low-hanging request evaluator performance fruit [5.2]
2 parents d6a5f21 + 9bcdade commit 880e9e6

File tree

8 files changed

+70
-53
lines changed

8 files changed

+70
-53
lines changed

include/swift/AST/Evaluator.h

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ class Evaluator {
187187
/// Whether to dump detailed debug info for cycles.
188188
bool debugDumpCycles;
189189

190+
/// Whether we're building a request dependency graph.
191+
bool buildDependencyGraph;
192+
190193
/// Used to report statistics about which requests were evaluated, if
191194
/// non-null.
192195
UnifiedStatsReporter *stats = nullptr;
@@ -237,7 +240,9 @@ class Evaluator {
237240
public:
238241
/// Construct a new evaluator that can emit cyclic-dependency
239242
/// diagnostics through the given diagnostics engine.
240-
Evaluator(DiagnosticEngine &diags, bool debugDumpCycles=false);
243+
Evaluator(DiagnosticEngine &diags,
244+
bool debugDumpCycles,
245+
bool buildDependencyGraph);
241246

242247
/// Emit GraphViz output visualizing the request graph.
243248
void emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath);
@@ -253,26 +258,28 @@ class Evaluator {
253258
void registerRequestFunctions(Zone zone,
254259
ArrayRef<AbstractRequestFunction *> functions);
255260

256-
/// Evaluate the given request and produce its result,
257-
/// consulting/populating the cache as required.
258-
template<typename Request>
261+
/// Retrieve the result produced by evaluating a request that can
262+
/// be cached.
263+
template<typename Request,
264+
typename std::enable_if<Request::isEverCached>::type * = nullptr>
259265
llvm::Expected<typename Request::OutputType>
260266
operator()(const Request &request) {
261-
// Check for a cycle.
262-
if (checkDependency(getCanonicalRequest(request))) {
263-
return llvm::Error(
264-
llvm::make_unique<CyclicalRequestError<Request>>(request, *this));
265-
}
267+
// The request can be cached, but check a predicate to determine
268+
// whether this particular instance is cached. This allows more
269+
// fine-grained control over which instances get cache.
270+
if (request.isCached())
271+
return getResultCached(request);
266272

267-
// Make sure we remove this from the set of active requests once we're
268-
// done.
269-
SWIFT_DEFER {
270-
assert(activeRequests.back().castTo<Request>() == request);
271-
activeRequests.pop_back();
272-
};
273+
return getResultUncached(request);
274+
}
273275

274-
// Get the result.
275-
return getResult(request);
276+
/// Retrieve the result produced by evaluating a request that
277+
/// will never be cached.
278+
template<typename Request,
279+
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
280+
llvm::Expected<typename Request::OutputType>
281+
operator()(const Request &request) {
282+
return getResultUncached(request);
276283
}
277284

278285
/// Evaluate a set of requests and return their results as a tuple.
@@ -340,37 +347,27 @@ class Evaluator {
340347
/// request to the \c activeRequests stack.
341348
bool checkDependency(const AnyRequest &request);
342349

343-
/// Retrieve the result produced by evaluating a request that can
344-
/// be cached.
345-
template<typename Request,
346-
typename std::enable_if<Request::isEverCached>::type * = nullptr>
347-
llvm::Expected<typename Request::OutputType>
348-
getResult(const Request &request) {
349-
// The request can be cached, but check a predicate to determine
350-
// whether this particular instance is cached. This allows more
351-
// fine-grained control over which instances get cache.
352-
if (request.isCached())
353-
return getResultCached(request);
354-
355-
return getResultUncached(request);
356-
}
357-
358-
/// Retrieve the result produced by evaluating a request that
359-
/// will never be cached.
360-
template<typename Request,
361-
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
362-
llvm::Expected<typename Request::OutputType>
363-
getResult(const Request &request) {
364-
return getResultUncached(request);
365-
}
366-
367350
/// Produce the result of the request without caching.
368351
template<typename Request>
369352
llvm::Expected<typename Request::OutputType>
370353
getResultUncached(const Request &request) {
354+
// Check for a cycle.
355+
if (checkDependency(getCanonicalRequest(request))) {
356+
return llvm::Error(
357+
llvm::make_unique<CyclicalRequestError<Request>>(request, *this));
358+
}
359+
360+
// Make sure we remove this from the set of active requests once we're
361+
// done.
362+
SWIFT_DEFER {
363+
assert(activeRequests.back().castTo<Request>() == request);
364+
activeRequests.pop_back();
365+
};
366+
371367
// Clear out the dependencies on this request; we're going to recompute
372368
// them now anyway.
373-
dependencies.find_as(request)->second.clear();
369+
if (buildDependencyGraph)
370+
dependencies.find_as(request)->second.clear();
374371

375372
PrettyStackTraceRequest<Request> prettyStackTrace(request);
376373

include/swift/Basic/LangOptions.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,10 @@ namespace swift {
173173

174174
/// Whether to dump debug info for request evaluator cycles.
175175
bool DebugDumpCycles = false;
176-
176+
177+
/// Whether to build a request dependency graph for debugging.
178+
bool BuildRequestDependencyGraph = false;
179+
177180
/// Enable SIL type lowering
178181
bool EnableSubstSILFunctionTypesForFunctionValues = false;
179182

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,10 @@ def debug_forbid_typecheck_prefix : Separate<["-"], "debug-forbid-typecheck-pref
246246

247247
def debug_cycles : Flag<["-"], "debug-cycles">,
248248
HelpText<"Print out debug dumps when cycles are detected in evaluation">;
249+
def build_request_dependency_graph : Flag<["-"], "build-request-dependency-graph">,
250+
HelpText<"Build request dependency graph">;
249251
def output_request_graphviz : Separate<["-"], "output-request-graphviz">,
250-
HelpText<"Emit GraphViz output visualizing the request graph">;
252+
HelpText<"Emit GraphViz output visualizing the request dependency graph">;
251253

252254
def debug_time_compilation : Flag<["-"], "debug-time-compilation">,
253255
HelpText<"Prints the time taken by each compilation phase">;

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,9 @@ ASTContext::ASTContext(LangOptions &langOpts, TypeCheckerOptions &typeckOpts,
530530
: LangOpts(langOpts),
531531
TypeCheckerOpts(typeckOpts),
532532
SearchPathOpts(SearchPathOpts), SourceMgr(SourceMgr), Diags(Diags),
533-
evaluator(Diags, langOpts.DebugDumpCycles),
533+
evaluator(Diags,
534+
langOpts.DebugDumpCycles,
535+
langOpts.BuildRequestDependencyGraph),
534536
TheBuiltinModule(createBuiltinModule(*this)),
535537
StdlibModuleName(getIdentifier(STDLIB_NAME)),
536538
SwiftShimsModuleName(getIdentifier(SWIFT_SHIMS_NAME)),

lib/AST/Evaluator.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,12 @@ void Evaluator::registerRequestFunctions(
6262
requestFunctionsByZone.push_back({zoneID, functions});
6363
}
6464

65-
Evaluator::Evaluator(DiagnosticEngine &diags, bool debugDumpCycles)
66-
: diags(diags), debugDumpCycles(debugDumpCycles) { }
65+
Evaluator::Evaluator(DiagnosticEngine &diags,
66+
bool debugDumpCycles,
67+
bool buildDependencyGraph)
68+
: diags(diags),
69+
debugDumpCycles(debugDumpCycles),
70+
buildDependencyGraph(buildDependencyGraph) { }
6771

6872
void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) {
6973
std::error_code error;
@@ -72,9 +76,11 @@ void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) {
7276
}
7377

7478
bool Evaluator::checkDependency(const AnyRequest &request) {
75-
// If there is an active request, record it's dependency on this request.
76-
if (!activeRequests.empty())
77-
dependencies[activeRequests.back()].push_back(request);
79+
if (buildDependencyGraph) {
80+
// If there is an active request, record it's dependency on this request.
81+
if (!activeRequests.empty())
82+
dependencies[activeRequests.back()].push_back(request);
83+
}
7884

7985
// Record this as an active request.
8086
if (activeRequests.insert(request)) {

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
390390
if (Args.getLastArg(OPT_debug_cycles))
391391
Opts.DebugDumpCycles = true;
392392

393+
if (Args.getLastArg(OPT_build_request_dependency_graph))
394+
Opts.BuildRequestDependencyGraph = true;
395+
393396
if (const Arg *A = Args.getLastArg(OPT_output_request_graphviz)) {
394397
Opts.RequestEvaluatorGraphVizPath = A->getValue();
395398
}

test/decl/class/circular_inheritance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: rm -rf %t/stats-dir
22
// RUN: mkdir -p %t/stats-dir
33
// RUN: %target-typecheck-verify-swift
4-
// RUN: not %target-swift-frontend -typecheck -debug-cycles %s -output-request-graphviz %t.dot -stats-output-dir %t/stats-dir 2> %t.cycles
4+
// RUN: not %target-swift-frontend -typecheck -debug-cycles %s -build-request-dependency-graph -output-request-graphviz %t.dot -stats-output-dir %t/stats-dir 2> %t.cycles
55
// RUN: %FileCheck %s < %t.cycles
66
// RUN: %FileCheck -check-prefix CHECK-DOT %s < %t.dot
77

unittests/AST/ArithmeticEvaluator.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ TEST(ArithmeticEvaluator, Simple) {
210210

211211
SourceManager sourceMgr;
212212
DiagnosticEngine diags(sourceMgr);
213-
Evaluator evaluator(diags);
213+
Evaluator evaluator(diags,
214+
/*debugDumpCycles=*/false,
215+
/*buildDependencyGraph=*/true);
214216
evaluator.registerRequestFunctions(Zone::ArithmeticEvaluator,
215217
arithmeticRequestFunctions);
216218

@@ -333,7 +335,9 @@ TEST(ArithmeticEvaluator, Cycle) {
333335

334336
SourceManager sourceMgr;
335337
DiagnosticEngine diags(sourceMgr);
336-
Evaluator evaluator(diags);
338+
Evaluator evaluator(diags,
339+
/*debugDumpCycles=*/false,
340+
/*buildDependencyGraph=*/false);
337341
evaluator.registerRequestFunctions(Zone::ArithmeticEvaluator,
338342
arithmeticRequestFunctions);
339343

0 commit comments

Comments
 (0)