Skip to content

Commit 6f3b618

Browse files
authored
Merge pull request #15665 from graydon/everybody-gets-a-tracer
2 parents be1aae4 + 4fcdbac commit 6f3b618

27 files changed

+326
-26
lines changed

docs/RequestEvaluator.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ The request-evaluator is relatively new to the Swift compiler, having been intro
6161
* Add API to the evaluator to add a specific (request, result) pair to the cache, and make it "stick" even if the cache is cleared. This API should be usable from places in the compiler that inject specific known state, such as when the Clang importer synthesizes ASTs.
6262
* 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?
6363
* Sometimes the compiler crashes or otherwise fails due to a cycle detected by the evaluator but (currently) not diagnosed. Add some logic to record cycles encountered during compilation, and if the compiler crashes (or otherwise fails), dump the cycles at the end of execution to help with debugging.
64-
* Automatically create appropriate [`FrontendStatsTracer`](https://github.com/apple/swift/blob/master/include/swift/Basic/Statistic.h) instances when evaluating requests that embed AST references to anything the stats-tracing logic can handle (`Decl*`, `ProtocolConformance*`, etc.). Try to do this automatically for `SimpleRequest` so specific requests don't need to opt in for it to work.
6564
* 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.
6665
* 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".
6766
* Try to eliminate more boilerplate from subclasses of [`SimpleRequest`](https://github.com/apple/swift/blob/master/include/swift/AST/SimpleRequest.h). We are going to have a *lot* of requests.

include/swift/AST/Evaluator.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/Basic/AnyValue.h"
2323
#include "swift/Basic/CycleDiagnosticKind.h"
2424
#include "swift/Basic/Defer.h"
25+
#include "swift/Basic/Statistic.h"
2526
#include "llvm/ADT/DenseMap.h"
2627
#include "llvm/ADT/Optional.h"
2728
#include "llvm/ADT/SetVector.h"
@@ -338,7 +339,8 @@ class Evaluator {
338339

339340
PrettyStackTraceRequest<Request> prettyStackTrace(request);
340341

341-
/// Update statistics.
342+
// Trace and/or count statistics.
343+
FrontendStatsTracer statsTracer = make_tracer(stats, request);
342344
if (stats) reportEvaluatedRequest(*stats, request);
343345

344346
return getRequestFunction<Request>()(request, *this);

include/swift/AST/SimpleRequest.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/DiagnosticEngine.h"
2121
#include "swift/AST/DiagnosticsCommon.h"
2222
#include "swift/Basic/SimpleDisplay.h"
23+
#include "swift/Basic/Statistic.h"
2324
#include "swift/Basic/TypeID.h"
2425
#include "llvm/ADT/Hashing.h"
2526
#include "llvm/ADT/STLExtras.h"
@@ -160,8 +161,12 @@ class SimpleRequest {
160161
out << TypeID<Derived>::getName();
161162
simple_display(out, request.storage);
162163
}
163-
};
164164

165+
friend FrontendStatsTracer
166+
make_tracer(UnifiedStatsReporter *Reporter, const Derived &request) {
167+
return make_tracer(Reporter, TypeID<Derived>::getName(), request.storage);
168+
}
169+
};
165170
}
166171

167172
#endif // SWIFT_BASIC_SIMPLEREQUEST_H

include/swift/Basic/Statistic.h

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "swift/Basic/LLVM.h"
1919
#include "swift/Basic/Timer.h"
2020

21+
#include <thread>
22+
#include <tuple>
23+
2124
#define SWIFT_FUNC_STAT \
2225
do { \
2326
static llvm::Statistic FStat = \
@@ -59,7 +62,11 @@ class ProtocolConformance;
5962
class Expr;
6063
class SILFunction;
6164
class FrontendStatsTracer;
65+
class Pattern;
66+
class SourceFile;
6267
class SourceManager;
68+
class Stmt;
69+
class TypeRepr;
6370

6471
class UnifiedStatsReporter {
6572

@@ -125,6 +132,7 @@ class UnifiedStatsReporter {
125132
SmallString<128> TraceFilename;
126133
SmallString<128> ProfileDirname;
127134
llvm::TimeRecord StartedTime;
135+
std::thread::id MainThreadID;
128136

129137
// This is unique_ptr because NamedRegionTimer is non-copy-constructable.
130138
std::unique_ptr<llvm::NamedRegionTimer> Timer;
@@ -169,6 +177,7 @@ class UnifiedStatsReporter {
169177

170178
AlwaysOnDriverCounters &getDriverCounters();
171179
AlwaysOnFrontendCounters &getFrontendCounters();
180+
void flushTracesAndProfiles();
172181
void noteCurrentProcessExitStatus(int);
173182
void saveAnyFrontendStatsEvents(FrontendStatsTracer const &T, bool IsEntry);
174183
};
@@ -216,6 +225,14 @@ class FrontendStatsTracer
216225
const Expr *E);
217226
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
218227
const SILFunction *F);
228+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
229+
const SourceFile *F);
230+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
231+
const Stmt *S);
232+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
233+
const Pattern *P);
234+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
235+
const TypeRepr *TR);
219236
};
220237

