Skip to content

Commit 35e4d1e

Browse files
committed
Merge branch 'master' into remove-reflectionlegacy
2 parents 03476e9 + 5d28e61 commit 35e4d1e

36 files changed

+964
-570
lines changed

docs/DriverInternals.rst

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,13 @@ in the current build. This is covered by checking if the input has been
9494
modified since the last build; if it hasn't, we only need to recompile if
9595
something it depends on has changed.
9696

97-
98-
Execute: Running the Jobs in a Compilation using a TaskQueue
99-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
97+
Schedule: Ordering and skipping jobs by dependency analysis
98+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
10099

101100
A Compilation's goal is to make sure every Job in its list of Jobs is handled.
102101
If a Job needs to be run, the Compilation attempts to *schedule* it. If the
103102
Job's dependencies have all been completed (or determined to be skippable), it
104-
is added to the TaskQueue; otherwise it is marked as *blocked.*
103+
is scheduled for execution; otherwise it is marked as *blocked.*
105104

106105
To support Jobs compiling individual Swift files, which may or may not need to
107106
be run, the Compilation keeps track of a DependencyGraph. (If file A depends on
@@ -111,6 +110,22 @@ that were directly blocked on it, and check to see if any other Jobs now need
111110
to run based on the DependencyGraph. See the section on :doc:`DependencyAnalysis`
112111
for more information.
113112

113+
Batch: Optionally combine similar jobs
114+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
115+
116+
The Driver has an experimental "batch mode" that examines the set of scheduled
117+
jobs just prior to execution, looking for jobs that are identical to one another
118+
aside from the primary input file they are compiling in a module. If it finds
119+
such a set, it may replace the set with a single BatchJob, before handing it off
120+
to the TaskQueue; this helps minimize the overall number of frontend processes
121+
that run (and thus do potentially redundant work).
122+
123+
Once any batching has taken place, the set of scheduled jobs (batched or
124+
otherwise) is transferred to the TaskQueue for execution.
125+
126+
Execute: Running the Jobs in a Compilation using a TaskQueue
127+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128+
114129
The Compilation's TaskQueue controls the low-level aspects of managing
115130
subprocesses. Multiple Jobs may execute simultaneously, but communication with
116131
the parent process (the driver) is handled on a single thread. The level of

include/swift/Basic/Statistic.h

Lines changed: 109 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515

1616
#include "llvm/ADT/SmallString.h"
1717
#include "llvm/ADT/Statistic.h"
18-
#include "swift/AST/Identifier.h"
19-
#include "swift/Basic/SourceLoc.h"
18+
#include "swift/Basic/LLVM.h"
2019
#include "swift/Basic/Timer.h"
2120

2221
#define SWIFT_FUNC_STAT \
@@ -56,35 +55,29 @@ namespace clang {
5655
namespace swift {
5756

5857
class Decl;
58+
class ProtocolConformance;
5959
class Expr;
6060
class SILFunction;
61+
class FrontendStatsTracer;
62+
class SourceManager;
6163

6264
class UnifiedStatsReporter {
6365

6466
public:
6567
struct AlwaysOnDriverCounters
6668
{
67-
#define DRIVER_STATISTIC(ID) size_t ID;
69+
#define DRIVER_STATISTIC(ID) int64_t ID;
6870
#include "Statistics.def"
6971
#undef DRIVER_STATISTIC
7072
};
7173

7274
struct AlwaysOnFrontendCounters
7375
{
74-
#define FRONTEND_STATISTIC(NAME, ID) size_t ID;
76+
#define FRONTEND_STATISTIC(NAME, ID) int64_t ID;
7577
#include "Statistics.def"
7678
#undef FRONTEND_STATISTIC
7779
};
7880

79-
struct AlwaysOnFrontendRecursiveSharedTimers {
80-
AlwaysOnFrontendRecursiveSharedTimers();
81-
#define FRONTEND_RECURSIVE_SHARED_TIMER(ID) RecursiveSharedTimer ID;
82-
#include "Statistics.def"
83-
#undef FRONTEND_RECURSIVE_SHARED_TIMER
84-
85-
int dummyInstanceVariableToGetConstructorToParse;
86-
};
87-
8881
// To trace an entity, you have to provide a TraceFormatter for it. This is a
8982
// separate type since we do not have retroactive conformances in C++, and it
9083
// is a type that takes void* arguments since we do not have existentials
@@ -98,63 +91,67 @@ class UnifiedStatsReporter {
9891
virtual ~TraceFormatter();
9992
};
10093

101-
struct FrontendStatsTracer
102-
{
103-
UnifiedStatsReporter *Reporter;
104-
llvm::TimeRecord SavedTime;
105-
StringRef EventName;
106-
const void *Entity;
107-
const TraceFormatter *Formatter;
108-
FrontendStatsTracer(StringRef EventName,
109-
const void *Entity,
110-
const TraceFormatter *Formatter,
111-
UnifiedStatsReporter *Reporter);
112-
FrontendStatsTracer();
113-
FrontendStatsTracer(FrontendStatsTracer&& other);
114-
FrontendStatsTracer& operator=(FrontendStatsTracer&&);
115-
~FrontendStatsTracer();
116-
FrontendStatsTracer(const FrontendStatsTracer&) = delete;
117-
FrontendStatsTracer& operator=(const FrontendStatsTracer&) = delete;
118-
};
119-
12094
struct FrontendStatsEvent
12195
{
12296
uint64_t TimeUSec;
12397
uint64_t LiveUSec;
12498
bool IsEntry;
12599
StringRef EventName;
126100
StringRef CounterName;
127-
size_t CounterDelta;
128-
size_t CounterValue;
101+
int64_t CounterDelta;
102+
int64_t CounterValue;
129103
const void *Entity;
130104
const TraceFormatter *Formatter;
131105
};
132106

107+
// We only write fine-grained trace entries when the user passed
108+
// -trace-stats-events, but we recycle the same FrontendStatsTracers to give
109+
// us some free recursion-save phase timings whenever -trace-stats-dir is
110+
// active at all. Reduces redundant machinery.
111+
class RecursionSafeTimers;
112+
113+
// We also keep a few banks of optional hierarchical profilers for times and
114+
// statistics, activated with -profile-stats-events and
115+
// -profile-stats-entities, which are part way between the detail level of the
116+
// aggregate statistic JSON files and the fine-grained CSV traces. Naturally
117+
// these are written in yet a different file format: the input format for
118+
// flamegraphs.
119+
struct StatsProfilers;
120+
133121
private:
134122
bool currentProcessExitStatusSet;
135123
int currentProcessExitStatus;
136124
SmallString<128> StatsFilename;
137125
SmallString<128> TraceFilename;
126+
SmallString<128> ProfileDirname;
138127
llvm::TimeRecord StartedTime;
128+
129+
// This is unique_ptr because NamedRegionTimer is non-copy-constructable.
139130
std::unique_ptr<llvm::NamedRegionTimer> Timer;
131+
140132
SourceManager *SourceMgr;
141133
clang::SourceManager *ClangSourceMgr;
142-
std::unique_ptr<AlwaysOnDriverCounters> DriverCounters;
143-
std::unique_ptr<AlwaysOnFrontendCounters> FrontendCounters;
144-
std::unique_ptr<AlwaysOnFrontendCounters> LastTracedFrontendCounters;
145-
std::vector<FrontendStatsEvent> FrontendStatsEvents;
146-
std::unique_ptr<AlwaysOnFrontendRecursiveSharedTimers>
147-
FrontendRecursiveSharedTimers;
134+
Optional<AlwaysOnDriverCounters> DriverCounters;
135+
Optional<AlwaysOnFrontendCounters> FrontendCounters;
136+
Optional<AlwaysOnFrontendCounters> LastTracedFrontendCounters;
137+
Optional<std::vector<FrontendStatsEvent>> FrontendStatsEvents;
138+
139+
// These are unique_ptr so we can use incomplete types here.
140+
std::unique_ptr<RecursionSafeTimers> RecursiveTimers;
141+
std::unique_ptr<StatsProfilers> EventProfilers;
142+
std::unique_ptr<StatsProfilers> EntityProfilers;
148143

149144
void publishAlwaysOnStatsToLLVM();
150-
void printAlwaysOnStatsAndTimers(llvm::raw_ostream &OS);
145+
void printAlwaysOnStatsAndTimers(raw_ostream &OS);
151146

152147
UnifiedStatsReporter(StringRef ProgramName,
153148
StringRef AuxName,
154149
StringRef Directory,
155150
SourceManager *SM,
156151
clang::SourceManager *CSM,
157-
bool TraceEvents);
152+
bool TraceEvents,
153+
bool ProfileEvents,
154+
bool ProfileEntities);
158155
public:
159156
UnifiedStatsReporter(StringRef ProgramName,
160157
StringRef ModuleName,
@@ -165,23 +162,83 @@ class UnifiedStatsReporter {
165162
StringRef Directory,
166163
SourceManager *SM=nullptr,
167164
clang::SourceManager *CSM=nullptr,
168-
bool TraceEvents=false);
165+
bool TraceEvents=false,
166+
bool ProfileEvents=false,
167+
bool ProfileEntities=false);
169168
~UnifiedStatsReporter();
170169

171170
AlwaysOnDriverCounters &getDriverCounters();
172171
AlwaysOnFrontendCounters &getFrontendCounters();
173-
AlwaysOnFrontendRecursiveSharedTimers &getFrontendRecursiveSharedTimers();
174172
void noteCurrentProcessExitStatus(int);
175-
// We declare 4 explicit overloads here, but the _definitions_ live in the
176-
// upper-level files (in libswiftAST or libswiftSIL) that provide the types
177-
// being traced. If you want to trace those types, it's assumed you're linking
178-
// with the object files that define the tracer.
179-
FrontendStatsTracer getStatsTracer(StringRef EventName, const Decl *D);
180-
FrontendStatsTracer getStatsTracer(StringRef EventName, const clang::Decl*D);
181-
FrontendStatsTracer getStatsTracer(StringRef EventName, const Expr *E);
182-
FrontendStatsTracer getStatsTracer(StringRef EventName, const SILFunction *F);
183173
void saveAnyFrontendStatsEvents(FrontendStatsTracer const &T, bool IsEntry);
184174
};
185175

176+
// This is a non-nested type just to make it less work to write at call sites.
177+
class FrontendStatsTracer
178+
{
179+
FrontendStatsTracer(UnifiedStatsReporter *Reporter,
180+
StringRef EventName,
181+
const void *Entity,
182+
const UnifiedStatsReporter::TraceFormatter *Formatter);
183+
184+
// In the general case we do not know how to format an entity for tracing.
185+
template<typename T> static
186+
const UnifiedStatsReporter::TraceFormatter *getTraceFormatter() {
187+
return nullptr;
188+
}
189+
190+
public:
191+
UnifiedStatsReporter *Reporter;
192+
llvm::TimeRecord SavedTime;
193+
StringRef EventName;
194+
const void *Entity;
195+
const UnifiedStatsReporter::TraceFormatter *Formatter;
196+
FrontendStatsTracer();
197+
FrontendStatsTracer(FrontendStatsTracer&& other);
198+
FrontendStatsTracer& operator=(FrontendStatsTracer&&);
199+
~FrontendStatsTracer();
200+
FrontendStatsTracer(const FrontendStatsTracer&) = delete;
201+
FrontendStatsTracer& operator=(const FrontendStatsTracer&) = delete;
202+
203+
/// These are the convenience constructors you want to be calling throughout
204+
/// the compiler: they select an appropriate trace formatter for the provided
205+
/// entity type, and produce a tracer that's either active or inert depending
206+
/// on whether the provided \p Reporter is null (nullptr means "tracing is
207+
/// disabled").
208+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName);
209+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
210+
const Decl *D);
211+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
212+
const ProtocolConformance *P);
213+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
214+
const clang::Decl *D);
215+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
216+
const Expr *E);
217+
FrontendStatsTracer(UnifiedStatsReporter *Reporter, StringRef EventName,
218+
const SILFunction *F);
219+
};
220+
221+
// In particular cases, we do know how to format traced entities: we declare
222+
// explicit specializations of getTraceFormatter() here, matching the overloaded
223+
// constructors of FrontendStatsTracer above, where the _definitions_ live in
224+
// the upper-level files (in libswiftAST or libswiftSIL), and provide tracing
225+
// for those entity types. If you want to trace those types, it's assumed you're
226+
// linking with the object files that define the tracer.
227+
228+
template<> const UnifiedStatsReporter::TraceFormatter*
229+
FrontendStatsTracer::getTraceFormatter<const Decl *>();
230+
231+
template<> const UnifiedStatsReporter::TraceFormatter*
232+
FrontendStatsTracer::getTraceFormatter<const ProtocolConformance *>();
233+
234+
template<> const UnifiedStatsReporter::TraceFormatter*
235+
FrontendStatsTracer::getTraceFormatter<const clang::Decl *>();
236+
237+
template<> const UnifiedStatsReporter::TraceFormatter*
238+
FrontendStatsTracer::getTraceFormatter<const Expr *>();
239+
240+
template<> const UnifiedStatsReporter::TraceFormatter*
241+
FrontendStatsTracer::getTraceFormatter<const SILFunction *>();
242+
186243
}
187244
#endif // SWIFT_BASIC_STATISTIC_H

