Skip to content

Commit

Permalink
Speculative Compilation
Browse files Browse the repository at this point in the history
[ORC] Remove Speculator Variants for Different Program Representations

[ORC] Block Freq Analysis

Speculative Compilation with Naive Block Frequency

Add Applications to OrcSpeculation

ORC v2 with Block Freq Query & Example

Deleted BenchMark Programs

Signed-off-by: preejackie <[email protected]>

ORCv2 comments resolved

[ORCV2] NFC

ORCv2 NFC

[ORCv2] Speculative compilation - CFGWalkQuery

ORCv2 Adapting IRSpeculationLayer to new locking scheme

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@367756 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
praveen-velliengiri committed Aug 3, 2019
1 parent 7ff3d07 commit 25b5b89
Show file tree
Hide file tree
Showing 12 changed files with 701 additions and 9 deletions.
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(HowToUseLLJIT)
add_subdirectory(LLJITExamples)
add_subdirectory(Kaleidoscope)
add_subdirectory(ModuleMaker)
add_subdirectory(SpeculativeJIT)

if(LLVM_ENABLE_EH AND (NOT WIN32) AND (NOT "${LLVM_NATIVE_ARCH}" STREQUAL "ARM"))
add_subdirectory(ExceptionDemo)
Expand Down
14 changes: 14 additions & 0 deletions examples/SpeculativeJIT/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(LLVM_LINK_COMPONENTS
Core
IRReader
OrcJIT
ExecutionEngine
Support
nativecodegen
Analysis
Passes
)

add_llvm_example(SpeculativeJIT
SpeculativeJIT.cpp
)
197 changes: 197 additions & 0 deletions examples/SpeculativeJIT/SpeculativeJIT.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h"
#include "llvm/ExecutionEngine/Orc/Speculation.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ThreadPool.h"

#include <list>
#include <string>

using namespace llvm;
using namespace llvm::orc;

static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore,
cl::desc("input files"));

static cl::list<std::string> InputArgv("args", cl::Positional,
cl::desc("<program arguments>..."),
cl::ZeroOrMore, cl::PositionalEatsArgs);

static cl::opt<unsigned> NumThreads("num-threads", cl::Optional,
cl::desc("Number of compile threads"),
cl::init(4));

ExitOnError ExitOnErr;

