Skip to content

Commit

Permalink
InstrProf: Set up the basic infrastructure for profiling swift
Browse files Browse the repository at this point in the history
This adds the -profile-generate flag, which enables LLVM's
instrumentation based profiling. It implements the instrumentation
for basic control flow, such as if statements, loops, and closures.

Swift SVN r25155
  • Loading branch information
bogner committed Feb 11, 2015
1 parent 3428430 commit a490082
Show file tree
Hide file tree
Showing 20 changed files with 386 additions and 9 deletions.
3 changes: 3 additions & 0 deletions include/swift/AST/ASTNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define SWIFT_AST_AST_NODE_H

#include "llvm/ADT/PointerUnion.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/TypeAlignments.h"

namespace swift {
Expand All @@ -38,6 +39,8 @@ namespace swift {

/// \brief Return the location of the end of the statement.
SourceLoc getEndLoc() const;

void walk(ASTWalker &Walker);
};

} // namespace swift
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/IRGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,16 @@ class IRGenOptions {
/// the given type names.
SmallVector<StringRef, 1> VerifyTypeLayoutNames;

/// Instrument code to generate profiling information.
unsigned GenerateProfile : 1;

IRGenOptions() : OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true),
Optimize(false), DebugInfoKind(IRGenDebugInfoKind::None),
UseJIT(false), EnableDynamicValueTypeLayout(false),
DisableLLVMOptzns(false), DisableLLVMARCOpts(false),
DisableLLVMSLPVectorizer(false),
DisableFPElim(true), HasUnderlyingModule(false),
Playground(false) {}
Playground(false), GenerateProfile(false) {}
};

} // end namespace swift
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class SILOptions {
/// Should we emit self as a guaranteed parameter?
bool EnableGuaranteedSelf = false;

/// Instrument code to generate profiling information.
bool GenerateProfile = false;

/// Should we use a pass pipeline passed in via a json file? Null by default.
StringRef ExternalPassPipelineFilename;
};
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,8 @@ def target_legacy_spelling : Joined<["--"], "target=">,
def target_cpu : Separate<["-"], "target-cpu">, Flags<[FrontendOption]>,
HelpText<"Generate code for a particular CPU variant">;

def profile_generate : Flag<["-"], "profile-generate">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Generate instrumented code to collect execution counts">;

include "FrontendOptions.td"
11 changes: 11 additions & 0 deletions lib/AST/ASTNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@ SourceLoc ASTNode::getStartLoc() const {
SourceLoc ASTNode::getEndLoc() const {
return getSourceRange().End;
}

void ASTNode::walk(ASTWalker &Walker) {
if (Expr *E = this->dyn_cast<Expr*>())
E->walk(Walker);
else if (Stmt *S = this->dyn_cast<Stmt*>())
S->walk(Walker);
else if (Decl *D = this->dyn_cast<Decl*>())
D->walk(Walker);
else
llvm_unreachable("unsupported AST node");
}
27 changes: 26 additions & 1 deletion lib/Driver/Tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/Driver/Job.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Option/Options.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
Expand Down Expand Up @@ -115,7 +116,8 @@ static void addCommonFrontendArgs(const ToolChain &TC,
inputArgs.AddLastArg(arguments, options::OPT_resource_dir);
inputArgs.AddLastArg(arguments, options::OPT_split_objc_selectors);
inputArgs.AddLastArg(arguments, options::OPT_solver_memory_threshold);

inputArgs.AddLastArg(arguments, options::OPT_profile_generate);

// Pass on any build config options
inputArgs.AddAllArgs(arguments, options::OPT_D);

Expand Down Expand Up @@ -601,6 +603,19 @@ Job *darwin::Linker::constructJob(const JobAction &JA,
Arguments.push_back("-L");
Arguments.push_back(Args.MakeArgString(RuntimeLibPath));

if (Args.hasArg(options::OPT_profile_generate)) {
SmallString<128> LibProfile(RuntimeLibPath);
llvm::sys::path::remove_filename(LibProfile); // remove platform name
llvm::sys::path::append(LibProfile, "clang", CLANG_VERSION_STRING);

StringRef RT = Triple.isiOS() ? "ios" : "osx";
llvm::sys::path::append(LibProfile, "lib", "darwin",
"libclang_rt.profile_" + RT + ".a");
Arguments.push_back(Args.MakeArgString(LibProfile));
}



// FIXME: We probably shouldn't be adding an rpath here unless we know ahead
// of time the standard library won't be copied.
Arguments.push_back("-rpath");
Expand Down Expand Up @@ -689,6 +704,16 @@ Job *linux::Linker::constructJob(const JobAction &JA,
Arguments.push_back("-L");
Arguments.push_back(Args.MakeArgString(RuntimeLibPath));

if (Args.hasArg(options::OPT_profile_generate)) {
SmallString<128> LibProfile(RuntimeLibPath);
llvm::sys::path::remove_filename(LibProfile); // remove platform name
llvm::sys::path::append(LibProfile, "clang", CLANG_VERSION_STRING);

llvm::sys::path::append(LibProfile, "lib", TC.getOS(),
"libclang_rt.profile-" + TC.getArchName() + ".a");
Arguments.push_back(Args.MakeArgString(LibProfile));
}

// FIXME: We probably shouldn't be adding an rpath here unless we know ahead
// of time the standard library won't be copied.
Arguments.push_back("-Xlinker");
Expand Down
4 changes: 4 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,8 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
if (const Arg *A = Args.getLastArg(OPT_external_pass_pipeline_filename))
Opts.ExternalPassPipelineFilename = A->getValue();

Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate);

return false;
}

Expand Down Expand Up @@ -937,6 +939,8 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
Opts.VerifyTypeLayoutNames.push_back(A->getValue());
}

Opts.GenerateProfile |= Args.hasArg(OPT_profile_generate);

return false;
}