221238
// In particular cases, we do know how to format traced entities: we declare
@@ -245,6 +262,18 @@ template <>
245262
const UnifiedStatsReporter::TraceFormatter *
246263
FrontendStatsTracer::getTraceFormatter<const SILFunction *>();
247264

265+
template<> const UnifiedStatsReporter::TraceFormatter*
266+
FrontendStatsTracer::getTraceFormatter<const SourceFile *>();
267+
268+
template<> const UnifiedStatsReporter::TraceFormatter*
269+
FrontendStatsTracer::getTraceFormatter<const Stmt *>();
270+
271+
template<> const UnifiedStatsReporter::TraceFormatter*
272+
FrontendStatsTracer::getTraceFormatter<const Pattern *>();
273+
274+
template<> const UnifiedStatsReporter::TraceFormatter*
275+
FrontendStatsTracer::getTraceFormatter<const TypeRepr *>();
276+
248277
// Provide inline definitions for the delegating constructors. These avoid
249278
// introducing a circular dependency between libParse and libSIL. They are
250279
// marked as `inline` explicitly to prevent ODR violations due to multiple
@@ -281,5 +310,88 @@ inline FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R,
281310
const SILFunction *F)
282311
: FrontendStatsTracer(R, S, F, getTraceFormatter<const SILFunction *>()) {}
283312

313+
inline FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R,
314+
StringRef S,
315+
const SourceFile *SF)
316+
: FrontendStatsTracer(R, S, SF, getTraceFormatter<const SourceFile *>()) {}
317+
318+
inline FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R,
319+
StringRef S,
320+
const Stmt *ST)
321+
: FrontendStatsTracer(R, S, ST, getTraceFormatter<const Stmt *>()) {}
322+
323+
inline FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R,
324+
StringRef S,
325+
const Pattern *P)
326+
: FrontendStatsTracer(R, S, P, getTraceFormatter<const Pattern *>()) {}
327+
328+
inline FrontendStatsTracer::FrontendStatsTracer(UnifiedStatsReporter *R,
329+
StringRef S,
330+
const TypeRepr *TR)
331+
: FrontendStatsTracer(R, S, TR, getTraceFormatter<const TypeRepr *>()) {}
332+
333+
/// Utilities for constructing TraceFormatters from entities in the request-evaluator:
334+
335+
template <typename T>
336+
typename std::enable_if<
337+
std::is_constructible<FrontendStatsTracer, UnifiedStatsReporter *,
338+
StringRef, const T *>::value,
339+
FrontendStatsTracer>::type
340+
make_tracer_direct(UnifiedStatsReporter *Reporter, StringRef Name, T *Value) {
341+
return FrontendStatsTracer(Reporter, Name, static_cast<const T *>(Value));
342+
}
343+
344+
template <typename T>
345+
typename std::enable_if<
346+
std::is_constructible<FrontendStatsTracer, UnifiedStatsReporter *,
347+
StringRef, const T *>::value,
348+
FrontendStatsTracer>::type
349+
make_tracer_direct(UnifiedStatsReporter *Reporter, StringRef Name,
350+
const T *Value) {
351+
return FrontendStatsTracer(Reporter, Name, Value);
352+
}
353+
354+
template <typename T>
355+
typename std::enable_if<
356+
!std::is_constructible<FrontendStatsTracer, UnifiedStatsReporter *,
357+
StringRef, const T *>::value,
358+
FrontendStatsTracer>::type
359+
make_tracer_direct(UnifiedStatsReporter *Reporter, StringRef Name, T *Value) {
360+
return FrontendStatsTracer(Reporter, Name);
361+
}
362+
363+
template <typename T>
364+
typename std::enable_if<!std::is_pointer<T>::value, FrontendStatsTracer>::type
365+
make_tracer_direct(UnifiedStatsReporter *Reporter, StringRef Name, T Value) {
366+
return FrontendStatsTracer(Reporter, Name);
367+
}
368+
369+
template <typename T> struct is_pointerunion : std::false_type {};
370+
template <typename T, typename U>
371+
struct is_pointerunion<llvm::PointerUnion<T, U>> : std::true_type {};
372+
373+
template <typename T, typename U>
374+
FrontendStatsTracer make_tracer_pointerunion(UnifiedStatsReporter *Reporter,
375+
StringRef Name,
376+
llvm::PointerUnion<T, U> Value) {
377+
if (Value.template is<T>())
378+
return make_tracer_direct(Reporter, Name, Value.template get<T>());
379+
else
380+
return make_tracer_direct(Reporter, Name, Value.template get<U>());
381+
}
382+
383+
template <typename T>
384+
typename std::enable_if<!is_pointerunion<T>::value, FrontendStatsTracer>::type
385+
make_tracer_pointerunion(UnifiedStatsReporter *Reporter, StringRef Name,
386+
T Value) {
387+
return make_tracer_direct(Reporter, Name, Value);
388+
}
389+
390+
template <typename First, typename... Rest>
391+
FrontendStatsTracer make_tracer(UnifiedStatsReporter *Reporter, StringRef Name,
392+
std::tuple<First, Rest...> Value) {
393+
return make_tracer_pointerunion(Reporter, Name, std::get<0>(Value));
394+
}
395+
284396
} // namespace swift
285397
#endif // SWIFT_BASIC_STATISTIC_H

