Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
916823d
[cxxmodules] Implement global module indexing to improve performance.
vgvassilev Feb 20, 2019
e4bb1a8
[cxxmodules] Do not cache the file lookup failure.
vgvassilev Jun 30, 2019
7c14fcf
[cxxmodules] Preload only common modules.
vgvassilev Jun 30, 2019
3bda1e6
[cxxmodules][cling] Add a callback for start/finish code generation.
vgvassilev Jul 4, 2019
3db4b28
[tcling] Modernize header file virtual -> override.
vgvassilev Jul 4, 2019
e96522a
[tcling] Modernize header file: use inline initialization.
vgvassilev Jul 4, 2019
66d6e47
[cxxmodules] Tighten the findInGlobalModuleIndex routine.
vgvassilev Jul 5, 2019
9822d02
[cxxmodules] Preload Hist because it has the same issue as Gpad.
vgvassilev Jul 5, 2019
0766260
Preload Graf for the same reason as Hist and Gpad
arpi-r Jul 12, 2019
a77d5ed
Add GenVector FIXMEModules
arpi-r Jul 25, 2019
661f9dd
Do not resolve from require complete type.
vgvassilev Jan 25, 2020
1d59f46
If the identifier is unknown, return false.
vgvassilev Jan 28, 2020
4b38143
Rename the interface, add documentation, make it bool.
vgvassilev Jan 28, 2020
9c06b0d
Preload modules which are not in the index.
vgvassilev Jan 28, 2020
d84e4a0
Add help how to automatically incorporate clang-format changes.
vgvassilev Jan 28, 2020
da1ec92
Preload Tree to fix the messy roottest-root-io-newstl-make
vgvassilev Jan 29, 2020
c0014fd
Do not load recursively modules.
vgvassilev Feb 3, 2020
7d936ae
Preload module Physics.
vgvassilev Feb 3, 2020
0eea44a
Preload Smatrix, TreePlayer, Proof and Geom.
vgvassilev Feb 11, 2020
774c08f
[cxxmodules] Make the global module index opt-in.
vgvassilev Feb 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .ci/format_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ else
echo -e "\n\nPlease apply the code formatting changes without bloating the history."
echo -e "\tConsider running:"
echo -e "\t\tgit checkout $TRAVIS_BRANCH"
echo -e "\t\tgit rebase -i --autosquash -x 'git-clang-format-7 master && git commit -a --amend --no-edit' master"
echo -e "\t\tgit rebase -i -x \"git-clang-format-7 master && git commit -a --allow-empty --fixup=HEAD\" --strategy-option=theirs origin/master"
echo -e "\t Then inspect the results with git log --oneline"
echo -e "\t Then squash without poluting the history with: git rebase --autosquash -i master"

exit 1
fi
131 changes: 109 additions & 22 deletions core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ clang/LLVM technology.
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Parse/Parser.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"

#include "cling/Interpreter/ClangInternalState.h"
#include "cling/Interpreter/DynamicLibraryManager.h"
Expand Down Expand Up @@ -1055,6 +1057,10 @@ static bool LoadModule(const std::string &ModuleName, cling::Interpreter &interp
std::string currentDir = gSystem->WorkingDirectory();
assert(!currentDir.empty());
gCling->RegisterPrebuiltModulePath(currentDir);
if (gDebug > 2)
::Info("TCling::__LoadModule", "Preloading module %s. \n",
ModuleName.c_str());

return interp.loadModule(ModuleName, /*Complain=*/true);
}

Expand All @@ -1073,19 +1079,61 @@ static bool IsFromRootCling() {
return foundSymbol;
}

static std::string GetModuleNameAsString(clang::Module *M, const clang::Preprocessor &PP)
/// Checks if there is an ASTFile on disk for the given module \c M.
static bool HasASTFileOnDisk(clang::Module *M, const clang::Preprocessor &PP, std::string *FullFileName = nullptr)
{
const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();

std::string ModuleFileName;
if (!HSOpts.PrebuiltModulePaths.empty())
// Load the module from *only* in the prebuilt module path.
ModuleFileName = PP.getHeaderSearchInfo().getModuleFileName(M->Name, /*ModuleMapPath*/"", /*UsePrebuiltPath*/ true);
if (ModuleFileName.empty()) return "";
if (FullFileName)
*FullFileName = ModuleFileName;

std::string ModuleName = llvm::sys::path::filename(ModuleFileName);
// Return stem of the filename
return std::string(llvm::sys::path::stem(ModuleName));
return !ModuleFileName.empty();
}