Expand Down
3 changes: 1 addition & 2 deletions lib/IRGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,4 @@ add_swift_library(swiftIRGen
# Clang dependencies.
# FIXME: Clang should really export these in some reasonable manner.
clangCodeGen
COMPONENT_DEPENDS profiledata)

COMPONENT_DEPENDS profiledata instrumentation)
5 changes: 5 additions & 0 deletions lib/IRGen/IRGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/ObjCARC.h"
Expand Down Expand Up @@ -333,6 +334,10 @@ static std::unique_ptr<llvm::Module> performIRGeneration(IRGenOptions &Opts,
if (!Opts.DisableLLVMARCOpts)
ModulePasses.add(createSwiftAliasAnalysisPass());

// If we're generating a profile, add the lowering pass now.
if (Opts.GenerateProfile)
ModulePasses.add(createInstrProfilingPass());

if (Opts.Verify)
ModulePasses.add(createVerifierPass());

Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ add_swift_library(swiftSILGen
SILGenLValue.cpp
SILGenPattern.cpp
SILGenPoly.cpp
SILGenProfiling.cpp
SILGenStmt.cpp
LINK_LIBRARIES swiftSIL)

8 changes: 7 additions & 1 deletion lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ SILGenFunction::~SILGenFunction() {

SILGenModule::SILGenModule(SILModule &M, Module *SM, bool makeModuleFragile)
: M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr),
makeModuleFragile(makeModuleFragile) {
Profiler(nullptr), makeModuleFragile(makeModuleFragile) {
}

SILGenModule::~SILGenModule() {
Expand Down Expand Up @@ -410,7 +410,11 @@ bool SILGenModule::hasFunction(SILDeclRef constant) {
}

void SILGenModule::visitFuncDecl(FuncDecl *fd) {
const auto &Opts = M.getOptions();
if (Opts.GenerateProfile)
Profiler = llvm::make_unique<SILGenProfiling>(*this);
emitFunction(fd);
Profiler = nullptr;
}

template<typename T>
Expand Down Expand Up @@ -501,6 +505,8 @@ void SILGenModule::emitFunction(FuncDecl *fd) {

SILDeclRef constant(decl);
SILFunction *f = preEmitFunction(constant, fd, fd);
if (Profiler && !Profiler->hasRegionCounters())
Profiler->assignRegionCounters(fd, *f);
SILGenFunction(*this, *f).emitFunction(fd);
postEmitFunction(constant, f);
}
Expand Down
7 changes: 6 additions & 1 deletion lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "ASTVisitor.h"
#include "Cleanup.h"
#include "SILGenProfiling.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/SIL/SILDebugScope.h"
Expand Down Expand Up @@ -52,7 +53,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
/// TopLevelSGF - The SILGenFunction used to visit top-level code, or null if
/// the current source file is not a script source file.
SILGenFunction /*nullable*/ *TopLevelSGF;


/// The profiler for instrumentation based profiling, or null if profiling is
/// disabled.
std::unique_ptr<SILGenProfiling> Profiler;

/// Mapping from SILDeclRefs to emitted SILFunctions.
llvm::DenseMap<SILDeclRef, SILFunction*> emittedFunctions;
/// Mapping from ProtocolConformances to emitted SILWitnessTables.
Expand Down
11 changes: 9 additions & 2 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3231,7 +3231,10 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
Type resultTy = fd->getResultType();
emitProlog(fd, fd->getBodyParamPatterns(), resultTy);
prepareEpilog(resultTy, CleanupLocation(fd));

emitProfilerIncrement(fd->getBody());
visit(fd->getBody());

emitEpilog(fd);
}

Expand All @@ -3240,12 +3243,14 @@ void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {

emitProlog(ace, ace->getParams(), ace->getResultType());
prepareEpilog(ace->getResultType(), CleanupLocation(ace));
if (auto *ce = dyn_cast<ClosureExpr>(ace))
if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
emitProfilerIncrement(ce);
visit(ce->getBody());
else {
} else {
auto *autoclosure = cast<AutoClosureExpr>(ace);
// Closure expressions implicitly return the result of their body
// expression.
emitProfilerIncrement(autoclosure);
emitReturnExpr(ImplicitReturnLocation(ace),
autoclosure->getSingleExpressionBody());
}
Expand Down Expand Up @@ -5529,6 +5534,7 @@ RValue RValueEmitter::visitIfExpr(IfExpr *E, SGFContext C) {
SGF.getLoweredType(E->getType()));

cond.enterTrue(SGF.B);
SGF.emitProfilerIncrement(E);
SILValue trueValue;
{
auto TE = E->getThenExpr();
Expand Down Expand Up @@ -5562,6 +5568,7 @@ RValue RValueEmitter::visitIfExpr(IfExpr *E, SGFContext C) {
/*hasFalse*/ true,
/*invertCondition*/ false);
cond.enterTrue(SGF.B);
SGF.emitProfilerIncrement(E);
{
auto TE = E->getThenExpr();
FullExpr trueScope(SGF.Cleanups, CleanupLocation(TE));
Expand Down
6 changes: 6 additions & 0 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
/// expansion to report the location of the call, instead of the location
/// of the original expr.
Optional<SourceLoc> overrideLocationForMagicIdentifiers;

/// Emit code to increment a counter for profiling.
void emitProfilerIncrement(ASTNode N) {
if (SGM.Profiler)
SGM.Profiler->emitCounterIncrement(B, N);
}

SILGenFunction(SILGenModule &SGM, SILFunction &F);
~SILGenFunction();
Expand Down
Loading

0 comments on commit a490082

Please sign in to comment.