// Add Layers
class SpeculativeJIT {
public:
static Expected<std::unique_ptr<SpeculativeJIT>> Create() {
auto JTMB = orc::JITTargetMachineBuilder::detectHost();
if (!JTMB)
return JTMB.takeError();

auto DL = JTMB->getDefaultDataLayoutForTarget();
if (!DL)
return DL.takeError();

auto ES = llvm::make_unique<ExecutionSession>();

auto LCTMgr = createLocalLazyCallThroughManager(
JTMB->getTargetTriple(), *ES,
pointerToJITTargetAddress(explodeOnLazyCompileFailure));
if (!LCTMgr)
return LCTMgr.takeError();

auto ISMBuilder =
createLocalIndirectStubsManagerBuilder(JTMB->getTargetTriple());
if (!ISMBuilder)
return make_error<StringError>("No indirect stubs manager for target",
inconvertibleErrorCode());

auto ProcessSymbolsSearchGenerator =
DynamicLibrarySearchGenerator::GetForCurrentProcess(
DL->getGlobalPrefix());
if (!ProcessSymbolsSearchGenerator)
return ProcessSymbolsSearchGenerator.takeError();

std::unique_ptr<SpeculativeJIT> SJ(new SpeculativeJIT(
std::move(ES), std::move(*DL), std::move(*JTMB), std::move(*LCTMgr),
std::move(ISMBuilder), std::move(*ProcessSymbolsSearchGenerator)));
return std::move(SJ);
}

ExecutionSession &getES() { return *ES; }

Error addModule(JITDylib &JD, ThreadSafeModule TSM) {
return CODLayer.add(JD, std::move(TSM));
}

Expected<JITEvaluatedSymbol> lookup(StringRef UnmangledName) {
return ES->lookup({&ES->getMainJITDylib()}, Mangle(UnmangledName));
}

~SpeculativeJIT() { CompileThreads.wait(); }

private:
using IndirectStubsManagerBuilderFunction =
std::function<std::unique_ptr<IndirectStubsManager>()>;

static void explodeOnLazyCompileFailure() {
errs() << "Lazy compilation failed, Symbol Implmentation not found!\n";
exit(1);
}

SpeculativeJIT(std::unique_ptr<ExecutionSession> ES, DataLayout DL,
orc::JITTargetMachineBuilder JTMB,
std::unique_ptr<LazyCallThroughManager> LCTMgr,
IndirectStubsManagerBuilderFunction ISMBuilder,
DynamicLibrarySearchGenerator ProcessSymbolsGenerator)
: ES(std::move(ES)), DL(std::move(DL)), LCTMgr(std::move(LCTMgr)),
CompileLayer(*this->ES, ObjLayer,
ConcurrentIRCompiler(std::move(JTMB))),
S(Imps, *this->ES),
SpeculateLayer(*this->ES, CompileLayer, S, BlockFreqQuery()),
CODLayer(*this->ES, SpeculateLayer, *this->LCTMgr,
std::move(ISMBuilder)) {
this->ES->getMainJITDylib().setGenerator(
std::move(ProcessSymbolsGenerator));
this->CODLayer.setImplMap(&Imps);
this->ES->setDispatchMaterialization(

[this](JITDylib &JD, std::unique_ptr<MaterializationUnit> MU) {
// FIXME: Switch to move capture once we have c 14.
auto SharedMU = std::shared_ptr<MaterializationUnit>(std::move(MU));
auto Work = [SharedMU, &JD]() { SharedMU->doMaterialize(JD); };
CompileThreads.async(std::move(Work));
});
JITEvaluatedSymbol SpeculatorSymbol(JITTargetAddress(&S),
JITSymbolFlags::Exported);
ExitOnErr(this->ES->getMainJITDylib().define(
absoluteSymbols({{Mangle("__orc_speculator"), SpeculatorSymbol}})));
LocalCXXRuntimeOverrides CXXRuntimeoverrides;
ExitOnErr(CXXRuntimeoverrides.enable(this->ES->getMainJITDylib(), Mangle));
}

static std::unique_ptr<SectionMemoryManager> createMemMgr() {
return llvm::make_unique<SectionMemoryManager>();
}

std::unique_ptr<ExecutionSession> ES;
DataLayout DL;
MangleAndInterner Mangle{*ES, DL};
ThreadPool CompileThreads{NumThreads};

Triple TT;
std::unique_ptr<LazyCallThroughManager> LCTMgr;
IRCompileLayer CompileLayer;
ImplSymbolMap Imps;
Speculator S;
RTDyldObjectLinkingLayer ObjLayer{*ES, createMemMgr};
IRSpeculationLayer SpeculateLayer;
CompileOnDemandLayer CODLayer;
};