include/swift/Basic/Timer.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,22 @@
2020
namespace swift {
2121
/// A convenience class for declaring a timer that's part of the Swift
2222
/// compilation timers group.
23+
///
24+
/// Please don't use this class directly for anything other than the flat,
25+
/// top-level compilation-phase timing numbers; unadorned SharedTimers are
26+
/// enabled, summed and reported via -debug-time-compilation, using LLVM's
27+
/// built-in logic for timer groups, and that logic doesn't work right if
28+
/// there's any nesting or reentry in timers at all (crashes on reentry,
29+
/// simply mis-reports nesting). Additional SharedTimers also confuse users
30+
/// who are expecting to see only top-level phase timings when they pass
31+
/// -debug-time-compilation.
32+
///
33+
/// Instead, please use FrontendStatsTracer objects and the -stats-output-dir
34+
/// subsystem in include/swift/Basic/Statistic.h. In addition to not
35+
/// interfering with users passing -debug-time-compilation, the
36+
/// FrontendStatsTracer objects automatically instantiate nesting-safe and
37+
/// reentry-safe SharedTimers themselves, as well as supporting event and
38+
/// source-entity tracing and profiling.
2339
class SharedTimer {
2440
enum class State {
2541
Initial,

lib/AST/Expr.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,20 +2168,23 @@ void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
21682168
}
21692169
}
21702170

2171-
// See swift/Basic/Statistic.h for declaration: this enables tracing Decls, is
2171+
// See swift/Basic/Statistic.h for declaration: this enables tracing Exprs, is
21722172
// defined here to avoid too much layering violation / circular linkage
21732173
// dependency.
21742174

21752175
struct ExprTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
21762176
void traceName(const void *Entity, raw_ostream &OS) const {
2177-
// Exprs don't have names.
2177+
if (!Entity)
2178+
return;
2179+
const Expr *E = static_cast<const Expr *>(Entity);
2180+
OS << Expr::getKindName(E->getKind());
21782181
}
21792182
void traceLoc(const void *Entity, SourceManager *SM,
21802183
clang::SourceManager *CSM, raw_ostream &OS) const {
21812184
if (!Entity)
21822185
return;
2183-
const Expr *D = static_cast<const Expr *>(Entity);
2184-
D->getSourceRange().print(OS, *SM, false);
2186+
const Expr *E = static_cast<const Expr *>(Entity);
2187+
E->getSourceRange().print(OS, *SM, false);
21852188
}
21862189
};
21872190

lib/AST/Module.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "swift/AST/ProtocolConformance.h"
3535
#include "swift/Basic/Compiler.h"
3636
#include "swift/Basic/SourceManager.h"
37+
#include "swift/Basic/Statistic.h"
3738
#include "swift/Parse/Token.h"
3839
#include "swift/Syntax/SyntaxNodes.h"
3940
#include "clang/Basic/Module.h"
@@ -1545,3 +1546,28 @@ const ModuleDecl* ModuleEntity::getAsSwiftModule() const {
15451546
return SwiftMod;
15461547
return nullptr;
15471548
}
1549+
1550+
// See swift/Basic/Statistic.h for declaration: this enables tracing SourceFiles, is
1551+
// defined here to avoid too much layering violation / circular linkage
1552+
// dependency.
1553+
1554+
struct SourceFileTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
1555+
void traceName(const void *Entity, raw_ostream &OS) const {
1556+
if (!Entity)
1557+
return;
1558+
const SourceFile *SF = static_cast<const SourceFile *>(Entity);
1559+
OS << llvm::sys::path::filename(SF->getFilename());
1560+
}
1561+
void traceLoc(const void *Entity, SourceManager *SM,
1562+
clang::SourceManager *CSM, raw_ostream &OS) const {
1563+
// SourceFiles don't have SourceLocs of their own; they contain them.
1564+
}
1565+
};
1566+
1567+
static SourceFileTraceFormatter TF;
1568+
1569+
template<>
1570+
const UnifiedStatsReporter::TraceFormatter*
1571+
FrontendStatsTracer::getTraceFormatter<const SourceFile *>() {
1572+
return &TF;
1573+
}

