diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 8a47df687be..01d057a186d 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -263,6 +263,9 @@ public: /// Optional table of counters to report, nullptr when not collecting. UnifiedStatsReporter *Stats = nullptr; + /// Set a new stats reporter. + void setStatsReporter(UnifiedStatsReporter *stats); + private: /// \brief The current generation number, which reflects the number of /// times that external modules have been loaded. diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 6b668149885..985b4c71290 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -41,6 +41,7 @@ using llvm::Optional; using llvm::None; class DiagnosticEngine; +class UnifiedStatsReporter; /// Pretty stack trace handler for an arbitrary request. template @@ -57,6 +58,12 @@ public: } }; +/// Report that a request of the given kind is being evaluated, so it +/// can be recoded by the stats reporter. +template +void reportEvaluatedRequest(UnifiedStatsReporter &stats, + const Request &request) { } + /// Evaluation engine that evaluates and caches "requests", checking for cyclic /// dependencies along the way. /// @@ -127,6 +134,10 @@ class Evaluator { /// Whether to diagnose cycles or ignore them completely. CycleDiagnosticKind shouldDiagnoseCycles; + /// Used to report statistics about which requests were evaluated, if + /// non-null. + UnifiedStatsReporter *stats = nullptr; + /// A vector containing all of the active evaluation requests, which /// is treated as a stack and is used to detect cycles. llvm::SetVector activeRequests; @@ -150,6 +161,10 @@ public: /// diagnostics through the given diagnostics engine. Evaluator(DiagnosticEngine &diags, CycleDiagnosticKind shouldDiagnoseCycles); + /// Set the unified stats reporter through which evaluated-request + /// statistics will be recorded. + void setStatsReporter(UnifiedStatsReporter *stats) { this->stats = stats; } + /// Evaluate the given request and produce its result, /// consulting/populating the cache as required. template @@ -228,6 +243,10 @@ private: dependencies[request].clear(); PrettyStackTraceRequest prettyStackTrace(request); + + /// Update statistics. + if (stats) reportEvaluatedRequest(*stats, request); + return request(*this); } @@ -245,6 +264,11 @@ private: // them now anyway. dependencies[request].clear(); + PrettyStackTraceRequest prettyStackTrace(request); + + /// Update statistics. + if (stats) reportEvaluatedRequest(*stats, request); + // Service the request. auto result = request(*this); diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def index 0a64bbedd56..ad90a8a32e1 100644 --- a/include/swift/Basic/Statistics.def +++ b/include/swift/Basic/Statistics.def @@ -195,6 +195,11 @@ FRONTEND_STATISTIC(Sema, NumTypesValidated) /// Number of lazy iterable declaration contexts left unloaded. FRONTEND_STATISTIC(Sema, NumUnloadedLazyIterableDeclContexts) +/// All type check requests go into the Sema area. +#define SWIFT_TYPEID(NAME) FRONTEND_STATISTIC(Sema, NAME) +#include "swift/Sema/TypeCheckerTypeIDZone.def" +#undef SWIFT_TYPEID + /// The next 10 statistics count 5 kinds of SIL entities present /// after the SILGen and SILOpt phases. The entities are functions, /// vtables, witness tables, default witness tables and global @@ -229,4 +234,5 @@ FRONTEND_STATISTIC(IRModule, NumIRInsts) /// of the frontend job, which should be the same as the size of /// the .o file you find on disk after the frontend exits. FRONTEND_STATISTIC(LLVM, NumLLVMBytesOutput) + #endif diff --git a/include/swift/Sema/TypeCheckRequests.h b/include/swift/Sema/TypeCheckRequests.h index ec62a095acb..2da145908e8 100644 --- a/include/swift/Sema/TypeCheckRequests.h +++ b/include/swift/Sema/TypeCheckRequests.h @@ -19,6 +19,7 @@ #include "swift/AST/Type.h" #include "swift/AST/Evaluator.h" #include "swift/AST/SimpleRequest.h" +#include "swift/Basic/Statistic.h" #include "llvm/ADT/Hashing.h" namespace swift { @@ -127,6 +128,16 @@ public: #define SWIFT_TYPEID_HEADER "swift/Sema/TypeCheckerTypeIDZone.def" #include "swift/Basic/DefineTypeIDZone.h" +// Set up reporting of evaluated requests. +#define SWIFT_TYPEID(RequestType) \ +template<> \ +inline void reportEvaluatedRequest(UnifiedStatsReporter &stats, \ + const RequestType &request) { \ + ++stats.getFrontendCounters().RequestType; \ +} +#include "swift/Sema/TypeCheckerTypeIDZone.def" +#undef SWIFT_TYPEID + } // end namespace swift #endif // SWIFT_SEMA_REQUESTS_H diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5eb6fe31fd0..61486df9bae 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -528,6 +528,12 @@ llvm::BumpPtrAllocator &ASTContext::getAllocator(AllocationArena arena) const { llvm_unreachable("bad AllocationArena"); } +/// Set a new stats reporter. +void ASTContext::setStatsReporter(UnifiedStatsReporter *stats) { + Stats = stats; + evaluator.setStatsReporter(stats); +} + syntax::SyntaxArena &ASTContext::getSyntaxArena() const { return getImpl().TheSyntaxArena; } diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index b5d779459b2..97798274ab8 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -1802,7 +1802,7 @@ int swift::performFrontend(ArrayRef Args, // Install stats-reporter somewhere visible for subsystems that // need to bump counters as they work, rather than measure // accumulated work on completion (mostly: TypeChecker). - Instance->getASTContext().Stats = StatsReporter.get(); + Instance->getASTContext().setStatsReporter(StatsReporter.get()); } // The compiler instance has been configured; notify our observer. diff --git a/test/decl/class/circular_inheritance.swift b/test/decl/class/circular_inheritance.swift index f4dad621f94..f75e56c9389 100644 --- a/test/decl/class/circular_inheritance.swift +++ b/test/decl/class/circular_inheritance.swift @@ -1,8 +1,13 @@ +// RUN: rm -rf %t/stats-dir +// RUN: mkdir -p %t/stats-dir // RUN: %target-typecheck-verify-swift -// RUN: not %target-swift-frontend -typecheck -debug-cycles %s -output-request-graphviz %t.dot 2> %t.cycles +// RUN: not %target-swift-frontend -typecheck -debug-cycles %s -output-request-graphviz %t.dot -stats-output-dir %t/stats-dir 2> %t.cycles // RUN: %FileCheck %s < %t.cycles // RUN: %FileCheck -check-prefix CHECK-DOT %s < %t.dot +// Check that we produced superclass type requests. +// RUN: %{python} %utils/process-stats-dir.py --evaluate 'SuperclassTypeRequest == 16' %t/stats-dir + class C : B { } // expected-error{{circular class inheritance 'C' -> 'B' -> 'A' -> 'C'}} class B : A { } // expected-note{{class 'B' declared here}} class A : C { } // expected-note{{class 'A' declared here}}