[Stats] Reduce layering violations in FrontendStatsTracer.

This commit is contained in:
Graydon Hoare
2018-01-30 01:32:12 -08:00
parent d39dc43cae
commit 9334779f33
7 changed files with 196 additions and 109 deletions

View File

@@ -13,7 +13,6 @@
#ifndef SWIFT_BASIC_STATISTIC_H
#define SWIFT_BASIC_STATISTIC_H
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "swift/AST/Identifier.h"
@@ -86,19 +85,29 @@ public:
int dummyInstanceVariableToGetConstructorToParse;
};
typedef llvm::PointerUnion4<const Decl*,
const clang::Decl*,
const Expr*,
const SILFunction*> TraceEntity;
// To trace an entity, you have to provide a TraceFormatter for it. This is a
// separate type since we do not have retroactive conformances in C++, and it
// is a type that takes void* arguments since we do not have existentials
// separate from objects in C++. Pity us.
struct TraceFormatter {
virtual void traceName(const void *Entity, raw_ostream &OS) const = 0;
virtual void traceLoc(const void *Entity,
SourceManager *SourceMgr,
clang::SourceManager *ClangSourceMgr,
raw_ostream &OS) const = 0;
virtual ~TraceFormatter();
};
struct FrontendStatsTracer
{
UnifiedStatsReporter *Reporter;
llvm::TimeRecord SavedTime;
StringRef EventName;
TraceEntity Entity;
const void *Entity;
const TraceFormatter *Formatter;
FrontendStatsTracer(StringRef EventName,
TraceEntity Entity,
const void *Entity,
const TraceFormatter *Formatter,
UnifiedStatsReporter *Reporter);
FrontendStatsTracer();
FrontendStatsTracer(FrontendStatsTracer&& other);
@@ -117,7 +126,8 @@ public:
StringRef CounterName;
size_t CounterDelta;
size_t CounterValue;
TraceEntity Entity;
const void *Entity;
const TraceFormatter *Formatter;
};
private:
@@ -162,9 +172,10 @@ public:
AlwaysOnFrontendCounters &getFrontendCounters();
AlwaysOnFrontendRecursiveSharedTimers &getFrontendRecursiveSharedTimers();
void noteCurrentProcessExitStatus(int);
// We provide 4 explicit overloads here, rather than a single function that
// takes a TraceEntity, to save all of our clients from having to include all
// 4 headers that define these 4 forward-declared types.
// We declare 4 explicit overloads here, but the _definitions_ live in the
// upper-level files (in libswiftAST or libswiftSIL) that provide the types
// being traced. If you want to trace those types, it's assumed you're linking
// with the object files that define the tracer.
FrontendStatsTracer getStatsTracer(StringRef EventName, const Decl *D);
FrontendStatsTracer getStatsTracer(StringRef EventName, const clang::Decl*D);
FrontendStatsTracer getStatsTracer(StringRef EventName, const Expr *E);

View File

@@ -5658,3 +5658,37 @@ void Decl::setClangNode(ClangNode Node) {
}
*(ptr - 1) = Node.getOpaqueValue();
}
// See swift/Basic/Statistic.h for declaration: this enables tracing Decls, is
// defined here to avoid too much layering violation / circular linkage
// dependency.
struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
void traceName(const void *Entity, raw_ostream &OS) const {
if (!Entity)
return;
const Decl *D = static_cast<const Decl *>(Entity);
if (auto const *VD = dyn_cast<const ValueDecl>(D)) {
VD->getFullName().print(OS, false);
}
}
void traceLoc(const void *Entity, SourceManager *SM,
clang::SourceManager *CSM, raw_ostream &OS) const {
if (!Entity)
return;
const Decl *D = static_cast<const Decl *>(Entity);
D->getSourceRange().print(OS, *SM, false);
}
};
static DeclTraceFormatter TF;
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Decl *D) {
if (LastTracedFrontendCounters)
// Return live tracer object.
return FrontendStatsTracer(EventName, D, &TF, this);
else
// Return inert tracer object.
return FrontendStatsTracer();
}

View File

@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "swift/AST/Expr.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/Unicode.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTVisitor.h"
@@ -2276,3 +2277,32 @@ void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
llvm_unreachable("no hashable conformances for this kind");
}
}
// See swift/Basic/Statistic.h for declaration: this enables tracing Decls, is
// defined here to avoid too much layering violation / circular linkage
// dependency.
struct ExprTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
void traceName(const void *Entity, raw_ostream &OS) const {
// Exprs don't have names.
}
void traceLoc(const void *Entity, SourceManager *SM,
clang::SourceManager *CSM, raw_ostream &OS) const {
if (!Entity)
return;
const Expr *D = static_cast<const Expr *>(Entity);
D->getSourceRange().print(OS, *SM, false);
}
};
static ExprTraceFormatter TF;
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName, const Expr *E) {
if (LastTracedFrontendCounters)
// Return live tracer object.
return FrontendStatsTracer(EventName, E, &TF, this);
else
// Return inert tracer object.
return FrontendStatsTracer();
}