lib/AST/NameLookup.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,6 @@ TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
15521552
DeclName name,
15531553
bool ignoreNewExtensions) {
15541554
ASTContext &ctx = getASTContext();
1555-
FrontendStatsTracer tracer(ctx.Stats, "lookup-direct", this);
15561555
if (auto s = ctx.Stats) {
15571556
++s->getFrontendCounters().NominalTypeLookupDirectCount;
15581557
}

lib/AST/Pattern.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTWalker.h"
2121
#include "swift/AST/GenericEnvironment.h"
2222
#include "swift/AST/TypeLoc.h"
23+
#include "swift/Basic/Statistic.h"
2324
#include "llvm/ADT/APFloat.h"
2425
#include "llvm/Support/raw_ostream.h"
2526
using namespace swift;
@@ -431,4 +432,33 @@ SourceLoc ExprPattern::getLoc() const {
431432
SourceRange ExprPattern::getSourceRange() const {
432433
return getSubExpr()->getSourceRange();
433434
}
434-
435+
436+
// See swift/Basic/Statistic.h for declaration: this enables tracing Patterns, is
437+
// defined here to avoid too much layering violation / circular linkage
438+
// dependency.
439+
440+
struct PatternTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
441+
void traceName(const void *Entity, raw_ostream &OS) const {
442+
if (!Entity)
443+
return;
444+
const Pattern *P = static_cast<const Pattern *>(Entity);
445+
if (const NamedPattern *NP = dyn_cast<NamedPattern>(P)) {
446+
OS << NP->getBoundName();
447+
}
448+
}
449+
void traceLoc(const void *Entity, SourceManager *SM,
450+
clang::SourceManager *CSM, raw_ostream &OS) const {
451+
if (!Entity)
452+
return;
453+
const Pattern *P = static_cast<const Pattern *>(Entity);
454+
P->getSourceRange().print(OS, *SM, false);
455+
}
456+
};
457+
458+
static PatternTraceFormatter TF;
459+
460+
template<>
461+
const UnifiedStatsReporter::TraceFormatter*
462+
FrontendStatsTracer::getTraceFormatter<const Pattern *>() {
463+
return &TF;
464+
}

lib/AST/Stmt.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/Expr.h"
2121
#include "swift/AST/Pattern.h"
22+
#include "swift/Basic/Statistic.h"
2223
#include "llvm/ADT/PointerUnion.h"
2324

2425
using namespace swift;
@@ -431,3 +432,31 @@ SwitchStmt *SwitchStmt::create(LabeledStmtInfo LabelInfo, SourceLoc SwitchLoc,
431432
theSwitch->getTrailingObjects<ASTNode>());
432433
return theSwitch;
433434
}
435+
436+
// See swift/Basic/Statistic.h for declaration: this enables tracing Stmts, is
437+
// defined here to avoid too much layering violation / circular linkage
438+
// dependency.
439+
440+
struct StmtTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
441+
void traceName(const void *Entity, raw_ostream &OS) const {
442+
if (!Entity)
443+
return;
444+
const Stmt *S = static_cast<const Stmt *>(Entity);
445+
OS << Stmt::getKindName(S->getKind());
446+
}
447+
void traceLoc(const void *Entity, SourceManager *SM,
448+
clang::SourceManager *CSM, raw_ostream &OS) const {
449+
if (!Entity)
450+
return;
451+
const Stmt *S = static_cast<const Stmt *>(Entity);
452+
S->getSourceRange().print(OS, *SM, false);
453+
}
454+
};
455+
456+
static StmtTraceFormatter TF;
457+
458+
template<>
459+
const UnifiedStatsReporter::TraceFormatter*
460+
FrontendStatsTracer::getTraceFormatter<const Stmt *>() {
461+
return &TF;
462+
}

0 commit comments

Comments
 (0)