Autoload less libraries

In previous allmodules&autoloading patch, we used callback from
DeserializationListener to get Decl and loaded corresponding libraries.
It worked, but the performance was bad because ROOT was loading
excessive libraries.

In this patch, we use TCling::LazyFunctionCreatorAutoloadForModule. This
function gets callback when "mangled_name" was not found in loaded
libraries thus we have to the load corresponding library and lookup
again.

I used unordered_map to store mangled identifier and library pair. I'm
doing an optimization by hashing mangled name and storing library not by
name but by uint8 and hold uint8-name information in another vector.
Also tried std::map but unorderd_map was more performant. There are
better hash table like:
https://probablydance.com/2018/05/28/a-new-fast-hash-table-in-response-to-googles-new-fast-hash-table/
we can try to use them if this part gets crucial.

With this patch:
```
Processing tutorials/hsimple.C...
hsimple   : Real Time =   0.04 seconds Cpu Time =   0.03 seconds
(TFile *) 0x562b37a14fe0
Processing /home/yuka/CERN/ROOT/memory.C...
cpu  time = 0.362307 seconds
sys  time = 0.039741 seconds
res  memory = 278.215 Mbytes
vir  memory = 448.973 Mbytes
```

W/o this patch:
```
Processing tutorials/hsimple.C...
hsimple   : Real Time =   0.08 seconds Cpu Time =   0.07 seconds
(TFile *) 0x5563018a1d30
Processing /home/yuka/CERN/ROOT/memory.C...
cpu  time = 1.524314 seconds
sys  time = 0.157075 seconds
res  memory = 546.867 Mbytes
vir  memory = 895.184 Mbytes
```

So it improves time by 4x times and memory by 2x.
This commit is contained in:
Yuka Takahashi 2018-05-30 11:15:15 +02:00 committed by sftnight
parent eb9fbe9f2c
commit 35a8988d50
8 changed files with 2 additions and 63 deletions

View File

@ -132,13 +132,6 @@ namespace cling {
///
virtual void TransactionCommitted(const Transaction&) {}
///\brief This callback is invoked before a transaction is executed.
/// This event happens after a transaction was committed and LLVM IR was produced.
///
///\param[in] - The transaction to be executed.
///
virtual void beforeExecuteTransaction(const Transaction&) {}
///\brief This callback is invoked whenever interpreter has reverted a
/// transaction that has been fully committed.
///

View File

@ -31,7 +31,6 @@ namespace clang {
class Preprocessor;
struct PrintingPolicy;
class Sema;
class Module;
}
namespace llvm {
@ -116,11 +115,6 @@ namespace cling {
typedef llvm::SmallVector<DelayCallInfo, 64> DeclQueue;
typedef llvm::SmallVector<Transaction*, 2> NestedTransactions;
///\brief The list of cxxmodules, which is collected by DeserializationListener
/// and will be used to load corresponding libraries.
///
std::vector<clang::Module*> m_CxxModules;
///\brief All seen declarations, except the deserialized ones.
/// If we collect the declarations by walking the clang::DeclContext we
/// will miss the injected onces (eg. template instantiations).
@ -274,17 +268,6 @@ namespace cling {
return const_reverse_nested_iterator(0);
}
void addClangModule(clang::Module* M) {
assert(M && "addClangModules: passed clang::Module pointer is null");
if (std::find(m_CxxModules.rbegin(), m_CxxModules.rend(), M) == m_CxxModules.rend())
m_CxxModules.push_back(M);
}
const std::vector<clang::Module*> &getClangModules() const {
return m_CxxModules;
}
/// Macro iteration
typedef MacroDirectiveInfoQueue::iterator macros_iterator;
typedef MacroDirectiveInfoQueue::const_iterator const_macros_iterator;

View File

@ -321,17 +321,4 @@ namespace cling {
m_Consumer->HandleCXXStaticMemberVarInstantiation(D);
}
void DeclCollector::DeclRead(clang::serialization::DeclID, const clang::Decl *D) {
assertHasTransaction(m_CurTransaction);
assert(D && "Decl doesn't exist!");
if (!D->hasOwningModule()) return;
clang::Module *M = D->getOwningModule();
M = M->getTopLevelModule();
// Add interesting module to Transaction's m_cxxmodules; Corresponding library will be loaded.
m_CurTransaction->addClangModule(M);
}
} // namespace cling

View File

@ -11,7 +11,6 @@
#define CLING_DECL_COLLECTOR_H
#include "clang/AST/ASTConsumer.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "ASTTransformer.h"
@ -25,7 +24,6 @@ namespace clang {
class DeclGroupRef;
class Preprocessor;
class Token;
class Module;
}
namespace cling {
@ -42,7 +40,7 @@ namespace cling {
/// cling::DeclCollector is responsible for appending all the declarations
/// seen by clang.
///
class DeclCollector : public clang::ASTConsumer , public clang::ASTDeserializationListener {
class DeclCollector : public clang::ASTConsumer {
/// \brief PPCallbacks overrides/ Macro support
class PPAdapter;
@ -118,11 +116,6 @@ namespace cling {
// dyn_cast/isa support
static bool classof(const clang::ASTConsumer*) { return true; }
static bool classof(const clang::ASTDeserializationListener*) { return true; }
///\brief ASTDeserializationListener function which gets callback when a decl is deserialized
void DeclRead(clang::serialization::DeclID, const clang::Decl *D) final;
};
} // namespace cling

View File

@ -44,7 +44,6 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@ -227,13 +226,6 @@ namespace cling {
Preprocessor& PP = m_CI->getPreprocessor();
DiagnosticsEngine& Diags = m_CI->getSema().getDiagnostics();
ASTReader* Reader = m_CI->getModuleManager().get();
assert(isa<ASTDeserializationListener>(m_Consumer));
ASTDeserializationListener* Listener = cast<ASTDeserializationListener>(m_Consumer);
// FIXME: We should create a multiplexing deserialization listener if there is one already attached.
if (Reader && Listener && !Reader->getDeserializationListener())
Reader->setDeserializationListener(Listener);
// Pull in PCH.
const std::string& PCHFileName
= m_CI->getInvocation().getPreprocessorOpts().ImplicitPCHInclude;

View File

@ -1529,9 +1529,6 @@ namespace cling {
assert(!isInSyntaxOnlyMode() && "Running on what?");
assert(T.getState() == Transaction::kCommitted && "Must be committed");
if (InterpreterCallbacks* callbacks = getCallbacks())
callbacks->beforeExecuteTransaction(T);
const std::shared_ptr<llvm::Module>& M = T.getModule();
if (!M)
return Interpreter::kExeNoModule;

View File

@ -1452,9 +1452,9 @@ namespace cling {
DigestArgsInput inputEval;
llvm::SmallVector<Expr*, 4> GivenArgs;
Interpreter::PushTransactionRAII pushedT(Interp);
if (!inputEval(GivenArgs,funcArgs,diagOnOff,P,Interp)) return 0;
Interpreter::PushTransactionRAII pushedT(Interp);
return findFunction(foundDC,
funcName, GivenArgs, objectIsConst,
Context, Interp, functionSelector,

View File

@ -77,12 +77,6 @@ namespace cling {
}
}
void beforeExecuteTransaction(const Transaction& T) override {
for (auto&& cb : m_Callbacks) {
cb->beforeExecuteTransaction(T);
}
}
void TransactionUnloaded(const Transaction& T) override {
for (auto&& cb : m_Callbacks) {
cb->TransactionUnloaded(T);