include/swift/Basic/Statistics.def

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919
// - Subsystem is a token to be stringified as a name prefix
2020
// - Id is an identifier suitable for use in C++
2121
//
22-
// FRONTEND_RECURSIVE_SHARED_TIMER(Id)
23-
// - Id is an identifier suitable for use in C++
24-
//
2522
//===----------------------------------------------------------------------===//
2623

2724
/// Driver statistics are collected for driver processes
@@ -219,13 +216,3 @@ FRONTEND_STATISTIC(IRModule, NumIRInsts)
219216
/// the .o file you find on disk after the frontend exits.
220217
FRONTEND_STATISTIC(LLVM, NumLLVMBytesOutput)
221218
#endif
222-
223-
/// Frontend timers for recursive routines
224-
#ifdef FRONTEND_RECURSIVE_SHARED_TIMER
225-
226-
/// Time spent in NominalTypeDecl::lookupDirect.
227-
FRONTEND_RECURSIVE_SHARED_TIMER(NominalTypeDecl__lookupDirect)
228-
229-
/// Time spent in ClangImporter::Implementation::loadAllMembers.
230-
FRONTEND_RECURSIVE_SHARED_TIMER(ClangImporter__Implementation__loadAllMembers)
231-
#endif

include/swift/Basic/Timer.h

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -45,66 +45,6 @@ namespace swift {
4545
CompilationTimersEnabled = State::Enabled;
4646
}
4747
};
48-
49-
/// A SharedTimer for recursive routines.
50-
/// void example() {
51-
/// RecursiveSharedTimer::Guard guard; // MUST BE AT TOP SCOPE of function to
52-
/// work right! if (auto s = getASTContext().Stats) {
53-
/// guard =
54-
/// ctx.Stats->getFrontendRecursiveSharedTimers().NominalTypeDecl__lookupDirect.getGuard();
55-
// }
56-
/// ...
57-
/// }
58-
59-
class RecursiveSharedTimer {
60-
private:
61-
int recursionCount = 0;
62-
const StringRef name;
63-
llvm::Optional<SharedTimer> timer;
64-
65-
void enterRecursiveFunction() {
66-
assert(recursionCount >= 0 && "too many exits");
67-
if (recursionCount++ == 0)
68-
timer.emplace(name);
69-
}
70-
void exitRecursiveFunction() {
71-
assert(recursionCount > 0 && "too many exits");
72-
if (--recursionCount == 0)
73-
timer.reset();
74-
}
75-
76-
public:
77-
RecursiveSharedTimer(StringRef name) : name(name) {}
78-
79-
struct Guard {
80-
RecursiveSharedTimer *recursiveTimerOrNull;
81-
82-
Guard(RecursiveSharedTimer *rst) : recursiveTimerOrNull(rst) {
83-
if (recursiveTimerOrNull)
84-
recursiveTimerOrNull->enterRecursiveFunction();
85-
}
86-
~Guard() {
87-
if (recursiveTimerOrNull)
88-
recursiveTimerOrNull->exitRecursiveFunction();
89-
}
90-
91-
// All this stuff is to do an RAII object that be moved.
92-
Guard() : recursiveTimerOrNull(nullptr) {}
93-
Guard(Guard &&other) {
94-
recursiveTimerOrNull = other.recursiveTimerOrNull;
95-
other.recursiveTimerOrNull = nullptr;
96-
}
97-
Guard &operator=(Guard &&other) {
98-
recursiveTimerOrNull = other.recursiveTimerOrNull;
99-
other.recursiveTimerOrNull = nullptr;
100-
return *this;
101-
}
102-
Guard(const Guard &) = delete;
103-
Guard &operator=(const Guard &) = delete;
104-
};
105-
106-
Guard getGuard() { return Guard(this); }
107-
};
10848
} // end namespace swift
10949

11050
#endif // SWIFT_BASIC_TIMER_H

include/swift/Frontend/FrontendOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ class FrontendOptions {
164164
/// Trace changes to stats to files in StatsOutputDir.
165165
bool TraceStats = false;
166166

167+
/// Profile changes to stats to files in StatsOutputDir.
168+
bool ProfileEvents = false;
169+
170+
/// Profile changes to stats to files in StatsOutputDir, grouped by source
171+
/// entity.
172+
bool ProfileEntities = false;
173+
167174
/// If true, serialization encodes an extra lookup table for use in module-
168175
/// merging when emitting partial modules (the per-file modules in a non-WMO
169176
/// build).

0 commit comments

Comments
 (0)