static bool HaveFullGlobalModuleIndex = false;
static GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc, cling::Interpreter &interp)
{
CompilerInstance &CI = *interp.getCI();
Preprocessor &PP = CI.getPreprocessor();
auto ModuleManager = CI.getModuleManager();
assert(ModuleManager);
// StringRef ModuleIndexPath = HSI.getModuleCachePath();
// HeaderSearch& HSI = PP.getHeaderSearchInfo();
// HSI.setModuleCachePath(TROOT::GetLibDir().Data());
std::string ModuleIndexPath = TROOT::GetLibDir().Data();
if (ModuleIndexPath.empty())
return nullptr;
// Get an existing global index. This loads it if not already loaded.
ModuleManager->resetForReload();
ModuleManager->loadGlobalIndex();
GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex();

// For finding modules needing to be imported for fixit messages,
// we need to make the global index cover all modules, so we do that here.
if (!GlobalIndex && !HaveFullGlobalModuleIndex) {
ModuleMap &MMap = PP.getHeaderSearchInfo().getModuleMap();
bool RecreateIndex = false;
for (ModuleMap::module_iterator I = MMap.module_begin(), E = MMap.module_end(); I != E; ++I) {
Module *TheModule = I->second;
// We want the index only of the prebuilt modules.
if (!HasASTFileOnDisk(TheModule, PP))
continue;
LoadModule(TheModule->Name, interp);
RecreateIndex = true;
}
if (RecreateIndex) {
GlobalModuleIndex::writeIndex(CI.getFileManager(), CI.getPCHContainerReader(), ModuleIndexPath);
ModuleManager->resetForReload();
ModuleManager->loadGlobalIndex();
GlobalIndex = ModuleManager->getGlobalIndex();
}
HaveFullGlobalModuleIndex = true;
}
return GlobalIndex;
}

static void RegisterCxxModules(cling::Interpreter &clingInterp)
Expand Down Expand Up @@ -1113,35 +1161,73 @@ static void RegisterCxxModules(cling::Interpreter &clingInterp)
"Core",
"RIO"};

LoadModules(CoreModules, clingInterp);

// FIXME: Reducing those will let us be less dependent on rootmap files
static constexpr std::array<const char *, 3> ExcludeModules = {
{"Rtools", "RSQLite", "RInterface"}};

LoadModules(CoreModules, clingInterp);

// Take this branch only from ROOT because we don't need to preload modules in rootcling
if (!IsFromRootCling()) {
// Dynamically get all the modules and load them if they are not in core modules
std::vector<std::string> CommonModules = {"MathCore"};
LoadModules(CommonModules, clingInterp);

// These modules should not be preloaded but they fix issues.
std::vector<std::string> FIXMEModules = {"Hist", "Gpad", "Graf",
"GenVector", "Smatrix", "Tree",
"TreePlayer", "Physics",
"Proof", "Geom"};
LoadModules(FIXMEModules, clingInterp);

clang::CompilerInstance &CI = *clingInterp.getCI();
clang::ModuleMap &moduleMap = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap();
GlobalModuleIndex *GlobalIndex = nullptr;
if (gSystem->Getenv("ROOT_EXPERIMENTAL_GMI")) {
loadGlobalModuleIndex(SourceLocation(), clingInterp);
GlobalIndex = CI.getModuleManager()->getGlobalIndex();
}
llvm::StringSet<> KnownModuleFileNames;
if (GlobalIndex)
GlobalIndex->getKnownModuleFileNames(KnownModuleFileNames);

clang::Preprocessor &PP = CI.getPreprocessor();
std::vector<std::string> ModulesPreloaded;
for (auto I = moduleMap.module_begin(), E = moduleMap.module_end(); I != E; ++I) {
std::vector<std::string> PendingModules;
PendingModules.reserve(256);
ModuleMap &MMap = PP.getHeaderSearchInfo().getModuleMap();
for (auto I = MMap.module_begin(), E = MMap.module_end(); I != E; ++I) {
clang::Module *M = I->second;
assert(M);

std::string ModuleName = GetModuleNameAsString(M, PP);
if (!ModuleName.empty() &&
std::find(CoreModules.begin(), CoreModules.end(), ModuleName) == CoreModules.end() &&
std::find(ExcludeModules.begin(), ExcludeModules.end(), ModuleName) ==
ExcludeModules.end()) {
if (M->IsSystem && !M->IsMissingRequirement)
LoadModule(ModuleName, clingInterp);
else if (!M->IsSystem && !M->IsMissingRequirement)
ModulesPreloaded.push_back(ModuleName);
// We want to load only already created modules.
std::string FullASTFilePath;
if (!HasASTFileOnDisk(M, PP, &FullASTFilePath))
continue;

if (GlobalIndex && KnownModuleFileNames.count(FullASTFilePath))
continue;

if (M->IsMissingRequirement)
continue;

if (GlobalIndex)
LoadModule(M->Name, clingInterp);
else {
// FIXME: We may be able to remove those checks as cling::loadModule
// checks if a module was alredy loaded.
if (std::find(CoreModules.begin(), CoreModules.end(), M->Name) != CoreModules.end())
continue; // This is a core module which was already loaded.

if (std::find(ExcludeModules.begin(), ExcludeModules.end(), M->Name) != ExcludeModules.end())
continue;

// Load system modules now and delay the other modules after we have
// loaded all system ones.
if (M->IsSystem)
LoadModule(M->Name, clingInterp);
else
PendingModules.push_back(M->Name);
}
}
LoadModules(ModulesPreloaded, clingInterp);
LoadModules(PendingModules, clingInterp);
}

// Check that the gROOT macro was exported by any core module.
Expand Down Expand Up @@ -1325,6 +1411,7 @@ TCling::TCling(const char *name, const char *title, const char* const argv[])

clingArgsStorage.push_back("-fmodule-map-file=" + ModuleMapLoc);
}
clingArgsStorage.push_back("-fmodules-cache-path=" + std::string(TROOT::GetLibDir()));
}