View File

@@ -260,19 +260,23 @@ UnifiedStatsReporter::printAlwaysOnStatsAndTimers(raw_ostream &OS) {
UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
StringRef EventName,
TraceEntity Entity,
const void *Entity,
const TraceFormatter *Formatter,
UnifiedStatsReporter *Reporter)
: Reporter(Reporter),
SavedTime(llvm::TimeRecord::getCurrentTime()),
EventName(EventName),
Entity(Entity)
Entity(Entity),
Formatter(Formatter)
{
if (Reporter)
Reporter->saveAnyFrontendStatsEvents(*this, true);
}
UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer()
: Reporter(nullptr)
: Reporter(nullptr),
Entity(nullptr),
Formatter(nullptr)
{
}
@@ -284,6 +288,7 @@ UnifiedStatsReporter::FrontendStatsTracer::operator=(
SavedTime = other.SavedTime;
EventName = other.EventName;
Entity = other.Entity;
Formatter = other.Formatter;
other.Reporter = nullptr;
return *this;
}
@@ -293,7 +298,8 @@ UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
: Reporter(other.Reporter),
SavedTime(other.SavedTime),
EventName(other.EventName),
Entity(other.Entity)
Entity(other.Entity),
Formatter(other.Formatter)
{
other.Reporter = nullptr;
}
@@ -304,47 +310,6 @@ UnifiedStatsReporter::FrontendStatsTracer::~FrontendStatsTracer()
Reporter->saveAnyFrontendStatsEvents(*this, false);
}
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const Decl *D)
{
if (LastTracedFrontendCounters)
// Return live tracer object.
return FrontendStatsTracer(EventName, D, this);
else
// Return inert tracer object.
return FrontendStatsTracer();
}
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const Expr *E) {
if (LastTracedFrontendCounters)
return FrontendStatsTracer(EventName, E, this);
else
return FrontendStatsTracer();
}
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const clang::Decl *D)
{
if (LastTracedFrontendCounters)
return FrontendStatsTracer(EventName, D, this);
else
return FrontendStatsTracer();
}
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const SILFunction *F)
{
if (LastTracedFrontendCounters)
return FrontendStatsTracer(EventName, F, this);
else
return FrontendStatsTracer();
}
void
UnifiedStatsReporter::saveAnyFrontendStatsEvents(
FrontendStatsTracer const& T,
@@ -366,7 +331,7 @@ UnifiedStatsReporter::saveAnyFrontendStatsEvents(
LastTracedFrontendCounters->NAME = C.NAME; \
FrontendStatsEvents.emplace_back(FrontendStatsEvent { \
NowUS, LiveUS, IsEntry, T.EventName, name, \
delta, total, T.Entity}); \
delta, total, T.Entity, T.Formatter}); \
} \
} while (0);
#include "swift/Basic/Statistics.def"
@@ -382,56 +347,7 @@ UnifiedStatsReporter::AlwaysOnFrontendRecursiveSharedTimers::
dummyInstanceVariableToGetConstructorToParse(0) {
}
static inline void
printTraceEntityName(raw_ostream &OS,
UnifiedStatsReporter::TraceEntity E) {
if (auto const *CD = E.dyn_cast<const clang::Decl*>()) {
if (auto const *ND = dyn_cast<const clang::NamedDecl>(CD)) {
ND->printName(OS);
}
} else if (auto const *D = E.dyn_cast<const Decl*>()) {
if (auto const *VD = dyn_cast<const ValueDecl>(D)) {
VD->getFullName().print(OS, false);
}
} else if (auto const *X = E.dyn_cast<const Expr*>()) {
// Exprs don't have names
} else if (auto const *F = E.dyn_cast<const SILFunction*>()) {
OS << F->getName();
}
}
static inline void
printClangShortLoc(raw_ostream &OS,
clang::SourceManager *CSM,
clang::SourceLocation L) {
if (!L.isValid() || !L.isFileID())
return;
auto PLoc = CSM->getPresumedLoc(L);
OS << llvm::sys::path::filename(PLoc.getFilename())
<< ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
}
static inline void
printTraceEntityLoc(raw_ostream &OS,
SourceManager *SM,
clang::SourceManager *CSM,
UnifiedStatsReporter::TraceEntity E) {
if (auto const *CD = E.dyn_cast<const clang::Decl*>()) {
if (CSM) {
auto Range = CD->getSourceRange();
printClangShortLoc(OS, CSM, Range.getBegin());
OS << '-';
printClangShortLoc(OS, CSM, Range.getEnd());
}
} else if (auto const *D = E.dyn_cast<const Decl*>()) {
D->getSourceRange().print(OS, *SM, false);
} else if (auto const *X = E.dyn_cast<const Expr*>()) {
X->getSourceRange().print(OS, *SM, false);
} else if (auto const *F = E.dyn_cast<const SILFunction*>()) {
F->getLocation().getSourceRange().print(OS, *SM, false);
}
}
UnifiedStatsReporter::TraceFormatter::~TraceFormatter() {}
UnifiedStatsReporter::~UnifiedStatsReporter()
{
@@ -519,10 +435,12 @@ UnifiedStatsReporter::~UnifiedStatsReporter()
<< E.CounterDelta << ','
<< E.CounterValue << ',';
tstream << '"';
printTraceEntityName(tstream, E.Entity);
if (E.Formatter)
E.Formatter->traceName(E.Entity, tstream);
tstream << '"' << ',';
tstream << '"';
printTraceEntityLoc(tstream, SourceMgr, ClangSourceMgr, E.Entity);
if (E.Formatter)
E.Formatter->traceLoc(E.Entity, SourceMgr, ClangSourceMgr, tstream);
tstream << '"' << '\n';
}
}