int main(int argc, char *argv[]) {
// Initialize LLVM.
InitLLVM X(argc, argv);

InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();

cl::ParseCommandLineOptions(argc, argv, "SpeculativeJIT");
ExitOnErr.setBanner(std::string(argv[0]) + ": ");

if (NumThreads < 1) {
errs() << "Speculative compilation requires one or more dedicated compile "
"threads\n";
return 1;
}

// Create a JIT instance.
auto SJ = ExitOnErr(SpeculativeJIT::Create());

// Load the IR inputs.
for (const auto &InputFile : InputFiles) {
SMDiagnostic Err;
auto Ctx = llvm::make_unique<LLVMContext>();
auto M = parseIRFile(InputFile, Err, *Ctx);
if (!M) {
Err.print(argv[0], errs());
return 1;
}

ExitOnErr(SJ->addModule(SJ->getES().getMainJITDylib(),
ThreadSafeModule(std::move(M), std::move(Ctx))));
}

// Build an argv array for the JIT'd main.
std::vector<const char *> ArgV;
ArgV.push_back(argv[0]);
for (const auto &InputArg : InputArgv)
ArgV.push_back(InputArg.data());
ArgV.push_back(nullptr);

// Look up the JIT'd main, cast it to a function pointer, then call it.

auto MainSym = ExitOnErr(SJ->lookup("main"));
int (*Main)(int, const char *[]) =
(int (*)(int, const char *[]))MainSym.getAddress();

Main(ArgV.size() - 1, ArgV.data());

return 0;
}
4 changes: 4 additions & 0 deletions include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
#include "llvm/ExecutionEngine/Orc/Legacy.h"
#include "llvm/ExecutionEngine/Orc/OrcError.h"
#include "llvm/ExecutionEngine/Orc/Speculation.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constant.h"
Expand Down Expand Up @@ -91,6 +92,8 @@ class CompileOnDemandLayer : public IRLayer {
/// Sets the partition function.
void setPartitionFunction(PartitionFunction Partition);

/// Sets the ImplSymbolMap
void setImplMap(ImplSymbolMap *Imp);
/// Emits the given module. This should not be called by clients: it will be
/// called by the JIT when a definition added via the add method is requested.
void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override;
Expand Down Expand Up @@ -128,6 +131,7 @@ class CompileOnDemandLayer : public IRLayer {
PerDylibResourcesMap DylibResources;
PartitionFunction Partition = compileRequested;
SymbolLinkagePromoter PromoteSymbols;
ImplSymbolMap *AliaseeImpls = nullptr;
};

/// Compile-on-demand layer.
Expand Down
9 changes: 6 additions & 3 deletions include/llvm/ExecutionEngine/Orc/LazyReexports.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/Speculation.h"

namespace llvm {

Expand Down Expand Up @@ -159,7 +160,7 @@ class LazyReexportsMaterializationUnit : public MaterializationUnit {
IndirectStubsManager &ISManager,
JITDylib &SourceJD,
SymbolAliasMap CallableAliases,
VModuleKey K);
ImplSymbolMap *SrcJDLoc, VModuleKey K);

StringRef getName() const override;

Expand All @@ -174,6 +175,7 @@ class LazyReexportsMaterializationUnit : public MaterializationUnit {
SymbolAliasMap CallableAliases;
std::shared_ptr<LazyCallThroughManager::NotifyResolvedFunction>
NotifyResolved;
ImplSymbolMap *AliaseeTable;
};

/// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export
Expand All @@ -182,9 +184,10 @@ class LazyReexportsMaterializationUnit : public MaterializationUnit {
inline std::unique_ptr<LazyReexportsMaterializationUnit>
lazyReexports(LazyCallThroughManager &LCTManager,
IndirectStubsManager &ISManager, JITDylib &SourceJD,
SymbolAliasMap CallableAliases, VModuleKey K = VModuleKey()) {
SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc = nullptr,
VModuleKey K = VModuleKey()) {
return llvm::make_unique<LazyReexportsMaterializationUnit>(
LCTManager, ISManager, SourceJD, std::move(CallableAliases),
LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc,
std::move(K));
}

Expand Down
72 changes: 72 additions & 0 deletions include/llvm/ExecutionEngine/Orc/SpeculateAnalyses.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===-- SpeculateAnalyses.h --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// \file
/// Contains the Analyses and Result Interpretation to select likely functions
/// to Speculatively compile before they are called. [Experimentation]
//===----------------------------------------------------------------------===//

#ifndef LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H
#define LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H

#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/Speculation.h"

#include <vector>

namespace {
using namespace llvm;
std::vector<const BasicBlock *> findBBwithCalls(const Function &F,
bool IndirectCall = false) {
std::vector<const BasicBlock *> BBs;

auto findCallInst = [&IndirectCall](const Instruction &I) {
if (auto Call = dyn_cast<CallBase>(&I)) {
if (Call->isIndirectCall())
return IndirectCall;
else
return true;
} else
return false;
};
for (auto &BB : F)
if (findCallInst(*BB.getTerminator()) ||
llvm::any_of(BB.instructionsWithoutDebug(), findCallInst))
BBs.emplace_back(&BB);

return BBs;
}
} // namespace

namespace llvm {

namespace orc {

// Direct calls in high frequency basic blocks are extracted.
class BlockFreqQuery {
private:
void findCalles(const BasicBlock *, DenseSet<StringRef> &);
size_t numBBToGet(size_t);

public:
using ResultTy = Optional<DenseMap<StringRef, DenseSet<StringRef>>>;

// Find likely next executables based on IR Block Frequency
ResultTy operator()(Function &F, FunctionAnalysisManager &FAM);
};

// Walk the CFG by exploting BranchProbabilityInfo
class CFGWalkQuery {
public:
using ResultTy = Optional<DenseMap<StringRef, DenseSet<StringRef>>>;
ResultTy operator()(Function &F, FunctionAnalysisManager &FAM);
};

} // namespace orc
} // namespace llvm

#endif // LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H
Loading

0 comments on commit 25b5b89

Please sign in to comment.