std::vector<const char*> interpArgs;
Expand Down
63 changes: 56 additions & 7 deletions core/metacling/src/TClingCallbacks.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "clang/Parse/Parser.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"

#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -74,11 +76,8 @@ extern "C" {
cling::Interpreter &interpreter, bool searchSystem);
}

TClingCallbacks::TClingCallbacks(cling::Interpreter* interp, bool hasCodeGen)
: InterpreterCallbacks(interp),
fLastLookupCtx(0), fROOTSpecialNamespace(0),
fFirstRun(true), fIsAutoLoading(false), fIsAutoLoadingRecursively(false),
fIsAutoParsingSuspended(false), fPPOldFlag(false), fPPChanged(false) {
TClingCallbacks::TClingCallbacks(cling::Interpreter *interp, bool hasCodeGen) : InterpreterCallbacks(interp)
{
if (hasCodeGen) {
Transaction* T = 0;
m_Interpreter->declare("namespace __ROOT_SpecialObjects{}", &T);
Expand Down Expand Up @@ -285,17 +284,61 @@ bool TClingCallbacks::LookupObject(LookupResult &R, Scope *S) {
return tryResolveAtRuntimeInternal(R, S);
}

bool TClingCallbacks::findInGlobalModuleIndex(DeclarationName Name, bool loadFirstMatchOnly /*=true*/)
{
const CompilerInstance *CI = m_Interpreter->getCI();
const LangOptions &LangOpts = CI->getPreprocessor().getLangOpts();

if (!LangOpts.Modules)
return false;

// We are currently building a module, we should not import .
if (LangOpts.isCompilingModule())
return false;

if (fIsCodeGening)
return false;

GlobalModuleIndex *Index = CI->getModuleManager()->getGlobalIndex();
if (!Index)
return false;

// FIXME: We should load only the first available and rely on other callbacks
// such as RequireCompleteType and LookupUnqualified to load all.
GlobalModuleIndex::FileNameHitSet FoundModules;

// Find the modules that reference the identifier.
// Note that this only finds top-level modules.
if (Index->lookupIdentifier(Name.getAsString(), FoundModules)) {
for (auto FileName : FoundModules) {
StringRef ModuleName = llvm::sys::path::stem(*FileName);
fIsLoadingModule = true;
m_Interpreter->loadModule(ModuleName);
fIsLoadingModule = false;
if (loadFirstMatchOnly)
break;
}
return true;
}
return false;
}

bool TClingCallbacks::LookupObject(const DeclContext* DC, DeclarationName Name) {
if (!fROOTSpecialNamespace) {
// init error or rootcling
return false;
}

if (!IsAutoLoadingEnabled() || fIsAutoLoadingRecursively) return false;
if (fIsLoadingModule)
return false;

if (Name.getNameKind() != DeclarationName::Identifier) return false;
if (!IsAutoLoadingEnabled() || fIsAutoLoadingRecursively) return false;

if (findInGlobalModuleIndex(Name, /*loadFirstMatchOnly*/ false))
return true;

if (Name.getNameKind() != DeclarationName::Identifier)
return false;

// Get the 'lookup' decl context.
// We need to cast away the constness because we will lookup items of this
Expand Down Expand Up @@ -343,9 +386,15 @@ bool TClingCallbacks::LookupObject(clang::TagDecl* Tag) {
return false;
}

if (fIsLoadingModule)
return false;

// Clang needs Tag's complete definition. Can we parse it?
if (fIsAutoLoadingRecursively || fIsAutoParsingSuspended) return false;

// if (findInGlobalModuleIndex(Tag->getDeclName(), /*loadFirstMatchOnly*/false))
// return true;

Sema &SemaR = m_Interpreter->getSema();

SourceLocation Loc = Tag->getLocation();
Expand Down
Loading