Skip to content

Commit 786cfc5

Browse files
authored
Merge pull request #14703 from graydon/profile-stats
2 parents 61fb610 + 9d34041 commit 786cfc5

23 files changed

+625
-267
lines changed

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).

include/swift/Option/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@ def stats_output_dir: Separate<["-"], "stats-output-dir">,
211211
def trace_stats_events: Flag<["-"], "trace-stats-events">,
212212
Flags<[FrontendOption, HelpHidden]>,
213213
HelpText<"Trace changes to stats in -stats-output-dir">;
214+
def profile_stats_events: Flag<["-"], "profile-stats-events">,
215+
Flags<[FrontendOption, HelpHidden]>,
216+
HelpText<"Profile changes to stats in -stats-output-dir">;
217+
def profile_stats_entities: Flag<["-"], "profile-stats-entities">,
218+
Flags<[FrontendOption, HelpHidden]>,
219+
HelpText<"Profile changes to stats in -stats-output-dir, subdivided by source entity">;
214220

215221
def emit_dependencies : Flag<["-"], "emit-dependencies">,
216222
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@ void ASTContext::loadObjCMethods(
14021402

14031403
void ASTContext::verifyAllLoadedModules() const {
14041404
#ifndef NDEBUG
1405-
SharedTimer("verifyAllLoadedModules");
1405+
FrontendStatsTracer tracer(Stats, "verify-all-loaded-modules");
14061406
for (auto &loader : Impl.ModuleLoaders)
14071407
loader->verifyAllModules();
14081408

lib/AST/Decl.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5677,6 +5677,10 @@ struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
56775677
const Decl *D = static_cast<const Decl *>(Entity);
56785678
if (auto const *VD = dyn_cast<const ValueDecl>(D)) {
56795679
VD->getFullName().print(OS, false);
5680+
} else {
5681+
OS << "<"
5682+
<< Decl::getDescriptiveKindName(D->getDescriptiveKind())
5683+
<< ">";
56805684
}
56815685
}
56825686
void traceLoc(const void *Entity, SourceManager *SM,
@@ -5690,14 +5694,10 @@ struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
56905694

56915695
static DeclTraceFormatter TF;
56925696

5693-
UnifiedStatsReporter::FrontendStatsTracer
5694-
UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Decl *D) {
5695-
if (LastTracedFrontendCounters)
5696-
// Return live tracer object.
5697-
return FrontendStatsTracer(EventName, D, &TF, this);
5698-
else
5699-
// Return inert tracer object.
5700-
return FrontendStatsTracer();
5697+
template<>
5698+
const UnifiedStatsReporter::TraceFormatter*
5699+
FrontendStatsTracer::getTraceFormatter<const Decl *>() {
5700+
return &TF;
57015701
}
57025702

57035703
TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {}

0 commit comments

Comments
 (0)