View File

@@ -8585,3 +8585,53 @@ ClangImporter::getEnumConstantName(const clang::EnumConstantDecl *enumConstant){
.getBaseIdentifier();
}
// See swift/Basic/Statistic.h for declaration: this enables tracing
// clang::Decls, is defined here to avoid too much layering violation / circular
// linkage dependency.
struct ClangDeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
void traceName(const void *Entity, raw_ostream &OS) const {
if (!Entity)
return;
const clang::Decl *CD = static_cast<const clang::Decl *>(Entity);
if (auto const *ND = dyn_cast<const clang::NamedDecl>(CD)) {
ND->printName(OS);
}
}
static inline void printClangShortLoc(raw_ostream &OS,
clang::SourceManager *CSM,
clang::SourceLocation L) {
if (!L.isValid() || !L.isFileID())
return;
auto PLoc = CSM->getPresumedLoc(L);
OS << llvm::sys::path::filename(PLoc.getFilename()) << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
}
void traceLoc(const void *Entity, SourceManager *SM,
clang::SourceManager *CSM, raw_ostream &OS) const {
if (!Entity)
return;
if (CSM) {
const clang::Decl *CD = static_cast<const clang::Decl *>(Entity);
auto Range = CD->getSourceRange();
printClangShortLoc(OS, CSM, Range.getBegin());
OS << '-';
printClangShortLoc(OS, CSM, Range.getEnd());
}
}
};
static ClangDeclTraceFormatter TF;
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const clang::Decl *D) {
if (LastTracedFrontendCounters)
// Return live tracer object.
return FrontendStatsTracer(EventName, D, &TF, this);
else
// Return inert tracer object.
return FrontendStatsTracer();
}

View File

@@ -19,6 +19,7 @@
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/Basic/OptimizationMode.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/GraphWriter.h"
@@ -490,3 +491,37 @@ SubstitutionList SILFunction::getForwardingSubstitutions() {
bool SILFunction::shouldVerifyOwnership() const {
return !hasSemanticsAttr("verify.ownership.sil.never");
}
// See swift/Basic/Statistic.h for declaration: this enables tracing
// SILFunctions, is defined here to avoid too much layering violation / circular
// linkage dependency.
struct SILFunctionTraceFormatter : public UnifiedStatsReporter::TraceFormatter {
void traceName(const void *Entity, raw_ostream &OS) const {
if (!Entity)
return;
const SILFunction *F = static_cast<const SILFunction *>(Entity);
OS << F->getName();
}
void traceLoc(const void *Entity, SourceManager *SM,
clang::SourceManager *CSM, raw_ostream &OS) const {
if (!Entity)
return;
const SILFunction *F = static_cast<const SILFunction *>(Entity);
F->getLocation().getSourceRange().print(OS, *SM, false);
}
};
static SILFunctionTraceFormatter TF;
UnifiedStatsReporter::FrontendStatsTracer
UnifiedStatsReporter::getStatsTracer(StringRef EventName,
const SILFunction *F) {
if (LastTracedFrontendCounters)
// Return live tracer object.
return FrontendStatsTracer(EventName, F, &TF, this);
else
// Return inert tracer object.
return FrontendStatsTracer();
}

View File

@@ -0,0 +1,9 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %target-swiftc_driver -o %t/main -module-name main -stats-output-dir %t %s -trace-stats-events
// RUN: %FileCheck -input-file %t/*.csv %s
// CHECK: {{"Sema.NumTypesDeserialized"}}
public func foo() {
print("hello")
}